[librsvg: 2/27] Replace with_saved_cr by a SavedCr that gets restored on Drop
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg: 2/27] Replace with_saved_cr by a SavedCr that gets restored on Drop
- Date: Fri, 5 Mar 2021 23:36:26 +0000 (UTC)
commit 5281167a3752afe811f93a4a1fb89ce4eaf8a886
Author: Federico Mena Quintero <federico gnome org>
Date: Thu Mar 4 17:53:47 2021 -0600
Replace with_saved_cr by a SavedCr that gets restored on Drop
I'm not sure yet if I like this, but it should help cut down on the
number of stack frames.
src/drawing_ctx.rs | 359 ++++++++++++++++++++++++++++++-----------------------
1 file changed, 201 insertions(+), 158 deletions(-)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 7d9c01e8..d591407c 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -226,6 +226,24 @@ pub fn draw_tree(
Ok(user_bbox)
}
+struct SavedCr<'a> {
+ draw_ctx: &'a mut DrawingCtx,
+}
+
+impl SavedCr<'_> {
+ /// Saves the draw_ctx.cr, which will be restored on Drop.
+ fn new(draw_ctx: &mut DrawingCtx) -> SavedCr<'_> {
+ draw_ctx.cr.save();
+ SavedCr { draw_ctx }
+ }
+}
+
+impl Drop for SavedCr<'_> {
+ fn drop(&mut self) {
+ self.draw_ctx.cr.restore();
+ }
+}
+
impl DrawingCtx {
fn new(
cr: &cairo::Context,
@@ -395,7 +413,7 @@ impl DrawingCtx {
/// Note that this actually changes the `draw_ctx.cr`'s transformation to match
/// the new coordinate space, but the old one is not restored after the
/// result's `ViewParams` is dropped. Thus, this function must be called
- /// inside `draw_ctx.with_saved_cr` or `draw_ctx.with_discrete_layer`.
+ /// inside `SavedCr` scope or `draw_ctx.with_discrete_layer`.
pub fn push_new_viewport(
&self,
vbox: Option<ViewBox>,
@@ -587,99 +605,120 @@ impl DrawingCtx {
if clipping {
draw_fn(acquired_nodes, self)
} else {
- self.with_saved_cr(&mut |dc| {
- let clip_path_value = values.clip_path();
- let mask_value = values.mask();
+ let saved_cr = SavedCr::new(self);
- let clip_uri = clip_path_value.0.get();
- let mask = mask_value.0.get();
+ let clip_path_value = values.clip_path();
+ let mask_value = values.mask();
- let filters = if node.is_element() {
- match *node.borrow_element() {
- Element::Mask(_) => Filter::None,
- _ => values.filter(),
- }
- } else {
- values.filter()
- };
+ let clip_uri = clip_path_value.0.get();
+ let mask = mask_value.0.get();
- let UnitInterval(opacity) = values.opacity().0;
+ let filters = if node.is_element() {
+ match *node.borrow_element() {
+ Element::Mask(_) => Filter::None,
+ _ => values.filter(),
+ }
+ } else {
+ values.filter()
+ };
- let affine_at_start = dc.get_transform();
+ let UnitInterval(opacity) = values.opacity().0;
- let (clip_in_user_space, clip_in_object_space) =
- get_clip_in_user_and_object_space(acquired_nodes, clip_uri);
+ let affine_at_start = saved_cr.draw_ctx.get_transform();
- // Here we are clipping in user space, so the bbox doesn't matter
- dc.clip_to_node(&clip_in_user_space, acquired_nodes, &dc.empty_bbox())?;
+ let (clip_in_user_space, clip_in_object_space) =
+ get_clip_in_user_and_object_space(acquired_nodes, clip_uri);
- let is_opaque = approx_eq!(f64, opacity, 1.0);
- let needs_temporary_surface = !(is_opaque
- && filters == Filter::None
- && mask.is_none()
- && values.mix_blend_mode() == MixBlendMode::Normal
- && clip_in_object_space.is_none());
+ // Here we are clipping in user space, so the bbox doesn't matter
+ saved_cr.draw_ctx.clip_to_node(
+ &clip_in_user_space,
+ acquired_nodes,
+ &saved_cr.draw_ctx.empty_bbox(),
+ )?;
- if needs_temporary_surface {
- // Compute our assortment of affines
+ let is_opaque = approx_eq!(f64, opacity, 1.0);
+ let needs_temporary_surface = !(is_opaque
+ && filters == Filter::None
+ && mask.is_none()
+ && values.mix_blend_mode() == MixBlendMode::Normal
+ && clip_in_object_space.is_none());
- let affines = CompositingAffines::new(
- affine_at_start,
- dc.initial_transform_with_offset(),
- dc.cr_stack.len(),
- );
+ if needs_temporary_surface {
+ // Compute our assortment of affines
- // Create temporary surface and its cr
+ let affines = CompositingAffines::new(
+ affine_at_start,
+ saved_cr.draw_ctx.initial_transform_with_offset(),
+ saved_cr.draw_ctx.cr_stack.len(),
+ );
- let cr = match filters {
- Filter::None => cairo::Context::new(
- &dc.create_similar_surface_for_toplevel_viewport(&dc.cr.get_target())?,
- ),
- Filter::List(_) => {
- cairo::Context::new(&*dc.create_surface_for_toplevel_viewport()?)
- }
- };
+ // Create temporary surface and its cr
- cr.set_matrix(affines.for_temporary_surface.into());
+ let cr = match filters {
+ Filter::None => cairo::Context::new(
+ &saved_cr
+ .draw_ctx
+ .create_similar_surface_for_toplevel_viewport(
+ &saved_cr.draw_ctx.cr.get_target(),
+ )?,
+ ),
+ Filter::List(_) => cairo::Context::new(
+ &*saved_cr.draw_ctx.create_surface_for_toplevel_viewport()?,
+ ),
+ };
- dc.push_cairo_context(cr);
+ cr.set_matrix(affines.for_temporary_surface.into());
- // Draw!
+ saved_cr.draw_ctx.push_cairo_context(cr);
- let mut res = draw_fn(acquired_nodes, dc);
+ // Draw!
- let bbox = if let Ok(ref bbox) = res {
- *bbox
- } else {
- BoundingBox::new().with_transform(affines.for_temporary_surface)
- };
+ let mut res = draw_fn(acquired_nodes, saved_cr.draw_ctx);
+
+ let bbox = if let Ok(ref bbox) = res {
+ *bbox
+ } else {
+ BoundingBox::new().with_transform(affines.for_temporary_surface)
+ };
- // Filter
- let source_surface =
- dc.run_filters(&filters, acquired_nodes, node, values, bbox)?;
+ // Filter
+ let source_surface =
+ saved_cr
+ .draw_ctx
+ .run_filters(&filters, acquired_nodes, node, values, bbox)?;
- dc.pop_cairo_context();
+ saved_cr.draw_ctx.pop_cairo_context();
- // Set temporary surface as source
+ // Set temporary surface as source
- dc.cr.set_matrix(affines.compositing.into());
- dc.cr.set_source_surface(&source_surface, 0.0, 0.0);
+ saved_cr.draw_ctx.cr.set_matrix(affines.compositing.into());
+ saved_cr
+ .draw_ctx
+ .cr
+ .set_source_surface(&source_surface, 0.0, 0.0);
- // Clip
+ // Clip
- dc.cr.set_matrix(affines.outside_temporary_surface.into());
- dc.clip_to_node(&clip_in_object_space, acquired_nodes, &bbox)?;
+ saved_cr
+ .draw_ctx
+ .cr
+ .set_matrix(affines.outside_temporary_surface.into());
+ saved_cr
+ .draw_ctx
+ .clip_to_node(&clip_in_object_space, acquired_nodes, &bbox)?;
- // Mask
+ // Mask
- if let Some(node_id) = mask {
- if let Ok(acquired) = acquired_nodes.acquire(node_id) {
- let mask_node = acquired.get();
+ if let Some(node_id) = mask {
+ if let Ok(acquired) = acquired_nodes.acquire(node_id) {
+ let mask_node = acquired.get();
- match *mask_node.borrow_element() {
- Element::Mask(ref m) => {
- res = res.and_then(|bbox| {
- dc.generate_cairo_mask(
+ match *mask_node.borrow_element() {
+ Element::Mask(ref m) => {
+ res = res.and_then(|bbox| {
+ saved_cr
+ .draw_ctx
+ .generate_cairo_mask(
&m,
&mask_node,
affines.for_temporary_surface,
@@ -688,48 +727,53 @@ impl DrawingCtx {
)
.map(|mask_surf| {
if let Some(surf) = mask_surf {
- dc.cr.set_matrix(affines.compositing.into());
- dc.cr.mask_surface(&surf, 0.0, 0.0);
+ saved_cr
+ .draw_ctx
+ .cr
+ .set_matrix(affines.compositing.into());
+ saved_cr.draw_ctx.cr.mask_surface(&surf, 0.0, 0.0);
}
})
.map(|_: ()| bbox)
- });
- }
- _ => {
- rsvg_log!(
- "element {} references \"{}\" which is not a mask",
- node,
- node_id
- );
- }
+ });
+ }
+ _ => {
+ rsvg_log!(
+ "element {} references \"{}\" which is not a mask",
+ node,
+ node_id
+ );
}
- } else {
- rsvg_log!(
- "element {} references nonexistent mask \"{}\"",
- node,
- node_id
- );
}
} else {
- // No mask, so composite the temporary surface
+ rsvg_log!(
+ "element {} references nonexistent mask \"{}\"",
+ node,
+ node_id
+ );
+ }
+ } else {
+ // No mask, so composite the temporary surface
- dc.cr.set_matrix(affines.compositing.into());
- dc.cr.set_operator(values.mix_blend_mode().into());
+ saved_cr.draw_ctx.cr.set_matrix(affines.compositing.into());
+ saved_cr
+ .draw_ctx
+ .cr
+ .set_operator(values.mix_blend_mode().into());
- if opacity < 1.0 {
- dc.cr.paint_with_alpha(opacity);
- } else {
- dc.cr.paint();
- }
+ if opacity < 1.0 {
+ saved_cr.draw_ctx.cr.paint_with_alpha(opacity);
+ } else {
+ saved_cr.draw_ctx.cr.paint();
}
+ }
- dc.cr.set_matrix(affine_at_start.into());
+ saved_cr.draw_ctx.cr.set_matrix(affine_at_start.into());
- res
- } else {
- draw_fn(acquired_nodes, dc)
- }
- })
+ res
+ } else {
+ draw_fn(acquired_nodes, saved_cr.draw_ctx)
+ }
}
}
@@ -812,17 +856,6 @@ impl DrawingCtx {
res
}
- /// Saves the current Cairo context, runs the draw_fn, and restores the context
- fn with_saved_cr(
- &mut self,
- draw_fn: &mut dyn FnMut(&mut DrawingCtx) -> Result<BoundingBox, RenderingError>,
- ) -> Result<BoundingBox, RenderingError> {
- self.cr.save();
- let res = draw_fn(self);
- self.cr.restore();
- res
- }
-
/// Wraps the draw_fn in a link to the given target
pub fn with_link_tag(
&mut self,
@@ -1351,17 +1384,23 @@ impl DrawingCtx {
};
self.with_discrete_layer(node, acquired_nodes, values, clipping, &mut |_an, dc| {
- dc.with_saved_cr(&mut |dc| {
- if let Some(_params) = dc.push_new_viewport(Some(vbox), rect, aspect, clip_mode) {
- if values.is_visible() {
- dc.paint_surface(surface, image_width, image_height);
- }
+ let saved_cr = SavedCr::new(dc);
+
+ if let Some(_params) =
+ saved_cr
+ .draw_ctx
+ .push_new_viewport(Some(vbox), rect, aspect, clip_mode)
+ {
+ if values.is_visible() {
+ saved_cr
+ .draw_ctx
+ .paint_surface(surface, image_width, image_height);
}
+ }
- // The bounding box for <image> is decided by the values of x, y, w, h
- // and not by the final computed image bounds.
- Ok(dc.empty_bbox().with_rect(rect))
- })
+ // The bounding box for <image> is decided by the values of x, y, w, h
+ // and not by the final computed image bounds.
+ Ok(saved_cr.draw_ctx.empty_bbox().with_rect(rect))
})
}
@@ -1389,22 +1428,25 @@ impl DrawingCtx {
bbox.unwrap()
};
- self.with_saved_cr(&mut |dc| {
- let cr = dc.cr.clone();
+ let saved_cr = SavedCr::new(self);
- cr.set_antialias(cairo::Antialias::from(values.text_rendering()));
- dc.setup_cr_for_stroke(&cr, &values);
- cr.move_to(x, y);
+ let cr = saved_cr.draw_ctx.cr.clone();
- let rotation = gravity.to_rotation();
- if !rotation.approx_eq_cairo(0.0) {
- cr.rotate(-rotation);
- }
+ cr.set_antialias(cairo::Antialias::from(values.text_rendering()));
+ saved_cr.draw_ctx.setup_cr_for_stroke(&cr, &values);
+ cr.move_to(x, y);
- let current_color = values.color().0;
+ let rotation = gravity.to_rotation();
+ if !rotation.approx_eq_cairo(0.0) {
+ cr.rotate(-rotation);
+ }
- let res = if !clipping {
- dc.set_source_paint_server(
+ let current_color = values.color().0;
+
+ let res = if !clipping {
+ saved_cr
+ .draw_ctx
+ .set_source_paint_server(
acquired_nodes,
&values.fill().0,
values.fill_opacity().0,
@@ -1420,15 +1462,17 @@ impl DrawingCtx {
}
};
})
- } else {
- Ok(())
- };
+ } else {
+ Ok(())
+ };
- if res.is_ok() {
- let mut need_layout_path = clipping;
+ if res.is_ok() {
+ let mut need_layout_path = clipping;
- let res = if !clipping {
- dc.set_source_paint_server(
+ let res = if !clipping {
+ saved_cr
+ .draw_ctx
+ .set_source_paint_server(
acquired_nodes,
&values.stroke().0,
values.stroke_opacity().0,
@@ -1441,30 +1485,29 @@ impl DrawingCtx {
need_layout_path = true;
}
})
- } else {
- Ok(())
- };
+ } else {
+ Ok(())
+ };
- if res.is_ok() && need_layout_path {
- pangocairo::functions::update_layout(&cr, &layout);
- pangocairo::functions::layout_path(&cr, &layout);
-
- if !clipping {
- let (x0, y0, x1, y1) = cr.stroke_extents();
- let r = Rect::new(x0, y0, x1, y1);
- let ib = BoundingBox::new()
- .with_transform(transform)
- .with_ink_rect(r);
- bbox.insert(&ib);
- if values.is_visible() {
- cr.stroke();
- }
+ if res.is_ok() && need_layout_path {
+ pangocairo::functions::update_layout(&cr, &layout);
+ pangocairo::functions::layout_path(&cr, &layout);
+
+ if !clipping {
+ let (x0, y0, x1, y1) = cr.stroke_extents();
+ let r = Rect::new(x0, y0, x1, y1);
+ let ib = BoundingBox::new()
+ .with_transform(transform)
+ .with_ink_rect(r);
+ bbox.insert(&ib);
+ if values.is_visible() {
+ cr.stroke();
}
}
}
+ }
- res.map(|_: ()| bbox)
- })
+ res.map(|_: ()| bbox)
}
pub fn get_snapshot(
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]