Merge pull request #1143 from Biromedic/fix/hidden-mask-art
Fix #1141: SVG import keeps a mask whose art is all hidden, so its object stays hidden
This commit is contained in:
commit
65a4847eed
File diff suppressed because one or more lines are too long
|
|
@ -965,8 +965,9 @@ impl Importer {
|
|||
nodes = rest;
|
||||
}
|
||||
let mut children: Vec<Arc<Node>> = nodes.iter().filter_map(|c| self.node(c, ts)).map(Arc::new).collect();
|
||||
// Mask art that is all hidden draws nothing: that is an empty mask, not no mask (black all
|
||||
// over when clipped, white when not, inverted when the mask is).
|
||||
let art = match children.len() {
|
||||
0 => return None,
|
||||
1 => Arc::unwrap_or_clone(children.pop()?),
|
||||
_ => self.named("", NodeKind::Group { children, clip: false }),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ use vectorcraft_color::{Color, Paint};
|
|||
use vectorcraft_doc::{Appearance, Document, Node, OpacityMask};
|
||||
use vectorcraft_geom::{Rect, shapes};
|
||||
use vectorcraft_svg::{ExportOptions, export, import_with_report};
|
||||
use vectorcraft_testkit::raster::{Image, render_artboard};
|
||||
|
||||
/// A red square masked by white art over its left half.
|
||||
fn masked(clip: bool, invert: bool) -> Document {
|
||||
|
|
@ -67,3 +68,37 @@ fn foreign_masks_keep_their_art() {
|
|||
assert!(m.clip && !m.invert);
|
||||
assert_eq!(m.art.children().map(|c| c.len()), Some(2));
|
||||
}
|
||||
|
||||
/// `svg` drawn by resvg, `w`×`h` on white.
|
||||
fn resvg_render(svg: &str, w: u32, h: u32) -> Image {
|
||||
let tree = resvg::usvg::Tree::from_str(svg, &resvg::usvg::Options::default()).expect("parse");
|
||||
let mut pm = resvg::tiny_skia::Pixmap::new(w, h).unwrap();
|
||||
pm.fill(resvg::tiny_skia::Color::WHITE);
|
||||
resvg::render(&tree, resvg::tiny_skia::Transform::identity(), &mut pm.as_mut());
|
||||
Image { width: w, height: h, rgba: pm.data().to_vec() }
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_mask_whose_art_is_all_hidden_hides_its_object() {
|
||||
// Hidden mask art draws nothing: the mask is black all over and the red square doesn't show,
|
||||
// as resvg draws the file. The square keeps its (empty) mask, so it can still be edited.
|
||||
for art in [
|
||||
r#"<rect width="100" height="100" fill="white" visibility="hidden"/>"#,
|
||||
r#"<g visibility="hidden"><rect width="100" height="100" fill="white"/></g>"#,
|
||||
] {
|
||||
let svg = format!(
|
||||
r#"<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
|
||||
<mask id="m" maskUnits="userSpaceOnUse" x="0" y="0" width="100" height="100">{art}</mask>
|
||||
<g mask="url(#m)"><rect width="100" height="100" fill="red"/></g></svg>"#
|
||||
);
|
||||
let (d, _) = import_with_report(&svg).unwrap();
|
||||
let [m] = &masks(&d)[..] else { panic!("the square keeps its mask: {svg}") };
|
||||
assert!(m.clip && !m.invert);
|
||||
assert!(m.art.geometric_bounds().is_none(), "no visible art: {:?}", m.art.kind);
|
||||
let (canvas, reference) = (render_artboard(&d), resvg_render(&svg, 100, 100));
|
||||
for (x, y) in [(10, 10), (50, 50), (90, 90)] {
|
||||
assert_eq!(reference.over_white(x, y), [255, 255, 255], "resvg ({x},{y}): {svg}");
|
||||
assert_eq!(canvas.over_white(x, y), [255, 255, 255], "canvas ({x},{y}): {svg}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue