summaryrefslogtreecommitdiff
path: root/rsvg_internals/src/filters/ffi.rs
diff options
context:
space:
mode:
Diffstat (limited to 'rsvg_internals/src/filters/ffi.rs')
-rw-r--r--rsvg_internals/src/filters/ffi.rs65
1 files changed, 55 insertions, 10 deletions
diff --git a/rsvg_internals/src/filters/ffi.rs b/rsvg_internals/src/filters/ffi.rs
index 28d4b0eb..957b38eb 100644
--- a/rsvg_internals/src/filters/ffi.rs
+++ b/rsvg_internals/src/filters/ffi.rs
@@ -6,8 +6,8 @@ use libc::c_char;
use drawing_ctx::RsvgDrawingCtx;
use length::RsvgLength;
-use node::{NodeType, RsvgCNodeImpl, RsvgNode};
-use state::{ComputedValues, RsvgComputedValues};
+use node::{NodeType, RsvgNode};
+use state::{ColorInterpolationFilters, ComputedValues, RsvgComputedValues};
use surface_utils::shared_surface::SharedImageSurface;
use super::context::{FilterContext, RsvgFilterContext};
@@ -51,6 +51,27 @@ pub(super) fn render<T: Filter>(
node.with_impl(|filter: &T| filter.render(node, ctx))
}
+/// The type of the `is_affected_by_color_interpolation_filters` function below.
+pub(super) type IsAffectedByColorInterpFunctionType = fn() -> bool;
+
+/// Container for the filter function pointers. Needed to pass them around with C pointers.
+#[derive(Clone, Copy)]
+pub(super) struct FilterFunctionPointers {
+ render: RenderFunctionType,
+ is_affected_by_color_interpolation_filters: IsAffectedByColorInterpFunctionType,
+}
+
+impl FilterFunctionPointers {
+ /// Creates a `FilterFunctionPointers` filled with pointers for `T`.
+ pub(super) fn new<T: Filter>() -> Self {
+ Self {
+ render: render::<T>,
+ is_affected_by_color_interpolation_filters:
+ T::is_affected_by_color_interpolation_filters,
+ }
+ }
+}
+
/// Creates a new surface applied the filter. This function will create a context for itself, set up
/// the coordinate systems execute all its little primitives and then clean up its own mess.
pub fn filter_render(
@@ -103,7 +124,17 @@ pub fn filter_render(
&& c.get_type() < NodeType::FilterPrimitiveLast
})
.filter(|c| !c.is_in_error())
- .for_each(|mut c| match c.get_type() {
+ .map(|c| {
+ let linear_rgb = {
+ let cascaded = c.get_cascaded_values();
+ let values = cascaded.get();
+
+ values.color_interpolation_filters == ColorInterpolationFilters::LinearRgb
+ };
+
+ (c, linear_rgb)
+ })
+ .for_each(|(mut c, linear_rgb)| match c.get_type() {
NodeType::FilterPrimitiveBlend
| NodeType::FilterPrimitiveComponentTransfer
| NodeType::FilterPrimitiveComposite
@@ -111,23 +142,37 @@ pub fn filter_render(
| NodeType::FilterPrimitiveImage
| NodeType::FilterPrimitiveMerge
| NodeType::FilterPrimitiveOffset => {
- let render = unsafe {
- *(&c.get_c_impl() as *const *const RsvgCNodeImpl as *const RenderFunctionType)
+ let pointers = unsafe { *(c.get_c_impl() as *const FilterFunctionPointers) };
+
+ let mut render = |filter_ctx: &mut FilterContext| {
+ match (pointers.render)(&c, filter_ctx) {
+ Ok(result) => filter_ctx.store_result(result),
+ Err(_) => { /* Do nothing for now */ }
+ }
};
- match render(&c, &filter_ctx) {
- Ok(result) => filter_ctx.store_result(result),
- Err(_) => { /* Do nothing for now */ }
+
+ if (pointers.is_affected_by_color_interpolation_filters)() && linear_rgb {
+ filter_ctx.with_linear_rgb(render);
+ } else {
+ render(&mut filter_ctx);
}
}
_ => {
let filter = unsafe { &mut *(c.get_c_impl() as *mut RsvgFilterPrimitive) };
- unsafe {
+
+ let mut render = |filter_ctx: &mut FilterContext| unsafe {
(filter.render.unwrap())(
&mut c,
&c.get_cascaded_values().get() as &ComputedValues as RsvgComputedValues,
filter,
- &mut filter_ctx,
+ filter_ctx,
);
+ };
+
+ if linear_rgb {
+ filter_ctx.with_linear_rgb(render);
+ } else {
+ render(&mut filter_ctx);
}
}
});