diff --git a/crates/usvg/src/writer.rs b/crates/usvg/src/writer.rs index 2cfb53122..21b89fd41 100644 --- a/crates/usvg/src/writer.rs +++ b/crates/usvg/src/writer.rs @@ -206,10 +206,10 @@ pub(crate) fn convert(tree: &Tree, opt: &XmlOptions) -> String { } xml.start_svg_element(EId::Defs); - conv_defs(tree, &mut ctx, &mut xml); + write_defs(tree, &mut ctx, &mut xml); xml.end_element(); - conv_elements(&tree.root, false, &mut ctx, &mut xml); + write_elements(&tree.root, false, &mut ctx, &mut xml); xml.end_document() } @@ -257,7 +257,7 @@ fn collect_node_ids(parent: &Node, ctx: &mut WriterContext) { } } -fn conv_filters(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { +fn write_filters(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { let mut filters = Vec::new(); tree.filters(|filter| { if !filters.iter().any(|other| Rc::ptr_eq(&filter, other)) { @@ -271,7 +271,7 @@ fn conv_filters(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { if let filter::Kind::Image(ref img) = fe.kind { if let filter::ImageKind::Use(ref node) = img.data { if !written_fe_image_nodes.iter().any(|id| id == &*node.id()) { - conv_element(node, false, ctx, xml); + write_element(node, false, ctx, xml); written_fe_image_nodes.push(node.id().to_string()); } } @@ -623,7 +623,9 @@ fn conv_filters(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { } } -fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { +fn write_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { + // Write gradients and text paths first, because they cannot reference other nodes. + let mut paint_servers: Vec = Vec::new(); tree.paint_servers(|paint| { if !paint_servers.contains(paint) { @@ -631,7 +633,7 @@ fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { } }); - for paint in paint_servers { + for paint in &paint_servers { match paint { Paint::Color(_) => {} Paint::LinearGradient(lg) => { @@ -655,30 +657,40 @@ fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { write_base_grad(&rg.base, ctx, xml); xml.end_element(); } - Paint::Pattern(pattern) => { - xml.start_svg_element(EId::Pattern); - ctx.prepare_defs_id(&pattern, &pattern.id, xml, |ctx| ctx.gen_pattern_id()); - xml.write_rect_attrs(pattern.rect); - xml.write_units(AId::PatternUnits, pattern.units, Units::ObjectBoundingBox); - xml.write_units( - AId::PatternContentUnits, - pattern.content_units, - Units::UserSpaceOnUse, - ); - xml.write_transform(AId::PatternTransform, pattern.transform, ctx); + Paint::Pattern(_) => {} // will be written later + } + } - if let Some(ref vbox) = pattern.view_box { - xml.write_viewbox(vbox); - } + if tree.has_text_nodes() { + write_text_path_paths(&tree.root, ctx, xml); + } - conv_elements(&pattern.root, false, ctx, xml); + // Now write nodes that can reference other nodes. - xml.end_element(); + for paint in paint_servers { + if let Paint::Pattern(pattern) = paint { + xml.start_svg_element(EId::Pattern); + ctx.prepare_defs_id(&pattern, &pattern.id, xml, |ctx| ctx.gen_pattern_id()); + xml.write_rect_attrs(pattern.rect); + xml.write_units(AId::PatternUnits, pattern.units, Units::ObjectBoundingBox); + xml.write_units( + AId::PatternContentUnits, + pattern.content_units, + Units::UserSpaceOnUse, + ); + xml.write_transform(AId::PatternTransform, pattern.transform, ctx); + + if let Some(ref vbox) = pattern.view_box { + xml.write_viewbox(vbox); } + + write_elements(&pattern.root, false, ctx, xml); + + xml.end_element(); } } - conv_filters(tree, ctx, xml); + write_filters(tree, ctx, xml); let mut clip_paths = Vec::new(); tree.clip_paths(|clip| { @@ -698,7 +710,7 @@ fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { xml.write_func_iri(AId::ClipPath, &clip.id, ctx); } - conv_elements(&clip.root, true, ctx, xml); + write_elements(&clip.root, true, ctx, xml); xml.end_element(); } @@ -729,14 +741,10 @@ fn conv_defs(tree: &Tree, ctx: &mut WriterContext, xml: &mut XmlWriter) { xml.write_func_iri(AId::Mask, &mask.id, ctx); } - conv_elements(&mask.root, false, ctx, xml); + write_elements(&mask.root, false, ctx, xml); xml.end_element(); } - - if tree.has_text_nodes() { - write_text_path_paths(&tree.root, ctx, xml); - } } fn write_text_path_paths(node: &Node, ctx: &mut WriterContext, xml: &mut XmlWriter) { @@ -764,13 +772,13 @@ fn write_text_path_paths(node: &Node, ctx: &mut WriterContext, xml: &mut XmlWrit } } -fn conv_elements(parent: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &mut XmlWriter) { +fn write_elements(parent: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &mut XmlWriter) { for n in parent.children() { - conv_element(&n, is_clip_path, ctx, xml); + write_element(&n, is_clip_path, ctx, xml); } } -fn conv_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &mut XmlWriter) { +fn write_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: &mut XmlWriter) { match *node.borrow() { NodeKind::Path(ref p) => { write_path(p, is_clip_path, Transform::default(), None, ctx, xml); @@ -895,13 +903,13 @@ fn conv_element(node: &Node, is_clip_path: bool, ctx: &mut WriterContext, xml: & ); } - conv_elements(node, false, ctx, xml); + write_elements(node, false, ctx, xml); xml.end_element(); } NodeKind::Text(ref text) => { if let Some(ref flattened) = text.flattened { - conv_element(flattened, is_clip_path, ctx, xml); + write_element(flattened, is_clip_path, ctx, xml); } else { xml.start_svg_element(EId::Text); @@ -1322,6 +1330,12 @@ fn has_xlink(node: &Node) -> bool { } _ => {} } + + let mut present = false; + n.subroots(|root| present |= has_xlink(&root)); + if present { + return true; + } } false diff --git a/crates/usvg/tests/files/preserve-text-in-clip-path-expected.svg b/crates/usvg/tests/files/preserve-text-in-clip-path-expected.svg new file mode 100644 index 000000000..91b0b3d92 --- /dev/null +++ b/crates/usvg/tests/files/preserve-text-in-clip-path-expected.svg @@ -0,0 +1,11 @@ + + + + + abcdefghijklmnopqrstuvwxyz + + + + + + diff --git a/crates/usvg/tests/files/preserve-text-in-mask-expected.svg b/crates/usvg/tests/files/preserve-text-in-mask-expected.svg new file mode 100644 index 000000000..58c8208ef --- /dev/null +++ b/crates/usvg/tests/files/preserve-text-in-mask-expected.svg @@ -0,0 +1,12 @@ + + + + + + abcdefghijklmnopqrstuvwxyz + + + + + + diff --git a/crates/usvg/tests/write.rs b/crates/usvg/tests/write.rs index 73c02b799..e538195d6 100644 --- a/crates/usvg/tests/write.rs +++ b/crates/usvg/tests/write.rs @@ -138,15 +138,15 @@ fn preserve_text_on_path() { resave_with_text("preserve-text-on-path"); } -// #[test] -// fn preserve_text_in_clip_path() { -// resave_with_text("preserve-text-in-clip-path"); -// } +#[test] +fn preserve_text_in_clip_path() { + resave_with_text("preserve-text-in-clip-path"); +} -// #[test] -// fn preserve_text_in_mask() { -// resave_with_text("preserve-text-in-mask"); -// } +#[test] +fn preserve_text_in_mask() { + resave_with_text("preserve-text-in-mask"); +} #[test] fn preserve_text_in_pattern() {