[librsvg: 16/45] Replace the two gradient nodes with a single NodeGradient
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 16/45] Replace the two gradient nodes with a single NodeGradient
- Date: Tue, 1 Oct 2019 15:08:17 +0000 (UTC)
commit cede339afc3f381161b976b855b25def0d7ba377
Author: Federico Mena Quintero <federico gnome org>
Date: Fri Sep 27 13:43:30 2019 -0500
Replace the two gradient nodes with a single NodeGradient
NodeGradient has an enum for the gradient's variant, instead of having
macros that generate two different gradient types.
This commit also removes conicalGradient, which is from Calligra's
Karbon; it was being rendered as a radialGradient as a hack to "just
do something" with it. Instead, we'll wait until Cairo supports
conical gradients (SVG1 and SVG2 don't).
rsvg_internals/src/create_node.rs | 10 +-
rsvg_internals/src/drawing_ctx.rs | 10 +-
rsvg_internals/src/gradient.rs | 385 ++++++++++++++++++++------------------
rsvg_internals/src/node.rs | 3 +-
4 files changed, 207 insertions(+), 201 deletions(-)
---
diff --git a/rsvg_internals/src/create_node.rs b/rsvg_internals/src/create_node.rs
index 0c21995e..32011d58 100644
--- a/rsvg_internals/src/create_node.rs
+++ b/rsvg_internals/src/create_node.rs
@@ -22,7 +22,7 @@ use crate::filters::{
turbulence::Turbulence,
};
-use crate::gradient::{NodeLinearGradient, NodeRadialGradient, NodeStop};
+use crate::gradient::{NodeGradient, NodeStop};
use crate::image::NodeImage;
use crate::link::NodeLink;
use crate::marker::NodeMarker;
@@ -75,8 +75,8 @@ mod creators {
n!(create_group, Group, NodeGroup::default);
n!(create_image, Image, NodeImage::default);
n!(create_fe_image, FeImage, Image::default);
- n!(create_linear_gradient, LinearGradient, NodeLinearGradient::default);
n!(create_line, Line, NodeLine::default);
+ n!(create_linear_gradient, Gradient, NodeGradient::new_linear);
n!(create_link, Link, NodeLink::default);
n!(create_marker, Marker, NodeMarker::default);
n!(create_mask, Mask, NodeMask::default);
@@ -90,7 +90,7 @@ mod creators {
n!(create_point_light, PointLight, LightSource::new_point_light);
n!(create_polygon, Polygon, NodePoly::new_closed);
n!(create_polyline, Polyline, NodePoly::new_open);
- n!(create_radial_gradient, RadialGradient, NodeRadialGradient::default);
+ n!(create_radial_gradient, Gradient, NodeGradient::new_radial);
n!(create_rect, Rect, NodeRect::default);
n!(create_specular_lighting, FeSpecularLighting, Lighting::new_specular);
n!(create_spot_light, SpotLight, LightSource::new_spot_light);
@@ -106,9 +106,6 @@ mod creators {
n!(create_turbulence, FeTurbulence, Turbulence::default);
n!(create_use, Use, NodeUse::default);
- // hack to partially support conical gradient
- n!(create_conical_gradient, RadialGradient, NodeRadialGradient::default);
-
// hack to make multiImage sort-of work
n!(create_multi_image, Switch, NodeSwitch::default);
n!(create_sub_image, Group, NodeGroup::default);
@@ -142,7 +139,6 @@ lazy_static! {
c!(h, "circle", true, create_circle);
c!(h, "clipPath", true, create_clip_path);
/* c!(h, "color-profile", false, ); */
- c!(h, "conicalGradient", true, create_conical_gradient);
/* c!(h, "cursor", false, ); */
c!(h, "defs", true, create_defs);
/* c!(h, "desc", true, ); */
diff --git a/rsvg_internals/src/drawing_ctx.rs b/rsvg_internals/src/drawing_ctx.rs
index 269eb118..c1b360f5 100644
--- a/rsvg_internals/src/drawing_ctx.rs
+++ b/rsvg_internals/src/drawing_ctx.rs
@@ -13,7 +13,7 @@ use crate::coord_units::CoordUnits;
use crate::dpi::Dpi;
use crate::error::RenderingError;
use crate::filters;
-use crate::gradient::{NodeLinearGradient, NodeRadialGradient};
+use crate::gradient::NodeGradient;
use crate::length::Dasharray;
use crate::mask::NodeMask;
use crate::node::{CascadedValues, NodeDraw, NodeType, RsvgNode};
@@ -619,13 +619,9 @@ impl DrawingCtx {
let node = acquired.get();
had_paint_server = match node.borrow().get_type() {
- NodeType::LinearGradient => node
+ NodeType::Gradient => node
.borrow()
- .get_impl::<NodeLinearGradient>()
- .resolve_fallbacks_and_set_pattern(&node, self, opacity, bbox)?,
- NodeType::RadialGradient => node
- .borrow()
- .get_impl::<NodeRadialGradient>()
+ .get_impl::<NodeGradient>()
.resolve_fallbacks_and_set_pattern(&node, self, opacity, bbox)?,
NodeType::Pattern => node
.borrow()
diff --git a/rsvg_internals/src/gradient.rs b/rsvg_internals/src/gradient.rs
index 1381113d..47b7182c 100644
--- a/rsvg_internals/src/gradient.rs
+++ b/rsvg_internals/src/gradient.rs
@@ -124,11 +124,7 @@ impl CommonGradient {
self.add_color_stops_to_pattern(pattern, opacity);
}
- fn add_color_stops_to_pattern(
- &self,
- pattern: &cairo::Gradient,
- opacity: &UnitInterval,
- ) {
+ fn add_color_stops_to_pattern(&self, pattern: &cairo::Gradient, opacity: &UnitInterval) {
for stop in &self.stops {
let UnitInterval(stop_offset) = stop.offset;
let &UnitInterval(o) = opacity;
@@ -185,7 +181,13 @@ impl CommonGradientData {
fn to_resolved(self) -> CommonGradient {
assert!(self.is_resolved());
- let CommonGradientData { units, affine, spread, stops, .. } = self;
+ let CommonGradientData {
+ units,
+ affine,
+ spread,
+ stops,
+ ..
+ } = self;
CommonGradient {
units: units.unwrap(),
@@ -237,10 +239,7 @@ impl CommonGradientData {
}
fn add_color_stops_from_node(&mut self, node: &RsvgNode) {
- assert!(
- node.borrow().get_type() == NodeType::LinearGradient
- || node.borrow().get_type() == NodeType::RadialGradient
- );
+ assert!(node.borrow().get_type() == NodeType::Gradient);
for child in node
.children()
@@ -521,150 +520,218 @@ impl NodeTrait for NodeStop {
}
}
-macro_rules! impl_node_trait {
- ($gradient_type:ty) => {
- impl NodeTrait for $gradient_type {
- fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
- self.common.set_atts(pbag)?;
- self.variant.set_atts(pbag)?;
+#[derive(Clone)]
+enum GradientVariant {
+ Linear(LinearGradientData),
+ Radial(RadialGradientData),
+}
- for (attr, value) in pbag.iter() {
- match attr {
- local_name!("xlink:href") => {
- self.fallback = Some(Fragment::parse(value).attribute(attr)?)
- }
- _ => (),
- }
- }
+enum ResolvedGradientVariant {
+ Linear(LinearGradient),
+ Radial(RadialGradient),
+}
+
+impl GradientVariant {
+ fn to_resolved(self) -> ResolvedGradientVariant {
+ match self {
+ GradientVariant::Linear(v) => ResolvedGradientVariant::Linear(v.to_resolved()),
+ GradientVariant::Radial(v) => ResolvedGradientVariant::Radial(v.to_resolved()),
+ }
+ }
+
+ fn is_resolved(&self) -> bool {
+ match *self {
+ GradientVariant::Linear(v) => v.is_resolved(),
+ GradientVariant::Radial(v) => v.is_resolved(),
+ }
+ }
+
+ fn resolve_from_fallback(&mut self, fallback: &GradientVariant) {
+ match (self, fallback) {
+ (&mut GradientVariant::Linear(ref mut v), &GradientVariant::Linear(ref f)) => {
+ v.resolve_from_fallback(f)
+ }
- Ok(())
+ (&mut GradientVariant::Radial(ref mut v), &GradientVariant::Radial(ref f)) => {
+ v.resolve_from_fallback(f)
}
+
+ _ => (), // If variants are of different types, then nothing to resolve
+ }
+ }
+
+ fn resolve_from_defaults(&mut self) {
+ match *self {
+ GradientVariant::Linear(ref mut v) => v.resolve_from_defaults(),
+ GradientVariant::Radial(ref mut v) => v.resolve_from_defaults(),
+ }
+ }
+}
+
+#[derive(Clone)]
+pub struct NodeGradient {
+ common: CommonGradientData,
+ variant: GradientVariant,
+ fallback: Option<Fragment>,
+}
+
+pub struct ResolvedGradient {
+ common: CommonGradient,
+ variant: ResolvedGradientVariant,
+}
+
+impl NodeGradient {
+ pub fn new_linear() -> NodeGradient {
+ NodeGradient {
+ common: Default::default(),
+ variant: GradientVariant::Linear(LinearGradientData::default()),
+ fallback: Default::default(),
+ }
+ }
+
+ pub fn new_radial() -> NodeGradient {
+ NodeGradient {
+ common: Default::default(),
+ variant: GradientVariant::Radial(RadialGradientData::default()),
+ fallback: Default::default(),
}
- };
+ }
+
+ fn to_resolved(self) -> ResolvedGradient {
+ let NodeGradient {
+ common, variant, ..
+ } = self;
+
+ match variant {
+ GradientVariant::Linear(_) => ResolvedGradient {
+ common: common.to_resolved(),
+ variant: variant.to_resolved(),
+ },
+
+ GradientVariant::Radial(_) => ResolvedGradient {
+ common: common.to_resolved(),
+ variant: variant.to_resolved(),
+ },
+ }
+ }
}
-macro_rules! impl_to_resolved {
- ($gradient_type:tt, $resolved:tt) => {
- impl $gradient_type {
- fn to_resolved(self) -> $resolved {
- assert!(self.is_resolved());
+impl NodeTrait for NodeGradient {
+ fn set_atts(&mut self, _: Option<&RsvgNode>, pbag: &PropertyBag<'_>) -> NodeResult {
+ self.common.set_atts(pbag)?;
- let $gradient_type { common, variant, .. } = self;
+ match self.variant {
+ GradientVariant::Linear(ref mut v) => v.set_atts(pbag)?,
+ GradientVariant::Radial(ref mut v) => v.set_atts(pbag)?,
+ }
- $resolved {
- common: common.to_resolved(),
- variant: variant.to_resolved(),
+ for (attr, value) in pbag.iter() {
+ match attr {
+ local_name!("xlink:href") => {
+ self.fallback = Some(Fragment::parse(value).attribute(attr)?)
}
+ _ => (),
}
}
- };
+
+ Ok(())
+ }
}
+impl Resolve for NodeGradient {
+ fn is_resolved(&self) -> bool {
+ self.common.is_resolved() && self.variant.is_resolved()
+ }
-macro_rules! impl_resolve {
- ($gradient_type:ty) => {
- impl Resolve for $gradient_type {
- fn is_resolved(&self) -> bool {
- self.common.is_resolved() && self.variant.is_resolved()
- }
+ fn resolve_from_fallback(&mut self, fallback: &NodeGradient) {
+ self.common.resolve_from_fallback(&fallback.common);
+ self.variant.resolve_from_fallback(&fallback.variant);
+ }
- fn resolve_from_fallback(&mut self, fallback: &$gradient_type) {
- self.common.resolve_from_fallback(&fallback.common);
- self.variant.resolve_from_fallback(&fallback.variant);
- }
+ fn resolve_from_defaults(&mut self) {
+ self.common.resolve_from_defaults();
+ self.variant.resolve_from_defaults();
+ }
+}
- fn resolve_from_defaults(&mut self) {
- self.common.resolve_from_defaults();
- self.variant.resolve_from_defaults();
- }
- }
- };
-}
-
-macro_rules! impl_paint_source {
- ($gradient:ty, $node_type:pat, $other_gradient:ty, $other_type:pat, $resolved:ty,) => {
- impl PaintSource for $gradient {
- type Resolved = $resolved;
-
- fn resolve(
- &self,
- node: &RsvgNode,
- draw_ctx: &mut DrawingCtx,
- bbox: &BoundingBox,
- ) -> Result<Option<Self::Resolved>, RenderingError> {
- let mut result = self.clone();
- result.common.add_color_stops_from_node(node);
-
- let mut stack = NodeStack::new();
-
- while !result.is_resolved() {
- let acquired = acquire_gradient(draw_ctx, result.fallback.as_ref());
-
- if let Some(acquired) = acquired {
- let a_node = acquired.get();
-
- if stack.contains(a_node) {
- rsvg_log!("circular reference in gradient {}", node);
- return Err(RenderingError::CircularReference);
- }
-
- match a_node.borrow().get_type() {
- // Same type, resolve all attributes
- $node_type => {
- let mut fallback = a_node.borrow().get_impl::<$gradient>().clone();
- fallback.common.add_color_stops_from_node(a_node);
- result.resolve_from_fallback(&fallback);
- }
- // Other type of gradient, resolve common attributes
- $other_type => {
- let mut fallback =
- a_node.borrow().get_impl::<$other_gradient>().clone();
- fallback.common.add_color_stops_from_node(a_node);
- result.common.resolve_from_fallback(&fallback.common);
- }
- _ => (),
- }
-
- stack.push(a_node);
-
- continue;
- }
-
- result.resolve_from_defaults();
- }
+impl PaintSource for NodeGradient {
+ type Resolved = ResolvedGradient;
+
+ fn resolve(
+ &self,
+ node: &RsvgNode,
+ draw_ctx: &mut DrawingCtx,
+ bbox: &BoundingBox,
+ ) -> Result<Option<Self::Resolved>, RenderingError> {
+ let mut result = self.clone();
+ result.common.add_color_stops_from_node(node);
+
+ let mut stack = NodeStack::new();
+
+ while !result.is_resolved() {
+ let acquired = acquire_gradient(draw_ctx, result.fallback.as_ref());
+
+ if let Some(acquired) = acquired {
+ let a_node = acquired.get();
- if result.common.bounds_are_valid(bbox) {
- Ok(Some(result.to_resolved()))
- } else {
- Ok(None)
+ if stack.contains(a_node) {
+ rsvg_log!("circular reference in gradient {}", node);
+ return Err(RenderingError::CircularReference);
}
+
+ let mut a_gradient = a_node.borrow().get_impl::<NodeGradient>().clone();
+ a_gradient.common.add_color_stops_from_node(a_node);
+ result.resolve_from_fallback(&a_gradient);
+
+ stack.push(a_node);
+
+ continue;
}
+
+ result.resolve_from_defaults();
}
- impl ResolvedPaintSource for $resolved {
- fn set_pattern_on_draw_context(
- self,
- values: &ComputedValues,
- draw_ctx: &mut DrawingCtx,
- opacity: &UnitInterval,
- bbox: &BoundingBox,
- ) -> Result<bool, RenderingError> {
- let units = self.common.units;
- let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
- draw_ctx.push_view_box(1.0, 1.0)
- } else {
- draw_ctx.get_view_params()
- };
+ if result.common.bounds_are_valid(bbox) {
+ Ok(Some(result.to_resolved()))
+ } else {
+ Ok(None)
+ }
+ }
+}
- let p = self.variant.to_cairo_gradient(values, ¶ms);
- self.common.set_on_cairo_pattern(&p, bbox, opacity);
- let cr = draw_ctx.get_cairo_context();
- cr.set_source(&p);
+impl ResolvedPaintSource for ResolvedGradient {
+ fn set_pattern_on_draw_context(
+ self,
+ values: &ComputedValues,
+ draw_ctx: &mut DrawingCtx,
+ opacity: &UnitInterval,
+ bbox: &BoundingBox,
+ ) -> Result<bool, RenderingError> {
+ let units = self.common.units;
+ let params = if units == GradientUnits(CoordUnits::ObjectBoundingBox) {
+ draw_ctx.push_view_box(1.0, 1.0)
+ } else {
+ draw_ctx.get_view_params()
+ };
- Ok(true)
+ let p = match self.variant {
+ ResolvedGradientVariant::Linear(v) => {
+ let g = v.to_cairo_gradient(values, ¶ms);
+ cairo::Gradient::clone(&g)
}
- }
- };
+
+ ResolvedGradientVariant::Radial(v) => {
+ let g = v.to_cairo_gradient(values, ¶ms);
+ cairo::Gradient::clone(&g)
+ }
+ };
+
+ self.common.set_on_cairo_pattern(&p, bbox, opacity);
+ let cr = draw_ctx.get_cairo_context();
+ cr.set_source(&p);
+
+ Ok(true)
+ }
}
fn acquire_gradient<'a>(
@@ -675,7 +742,7 @@ fn acquire_gradient<'a>(
.and_then(|acquired| {
let node_type = acquired.get().borrow().get_type();
- if node_type == NodeType::LinearGradient || node_type == NodeType::RadialGradient {
+ if node_type == NodeType::Gradient {
Some(acquired)
} else {
None
@@ -683,58 +750,6 @@ fn acquire_gradient<'a>(
})
}
-#[derive(Clone, Default)]
-pub struct NodeLinearGradient {
- common: CommonGradientData,
- variant: LinearGradientData,
- fallback: Option<Fragment>,
-}
-
-pub struct ResolvedLinearGradient {
- common: CommonGradient,
- variant: LinearGradient,
-}
-
-impl_node_trait!(NodeLinearGradient);
-
-impl_to_resolved!(NodeLinearGradient, ResolvedLinearGradient);
-
-impl_resolve!(NodeLinearGradient);
-
-impl_paint_source!(
- NodeLinearGradient,
- NodeType::LinearGradient,
- NodeRadialGradient,
- NodeType::RadialGradient,
- ResolvedLinearGradient,
-);
-
-#[derive(Clone, Default)]
-pub struct NodeRadialGradient {
- common: CommonGradientData,
- variant: RadialGradientData,
- fallback: Option<Fragment>,
-}
-
-pub struct ResolvedRadialGradient {
- common: CommonGradient,
- variant: RadialGradient,
-}
-
-impl_node_trait!(NodeRadialGradient);
-
-impl_to_resolved!(NodeRadialGradient, ResolvedRadialGradient);
-
-impl_resolve!(NodeRadialGradient);
-
-impl_paint_source!(
- NodeRadialGradient,
- NodeType::RadialGradient,
- NodeLinearGradient,
- NodeType::LinearGradient,
- ResolvedRadialGradient,
-);
-
#[cfg(test)]
mod tests {
use super::*;
@@ -770,11 +785,11 @@ mod tests {
#[test]
fn gradient_resolved_from_defaults_is_really_resolved() {
- let mut l = NodeLinearGradient::default();
+ let mut l = NodeGradient::new_linear();
l.resolve_from_defaults();
assert!(l.is_resolved());
- let mut r = NodeRadialGradient::default();
+ let mut r = NodeGradient::new_radial();
r.resolve_from_defaults();
assert!(r.is_resolved());
}
diff --git a/rsvg_internals/src/node.rs b/rsvg_internals/src/node.rs
index fa3f7b26..7ff22d7a 100644
--- a/rsvg_internals/src/node.rs
+++ b/rsvg_internals/src/node.rs
@@ -406,10 +406,10 @@ pub enum NodeType {
DistantLight,
Ellipse,
Filter,
+ Gradient,
Group,
Image,
Line,
- LinearGradient,
Link,
Marker,
Mask,
@@ -419,7 +419,6 @@ pub enum NodeType {
PointLight,
Polygon,
Polyline,
- RadialGradient,
Rect,
SpotLight,
Stop,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]