1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
use libc;
use std::cell::Cell;
use cairo::{self, MatrixTrait};
use attributes::Attribute;
use coord_units::CoordUnits;
use drawing_ctx::{self, RsvgDrawingCtx};
use handle::RsvgHandle;
use node::{
boxed_node_new,
CascadedValues,
NodeResult,
NodeTrait,
NodeType,
RsvgCNodeImpl,
RsvgNode,
};
use parsers::parse;
use property_bag::PropertyBag;
coord_units!(ClipPathUnits, CoordUnits::UserSpaceOnUse);
pub struct NodeClipPath {
units: Cell<ClipPathUnits>,
}
impl NodeClipPath {
fn new() -> NodeClipPath {
NodeClipPath {
units: Cell::new(ClipPathUnits::default()),
}
}
pub fn get_units(&self) -> ClipPathUnits {
self.units.get()
}
pub fn to_cairo_context(&self, node: &RsvgNode, draw_ctx: *mut RsvgDrawingCtx) {
let cascaded = node.get_cascaded_values();
let clip_units = self.units.get();
let orig_bbox = drawing_ctx::get_bbox(draw_ctx).clone();
let cr = drawing_ctx::get_cairo_context(draw_ctx);
// let cr_save_transform = cr.get_matrix();
let child_matrix = if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
let rect = orig_bbox.rect.unwrap();
let mut bbtransform =
cairo::Matrix::new(rect.width, 0.0, 0.0, rect.height, rect.x, rect.y);
cairo::Matrix::multiply(&bbtransform, &cr.get_matrix())
} else {
cr.get_matrix()
};
let cr = drawing_ctx::get_cairo_context(draw_ctx);
cr.set_matrix(child_matrix);
node.draw_children(&cascaded, draw_ctx, -1, true);
// 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();
// if clip_units == ClipPathUnits(CoordUnits::ObjectBoundingBox) {
// cr.set_matrix(cr_save_transform);
// }
}
}
impl NodeTrait for NodeClipPath {
fn set_atts(&self, _: &RsvgNode, _: *const RsvgHandle, pbag: &PropertyBag) -> NodeResult {
for (_key, attr, value) in pbag.iter() {
match attr {
Attribute::ClipPathUnits => {
self.units.set(parse("clipPathUnits", value, (), None)?)
}
_ => (),
}
}
Ok(())
}
fn draw(&self, _: &RsvgNode, _: &CascadedValues, _: *mut RsvgDrawingCtx, _: i32, _: bool) {
// nothing; clip paths are handled specially
}
fn get_c_impl(&self) -> *const RsvgCNodeImpl {
unreachable!();
}
}
#[no_mangle]
pub extern "C" fn rsvg_node_clip_path_new(
_: *const libc::c_char,
raw_parent: *const RsvgNode,
) -> *const RsvgNode {
boxed_node_new(
NodeType::ClipPath,
raw_parent,
Box::new(NodeClipPath::new()),
)
}
|