rsvg_cairo_clip() - port to Rust as NodeClipPath::to_cairo_context()

Thanks to Paolo for providing the template for doing this in the port
of rsvg_cairo_generate_mask().
parent 95b5210c
......@@ -55,58 +55,6 @@ void rsvg_drawing_ctx_transformed_image_bounding_box (cairo_matrix_t *affine,
double width, double height,
double *bbx, double *bby, double *bbw, double *bbh);
void
rsvg_cairo_clip (RsvgDrawingCtx *ctx, RsvgNode *node_clip_path, RsvgBbox *bbox)
{
cairo_matrix_t affinesave;
RsvgState *clip_path_state;
RsvgCoordUnits clip_units;
RsvgBbox *orig_bbox;
g_assert (rsvg_node_get_type (node_clip_path) == RSVG_NODE_TYPE_CLIP_PATH);
clip_units = rsvg_node_clip_path_get_units (node_clip_path);
clip_path_state = rsvg_node_get_state (node_clip_path);
/* Horribly dirty hack to have the bbox premultiplied to everything */
if (clip_units == objectBoundingBox) {
cairo_rectangle_t rect;
cairo_matrix_t bbtransform;
rsvg_bbox_get_rect (bbox, &rect, NULL);
cairo_matrix_init (&bbtransform,
rect.width,
0,
0,
rect.height,
rect.x,
rect.y);
affinesave = rsvg_state_get_affine (clip_path_state);
cairo_matrix_multiply (&bbtransform, &bbtransform, &affinesave);
rsvg_state_set_affine (clip_path_state, bbtransform);
}
orig_bbox = rsvg_bbox_clone (ctx->bbox);
rsvg_drawing_ctx_state_push (ctx);
rsvg_node_draw_children (node_clip_path, ctx, TRUE);
rsvg_drawing_ctx_state_pop (ctx);
if (clip_units == objectBoundingBox) {
rsvg_state_set_affine (clip_path_state, affinesave);
}
/* FIXME: this is an EPIC HACK to keep the clipping context from
* accumulating bounding boxes. We'll remove this later, when we
* are able to extract bounding boxes from outside the
* general drawing loop.
*/
rsvg_bbox_free (ctx->bbox);
ctx->bbox = orig_bbox;
cairo_clip (ctx->cr);
}
RsvgDrawingCtx *
rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle)
{
......
......@@ -58,9 +58,6 @@ RsvgDrawingCtx *rsvg_drawing_ctx_new (cairo_t *cr, RsvgHandle *handle);
G_GNUC_INTERNAL
void rsvg_drawing_ctx_free (RsvgDrawingCtx *draw_ctx);
G_GNUC_INTERNAL
void rsvg_cairo_clip (RsvgDrawingCtx *ctx, RsvgNode *node_clip_path, RsvgBbox *bbox);
G_GNUC_INTERNAL
cairo_t *rsvg_drawing_ctx_get_cairo_context (RsvgDrawingCtx *ctx);
G_GNUC_INTERNAL
......
......@@ -118,10 +118,6 @@ RsvgNode *rsvg_node_mask_new (const char *element_name, RsvgNode *node);
G_GNUC_INTERNAL
RsvgNode *rsvg_node_clip_path_new (const char *element_name, RsvgNode *node);
/* Implemented in rust/src/clip_path.rs */
G_GNUC_INTERNAL
RsvgCoordUnits rsvg_node_clip_path_get_units (RsvgNode *node);
/* Implemented in rust/src/shapes.rs */
G_GNUC_INTERNAL
RsvgNode *rsvg_node_path_new (const char *element_name, RsvgNode *parent);
......
use libc;
use std::cell::Cell;
use cairo::{self, MatrixTrait};
use attributes::Attribute;
use coord_units::CoordUnits;
use drawing_ctx::RsvgDrawingCtx;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use node::{boxed_node_new, NodeResult, NodeTrait, NodeType, RsvgCNodeImpl, RsvgNode};
use parsers::parse;
......@@ -25,6 +27,46 @@ impl NodeClipPath {
pub fn get_units(&self) -> ClipPathUnits {
self.units.get()
}
pub fn to_cairo_context(&self, node: &RsvgNode, draw_ctx: *mut RsvgDrawingCtx) {
let clip_units = self.units.get();
let clip_path_state = node.get_state_mut();
let affine_save = clip_path_state.affine;
let orig_bbox = drawing_ctx::get_bbox(draw_ctx).clone();
if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
let rect = orig_bbox.rect.unwrap();
let bbtransform = cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y);
let bbtransform = cairo::Matrix::multiply(&bbtransform, &affine_save);
clip_path_state.affine = bbtransform;
}
drawing_ctx::state_push(draw_ctx);
drawing_ctx::state_reinherit_top(draw_ctx, node.get_state(), 0);
drawing_ctx::push_discrete_layer(draw_ctx, &node.get_computed_values(), true);
node.draw_children(draw_ctx, -1, true);
drawing_ctx::pop_discrete_layer(draw_ctx, &node.get_computed_values(), true);
drawing_ctx::state_pop(draw_ctx);
if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
clip_path_state.affine = affine_save;
}
// FIXME: this is an EPIC HACK to keep the clipping context from
// accumulating bounding boxes. We'll remove this later, when we
// are able to extract bounding boxes from outside the
// general drawing loop.
drawing_ctx::set_bbox(draw_ctx, &orig_bbox);
let cr = drawing_ctx::get_cairo_context(draw_ctx);
cr.clip();
}
}
impl NodeTrait for NodeClipPath {
......@@ -62,17 +104,3 @@ pub extern "C" fn rsvg_node_clip_path_new(
Box::new(NodeClipPath::new()),
)
}
#[no_mangle]
pub extern "C" fn rsvg_node_clip_path_get_units(raw_node: *const RsvgNode) -> CoordUnits {
assert!(!raw_node.is_null());
let node: &RsvgNode = unsafe { &*raw_node };
let mut units = ClipPathUnits::default();
node.with_impl(|clip_path: &NodeClipPath| {
units = clip_path.get_units();
});
CoordUnits::from(units)
}
use std::ptr;
use cairo;
use cairo::MatrixTrait;
use cairo_sys;
......@@ -16,8 +14,8 @@ use coord_units::CoordUnits;
use filters::rsvg_filter_render;
use iri::IRI;
use length::LengthUnit;
use node::{box_node, NodeType, RsvgNode};
use mask::NodeMask;
use node::{box_node, NodeType, RsvgNode};
use rect::RectangleExt;
use state::{
self,
......@@ -265,15 +263,11 @@ pub fn pop_discrete_layer(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues
}
pub fn get_width(draw_ctx: *const RsvgDrawingCtx) -> f64 {
unsafe {
rsvg_drawing_ctx_get_width(draw_ctx)
}
unsafe { rsvg_drawing_ctx_get_width(draw_ctx) }
}
pub fn get_height(draw_ctx: *const RsvgDrawingCtx) -> f64 {
unsafe {
rsvg_drawing_ctx_get_height(draw_ctx)
}
unsafe { rsvg_drawing_ctx_get_height(draw_ctx) }
}
pub fn get_offset(draw_ctx: *const RsvgDrawingCtx) -> (f64, f64) {
......@@ -332,6 +326,12 @@ pub fn insert_bbox(draw_ctx: *const RsvgDrawingCtx, bbox: &BoundingBox) {
draw_ctx_bbox.insert(bbox);
}
pub fn set_bbox(draw_ctx: *mut RsvgDrawingCtx, bbox: &BoundingBox) {
let draw_ctx_bbox = get_bbox_mut(draw_ctx);
*draw_ctx_bbox = *bbox;
}
pub fn draw_node_from_stack(
draw_ctx: *const RsvgDrawingCtx,
node: *const RsvgNode,
......@@ -418,8 +418,6 @@ pub fn get_bbox<'a>(draw_ctx: *const RsvgDrawingCtx) -> &'a BoundingBox {
}
extern "C" {
fn rsvg_cairo_clip(draw_ctx: *mut RsvgDrawingCtx, node: *const RsvgNode, bbox: *const RsvgBbox);
fn rsvg_drawing_ctx_get_width(draw_ctx: *const RsvgDrawingCtx) -> f64;
fn rsvg_drawing_ctx_get_height(draw_ctx: *const RsvgDrawingCtx) -> f64;
......@@ -466,21 +464,15 @@ fn push_render_stack(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues) {
if let Some(acquired) = get_acquired_node_of_type(draw_ctx, clip_path, NodeType::ClipPath) {
let node = acquired.get();
let mut clip_path_units = ClipPathUnits::default();
node.with_impl(|clip_path: &NodeClipPath| {
clip_path_units = clip_path.get_units();
});
match clip_path_units {
ClipPathUnits(CoordUnits::UserSpaceOnUse) => unsafe {
rsvg_cairo_clip(draw_ctx, acquired.1, ptr::null());
},
node.with_impl(|clip_path: &NodeClipPath| match clip_path.get_units() {
ClipPathUnits(CoordUnits::UserSpaceOnUse) => {
clip_path.to_cairo_context(&node, draw_ctx);
}
ClipPathUnits(CoordUnits::ObjectBoundingBox) => {
late_clip = true;
}
}
});
}
}
......@@ -621,9 +613,11 @@ fn pop_render_stack(draw_ctx: *mut RsvgDrawingCtx, values: &ComputedValues) {
if let Some(acquired) =
get_acquired_node_of_type(draw_ctx, clip_path, NodeType::ClipPath)
{
unsafe {
rsvg_cairo_clip(draw_ctx, acquired.1, rsvg_drawing_ctx_get_bbox(draw_ctx));
}
let node = acquired.get();
node.with_impl(|clip_path: &NodeClipPath| {
clip_path.to_cairo_context(&node, draw_ctx);
});
}
}
}
......
......@@ -34,7 +34,7 @@ pub use bbox::{
RsvgBbox,
};
pub use clip_path::{rsvg_node_clip_path_get_units, rsvg_node_clip_path_new};
pub use clip_path::rsvg_node_clip_path_new;
pub use cnode::{rsvg_rust_cnode_get_impl, rsvg_rust_cnode_new};
......
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