[librsvg/librsvg-2.52: 7/19] Path::from_cairo() - New function to convert a librsvg path to a Cairo path
- From: Federico Mena Quintero <federico src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [librsvg/librsvg-2.52: 7/19] Path::from_cairo() - New function to convert a librsvg path to a Cairo path
- Date: Thu, 17 Feb 2022 03:49:55 +0000 (UTC)
commit ef7dfe2a87161262668db890a134bb830c26f51a
Author: Federico Mena Quintero <federico gnome org>
Date: Fri Feb 4 20:02:47 2022 -0600
Path::from_cairo() - New function to convert a librsvg path to a Cairo path
This handles the quirk quere Cairo sometimes appends a MoveTo to
paths, and in particular, for empty paths that should have no commands
at all.
The text rendering code really needs to know whether a path produced
inked pixels or not, so that for "empty text" (an empty string, or
just whitespace) it can avoid producing a bounding box equal to a
zero-sized rectangle - it wants to really produce "no bounds" in that
case.
So, let's strip Cairo's MoveTo(0, 0) from paths that have no other commands.
Part-of: <https://gitlab.gnome.org/GNOME/librsvg/-/merge_requests/660>
src/drawing_ctx.rs | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 64 insertions(+)
---
diff --git a/src/drawing_ctx.rs b/src/drawing_ctx.rs
index 1b05b22af..b9550057b 100644
--- a/src/drawing_ctx.rs
+++ b/src/drawing_ctx.rs
@@ -2184,6 +2184,36 @@ impl Path {
cr.status().map_err(|e| e.into())
}
+
+ /// Converts a `cairo::Path` to a librsvg `Path`.
+ fn from_cairo(cairo_path: cairo::Path) -> Path {
+ let mut builder = PathBuilder::default();
+
+ // First, see if the path is a single MoveTo(0, 0). Cairo does this when the code that
+ // generated the path didn't include any commands, due to the way it appends a MoveTo to
+ // some paths.
+ //
+ // Only do the conversion if the path is not empty; otherwise
+ // really return a librsvg path with no commands.
+
+ if !cairo_path
+ .iter()
+ .eq([cairo::PathSegment::MoveTo((0.0, 0.0))])
+ {
+ for segment in cairo_path.iter() {
+ match segment {
+ cairo::PathSegment::MoveTo((x, y)) => builder.move_to(x, y),
+ cairo::PathSegment::LineTo((x, y)) => builder.line_to(x, y),
+ cairo::PathSegment::CurveTo((x2, y2), (x3, y3), (x4, y4)) => {
+ builder.curve_to(x2, y2, x3, y3, x4, y4)
+ }
+ cairo::PathSegment::ClosePath => builder.close_path(),
+ }
+ }
+ }
+
+ builder.into_path()
+ }
}
impl PathCommand {
@@ -2232,3 +2262,37 @@ impl CubicBezierCurve {
cr.curve_to(pt1.0, pt1.1, pt2.0, pt2.1, to.0, to.1);
}
}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn rsvg_path_from_cairo_path() {
+ let surface = cairo::ImageSurface::create(cairo::Format::ARgb32, 10, 10).unwrap();
+ let cr = cairo::Context::new(&surface).unwrap();
+
+ cr.move_to(1.0, 2.0);
+ cr.line_to(3.0, 4.0);
+ cr.curve_to(5.0, 6.0, 7.0, 8.0, 9.0, 10.0);
+ cr.close_path();
+
+ let cairo_path = cr.copy_path().unwrap();
+ let path = Path::from_cairo(cairo_path);
+
+ assert_eq!(
+ path.iter().collect::<Vec<PathCommand>>(),
+ vec![
+ PathCommand::MoveTo(1.0, 2.0),
+ PathCommand::LineTo(3.0, 4.0),
+ PathCommand::CurveTo(CubicBezierCurve {
+ pt1: (5.0, 6.0),
+ pt2: (7.0, 8.0),
+ to: (9.0, 10.0),
+ }),
+ PathCommand::ClosePath,
+ PathCommand::MoveTo(1.0, 2.0), // cairo inserts a MoveTo after ClosePath
+ ],
+ );
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]