Commit a9f76253 authored by Federico Mena Quintero's avatar Federico Mena Quintero

Merge branch 'YaLTeR/librsvg-filters-to-rust-2'

parents 072e1c11 8cee3df6
Pipeline #14299 passed with stages
in 28 minutes and 42 seconds
......@@ -52,7 +52,6 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/rsvg-defs.c \
librsvg/rsvg-defs.h \
librsvg/rsvg-file-util.c \
librsvg/rsvg-filter.c \
librsvg/rsvg-filter.h \
librsvg/rsvg-handle.c \
librsvg/rsvg-io.c \
......@@ -90,7 +89,9 @@ RUST_SRC = \
rsvg_internals/src/filters/error.rs \
rsvg_internals/src/filters/ffi.rs \
rsvg_internals/src/filters/mod.rs \
rsvg_internals/src/filters/node.rs \
rsvg_internals/src/filters/input.rs \
rsvg_internals/src/filters/iterators.rs \
rsvg_internals/src/filters/offset.rs \
rsvg_internals/src/error.rs \
rsvg_internals/src/float_eq_cairo.rs \
......
......@@ -441,15 +441,15 @@ rsvg_art_affine_image (cairo_surface_t *img,
return TRUE;
}
void
rsvg_filter_free_pair (gpointer value)
{
RsvgFilterPrimitiveOutput *output;
output = (RsvgFilterPrimitiveOutput *) value;
cairo_surface_destroy (output->surface);
g_free (output);
}
// void
// rsvg_filter_free_pair (gpointer value)
// {
// RsvgFilterPrimitiveOutput *output;
//
// output = (RsvgFilterPrimitiveOutput *) value;
// cairo_surface_destroy (output->surface);
// g_free (output);
// }
// void
// rsvg_filter_context_free (RsvgFilterContext * ctx)
......@@ -671,61 +671,61 @@ rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx)
return surface;
}
void
rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
{
RsvgFilter *filter = impl;
RsvgPropertyBagIter *iter;
const char *key;
RsvgAttribute attr;
const char *value;
iter = rsvg_property_bag_iter_begin (atts);
while (rsvg_property_bag_iter_next (iter, &key, &attr, &value)) {
switch (attr) {
case RSVG_ATTRIBUTE_FILTER_UNITS:
if (!strcmp (value, "userSpaceOnUse"))
filter->filterunits = userSpaceOnUse;
else
filter->filterunits = objectBoundingBox;
break;
case RSVG_ATTRIBUTE_PRIMITIVE_UNITS:
if (!strcmp (value, "objectBoundingBox"))
filter->primitiveunits = objectBoundingBox;
else
filter->primitiveunits = userSpaceOnUse;
break;
case RSVG_ATTRIBUTE_X:
filter->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
break;
case RSVG_ATTRIBUTE_Y:
filter->y = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
break;
case RSVG_ATTRIBUTE_WIDTH:
filter->width = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
break;
case RSVG_ATTRIBUTE_HEIGHT:
filter->height = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
break;
default:
break;
}
}
rsvg_property_bag_iter_end (iter);
}
void
rsvg_filter_free (gpointer impl)
{
RsvgFilter *filter = impl;
g_free (filter);
}
// void
// rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
// {
// RsvgFilter *filter = impl;
// RsvgPropertyBagIter *iter;
// const char *key;
// RsvgAttribute attr;
// const char *value;
//
// iter = rsvg_property_bag_iter_begin (atts);
//
// while (rsvg_property_bag_iter_next (iter, &key, &attr, &value)) {
// switch (attr) {
// case RSVG_ATTRIBUTE_FILTER_UNITS:
// if (!strcmp (value, "userSpaceOnUse"))
// filter->filterunits = userSpaceOnUse;
// else
// filter->filterunits = objectBoundingBox;
// break;
//
// case RSVG_ATTRIBUTE_PRIMITIVE_UNITS:
// if (!strcmp (value, "objectBoundingBox"))
// filter->primitiveunits = objectBoundingBox;
// else
// filter->primitiveunits = userSpaceOnUse;
// break;
//
// case RSVG_ATTRIBUTE_X:
// filter->x = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
// break;
//
// case RSVG_ATTRIBUTE_Y:
// filter->y = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
// break;
//
// case RSVG_ATTRIBUTE_WIDTH:
// filter->width = rsvg_length_parse (value, LENGTH_DIR_HORIZONTAL);
// break;
//
// case RSVG_ATTRIBUTE_HEIGHT:
// filter->height = rsvg_length_parse (value, LENGTH_DIR_VERTICAL);
// break;
//
// default:
// break;
// }
// }
//
// rsvg_property_bag_iter_end (iter);
// }
//
// void
// rsvg_filter_free (gpointer impl)
// {
// RsvgFilter *filter = impl;
//
// g_free (filter);
// }
......@@ -105,22 +105,22 @@ gboolean rsvg_art_affine_image (cairo_surface_t *img,
double w,
double h);
G_GNUC_INTERNAL
void rsvg_filter_draw (RsvgNode *node,
gpointer impl,
RsvgDrawingCtx *ctx,
RsvgState *state,
int dominate,
gboolean clipping);
// G_GNUC_INTERNAL
// void rsvg_filter_draw (RsvgNode *node,
// gpointer impl,
// RsvgDrawingCtx *ctx,
// RsvgState *state,
// int dominate,
// gboolean clipping);
// G_GNUC_INTERNAL
// void rsvg_filter_fix_coordinate_system (RsvgFilterContext * ctx, RsvgState * state, RsvgBbox *bbox);
G_GNUC_INTERNAL
void rsvg_filter_free (gpointer impl);
// G_GNUC_INTERNAL
// void rsvg_filter_free (gpointer impl);
G_GNUC_INTERNAL
void rsvg_filter_free_pair (gpointer value);
// G_GNUC_INTERNAL
// void rsvg_filter_free_pair (gpointer value);
G_GNUC_INTERNAL
cairo_surface_t *rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx);
......@@ -128,8 +128,8 @@ cairo_surface_t *rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx);
G_GNUC_INTERNAL
RsvgFilterPrimitiveOutput rsvg_filter_get_result (GString * name, RsvgFilterContext * ctx);
G_GNUC_INTERNAL
void rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts);
// G_GNUC_INTERNAL
// void rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts);
// G_GNUC_INTERNAL
// void rsvg_filter_store_result (GString * name,
......@@ -150,9 +150,6 @@ gint rsvg_filter_context_get_width (const RsvgFilterContext *ctx);
G_GNUC_INTERNAL
gint rsvg_filter_context_get_height (const RsvgFilterContext *ctx);
G_GNUC_INTERNAL
const RsvgFilter *rsvg_filter_context_get_filter (const RsvgFilterContext *ctx);
G_GNUC_INTERNAL
cairo_surface_t *rsvg_filter_context_get_source_surface (RsvgFilterContext *ctx);
......
/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* vim: set sw=4 sts=4 expandtab: */
/*
rsvg-filter.c: Provides filters
Copyright (C) 2004 Caleb Moore
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this program; if not, write to the
Free Software Foundation, Inc., 59 Temple Place - Suite 330,
Boston, MA 02111-1307, USA.
Author: Caleb Moore <c.moore@student.unsw.edu.au>
*/
#include "config.h"
#include "rsvg-private.h"
#include "rsvg-filter.h"
#include "rsvg-styles.h"
#include "rsvg-css.h"
#include "rsvg-drawing-ctx.h"
#include "filters/common.h"
/**
* rsvg_new_filter:
*
* Creates a blank filter and assigns default values to everything
**/
RsvgNode *
rsvg_new_filter (const char *element_name, RsvgNode *parent)
{
RsvgFilter *filter;
filter = g_new0 (RsvgFilter, 1);
filter->filterunits = objectBoundingBox;
filter->primitiveunits = userSpaceOnUse;
filter->x = rsvg_length_parse ("-10%", LENGTH_DIR_HORIZONTAL);
filter->y = rsvg_length_parse ("-10%", LENGTH_DIR_VERTICAL);
filter->width = rsvg_length_parse ("120%", LENGTH_DIR_HORIZONTAL);
filter->height = rsvg_length_parse ("120%", LENGTH_DIR_VERTICAL);
return rsvg_rust_cnode_new (RSVG_NODE_TYPE_FILTER,
parent,
filter,
rsvg_filter_set_atts,
rsvg_filter_free);
}
......@@ -34,13 +34,13 @@ typedef struct {
int x0, y0, x1, y1;
} RsvgIRect;
typedef RsvgCoordUnits RsvgFilterUnits;
struct _RsvgFilter {
RsvgLength x, y, width, height;
RsvgFilterUnits filterunits;
RsvgFilterUnits primitiveunits;
};
// typedef RsvgCoordUnits RsvgFilterUnits;
//
// struct _RsvgFilter {
// RsvgLength x, y, width, height;
// RsvgFilterUnits filterunits;
// RsvgFilterUnits primitiveunits;
// };
/**
* rsvg_filter_render:
......@@ -61,8 +61,10 @@ cairo_surface_t *rsvg_filter_render (RsvgNode *filter_node,
RsvgDrawingCtx *context,
char *channelmap);
/* Implemented in rust/src/filters/node.rs */
G_GNUC_INTERNAL
RsvgNode *rsvg_new_filter (const char *element_name, RsvgNode *parent);
G_GNUC_INTERNAL
RsvgNode *rsvg_new_filter_primitive_blend (const char *element_name, RsvgNode *parent);
G_GNUC_INTERNAL
......
......@@ -61,5 +61,5 @@ version = "0.6"
[lib]
name = "rsvg_internals"
crate-type = ["staticlib"]
crate-type = ["staticlib", "lib"]
#![feature(test)]
extern crate cairo;
extern crate cairo_sys;
extern crate rsvg_internals;
extern crate test;
#[cfg(test)]
mod tests {
use super::*;
use rsvg_internals::filters::context::IRect;
use rsvg_internals::filters::iterators;
use test::Bencher;
const SURFACE_SIDE: i32 = 512;
const BOUNDS: IRect = IRect {
x0: 64,
y0: 32,
x1: 448,
y1: 480,
};
#[bench]
fn bench_straightforward(b: &mut Bencher) {
let mut surface =
cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE).unwrap();
let stride = surface.get_stride();
let data = surface.get_data().unwrap();
b.iter(|| {
let mut r = 0usize;
let mut g = 0usize;
let mut b = 0usize;
let mut a = 0usize;
for y in BOUNDS.y0..BOUNDS.y1 {
for x in BOUNDS.x0..BOUNDS.x1 {
let base = (y * stride + x * 4) as usize;
r += data[base + 0] as usize;
g += data[base + 1] as usize;
b += data[base + 2] as usize;
a += data[base + 3] as usize;
}
}
(r, g, b, a)
})
}
#[bench]
fn bench_straightforward_getpixel(b: &mut Bencher) {
let surface =
cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE).unwrap();
let data = iterators::ImageSurfaceDataShared::new(&surface).unwrap();
b.iter(|| {
let mut r = 0usize;
let mut g = 0usize;
let mut b = 0usize;
let mut a = 0usize;
for y in BOUNDS.y0..BOUNDS.y1 {
for x in BOUNDS.x0..BOUNDS.x1 {
let pixel = data.get_pixel(x as usize, y as usize);
r += pixel.r as usize;
g += pixel.g as usize;
b += pixel.b as usize;
a += pixel.a as usize;
}
}
(r, g, b, a)
})
}
#[bench]
fn bench_pixels(b: &mut Bencher) {
let surface =
cairo::ImageSurface::create(cairo::Format::ARgb32, SURFACE_SIDE, SURFACE_SIDE).unwrap();
let data = iterators::ImageSurfaceDataShared::new(&surface).unwrap();
b.iter(|| {
let mut r = 0usize;
let mut g = 0usize;
let mut b = 0usize;
let mut a = 0usize;
for (_x, _y, pixel) in iterators::Pixels::new(data, BOUNDS) {
r += pixel.r as usize;
g += pixel.g as usize;
b += pixel.b as usize;
a += pixel.a as usize;
}
(r, g, b, a)
})
}
}
use std::cell::{Cell, RefCell};
use std::slice;
use cairo::prelude::SurfaceExt;
use cairo::{self, ImageSurface};
use cairo_sys;
use libc::c_char;
use attributes::Attribute;
......@@ -17,7 +14,8 @@ use util::clamp;
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::{Filter, FilterError, PrimitiveWithInput};
use super::iterators::{ImageSurfaceDataShared, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};
/// Enumeration of the possible compositing operations.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
......@@ -101,59 +99,25 @@ impl Filter for Composite {
fn render(&self, _node: &RsvgNode, ctx: &FilterContext) -> Result<FilterResult, FilterError> {
let bounds = self.base.get_bounds(ctx);
let input_surface = match self.base.get_input(ctx) {
Some(FilterOutput { surface, .. }) => surface,
None => return Err(FilterError::InvalidInput),
};
let input_2_surface = match ctx.get_input(self.in2.borrow().as_ref()) {
Some(FilterOutput { surface, .. }) => surface,
None => return Err(FilterError::InvalidInput),
};
let input_surface = get_surface(self.base.get_input(ctx))?;
let input_2_surface = get_surface(ctx.get_input(self.in2.borrow().as_ref()))?;
// It's important to linearize sRGB before doing any blending, since otherwise the colors
// will be darker than they should be.
let input_surface =
linearize_surface(&input_surface, bounds).map_err(FilterError::BadInputSurfaceStatus)?;
let width = input_surface.get_width();
let height = input_surface.get_height();
let input_stride = input_surface.get_stride();
let input_2_stride = input_2_surface.get_stride();
let output_surface = if self.operator.get() == Operator::Arithmetic {
// TODO: this currently gives "non-exclusive access" (can we make read-only borrows?)
// let input_data = input_surface.get_data().unwrap();
input_surface.flush();
if input_surface.status() != cairo::Status::Success {
return Err(FilterError::BadInputSurfaceStatus(input_surface.status()));
}
let input_data_ptr =
unsafe { cairo_sys::cairo_image_surface_get_data(input_surface.to_raw_none()) };
if input_data_ptr.is_null() {
return Err(FilterError::InputSurfaceDataAccess);
}
let input_data_len = input_stride as usize * height as usize;
let input_data = unsafe { slice::from_raw_parts(input_data_ptr, input_data_len) };
let input_2_surface = linearize_surface(&input_2_surface, bounds)
.map_err(FilterError::BadInputSurfaceStatus)?;
input_2_surface.flush();
if input_2_surface.status() != cairo::Status::Success {
return Err(FilterError::BadInputSurfaceStatus(input_2_surface.status()));
}
let input_2_data_ptr =
unsafe { cairo_sys::cairo_image_surface_get_data(input_2_surface.to_raw_none()) };
if input_2_data_ptr.is_null() {
return Err(FilterError::InputSurfaceDataAccess);
}
let input_2_data_len = input_2_stride as usize * height as usize;
let input_2_data = unsafe { slice::from_raw_parts(input_2_data_ptr, input_2_data_len) };
let input_data = ImageSurfaceDataShared::new(&input_surface)?;
let input_2_data = ImageSurfaceDataShared::new(&input_2_surface)?;
let mut output_surface = ImageSurface::create(cairo::Format::ARgb32, width, height)
.map_err(FilterError::OutputSurfaceCreation)?;
let mut output_surface = ImageSurface::create(
cairo::Format::ARgb32,
input_data.width as i32,
input_data.height as i32,
).map_err(FilterError::OutputSurfaceCreation)?;
let output_stride = output_surface.get_stride();
let output_stride = output_surface.get_stride() as usize;
{
let mut output_data = output_surface.get_data().unwrap();
......@@ -162,36 +126,38 @@ impl Filter for Composite {
let k3 = self.k3.get();
let k4 = self.k4.get();
for y in bounds.y0..bounds.y1 {
for x in bounds.x0..bounds.x1 {
let i1a =
f64::from(input_data[(y * input_stride + 4 * x + 3) as usize]) / 255f64;
let i2a = f64::from(input_2_data[(y * input_2_stride + 4 * x + 3) as usize])
/ 255f64;
let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
let oa = clamp(oa, 0f64, 1f64);
// Contents of image surfaces are transparent by default, so if the
// resulting pixel is transparent there's no need
// to do anything.
if oa > 0f64 {
output_data[(y * output_stride + 4 * x + 3) as usize] =
(oa * 255f64).round() as u8;
for ch in 0..3 {
let i1 = f64::from(
input_data[(y * input_stride + 4 * x + ch) as usize],
) / 255f64;
let i2 = f64::from(
input_2_data[(y * input_2_stride + 4 * x + ch) as usize],
) / 255f64;
let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
let o = clamp(o, 0f64, oa);
let o = (o * 255f64).round() as u8;
output_data[(y * output_stride + 4 * x + ch) as usize] = o;
}
for (x, y, pixel, pixel_2) in Pixels::new(input_data, bounds)
.map(|(x, y, p)| (x, y, p, input_2_data.get_pixel(x, y)))
{
let i1a = f64::from(pixel.a) / 255f64;
let i2a = f64::from(pixel_2.a) / 255f64;
let oa = k1 * i1a * i2a + k2 * i1a + k3 * i2a + k4;
let oa = clamp(oa, 0f64, 1f64);
let output_base = y * output_stride + 4 * x;
// Contents of image surfaces are transparent by default, so if the
// resulting pixel is transparent there's no need
// to do anything.
if oa > 0f64 {
output_data[output_base + 3] = (oa * 255f64).round() as u8;
// TODO: make this much better with mutable pixel iterators for output.
for (ch, &(i1, i2)) in [
(pixel.r, pixel_2.r),
(pixel.g, pixel_2.g),
(pixel.b, pixel_2.b),
].iter()
.enumerate()
{
let i1 = f64::from(i1) / 255f64;
let i2 = f64::from(i2) / 255f64;
let o = k1 * i1 * i2 + k2 * i1 + k3 * i2 + k4;
let o = clamp(o, 0f64, oa);
let o = (o * 255f64).round() as u8;
output_data[output_base + ch] = o;
}
}
}
......
......@@ -15,6 +15,7 @@ use node::RsvgNode;
use state::ComputedValues;
use super::input::Input;
use super::node::NodeFilter;
use super::RsvgFilterPrimitive;
// Required by the C code until all filters are ported to Rust.
......@@ -29,21 +30,6 @@ pub struct IRect {
pub y1: i32,
}
// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/rsvg-filter.h:_RsvgFilter
#[repr(C)]
pub struct RsvgFilter {
pub x: RsvgLength,
pub y: RsvgLength,
pub width: RsvgLength,
pub height: RsvgLength,
pub filterunits: CoordUnits,
pub primitiveunits: CoordUnits,
}
pub type RsvgFilterContext = FilterContext;
// Required by the C code until all filters are ported to Rust.
// Keep this in sync with
// ../../librsvg/librsvg/filters/common.h:_RsvgFilterPrimitiveOutput
......@@ -73,9 +59,11 @@ pub struct FilterResult {
pub output: FilterOutput,
}
pub type RsvgFilterContext = FilterContext;
/// The filter rendering context.
pub struct FilterContext {
/// the <filter> node
/// The <filter> node.
node: RsvgNode,
/// The source graphic surface.
source_surface: cairo::ImageSurface,
......@@ -86,7 +74,6 @@ pub struct FilterContext {
affine: cairo::Matrix,
paffine: cairo::Matrix,
filter: *mut RsvgFilter,
drawing_ctx: *mut RsvgDrawingCtx,
channelmap: [i32; 4],
}
......@@ -94,14 +81,11 @@ pub struct FilterContext {
impl FilterContext {
/// Creates a new `FilterContext`.
pub fn new(
filter: *mut RsvgFilter,
filter_node: &RsvgNode,
source_surface: cairo::ImageSurface,
draw_ctx: *mut RsvgDrawingCtx,
channelmap: [i32; 4],
) -> Self {
assert!(!filter.is_null());
let cascaded = filter_node.get_cascaded_values();
let values = cascaded.get();
......@@ -109,7 +93,9 @@ impl FilterContext {
let bbox = drawing_ctx::get_bbox(draw_ctx);
let bbox_rect = bbox.rect.unwrap();
let affine = match unsafe { (*filter).filterunits } {
let filter = filter_node.get_impl::<NodeFilter>().unwrap();
let affine = match filter.filterunits.get() {
CoordUnits::UserSpaceOnUse => cr_affine,
CoordUnits::ObjectBoundingBox => {
let affine = cairo::Matrix::new(
......@@ -124,7 +110,7 @@ impl FilterContext {
}
};
let paffine = match unsafe { (*filter).primitiveunits } {
let paffine = match filter.primitiveunits.get() {
CoordUnits::UserSpaceOnUse => cr_affine,
CoordUnits::ObjectBoundingBox => {
let affine = cairo::Matrix::new(
......@@ -146,7 +132,6 @@ impl FilterContext {
previous_results: HashMap::new(),
affine,
paffine,
filter,
drawing_ctx: draw_ctx,
channelmap,
};
......@@ -160,6 +145,8 @@ impl FilterContext {
rv
}
/// Returns the <filter> node for this context.
#[inline]
pub fn get_filter_node(&self) -> RsvgNode {
self.node.clone()
}
......@@ -228,21 +215,21 @@ impl FilterContext {
width: Option<RsvgLength>,
height: Option<RsvgLength>,
) -> IRect {
let filter = unsafe { &*self.filter };
let filter = self.node.get_impl::<NodeFilter>().unwrap();
let mut bbox = BoundingBox::new(&cairo::Matrix::identity());
if filter.filterunits == CoordUnits::ObjectBoundingBox {
if filter.filterunits.get() == CoordUnits::ObjectBoundingBox {
drawing_ctx::push_view_box(self.drawing_ctx, 1f64, 1f64);
}
let rect = cairo::Rectangle {
x: filter.x.normalize(values, self.drawing_ctx),
y: filter.y.normalize(values, self.drawing_ctx),
width: filter.width.normalize(values, self.drawing_ctx),
height: filter.height.normalize(values, self.drawing_ctx),
x: filter.x.get().normalize(values, self.drawing_ctx),
y: filter.y.get().normalize(values, self.drawing_ctx),
width: filter.width.get().normalize(values, self.drawing_ctx),
height: filter.height.get().normalize(values, self.drawing_ctx),
};
if filter.filterunits == CoordUnits::ObjectBoundingBox {
if filter.filterunits.get() == CoordUnits::ObjectBoundingBox {
drawing_ctx::pop_view_box(self.drawing_ctx);
}
......@@ -250,7 +237,7 @@ impl FilterContext {
bbox.insert(&other_bbox);
if x.is_some() || y.is_some() || width.is_some() || height.is_some() {
if filter.primitiveunits == CoordUnits::ObjectBoundingBox {
if filter.primitiveunits.get() == CoordUnits::ObjectBoundingBox {
drawing_ctx::push_view_box(self.drawing_ctx, 1f64, 1f64);
}
......@@ -273,7 +260,7 @@ impl FilterContext {
.unwrap_or(vbox_height);
}
if filter.primitiveunits == CoordUnits::ObjectBoundingBox {
if filter.primitiveunits.get() == CoordUnits::ObjectBoundingBox {
drawing_ctx::pop_view_box(self.drawing_ctx);