(#273) - Pass the node being filtered down to the filter rendering functions

feImage wants to render the node it is referencing via href, but with
a cascade from the node to which the filter is being applied - similar
to the <use> element.  This requires that we are able to obtain the
node, to which the filter is being applied, from the filter rendering
function.

This commit introduces FilterContext::get_node_being_filtered().

pop_discrete_layer() also takes a node - this is so that it can create
the FilterContext with the node that is being filtered.

Also, Node::draw_children() now takes a node argument, so it can pass
it to pop_discrete_layer().

This makes filters-composite-02-b.svg render almost exactly like the
SVG 1.1 official reference image, except for the Arithmetic column;
the lower-right item has an extra row of pixels on top...

We regenerate filters-composite-02-b-ref.png for now.

GNOME/librsvg#273
parent 778e0b93
Pipeline #14405 passed with stages
in 28 minutes and 59 seconds
......@@ -171,6 +171,9 @@ const int *rsvg_filter_context_get_channelmap (const RsvgFilterContext *ctx);
G_GNUC_INTERNAL
RsvgDrawingCtx *rsvg_filter_context_get_drawing_ctx (RsvgFilterContext *ctx);
G_GNUC_INTERNAL
RsvgNode *rsvg_filter_context_get_node_being_filtered (RsvgFilterContext *ctx);
G_GNUC_INTERNAL
int rsvg_filter_context_get_previous_result (GString *name,
const RsvgFilterContext *ctx,
......
......@@ -44,6 +44,7 @@ rsvg_filter_primitive_image_render_in (RsvgFilterPrimitiveImage *image, RsvgFilt
{
RsvgDrawingCtx *ctx;
RsvgNode *drawable;
RsvgNode *node_being_filtered;
cairo_matrix_t paffine;
cairo_t *cr;
cairo_surface_t *result;
......@@ -67,13 +68,17 @@ rsvg_filter_primitive_image_render_in (RsvgFilterPrimitiveImage *image, RsvgFilt
if (!result)
return NULL;
node_being_filtered = rsvg_filter_context_get_node_being_filtered (context);
rsvg_drawing_ctx_draw_node_on_surface (ctx,
drawable,
NULL,
node_being_filtered,
result,
rsvg_filter_context_get_width (context),
rsvg_filter_context_get_height (context));
node_being_filtered = rsvg_node_unref (node_being_filtered);
rsvg_drawing_ctx_release_node (ctx, drawable);
return result;
......
......@@ -55,7 +55,7 @@ impl NodeClipPath {
let save_affine = cr.get_matrix();
cr.set_matrix(child_matrix);
node.draw_children(&cascaded, draw_ctx, false, true);
node.draw_children(node, &cascaded, draw_ctx, false, true);
cr.set_matrix(save_affine);
......
......@@ -156,9 +156,14 @@ pub fn push_discrete_layer(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValue
}
}
pub fn pop_discrete_layer(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues, clipping: bool) {
pub fn pop_discrete_layer(
draw_ctx: *mut RsvgDrawingCtx,
node: &RsvgNode,
values: &ComputedValues,
clipping: bool,
) {
if !clipping {
pop_render_stack(draw_ctx, values);
pop_render_stack(draw_ctx, node, values);
get_cairo_context(draw_ctx).restore();
}
}
......@@ -342,7 +347,7 @@ fn push_render_stack(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues) {
}
}
fn pop_render_stack(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues) {
fn pop_render_stack(draw_ctx: *mut RsvgDrawingCtx, node: &RsvgNode, values: &ComputedValues) {
let child_cr = get_cairo_context(draw_ctx);
let clip_path = match values.clip_path {
......@@ -407,6 +412,7 @@ fn pop_render_stack(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues) {
if let Some(acquired) = get_acquired_node_of_type(draw_ctx, filter, NodeType::Filter) {
filter_render(
&acquired.get(),
node,
&output,
draw_ctx,
"2103".as_ptr() as *const i8,
......@@ -525,7 +531,7 @@ pub extern "C" fn rsvg_drawing_ctx_draw_node_from_stack(
let cascade_from = if raw_cascade_from.is_null() {
None
} else {
Some (unsafe { &*raw_cascade_from })
Some(unsafe { &*raw_cascade_from })
};
let clipping: bool = from_glib(clipping);
......
......@@ -11,7 +11,7 @@ use bbox::BoundingBox;
use coord_units::CoordUnits;
use drawing_ctx::{self, RsvgDrawingCtx};
use length::RsvgLength;
use node::RsvgNode;
use node::{box_node, RsvgNode};
use state::ComputedValues;
use super::input::Input;
......@@ -65,6 +65,8 @@ pub type RsvgFilterContext = FilterContext;
pub struct FilterContext {
/// The <filter> node.
node: RsvgNode,
/// The node which referenced this filter
node_being_filtered: RsvgNode,
/// The source graphic surface.
source_surface: cairo::ImageSurface,
/// Output of the last filter primitive.
......@@ -82,6 +84,7 @@ impl FilterContext {
/// Creates a new `FilterContext`.
pub fn new(
filter_node: &RsvgNode,
node_being_filtered: &RsvgNode,
source_surface: cairo::ImageSurface,
draw_ctx: *mut RsvgDrawingCtx,
channelmap: [i32; 4],
......@@ -127,6 +130,7 @@ impl FilterContext {
let mut rv = Self {
node: filter_node.clone(),
node_being_filtered: node_being_filtered.clone(),
source_surface,
last_result: None,
previous_results: HashMap::new(),
......@@ -151,6 +155,12 @@ impl FilterContext {
self.node.clone()
}
/// Returns the node that referenced this filter.
#[inline]
pub fn get_node_being_filtered(&self) -> RsvgNode {
self.node_being_filtered.clone()
}
/// Returns the surface corresponding to the last filter primitive's result.
#[inline]
pub fn last_result(&self) -> Option<&FilterOutput> {
......@@ -368,6 +378,15 @@ pub unsafe extern "C" fn rsvg_filter_context_get_height(ctx: *const RsvgFilterCo
(*ctx).source_surface.get_height()
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_filter_context_get_node_being_filtered(
ctx: *const RsvgFilterContext,
) -> *mut RsvgNode {
assert!(!ctx.is_null());
box_node((*ctx).get_node_being_filtered())
}
#[no_mangle]
pub unsafe extern "C" fn rsvg_filter_context_get_channelmap(
ctx: *const RsvgFilterContext,
......
......@@ -54,6 +54,7 @@ pub(super) fn render<T: Filter>(
/// the coordinate systems execute all its little primitives and then clean up its own mess.
pub fn filter_render(
filter_node: &RsvgNode,
node_being_filtered: &RsvgNode,
source: &cairo::ImageSurface,
context: *mut RsvgDrawingCtx,
channelmap: *const c_char,
......@@ -71,7 +72,13 @@ pub fn filter_render(
}
}
let mut filter_ctx = FilterContext::new(filter_node, source.clone(), context, channelmap_arr);
let mut filter_ctx = FilterContext::new(
filter_node,
node_being_filtered,
source.clone(),
context,
channelmap_arr,
);
filter_node
.children()
......
......@@ -107,7 +107,7 @@ impl NodeTrait for NodeImage {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -145,7 +145,7 @@ impl NodeTrait for NodeImage {
cr.restore();
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
}
}
}
......
......@@ -52,6 +52,7 @@ pub use filters::context::{
rsvg_filter_context_get_drawing_ctx,
rsvg_filter_context_get_height,
rsvg_filter_context_get_lastresult,
rsvg_filter_context_get_node_being_filtered,
rsvg_filter_context_get_paffine,
rsvg_filter_context_get_previous_result,
rsvg_filter_context_get_source_surface,
......
......@@ -59,6 +59,7 @@ impl NodeTrait for NodeLink {
attributes.as_ref().map(|i| i.as_str()),
|| {
node.draw_children(
node,
&CascadedValues::new(cascaded, node),
draw_ctx,
with_layer,
......@@ -68,6 +69,7 @@ impl NodeTrait for NodeLink {
)
} else {
node.draw_children(
node,
&CascadedValues::new(cascaded, node),
draw_ctx,
with_layer,
......
......@@ -190,9 +190,9 @@ impl NodeMarker {
}
}
node.draw_children(&cascaded, draw_ctx, false, clipping);
node.draw_children(node, &cascaded, draw_ctx, false, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, &values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, &values, clipping);
drawing_ctx::pop_view_box(draw_ctx);
......
......@@ -130,7 +130,7 @@ impl NodeMask {
drawing_ctx::push_view_box(draw_ctx, 1.0, 1.0);
}
node.draw_children(&cascaded, draw_ctx, true, false);
node.draw_children(node, &cascaded, draw_ctx, true, false);
if content_units == CoordUnits::ObjectBoundingBox {
drawing_ctx::pop_view_box(draw_ctx);
......
......@@ -411,6 +411,7 @@ impl Node {
pub fn draw_children(
&self,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
with_layer: bool,
......@@ -433,7 +434,7 @@ impl Node {
}
if with_layer {
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
}
}
......
......@@ -418,9 +418,9 @@ fn set_pattern_on_draw_context(
drawing_ctx::push_discrete_layer(draw_ctx, pattern_values, false);
cr_pattern.set_matrix(caffine);
pattern_node.draw_children(&pattern_cascaded, draw_ctx, false, false);
pattern_node.draw_children(&pattern_node, &pattern_cascaded, draw_ctx, false, false);
drawing_ctx::pop_discrete_layer(draw_ctx, pattern_values, false);
drawing_ctx::pop_discrete_layer(draw_ctx, &pattern_node, pattern_values, false);
// Return to the original coordinate system and rendering context
......
......@@ -21,6 +21,7 @@ use util::utf8_cstr_opt;
fn render_path_builder(
builder: &PathBuilder,
draw_ctx: *mut RsvgDrawingCtx,
node: &RsvgNode,
values: &ComputedValues,
render_markers: bool,
clipping: bool,
......@@ -29,7 +30,7 @@ fn render_path_builder(
draw_path_builder(draw_ctx, values, builder, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
if render_markers {
marker::render_markers_for_path_builder(builder, draw_ctx, values, clipping);
......@@ -42,6 +43,7 @@ fn render_ellipse(
rx: f64,
ry: f64,
draw_ctx: *mut RsvgDrawingCtx,
node: &RsvgNode,
values: &ComputedValues,
clipping: bool,
) {
......@@ -96,7 +98,7 @@ fn render_ellipse(
builder.close_path();
render_path_builder(&builder, draw_ctx, values, false, clipping);
render_path_builder(&builder, draw_ctx, node, values, false, clipping);
}
// ************ NodePath ************
......@@ -132,7 +134,7 @@ impl NodeTrait for NodePath {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -141,7 +143,7 @@ impl NodeTrait for NodePath {
let values = cascaded.get();
if let Some(ref builder) = *self.builder.borrow() {
render_path_builder(builder, draw_ctx, values, true, clipping);
render_path_builder(builder, draw_ctx, node, values, true, clipping);
}
}
}
......@@ -192,7 +194,7 @@ impl NodeTrait for NodePoly {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -215,7 +217,7 @@ impl NodeTrait for NodePoly {
builder.close_path();
}
render_path_builder(&builder, draw_ctx, values, true, clipping);
render_path_builder(&builder, draw_ctx, node, values, true, clipping);
}
}
}
......@@ -260,7 +262,7 @@ impl NodeTrait for NodeLine {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -278,7 +280,7 @@ impl NodeTrait for NodeLine {
builder.move_to(x1, y1);
builder.line_to(x2, y2);
render_path_builder(&builder, draw_ctx, values, true, clipping);
render_path_builder(&builder, draw_ctx, node, values, true, clipping);
}
}
......@@ -354,7 +356,7 @@ impl NodeTrait for NodeRect {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -496,7 +498,7 @@ impl NodeTrait for NodeRect {
builder.close_path ();
}
render_path_builder(&builder, draw_ctx, values, false, clipping);
render_path_builder(&builder, draw_ctx, node, values, false, clipping);
}
}
......@@ -541,7 +543,7 @@ impl NodeTrait for NodeCircle {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -553,7 +555,7 @@ impl NodeTrait for NodeCircle {
let cy = self.cy.get().normalize(values, draw_ctx);
let r = self.r.get().normalize(values, draw_ctx);
render_ellipse(cx, cy, r, r, draw_ctx, values, clipping);
render_ellipse(cx, cy, r, r, draw_ctx, node, values, clipping);
}
}
......@@ -607,7 +609,7 @@ impl NodeTrait for NodeEllipse {
fn draw(
&self,
_node: &RsvgNode,
node: &RsvgNode,
cascaded: &CascadedValues,
draw_ctx: *mut RsvgDrawingCtx,
_with_layer: bool,
......@@ -620,7 +622,7 @@ impl NodeTrait for NodeEllipse {
let rx = self.rx.get().normalize(values, draw_ctx);
let ry = self.ry.get().normalize(values, draw_ctx);
render_ellipse(cx, cy, rx, ry, draw_ctx, values, clipping);
render_ellipse(cx, cy, rx, ry, draw_ctx, node, values, clipping);
}
}
......
......@@ -41,7 +41,7 @@ impl NodeTrait for NodeGroup {
with_layer: bool,
clipping: bool,
) {
node.draw_children(cascaded, draw_ctx, with_layer, clipping);
node.draw_children(node, cascaded, draw_ctx, with_layer, clipping);
}
}
......@@ -96,7 +96,7 @@ impl NodeTrait for NodeSwitch {
);
}
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
}
}
......@@ -207,12 +207,13 @@ impl NodeTrait for NodeSvg {
do_clip,
self.vbox.get(),
self.preserve_aspect_ratio.get(),
node,
values,
drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
draw_ctx,
clipping,
|| {
node.draw_children(cascaded, draw_ctx, false, clipping);
node.draw_children(node, cascaded, draw_ctx, false, clipping);
},
);
}
......@@ -340,7 +341,7 @@ impl NodeTrait for NodeUse {
clipping,
);
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
} else {
child.with_impl(|symbol: &NodeSymbol| {
let do_clip = !values.is_overflow()
......@@ -355,6 +356,7 @@ impl NodeTrait for NodeUse {
do_clip,
symbol.vbox.get(),
symbol.preserve_aspect_ratio.get(),
node,
values,
drawing_ctx::get_cairo_context(draw_ctx).get_matrix(),
draw_ctx,
......@@ -362,12 +364,13 @@ impl NodeTrait for NodeUse {
|| {
drawing_ctx::push_discrete_layer(draw_ctx, values, clipping);
child.draw_children(
&child,
&CascadedValues::new_from_values(&child, values),
draw_ctx,
false,
clipping,
);
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
},
);
});
......
......@@ -669,7 +669,7 @@ fn render_children(
render_child(&child, cascaded, draw_ctx, x, y, textonly, clipping);
}
drawing_ctx::pop_discrete_layer(draw_ctx, values, clipping);
drawing_ctx::pop_discrete_layer(draw_ctx, node, values, clipping);
}
fn render_child(
......
......@@ -5,6 +5,7 @@ use aspect_ratio::AspectRatio;
use draw::add_clipping_rect;
use drawing_ctx::{self, RsvgDrawingCtx};
use float_eq_cairo::ApproxEqCairo;
use node::RsvgNode;
use state::ComputedValues;
use viewbox::*;
......@@ -23,6 +24,7 @@ pub fn draw_in_viewport<F>(
do_clip: bool,
vbox: Option<ViewBox>,
preserve_aspect_ratio: AspectRatio,
node: &RsvgNode,
values: &ComputedValues,
affine: cairo::Matrix,
draw_ctx: *mut RsvgDrawingCtx,
......@@ -43,6 +45,7 @@ pub fn draw_in_viewport<F>(
do_clip,
vbox,
preserve_aspect_ratio,
node,
values,
affine,
clipping,
......@@ -54,7 +57,7 @@ trait ViewportCtx {
fn push_view_box(&mut self, width: f64, height: f64);
fn pop_view_box(&mut self);
fn push_discrete_layer(&mut self, values: &ComputedValues, clipping: bool);
fn pop_discrete_layer(&mut self, values: &ComputedValues, clipping: bool);
fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool);
fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64);
fn set_affine(&mut self, affine: cairo::Matrix);
}
......@@ -74,8 +77,8 @@ impl ViewportCtx for RsvgDrawingCtxWrapper {
drawing_ctx::push_discrete_layer(self.0, values, clipping);
}
fn pop_discrete_layer(&mut self, values: &ComputedValues, clipping: bool) {
drawing_ctx::pop_discrete_layer(self.0, values, clipping);
fn pop_discrete_layer(&mut self, node: &RsvgNode, values: &ComputedValues, clipping: bool) {
drawing_ctx::pop_discrete_layer(self.0, node, values, clipping);
}
fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
......@@ -97,6 +100,7 @@ fn in_viewport<F>(
do_clip: bool,
vbox: Option<ViewBox>,
preserve_aspect_ratio: AspectRatio,
node: &RsvgNode,
values: &ComputedValues,
mut affine: cairo::Matrix,
clipping: bool,
......@@ -158,14 +162,28 @@ fn in_viewport<F>(
draw_fn();
ctx.pop_view_box();
ctx.pop_discrete_layer(values, clipping);
ctx.pop_discrete_layer(node, values, clipping);
}
#[cfg(test)]
mod tests {
use super::*;
use std::ptr;
use std::rc::Rc;
use handle::RsvgHandle;
use node::{Node, NodeResult, NodeTrait, NodeType};
use parsers::Parse;
use property_bag::PropertyBag;
struct TestNodeImpl {}
impl NodeTrait for TestNodeImpl {
fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, _: &PropertyBag) -> NodeResult {
Ok(())
}
}
#[derive(Default, PartialEq)]
struct Ctx {
pub view_box_size: Option<(f64, f64)>,
......@@ -186,7 +204,13 @@ mod tests {
fn push_discrete_layer(&mut self, _values: &ComputedValues, _clipping: bool) {}
fn pop_discrete_layer(&mut self, _values: &ComputedValues, _clipping: bool) {}
fn pop_discrete_layer(
&mut self,
_node: &RsvgNode,
_values: &ComputedValues,
_clipping: bool,
) {
}
fn add_clipping_rect(&mut self, x: f64, y: f64, w: f64, h: f64) {
self.clipping_rect = Some((x, y, w, h));
......@@ -209,6 +233,14 @@ mod tests {
affine: cairo::Matrix,
ctx: &mut Ctx,
) {
let node = Rc::new(Node::new(
NodeType::Path,
None,
None,
ptr::null_mut(),
Box::new(TestNodeImpl {}),
));
in_viewport(
ctx,
vx,
......@@ -219,6 +251,7 @@ mod tests {
do_clip,
vbox,
preserve_aspect_ratio,
&node,
&ComputedValues::default(),
affine,
false,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment