viewport.rs: new draw_in_viewport() function

The general "establish a new viewport" pattern is done in different
ways in several places in the code.  We capture this pattern in a
single function which takes care of setting up a clipping rectangle
and a transformation matrix, and call a lambda to actually draw the
contents.
parent ecb670f4
......@@ -96,7 +96,8 @@ RUST_SOURCES = \
rust/src/structure.rs \
rust/src/transform.rs \
rust/src/util.rs \
rust/src/viewbox.rs
rust/src/viewbox.rs \
rust/src/viewport.rs
RUST_EXTRA = \
rust/Cargo.lock \
......
......@@ -155,3 +155,4 @@ mod structure;
mod transform;
mod util;
mod viewbox;
mod viewport;
......@@ -18,6 +18,7 @@ use property_bag;
use property_bag::*;
use util::*;
use viewbox::*;
use viewport::draw_in_viewport;
/***** NodeGroup *****/
......@@ -171,60 +172,21 @@ impl NodeTrait for NodeSvg {
let nw = self.w.get ().normalize (draw_ctx);
let nh = self.h.get ().normalize (draw_ctx);
// width or height set to 0 disables rendering of the element
// https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
if double_equals (nw, 0.0) || double_equals (nh, 0.0) {
return;
}
drawing_ctx::state_reinherit_top (draw_ctx, node.get_state (), dominate);
let state = drawing_ctx::get_current_state (draw_ctx);
let affine_old = drawing_ctx::get_current_state_affine (draw_ctx);
if let Some (vbox) = self.vbox.get () {
// viewBox width==0 or height==0 disables rendering of the element
// https://www.w3.org/TR/SVG/coords.html#ViewBoxAttribute
if double_equals (vbox.0.width, 0.0) || double_equals (vbox.0.height, 0.0) {
return;
}
let (x, y, w, h) = self.preserve_aspect_ratio.get ().compute (vbox.0.width, vbox.0.height,
nx, ny, nw, nh);
let mut affine = affine_old;
affine.translate (x, y);
affine.scale (w / vbox.0.width, h / vbox.0.height);
affine.translate (-vbox.0.x, -vbox.0.y);
drawing_ctx::set_current_state_affine (draw_ctx, affine);
drawing_ctx::push_view_box (draw_ctx, vbox.0.width, vbox.0.height);
} else {
let mut affine = affine_old;
affine.translate (nx, ny);
drawing_ctx::set_current_state_affine (draw_ctx, affine);
drawing_ctx::push_view_box (draw_ctx, nw, nh);
}
let affine_new = drawing_ctx::get_current_state_affine (draw_ctx);
drawing_ctx::push_discrete_layer (draw_ctx);
// Bounding box addition must be AFTER the discrete layer
// push, which must be AFTER the transformation happens.
if !drawing_ctx::state_is_overflow (state) && node.get_parent ().is_some () {
drawing_ctx::set_current_state_affine (draw_ctx, affine_old);
drawing_ctx::add_clipping_rect (draw_ctx, nx, ny, nw, nh);
drawing_ctx::set_current_state_affine (draw_ctx, affine_new);
}
node.draw_children (draw_ctx, -1); // dominate==-1 so it won't reinherit or push a layer
drawing_ctx::pop_discrete_layer (draw_ctx);
drawing_ctx::pop_view_box (draw_ctx);
let do_clip = !drawing_ctx::state_is_overflow (state) && node.get_parent ().is_some ();
draw_in_viewport(nx, ny, nw, nh,
do_clip,
self.vbox.get(),
self.preserve_aspect_ratio.get(),
drawing_ctx::get_current_state_affine(draw_ctx),
draw_ctx,
|affine| {
drawing_ctx::state_push(draw_ctx);
drawing_ctx::set_current_state_affine(draw_ctx, affine);
node.draw_children(draw_ctx, -1); // dominate==-1 so it won't reinherit or push a layer
drawing_ctx::state_pop(draw_ctx);
});
}
fn get_c_impl (&self) -> *const RsvgCNodeImpl {
......
use cairo;
use cairo::MatrixTrait;
use aspect_ratio::AspectRatio;
use drawing_ctx;
use drawing_ctx::RsvgDrawingCtx;
use util::*;
use viewbox::*;
pub fn draw_in_viewport<F>(vx: f64, vy: f64, vw: f64, vh: f64,
do_clip: bool,
vbox: Option<ViewBox>,
preserve_aspect_ratio: AspectRatio,
mut affine: cairo::Matrix,
draw_ctx: *const RsvgDrawingCtx,
draw_fn: F)
where F: FnOnce(cairo::Matrix)
{
// width or height set to 0 disables rendering of the element
// https://www.w3.org/TR/SVG/struct.html#SVGElementWidthAttribute
// https://www.w3.org/TR/SVG/struct.html#UseElementWidthAttribute
// https://www.w3.org/TR/SVG/struct.html#ImageElementWidthAttribute
// https://www.w3.org/TR/SVG/painting.html#MarkerWidthAttribute
if double_equals(vw, 0.0) || double_equals(vh, 0.0) {
return;
}
let vbox_size;
if let Some(vbox) = vbox {
// the preserveAspectRatio attribute is only used if viewBox is specified
// https://www.w3.org/TR/SVG/coords.html#PreserveAspectRatioAttribute
let (x, y, w, h) = preserve_aspect_ratio.compute(vbox.0.width, vbox.0.height,
vx, vy, vw, vh);
affine.translate(x, y);
affine.scale(w / vbox.0.width, h / vbox.0.height);
affine.translate(-vbox.0.x, -vbox.0.y);
vbox_size = (vbox.0.width, vbox.0.height);
} else {
affine.translate(vx, vy);
vbox_size = (vw, vh);
}
drawing_ctx::push_view_box(draw_ctx, vbox_size.0, vbox_size.1);
drawing_ctx::push_discrete_layer(draw_ctx);
if do_clip {
drawing_ctx::add_clipping_rect(draw_ctx, vx, vy, vw, vh);
}
draw_fn(affine);
drawing_ctx::pop_discrete_layer(draw_ctx);
drawing_ctx::pop_view_box(draw_ctx);
}
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