diff --git a/crates/svg/src/import/prepass.rs b/crates/svg/src/import/prepass.rs index 2afa651a5..8ed825948 100644 --- a/crates/svg/src/import/prepass.rs +++ b/crates/svg/src/import/prepass.rs @@ -40,6 +40,8 @@ pub(crate) struct Edits { list: Vec<(std::ops::Range, String)>, /// The ids made up so far, by element. ids: HashMap, + /// The ids in the file and those made up, read when the first id is made up. + taken: Option>, /// Declarations added to elements' `style`s, by element: (where they go, whether the element /// has a `style` attribute, the declarations, XML-escaped). styles: HashMap, @@ -50,7 +52,8 @@ impl Edits { self.list.push((at..at, text)); } - /// The id of element `n` (in `svg`), made up and written in when it has none. + /// The id of element `n` (in `svg`), made up and written in when it has none. A made-up id is + /// one no element of the file has. pub(super) fn id(&mut self, svg: &str, n: XNode) -> String { if let Some(id) = n.attribute("id").filter(|id| !id.is_empty()) { return id.to_string(); @@ -58,7 +61,16 @@ impl Edits { if let Some(id) = self.ids.get(&n.id()) { return id.clone(); } - let id = format!("{MADE_UP_ID}{}", self.ids.len()); + let taken = self.taken.get_or_insert_with(|| n.document().descendants().filter_map(|e| e.attribute("id")).map(str::to_string).collect()); + let mut i = self.ids.len(); + let id = loop { + let id = format!("{MADE_UP_ID}{i}"); + if !taken.contains(&id) { + break id; + } + i += 1; + }; + taken.insert(id.clone()); self.set(svg, n, "id", &id); self.ids.insert(n.id(), id.clone()); id @@ -119,7 +131,8 @@ impl Edits { /// ([`user_events`]), and the `