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

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

parents 5a2dd2a8 0d6e1b81
Pipeline #14436 failed with stages
in 10 minutes and 6 seconds
......@@ -34,7 +34,6 @@ librsvg_@RSVG_API_MAJOR_VERSION@_la_SOURCES = \
librsvg/filters/image.c \
librsvg/filters/light_source.c \
librsvg/filters/light_source.h \
librsvg/filters/merge.c \
librsvg/filters/specular_lighting.c \
librsvg/filters/tile.c \
librsvg/filters/turbulence.c \
......@@ -88,6 +87,7 @@ RUST_SRC = \
rsvg_internals/src/filters/context.rs \
rsvg_internals/src/filters/error.rs \
rsvg_internals/src/filters/ffi.rs \
rsvg_internals/src/filters/merge.rs \
rsvg_internals/src/filters/mod.rs \
rsvg_internals/src/filters/node.rs \
rsvg_internals/src/filters/input.rs \
......
......@@ -560,36 +560,36 @@ surface_get_alpha (cairo_surface_t *source,
return surface;
}
static cairo_surface_t *
rsvg_compile_bg (RsvgDrawingCtx * ctx)
{
cairo_surface_t *surface;
cairo_t *cr;
double x, y;
GList *i;
surface = _rsvg_image_surface_new (rsvg_drawing_ctx_get_width (ctx),
rsvg_drawing_ctx_get_height (ctx));
if (surface == NULL)
return NULL;
cr = cairo_create (surface);
rsvg_drawing_ctx_get_raw_offset (ctx, &x, &y);
for (i = g_list_last (ctx->cr_stack); i != NULL; i = g_list_previous (i)) {
cairo_t *draw = i->data;
gboolean nest = rsvg_drawing_ctx_is_cairo_context_nested (ctx, draw);
cairo_set_source_surface (cr, cairo_get_target (draw),
nest ? 0 : -x,
nest ? 0 : -y);
cairo_paint (cr);
}
cairo_destroy (cr);
return surface;
}
// static cairo_surface_t *
// rsvg_compile_bg (RsvgDrawingCtx * ctx)
// {
// cairo_surface_t *surface;
// cairo_t *cr;
// double x, y;
// GList *i;
//
// surface = _rsvg_image_surface_new (rsvg_drawing_ctx_get_width (ctx),
// rsvg_drawing_ctx_get_height (ctx));
// if (surface == NULL)
// return NULL;
//
// cr = cairo_create (surface);
//
// rsvg_drawing_ctx_get_raw_offset (ctx, &x, &y);
//
// for (i = g_list_last (ctx->cr_stack); i != NULL; i = g_list_previous (i)) {
// cairo_t *draw = i->data;
// gboolean nest = rsvg_drawing_ctx_is_cairo_context_nested (ctx, draw);
// cairo_set_source_surface (cr, cairo_get_target (draw),
// nest ? 0 : -x,
// nest ? 0 : -y);
// cairo_paint (cr);
// }
//
// cairo_destroy (cr);
//
// return surface;
// }
/**
* rsvg_filter_get_bg:
......@@ -605,71 +605,61 @@ rsvg_compile_bg (RsvgDrawingCtx * ctx)
// return ctx->bg_surface;
// }
/**
* rsvg_filter_get_result:
* @name: The name of the surface
* @ctx: the context that this was called in
*
* Gets a surface for a primitive
*
* Returns: (nullable): a pointer to the result that the name refers to, a special
* surface if the name is a special keyword or %NULL if nothing was found
**/
RsvgFilterPrimitiveOutput
rsvg_filter_get_result (GString * name, RsvgFilterContext * ctx)
{
RsvgFilterPrimitiveOutput output;
output.bounds.x0 = output.bounds.x1 = output.bounds.y0 = output.bounds.y1 = 0;
if (!strcmp (name->str, "SourceGraphic")) {
output.surface = cairo_surface_reference (rsvg_filter_context_get_source_surface (ctx));
return output;
} else if (!strcmp (name->str, "BackgroundImage")) {
output.surface = rsvg_filter_context_get_bg_surface (ctx);
if (output.surface)
cairo_surface_reference (output.surface);
return output;
} else if (!strcmp (name->str, "") || !strcmp (name->str, "none")) {
output = rsvg_filter_context_get_lastresult (ctx);
cairo_surface_reference (output.surface);
return output;
} else if (!strcmp (name->str, "SourceAlpha")) {
output.surface = surface_get_alpha (rsvg_filter_context_get_source_surface (ctx), ctx);
return output;
} else if (!strcmp (name->str, "BackgroundAlpha")) {
output.surface = surface_get_alpha (rsvg_filter_context_get_bg_surface (ctx), ctx);
return output;
}
/* outputpointer = (RsvgFilterPrimitiveOutput *) (g_hash_table_lookup (ctx->results, name->str)); */
/* */
/* if (outputpointer != NULL) { */
/* output = *outputpointer; */
/* cairo_surface_reference (output.surface); */
/* return output; */
/* } */
if (rsvg_filter_context_get_previous_result(name, ctx, &output)) {
cairo_surface_reference (output.surface);
return output;
}
output.surface = NULL;
return output;
}
cairo_surface_t *
rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx)
{
cairo_surface_t *surface;
surface = rsvg_filter_get_result (name, ctx).surface;
if (surface == NULL || cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
return NULL;
}
// RsvgFilterPrimitiveOutput
// rsvg_filter_get_result (GString * name, RsvgFilterContext * ctx)
// {
// RsvgFilterPrimitiveOutput output;
// output.bounds.x0 = output.bounds.x1 = output.bounds.y0 = output.bounds.y1 = 0;
//
// if (!strcmp (name->str, "SourceGraphic")) {
// output.surface = cairo_surface_reference (rsvg_filter_context_get_source_surface (ctx));
// return output;
// } else if (!strcmp (name->str, "BackgroundImage")) {
// output.surface = rsvg_filter_context_get_bg_surface (ctx);
// if (output.surface)
// cairo_surface_reference (output.surface);
// return output;
// } else if (!strcmp (name->str, "") || !strcmp (name->str, "none")) {
// output = rsvg_filter_context_get_lastresult (ctx);
// cairo_surface_reference (output.surface);
// return output;
// } else if (!strcmp (name->str, "SourceAlpha")) {
// output.surface = surface_get_alpha (rsvg_filter_context_get_source_surface (ctx), ctx);
// return output;
// } else if (!strcmp (name->str, "BackgroundAlpha")) {
// output.surface = surface_get_alpha (rsvg_filter_context_get_bg_surface (ctx), ctx);
// return output;
// }
//
// /* outputpointer = (RsvgFilterPrimitiveOutput *) (g_hash_table_lookup (ctx->results, name->str)); */
// /* */
// /* if (outputpointer != NULL) { */
// /* output = *outputpointer; */
// /* cairo_surface_reference (output.surface); */
// /* return output; */
// /* } */
//
// if (rsvg_filter_context_get_previous_result(name, ctx, &output)) {
// cairo_surface_reference (output.surface);
// return output;
// }
//
// output.surface = NULL;
// return output;
// }
return surface;
}
// cairo_surface_t *
// rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx)
// {
// cairo_surface_t *surface;
//
// surface = rsvg_filter_get_result (name, ctx).surface;
// if (surface == NULL || cairo_surface_status (surface) != CAIRO_STATUS_SUCCESS) {
// return NULL;
// }
//
// return surface;
// }
// void
// rsvg_filter_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
......
......@@ -122,9 +122,21 @@ gboolean rsvg_art_affine_image (cairo_surface_t *img,
// G_GNUC_INTERNAL
// void rsvg_filter_free_pair (gpointer value);
/* Implemented in rust/src/filters/context.rs */
G_GNUC_INTERNAL
cairo_surface_t *rsvg_filter_get_in (GString * name, RsvgFilterContext * ctx);
/**
* rsvg_filter_get_result:
* @name: The name of the surface
* @ctx: the context that this was called in
*
* Gets a surface for a primitive
*
* Returns: (nullable): a pointer to the result that the name refers to, a special
* surface if the name is a special keyword or %NULL if nothing was found
**/
/* Implemented in rust/src/filters/context.rs */
G_GNUC_INTERNAL
RsvgFilterPrimitiveOutput rsvg_filter_get_result (GString * name, RsvgFilterContext * ctx);
......@@ -139,11 +151,11 @@ RsvgFilterPrimitiveOutput rsvg_filter_get_result (GString * name, RsvgFilterCont
G_GNUC_INTERNAL
void rsvg_filter_primitive_free (gpointer impl);
/* Implemented in rust/src/filter_context.rs */
/* Implemented in rust/src/filters/context.rs */
G_GNUC_INTERNAL
RsvgIRect rsvg_filter_primitive_get_bounds (const RsvgFilterPrimitive * self, const RsvgFilterContext * ctx);
/* Implemented in rust/src/filter_context.rs */
/* Implemented in rust/src/filters/context.rs */
G_GNUC_INTERNAL
gint rsvg_filter_context_get_width (const RsvgFilterContext *ctx);
......
......@@ -425,7 +425,7 @@ find_light_source_in_children (RsvgNode *node)
iter = rsvg_node_children_iter_begin (node);
while (rsvg_node_children_iter_next_back (iter, &child)) {
if (rsvg_node_get_type (node) == RSVG_NODE_TYPE_LIGHT_SOURCE) {
if (rsvg_node_get_type (child) == RSVG_NODE_TYPE_LIGHT_SOURCE) {
break;
}
......
/* -*- 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-styles.h"
#include "../rsvg-css.h"
#include "../rsvg-drawing-ctx.h"
#include "common.h"
typedef struct _RsvgFilterPrimitiveMerge RsvgFilterPrimitiveMerge;
struct _RsvgFilterPrimitiveMerge {
RsvgFilterPrimitive super;
};
static void
merge_render_child(RsvgNode *node,
cairo_surface_t *output,
RsvgIRect boundarys,
RsvgFilterContext *ctx)
{
RsvgFilterPrimitive *fp;
cairo_surface_t *in;
if (rsvg_node_get_type (node) != RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE_NODE)
return;
fp = rsvg_rust_cnode_get_impl (node);
in = rsvg_filter_get_in (fp->in, ctx);
if (in == NULL)
return;
rsvg_alpha_blt (in,
boundarys.x0,
boundarys.y0,
boundarys.x1 - boundarys.x0,
boundarys.y1 - boundarys.y0,
output,
boundarys.x0,
boundarys.y0);
cairo_surface_destroy (in);
}
static void
rsvg_filter_primitive_merge_render (RsvgNode *node, RsvgComputedValues *values, RsvgFilterPrimitive *primitive, RsvgFilterContext *ctx)
{
RsvgNodeChildrenIter *iter;
RsvgNode *child;
RsvgIRect boundarys;
cairo_surface_t *output;
boundarys = rsvg_filter_primitive_get_bounds (primitive, ctx);
output = _rsvg_image_surface_new (rsvg_filter_context_get_width (ctx), rsvg_filter_context_get_height (ctx));
if (output == NULL) {
return;
}
iter = rsvg_node_children_iter_begin (node);
while (rsvg_node_children_iter_next (iter, &child)) {
merge_render_child (child, output, boundarys, ctx);
child = rsvg_node_unref (child);
}
rsvg_node_children_iter_end (iter);
RsvgFilterPrimitiveOutput op;
op.surface = output;
op.bounds = boundarys;
rsvg_filter_store_output(primitive->result, op, ctx);
/* rsvg_filter_store_result (primitive->result, output, ctx); */
cairo_surface_destroy (output);
}
static void
rsvg_filter_primitive_merge_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
{
RsvgFilterPrimitiveMerge *filter = impl;
RsvgPropertyBagIter *iter;
const char *key;
RsvgAttribute attr;
const char *value;
filter_primitive_set_x_y_width_height_atts ((RsvgFilterPrimitive *) filter, atts);
iter = rsvg_property_bag_iter_begin (atts);
while (rsvg_property_bag_iter_next (iter, &key, &attr, &value)) {
switch (attr) {
case RSVG_ATTRIBUTE_RESULT:
g_string_assign (filter->super.result, value);
break;
default:
break;
}
}
rsvg_property_bag_iter_end (iter);
}
RsvgNode *
rsvg_new_filter_primitive_merge (const char *element_name, RsvgNode *parent, const char *id)
{
RsvgFilterPrimitiveMerge *filter;
filter = g_new0 (RsvgFilterPrimitiveMerge, 1);
filter->super.result = g_string_new ("none");
filter->super.render = rsvg_filter_primitive_merge_render;
return rsvg_rust_cnode_new (RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE,
parent,
id,
filter,
rsvg_filter_primitive_merge_set_atts,
rsvg_filter_primitive_free);
}
static void
rsvg_filter_primitive_merge_node_set_atts (RsvgNode *node, gpointer impl, RsvgHandle *handle, RsvgPropertyBag atts)
{
RsvgFilterPrimitive *primitive = 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_IN:
/* see bug 145149 - sodipodi generates bad SVG... */
g_string_assign (primitive->in, value);
break;
default:
break;
}
}
rsvg_property_bag_iter_end (iter);
}
static void
rsvg_filter_primitive_merge_node_render (RsvgNode *node, RsvgComputedValues *values, RsvgFilterPrimitive *primitive, RsvgFilterContext *ctx)
{
/* todo */
}
RsvgNode *
rsvg_new_filter_primitive_merge_node (const char *element_name, RsvgNode *parent, const char *id)
{
RsvgFilterPrimitive *filter;
filter = g_new0 (RsvgFilterPrimitive, 1);
filter->in = g_string_new ("none");
filter->render = rsvg_filter_primitive_merge_node_render;
return rsvg_rust_cnode_new (RSVG_NODE_TYPE_FILTER_PRIMITIVE_MERGE_NODE,
parent,
id,
filter,
rsvg_filter_primitive_merge_node_set_atts,
rsvg_filter_primitive_free);
}
......@@ -456,6 +456,12 @@ rsvg_drawing_ctx_get_dpi (RsvgDrawingCtx *ctx, double *out_dpi_x, double *out_dp
*out_dpi_y = ctx->dpi_y;
}
GList *
rsvg_drawing_ctx_get_cr_stack (RsvgDrawingCtx *ctx)
{
return ctx->cr_stack;
}
gboolean
rsvg_drawing_ctx_is_testing (RsvgDrawingCtx *ctx)
{
......
......@@ -144,6 +144,9 @@ void rsvg_drawing_ctx_draw_node_on_surface (RsvgDrawingCtx *ctx,
G_GNUC_INTERNAL
gboolean rsvg_drawing_ctx_is_testing (RsvgDrawingCtx *ctx);
G_GNUC_INTERNAL
GList *rsvg_drawing_ctx_get_cr_stack (RsvgDrawingCtx *ctx);
G_END_DECLS
#endif /*RSVG_DRAWING_CTX_H */
......@@ -2,7 +2,7 @@ use error::*;
use parsers::Parse;
use std::marker::PhantomData;
#[allow(unused_imports)]
#[allow(unused_imports, deprecated)]
use std::ascii::AsciiExt;
// No extensions at the moment.
......
......@@ -68,8 +68,21 @@ extern "C" {
out_y: *mut f64,
);
fn rsvg_drawing_ctx_get_raw_offset(
draw_ctx: *const RsvgDrawingCtx,
out_x: *mut f64,
out_y: *mut f64,
);
fn rsvg_drawing_ctx_get_bbox(draw_ctx: *const RsvgDrawingCtx) -> *mut RsvgBbox;
fn rsvg_drawing_ctx_get_cr_stack(draw_ctx: *mut RsvgDrawingCtx) -> *mut glib_sys::GList;
fn rsvg_drawing_ctx_is_cairo_context_nested(
draw_ctx: *const RsvgDrawingCtx,
cr: *mut cairo_sys::cairo_t,
) -> glib_sys::gboolean;
fn rsvg_drawing_ctx_is_testing(draw_ctx: *const RsvgDrawingCtx) -> glib_sys::gboolean;
}
......@@ -187,6 +200,17 @@ pub fn get_offset(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
(w, h)
}
pub fn get_raw_offset(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
let mut w: f64 = 0.0;
let mut h: f64 = 0.0;
unsafe {
rsvg_drawing_ctx_get_raw_offset(draw_ctx, &mut w, &mut h);
}
(w, h)
}
// remove this binding once pangocairo-rs has ContextExt::set_resolution()
fn set_resolution(context: &pango::Context, dpi: f64) {
unsafe {
......@@ -249,6 +273,27 @@ pub fn get_bbox<'a>(draw_ctx: *const RsvgDrawingCtx) -> &'a BoundingBox {
get_bbox_mut(draw_ctx)
}
pub fn get_cr_stack(draw_ctx: *mut RsvgDrawingCtx) -> Vec<cairo::Context> {
let mut res = Vec::new();
unsafe {
let list = rsvg_drawing_ctx_get_cr_stack(draw_ctx);
let mut list = glib_sys::g_list_first(mut_override(list));
while !list.is_null() {
res.push(from_glib_none((*list).data as *mut cairo_sys::cairo_t));
list = (*list).next;
}
}
res
}
pub fn is_cairo_context_nested(draw_ctx: *const RsvgDrawingCtx, cr: &cairo::Context) -> bool {
let cr = cr.to_glib_none();
from_glib(unsafe { rsvg_drawing_ctx_is_cairo_context_nested(draw_ctx, cr.0) })
}
extern "C" {
fn rsvg_drawing_ctx_get_width(draw_ctx: *const RsvgDrawingCtx) -> f64;
fn rsvg_drawing_ctx_get_height(draw_ctx: *const RsvgDrawingCtx) -> f64;
......@@ -475,6 +520,7 @@ fn pop_render_stack(draw_ctx: *mut RsvgDrawingCtx, node: &RsvgNode, values: &Com
}
}
#[allow(improper_ctypes)]
extern "C" {
fn rsvg_drawing_ctx_should_draw_node_from_stack(
draw_ctx: *const RsvgDrawingCtx,
......
......@@ -14,7 +14,7 @@ use util::{clamp, utf8_cstr_opt};
use super::context::{FilterContext, FilterOutput, FilterResult};
use super::input::Input;
use super::iterators::{ImageSurfaceDataShared, Pixels};
use super::iterators::{ImageSurfaceDataExt, ImageSurfaceDataShared, Pixel, Pixels};
use super::{get_surface, Filter, FilterError, PrimitiveWithInput};
/// Enumeration of the possible compositing operations.
......@@ -134,31 +134,27 @@ impl Filter for Composite {
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 compute = |i1, i2| {
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;
}
(o * 255f64).round() as u8
};
let output_pixel = Pixel {
r: compute(pixel.r, pixel_2.r),
g: compute(pixel.g, pixel_2.g),
b: compute(pixel.b, pixel_2.b),
a: (oa * 255f64).round() as u8,
};
output_data.set_pixel(output_stride, output_pixel, x, y);
}
}
}
......
use std::cell::UnsafeCell;
use std::collections::HashMap;
use std::ffi::CStr;
use std::{mem, ptr};
use cairo::prelude::SurfaceExt;
use cairo::{self, MatrixTrait};
......@@ -12,9 +14,9 @@ use coord_units::CoordUnits;
use drawing_ctx::{self, RsvgDrawingCtx};
use length::RsvgLength;
use node::{box_node, RsvgNode};
use state::ComputedValues;
use super::input::Input;
use super::iterators::{ImageSurfaceDataShared, Pixel, Pixels};
use super::node::NodeFilter;
use super::RsvgFilterPrimitive;
......@@ -73,6 +75,8 @@ pub struct FilterContext {
last_result: Option<FilterOutput>,
/// Surfaces of the previous filter primitives by name.
previous_results: HashMap<String, FilterOutput>,
/// The background surface. Computed lazily.
background_surface: UnsafeCell<Option<Result<cairo::ImageSurface, cairo::Status>>>,
affine: cairo::Matrix,
paffine: cairo::Matrix,
......@@ -80,6 +84,36 @@ pub struct FilterContext {
channelmap: [i32; 4],
}
/// Returns a surface with black background and alpha channel matching the input surface.
fn extract_alpha(
surface: &cairo::ImageSurface,
bounds: IRect,
) -> Result<cairo::ImageSurface, cairo::Status> {
let data = ImageSurfaceDataShared::new(surface).unwrap();
let mut output_surface =
cairo::ImageSurface::create(cairo::Format::ARgb32, data.width as i32, data.height as i32)?;
let output_stride = output_surface.get_stride() as usize;
{
let mut output_data = output_surface.get_data().unwrap();
for (x, y, Pixel { a, .. }) in Pixels::new(data, bounds) {
output_data[y * output_stride + x * 4 + 3] = a;
}
}
Ok(output_surface)
}
impl IRect {
/// Returns true if the `IRect` contains the given coordinates.
#[inline]
pub fn contains(self, x: i32, y: i32) -> bool {
x >= self.x0 && x < self.x1 && y >= self.y0 && y < self.y1
}
}
impl FilterContext {
/// Creates a new `FilterContext`.
pub fn new(
......@@ -89,9 +123,6 @@ impl FilterContext {
draw_ctx: *mut RsvgDrawingCtx,
channelmap: [i32; 4],
) -> Self {
let cascaded = filter_node.get_cascaded_values();
let values = cascaded.get();
let cr_affine = drawing_ctx::get_cairo_context(draw_ctx).get_matrix();
let bbox = drawing_ctx::get_bbox(draw_ctx);
let bbox_rect = bbox.rect.unwrap();
......@@ -134,6 +165,7 @@ impl FilterContext {
source_surface,
last_result: None,
previous_results: HashMap::new(),
background_surface: UnsafeCell::new(None),
affine,
paffine,
drawing_ctx: draw_ctx,
......@@ -142,7 +174,7 @@ impl FilterContext {
let last_result = FilterOutput {
surface: rv.source_surface.clone(),
bounds: rv.compute_bounds(&values, None, None, None, None),
bounds: rv.compute_bounds(None, None, None, None),
};
rv.last_result = Some(last_result);
......@@ -173,10 +205,66 @@ impl FilterContext {
&self.source_surface
}
/// Returns the surface containing the source graphic alpha.
#[inline]
pub fn source_alpha(&self, bounds: IRect) -> Result<cairo::ImageSurface, cairo::Status> {
extract_alpha(self.source_graphic(), bounds)
}
/// Computes and returns the background image snapshot.
fn compute_background_image(&self) -> Result<cairo::ImageSurface, cairo::Status> {
let surface = cairo::ImageSurface::create(
cairo::Format::ARgb32,
self.source_surface.get_width(),
self.source_surface.get_height(),
)?;
let (x, y) = drawing_ctx::get_raw_offset(self.drawing_ctx);
let stack = drawing_ctx::get_cr_stack(self.drawing_ctx);
let cr = cairo::Context::new(&surface);
for draw in stack.into_iter().rev() {
let nested = drawing_ctx::is_cairo_context_nested(self.drawing_ctx, &draw);
cr.set_source_surface(
&draw.get_target(),
if nested { 0f64 } else { -x },
if nested { 0f64 } else { -y },
);
cr.paint();