use gio::prelude::*;
use rsvg::tests_only::{SharedImageSurface, SurfaceType};
use rsvg::{CairoRenderer, RenderingError};
use rsvg::test_utils::load_svg;
use rsvg::test_utils::reference_utils::{Compare, Evaluate, Reference};
#[test]
fn has_element_with_id_works() {
let svg = load_svg(
br#"
"#,
)
.unwrap();
assert!(svg.has_element_with_id("#foo").unwrap());
assert!(!svg.has_element_with_id("#bar").unwrap());
assert!(matches!(
svg.has_element_with_id(""),
Err(RenderingError::InvalidId(_))
));
assert!(matches!(
svg.has_element_with_id("not a fragment"),
Err(RenderingError::InvalidId(_))
));
assert!(matches!(
svg.has_element_with_id("notfragment#fragment"),
Err(RenderingError::InvalidId(_))
));
}
#[test]
fn render_layer() {
let svg = load_svg(
br##"
"##,
)
.unwrap();
let renderer = CairoRenderer::new(&svg);
let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
let res = {
let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
let viewport = cairo::Rectangle::new(100.0, 100.0, 100.0, 100.0);
renderer.render_layer(&cr, Some("#bar"), &viewport)
};
let output_surf = res
.map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
.unwrap();
let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
{
let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
cr.translate(100.0, 100.0);
cr.rectangle(20.0, 20.0, 30.0, 30.0);
cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
cr.fill().unwrap();
}
Reference::from_surface(reference_surf)
.compare(&output_surf)
.evaluate(&output_surf, "render_layer");
}
#[test]
fn untransformed_element() {
// This has a rectangle inside a transformed group. The rectangle
// inherits its stroke-width from the group.
//
// The idea is that we'll be able to extract the geometry of the rectangle
// as if it were not transformed by its ancestors, but still retain the
// cascade from the ancestors.
let svg = load_svg(
br##"
"##,
)
.unwrap();
let renderer = CairoRenderer::new(&svg);
/* Measuring */
let (ink_r, logical_r) = renderer.geometry_for_element(Some("#foo")).unwrap();
assert_eq!(ink_r, cairo::Rectangle::new(0.0, 0.0, 40.0, 50.0));
assert_eq!(logical_r, cairo::Rectangle::new(5.0, 5.0, 30.0, 40.0));
/* Rendering */
let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
let res = {
let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
let viewport = cairo::Rectangle::new(100.0, 100.0, 100.0, 100.0);
renderer.render_element(&cr, Some("#foo"), &viewport)
};
let output_surf = res
.map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
.unwrap();
let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 300, 300).unwrap();
{
let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
cr.translate(100.0, 100.0);
cr.rectangle(10.0, 10.0, 60.0, 80.0);
cr.set_source_rgba(0.0, 0.0, 1.0, 1.0);
cr.fill_preserve().unwrap();
cr.set_line_width(20.0);
cr.set_source_rgba(0.0, 0.0, 0.0, 1.0);
cr.stroke().unwrap();
}
Reference::from_surface(reference_surf)
.compare(&output_surf)
.evaluate(&output_surf, "untransformed_element");
}
#[test]
fn set_stylesheet() {
// This has a rectangle which we style from a user-supplied stylesheet.
let mut svg = load_svg(
br##"
"##,
)
.unwrap();
svg.set_stylesheet("rect { fill: #00ff00; }")
.expect("should be a valid stylesheet");
let renderer = CairoRenderer::new(&svg);
let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
let res = {
let cr = cairo::Context::new(&output).expect("Failed to create cairo context");
let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
renderer.render_document(&cr, &viewport)
};
let output_surf = res
.map(|_| SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap())
.unwrap();
let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
{
let cr = cairo::Context::new(&reference_surf).expect("Failed to create a cairo context");
cr.rectangle(10.0, 20.0, 30.0, 40.0);
cr.set_source_rgba(0.0, 1.0, 0.0, 1.0);
cr.fill().unwrap();
}
Reference::from_surface(reference_surf)
.compare(&output_surf)
.evaluate(&output_surf, "set_stylesheet");
}
// https://gitlab.gnome.org/GNOME/librsvg/-/issues/799
#[test]
fn text_doesnt_leave_points_in_current_path() {
let svg = load_svg(
br##"
"##,
)
.unwrap();
let renderer = CairoRenderer::new(&svg);
let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
let cr = cairo::Context::new(&output).unwrap();
assert!(!cr.has_current_point().unwrap());
let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
renderer.render_document(&cr, &viewport).unwrap();
assert!(!cr.has_current_point().unwrap());
}
#[test]
fn cancellation_works() {
let svg = load_svg(
br##"
"##,
)
.unwrap();
// To test cancellation, we'll start out by creating a cancellable and a renderer, and
// immediately cancelling the operation. Then we'll start rendering. In theory this
// will cause nothing to be rendered.
let cancellable = gio::Cancellable::new();
let renderer = CairoRenderer::new(&svg).with_cancellable(&cancellable);
cancellable.cancel();
let output = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
{
let cr = cairo::Context::new(&output).unwrap();
let viewport = cairo::Rectangle::new(0.0, 0.0, 100.0, 100.0);
// Test that cancellation happens...
assert!(matches!(
renderer.render_document(&cr, &viewport),
Err(RenderingError::Cancelled)
));
}
let output_surf = SharedImageSurface::wrap(output, SurfaceType::SRgb).unwrap();
// ... and test that we got an empty surface, since hopefully cancellation occurred
// before actually rendering anything.
let reference_surf = cairo::ImageSurface::create(cairo::Format::ARgb32, 100, 100).unwrap();
Reference::from_surface(reference_surf)
.compare(&output_surf)
.evaluate(&output_surf, "cancellation_works");
}