diff options
Diffstat (limited to 'rsvg_internals/src/filters/ffi.rs')
-rw-r--r-- | rsvg_internals/src/filters/ffi.rs | 65 |
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); } } }); |