diff --git a/Cargo.lock b/Cargo.lock index a2b8abe16..83fb56e5b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1242,10 +1242,10 @@ dependencies = [ [[package]] name = "craft-idml" version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=121bd72ba#121bd72ba6a12c5b53da8acd2b3d95bd3c9c664d" +source = "git+https://github.com/storytold/craft-libs?rev=cbd672594#cbd672594eedcbb95624735e5c9f473720faf591" dependencies = [ - "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", - "craft-zip 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", + "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", + "craft-zip 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", "thiserror 2.0.21", ] @@ -1644,15 +1644,6 @@ dependencies = [ "thiserror 2.0.21", ] -[[package]] -name = "craft-xml" -version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=121bd72ba#121bd72ba6a12c5b53da8acd2b3d95bd3c9c664d" -dependencies = [ - "quick-xml 0.41.0", - "thiserror 2.0.21", -] - [[package]] name = "craft-xml" version = "0.1.0" @@ -1680,6 +1671,15 @@ dependencies = [ "thiserror 2.0.21", ] +[[package]] +name = "craft-xml" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=cbd672594#cbd672594eedcbb95624735e5c9f473720faf591" +dependencies = [ + "quick-xml 0.41.0", + "thiserror 2.0.21", +] + [[package]] name = "craft-xml" version = "0.1.0" @@ -1717,16 +1717,6 @@ dependencies = [ "thiserror 2.0.21", ] -[[package]] -name = "craft-zip" -version = "0.1.0" -source = "git+https://github.com/storytold/craft-libs?rev=121bd72ba#121bd72ba6a12c5b53da8acd2b3d95bd3c9c664d" -dependencies = [ - "flate2", - "thiserror 2.0.21", - "zip 9.1.1", -] - [[package]] name = "craft-zip" version = "0.1.0" @@ -1757,6 +1747,16 @@ dependencies = [ "zip 9.1.1", ] +[[package]] +name = "craft-zip" +version = "0.1.0" +source = "git+https://github.com/storytold/craft-libs?rev=cbd672594#cbd672594eedcbb95624735e5c9f473720faf591" +dependencies = [ + "flate2", + "thiserror 2.0.21", + "zip 9.1.1", +] + [[package]] name = "craft-zip" version = "0.1.0" @@ -2021,7 +2021,7 @@ dependencies = [ "craft-prepress", "craft-print", "craft-svg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)", - "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", + "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=f23b0f33f0d00b157476533a43cbbcfd901aa1f1)", "designcraft-color", "designcraft-compose", @@ -2103,9 +2103,9 @@ name = "designcraft-idml" version = "0.20.1" dependencies = [ "craft-file-formats", - "craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", + "craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", "craft-svg 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cc23ffd4d26f3074808e2187d332564817624f8f)", - "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", + "craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", "designcraft-color", "designcraft-compose", "designcraft-doc", @@ -2222,7 +2222,7 @@ version = "0.20.1" dependencies = [ "craft-docx", "craft-file-formats", - "craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=121bd72ba)", + "craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=cbd672594)", "craft-rtf", "craft-wordmodel", "craft-xlsx", diff --git a/Cargo.toml b/Cargo.toml index e2db67bf1..4964732d1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,10 +16,10 @@ craft-pdf = { git = "https://github.com/storytold/craft-libs", rev = "4052591363 craft-designcraft-format = { git = "https://github.com/storytold/craft-libs", rev = "19692b6190465671e41967c75d0cd4c439d0c84c", version = "=0.1.0" } craft-eps = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" } craft-epub = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" } -craft-idml = { git = "https://github.com/storytold/craft-libs", rev = "121bd72ba", version = "=0.1.0" } +craft-idml = { git = "https://github.com/storytold/craft-libs", rev = "cbd672594", version = "=0.1.0" } craft-indd = { git = "https://github.com/storytold/craft-libs", rev = "47bf5650b0d503b97bfb5e841746c4957897d11f", version = "=0.1.0" } craft-svg = { git = "https://github.com/storytold/craft-libs", rev = "cc23ffd4d26f3074808e2187d332564817624f8f", version = "=0.1.0", features = ["tree-render", "tree-text"] } -craft-xml = { git = "https://github.com/storytold/craft-libs", rev = "121bd72ba", version = "=0.1.0" } +craft-xml = { git = "https://github.com/storytold/craft-libs", rev = "cbd672594", version = "=0.1.0" } craft-xml-dtd = { package = "craft-xml", git = "https://github.com/storytold/craft-libs", rev = "f23b0f33f0d00b157476533a43cbbcfd901aa1f1", version = "=0.1.0" } craft-rtf = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" } craft-xlsx = { git = "https://github.com/storytold/craft-libs", rev = "ba24fe2435adb3c81ad6057faf36365fbba736cf", version = "=0.1.0" } diff --git a/crates/idml/src/import.rs b/crates/idml/src/import.rs index 269b6b5a8..52a0aa48e 100644 --- a/crates/idml/src/import.rs +++ b/crates/idml/src/import.rs @@ -3,6 +3,7 @@ use std::collections::{BTreeMap, HashMap, HashSet}; use std::sync::Arc; +use craft_idml::model::{TopLevelKind as TopKind, TopLevelNode}; use designcraft_color::cms::lab; use designcraft_color::{Color, ColorType, Gradient, GradientKind, GradientStop, Swatch, SwatchValue, swatch}; use designcraft_doc::{ @@ -40,6 +41,14 @@ pub(crate) use package::{percent_decode, uri_to_path}; use text_attrs::mojikumi_row; use values::{nums, xmp_date}; +fn top_el(node: &TopLevelNode) -> El { + crate::xml::from_craft(node.to_el()) +} + +fn top_els_of(top: &[TopLevelNode], kind: TopKind) -> impl Iterator + '_ { + top.iter().filter(move |node| node.kind == kind).map(top_el) +} + /// Import an IDML package without reading its linked images from disk: this crate never touches /// the file system, so a caller that wants the links brings its own reader /// ([`import_idml_with`]). The engine passes one that checks the automation roots. @@ -79,8 +88,8 @@ pub fn import_idml_report_with_previews( ) -> Result { let mut pkg = Package::open(bytes)?; let package = pkg.document()?; - let root = crate::xml::from_craft(package.root); - let top: Vec = package.top.into_iter().map(crate::xml::from_craft).collect(); + let root = package.root; + let top = package.top; let mut warnings = package.warnings; let mut im = Importer::new(read_link, previews); if let Some(m) = package.metadata { @@ -325,17 +334,18 @@ impl<'r> Importer<'r> { self.next_id } - fn read_preferences(&mut self, top: &[El]) { + fn read_preferences(&mut self, top: &[TopLevelNode]) { // Preferences first (page size, facing pages). - for e in top { - match e.local() { - "DocumentPreference" => self.doc_prefs(e), - "TransparencyPreference" => { + for node in top { + let e = top_el(node); + match node.kind { + TopKind::DocumentPreference => self.doc_prefs(&e), + TopKind::TransparencyPreference => { if let Some(v) = e.get("BlendingSpace") { self.settings.blend_space = if v == "RGB" { designcraft_doc::BlendSpace::Rgb } else { designcraft_doc::BlendSpace::Cmyk }; } } - "TextPreference" => { + TopKind::TextPreference => { let a = &mut self.settings.advanced_type; for (k, v) in [ ("SuperscriptSize", &mut a.superscript_size), @@ -348,11 +358,11 @@ impl<'r> Importer<'r> { } } } - "MarginPreference" => { - let (m, c) = margins_of_el(e); + TopKind::MarginPreference => { + let (m, c) = margins_of_el(&e); self.default_margins = Some((m, c)); } - "ViewPreference" => { + TopKind::ViewPreference => { for (attr, ruler) in [("HorizontalMeasurementUnits", "horizontal"), ("VerticalMeasurementUnits", "vertical")] { let Some(u) = e.get(attr) else { continue }; let unit = names::unit_in(u).unwrap_or_else(|| { @@ -375,8 +385,8 @@ impl<'r> Importer<'r> { _ => {} } } - "GridPreference" => self.grid_prefs(e), - "PasteboardPreference" => { + TopKind::GridPreference => self.grid_prefs(&e), + TopKind::PasteboardPreference => { if let Some(v) = e.get("PasteboardMargins").map(nums) && v.len() == 2 && v[0] >= 0.0 @@ -390,8 +400,8 @@ impl<'r> Importer<'r> { } } - fn read_composite_fonts(&mut self, top: &[El]) { - for e in top.iter().filter(|e| e.local() == "CompositeFont") { + fn read_composite_fonts(&mut self, top: &[TopLevelNode]) { + for e in top_els_of(top, TopKind::CompositeFont) { let name = e.get("Name").map(str::to_string).unwrap_or_else(|| unescape_id(e.get("Self").unwrap_or("").trim_start_matches("CompositeFont/"))); if let Some(id) = e.get("Self") { @@ -417,8 +427,8 @@ impl<'r> Importer<'r> { } } - fn read_cjk_tables(&mut self, top: &[El]) -> Result<()> { - for e in top.iter().filter(|e| e.local() == "KinsokuTable") { + fn read_cjk_tables(&mut self, top: &[TopLevelNode]) -> Result<()> { + for e in top_els_of(top, TopKind::KinsokuTable) { if e.get("CantBeginLineChars").is_some() || e.get("CantEndLineChars").is_some() { self.kinsoku.insert( e.get("Self").unwrap_or("").into(), @@ -432,7 +442,7 @@ impl<'r> Importer<'r> { ); } } - for e in top.iter().filter(|e| e.local() == "MojikumiTable") { + for e in top_els_of(top, TopKind::MojikumiTable) { if let (Some(id), Some(name)) = (e.get("Self"), e.get("Name")) { self.mojikumi_names.insert(id.into(), format!("MojikumiTable/{}", unescape_id(name))); } @@ -450,19 +460,19 @@ impl<'r> Importer<'r> { Ok(()) } - fn run(&mut self, _root: &El, top: &[El]) -> Result<()> { + fn run(&mut self, _root: &craft_idml::model::Values, top: &[TopLevelNode]) -> Result<()> { self.read_preferences(top); self.read_composite_fonts(top); self.read_cjk_tables(top)?; self.graphics(top); self.styles(top); - if let Some(e) = top.iter().find(|e| e.local() == "FootnoteOption") { - self.footnote_option(e); + if let Some(e) = top_els_of(top, TopKind::FootnoteOption).next() { + self.footnote_option(&e); } - if let Some(e) = top.iter().find(|e| e.local() == "EPubExportPreference") { - self.epub_split(e); + if let Some(e) = top_els_of(top, TopKind::EpubExportPreference).next() { + self.epub_split(&e); } - for e in top.iter().filter(|e| e.local() == "Layer") { + for e in top_els_of(top, TopKind::Layer) { let id = LayerId(self.alloc()); let color = match e.prop_el("LayerColor") { Some(c) if c.get("type") == Some("list") => { @@ -501,33 +511,34 @@ impl<'r> Importer<'r> { suppress_wrap_when_hidden: false, }); } - for e in top.iter().filter(|e| e.local() == "CrossReferenceFormat") { - self.xref_format(e); + for e in top_els_of(top, TopKind::CrossReferenceFormat) { + self.xref_format(&e); } self.read_hyperlinks(top); - if let Some(ix) = top.iter().find(|e| e.local() == "Index") { - self.index_topics_of(ix, &IndexTopic::default()); + if let Some(ix) = top_els_of(top, TopKind::Index).next() { + self.index_topics_of(&ix, &IndexTopic::default()); } - for e in top.iter().filter(|e| e.local() == "TextVariable") { - self.text_variable(e); + for e in top_els_of(top, TopKind::TextVariable) { + self.text_variable(&e); } // Stories (ids first so frames can reference them). let mut pending_stories = Vec::new(); - for e in top.iter().filter(|e| e.local() == "Story") { + for node in top.iter().filter(|node| node.kind == TopKind::Story) { + let Some(source) = node.story() else { continue }; let id = StoryId(self.alloc()); - if let Some(s) = e.get("Self") { + if let Some(s) = source.values.self_id() { self.story_ids.insert(s.to_string(), id); } - pending_stories.push((id, e)); + pending_stories.push((id, source.clone())); } - for (id, e) in pending_stories { - let story = self.story(id, e); + for (id, source) in pending_stories { + let story = self.story_from_model(id, source, ParaFormat::default()); self.stories.insert(id, story); } self.toc = self.toc_of(top); self.place_index_xrefs(); // Cross-references point at their hyperlink's destination. - for h in top.iter().filter(|e| e.local() == "Hyperlink") { + for h in top_els_of(top, TopKind::Hyperlink) { let (Some(src), Some(dest)) = (h.get("Source"), h.prop("Destination")) else { continue }; let (Some(&(sid, k)), Some(&target)) = (self.xref_srcs.get(src), self.anchor_ids.get(dest.trim())) else { continue }; if let Some(x) = self.stories.get_mut(&sid).and_then(|st| st.xrefs.get_mut(k)) { @@ -535,27 +546,28 @@ impl<'r> Importer<'r> { } } // Parent spreads: ids first (pages reference other parents). - let masters: Vec<&El> = top.iter().filter(|e| e.local() == "MasterSpread").collect(); + let masters: Vec = + top.iter().filter(|node| node.kind == TopKind::MasterSpread).filter_map(|node| node.spread().cloned()).collect(); let mut master_ids = Vec::new(); for m in &masters { let id = SpreadId(self.alloc()); - if let Some(s) = m.get("Self") { + if let Some(s) = m.values.self_id() { self.parent_ids.insert(s.to_string(), id); } master_ids.push(id); } for (m, id) in masters.iter().zip(master_ids) { - let sp = self.spread(m, id, true); + let sp = self.spread_from_model(m, id, true); self.parents.push(sp); } - for e in top.iter().filter(|e| e.local() == "Spread") { + for model_spread in top.iter().filter(|node| node.kind == TopKind::Spread).filter_map(TopLevelNode::spread) { let id = SpreadId(self.alloc()); - let sp = self.spread(e, id, false); + let sp = self.spread_from_model(model_spread, id, false); self.spreads.push(sp); } // Sections. A section whose AlternateLayout differs from the one before starts that layout. let mut last_layout: Option = None; - for e in top.iter().filter(|e| e.local() == "Section") { + for e in top_els_of(top, TopKind::Section) { let Some(start) = e.get("PageStart").and_then(|p| self.page_index.get(p)).copied() else { continue }; let layout = e.get("AlternateLayout").map(str::trim).filter(|l| !l.is_empty()).map(str::to_string); let starts_layout = layout.clone().filter(|l| last_layout.as_ref() != Some(l)); @@ -601,35 +613,36 @@ impl<'r> Importer<'r> { /// Hyperlink sources, destinations and the `Hyperlink` elements that join them (#1446), by /// name: the pages, page items and anchors they name are read later, so `finish` puts the two /// ends together. - fn read_hyperlinks(&mut self, top: &[El]) { - for e in top { + fn read_hyperlinks(&mut self, top: &[TopLevelNode]) { + for node in top { + let e = top_el(node); let me = || e.get("Self").unwrap_or("").trim().to_string(); - match e.local() { - "HyperlinkURLDestination" => { - if let Some(u) = attr_or_prop(e, "DestinationURL") { + match node.kind { + TopKind::HyperlinkUrlDestination => { + if let Some(u) = attr_or_prop(&e, "DestinationURL") { self.link_dests.insert(me(), PendingDest::Url(u)); } } - "HyperlinkPageDestination" => { - if let Some(pg) = attr_or_prop(e, "DestinationPage") { + TopKind::HyperlinkPageDestination => { + if let Some(pg) = attr_or_prop(&e, "DestinationPage") { self.link_dests.insert(me(), PendingDest::Page(pg)); } } - "HyperlinkPageItemSource" => { - if let Some(it) = attr_or_prop(e, "SourcePageItem") { + TopKind::HyperlinkPageItemSource => { + if let Some(it) = attr_or_prop(&e, "SourcePageItem") { self.link_item_srcs.insert(me(), it); } } - "Hyperlink" => { - if let (Some(src), Some(dest)) = (attr_or_prop(e, "Source"), attr_or_prop(e, "Destination")) { + TopKind::Hyperlink => { + if let (Some(src), Some(dest)) = (attr_or_prop(&e, "Source"), attr_or_prop(&e, "Destination")) { let name = e.get("Name").unwrap_or("").trim().to_string(); self.links.push((name, src, dest)); } } // A destination kind this importer does not read (an external page, say): kept // by name so a link dropped for it can say what it led to. - other if other.starts_with("Hyperlink") && other.ends_with("Destination") => { - self.other_dests.insert(me(), other.to_string()); + TopKind::HyperlinkOtherDestination => { + self.other_dests.insert(me(), e.local().to_string()); } _ => {} } @@ -740,7 +753,7 @@ impl<'r> Importer<'r> { } /// The finished document, and the warnings raised while finishing it. - fn finish(mut self, root: &El) -> Result<(Document, Vec)> { + fn finish(mut self, root: &craft_idml::model::Values) -> Result<(Document, Vec)> { let title = root.get("Name").map(|n| n.trim_end_matches(".indd").to_string()).filter(|n| !n.is_empty()).unwrap_or_else(|| "Untitled".into()); if self.spreads.is_empty() { return Err(IdmlError::Invalid("document has no spreads".into())); diff --git a/crates/idml/src/import/document.rs b/crates/idml/src/import/document.rs index 2d4e5bb11..12a46c2df 100644 --- a/crates/idml/src/import/document.rs +++ b/crates/idml/src/import/document.rs @@ -1,5 +1,5 @@ use super::values::tint; -use super::{BaselineGrid, El, GridRelative, Importer, PARA_BUILTINS, names}; +use super::{BaselineGrid, El, GridRelative, Importer, PARA_BUILTINS, TopKind, TopLevelNode, names}; /// IDML stores a sort key on each topic, rather than on its page references. #[derive(Clone, Default)] @@ -312,12 +312,13 @@ impl<'r> Importer<'r> { /// The table of contents: the TOC style a story is generated from (`AppliedTOCStyle`), with /// its entries. Styles the document doesn't have fall back to the generated TOC styles. - pub(super) fn toc_of(&self, top: &[El]) -> Option { + pub(super) fn toc_of(&self, top: &[TopLevelNode]) -> Option { use designcraft_doc::{TocEntry, TocPageNumber}; - let (ts, story) = top.iter().filter(|e| e.local() == "TOCStyle").find_map(|ts| { + let (ts, story) = top.iter().filter(|node| node.kind == TopKind::TocStyle).find_map(|node| { + let ts = crate::xml::from_craft(node.to_el()); let id = ts.get("Self")?; - let story = top.iter().find(|e| e.local() == "Story" && e.get("AppliedTOCStyle") == Some(id))?; - Some((ts, *self.story_ids.get(story.get("Self")?)?)) + let story = top.iter().find(|node| node.kind == TopKind::Story && node.values().get("AppliedTOCStyle") == Some(id))?; + Some((ts, *self.story_ids.get(story.values().self_id()?)?)) })?; // Property children are element text: formatting whitespace around a reference is dropped // unless the reference as written names a style. diff --git a/crates/idml/src/import/package.rs b/crates/idml/src/import/package.rs index 2f9601099..c65dd75c8 100644 --- a/crates/idml/src/import/package.rs +++ b/crates/idml/src/import/package.rs @@ -11,8 +11,8 @@ impl<'a> Package<'a> { } /// Reads the designmap, XML parts, included resources and metadata with the shared parser. - pub(super) fn document(&mut self) -> Result { - self.inner.document().map_err(|e| match e { + pub(super) fn document(&mut self) -> Result { + self.inner.document().map(craft_idml::model::ModelDocument::from_package).map_err(|e| match e { craft_idml::Error::TooLarge { part, limit } => IdmlError::Part { part, msg: format!("larger than the {limit}-byte package read limit") }, craft_idml::Error::Part { part, msg } => IdmlError::Part { part, msg }, other => IdmlError::NotIdml(other.to_string()), diff --git a/crates/idml/src/import/spread.rs b/crates/idml/src/import/spread.rs index 0ec3f88ed..b0c58ef13 100644 --- a/crates/idml/src/import/spread.rs +++ b/crates/idml/src/import/spread.rs @@ -1,6 +1,6 @@ use super::frame::{fit_columns, margins_of}; use super::{ - Affine, Arc, Columns, El, Guide, Importer, ItemId, Margins, Orientation, Page, PageId, PageSide, ParentInfo, Point, Rect, Spread, SpreadId, names, + Affine, Arc, Columns, Guide, Importer, ItemId, Margins, Orientation, Page, PageId, PageSide, ParentInfo, Point, Rect, Spread, SpreadId, names, }; impl<'r> Importer<'r> { @@ -82,11 +82,10 @@ impl<'r> Importer<'r> { (margins, columns, local_margins) } - pub(super) fn spread(&mut self, e: &El, id: SpreadId, master: bool) -> Spread { - let model_spread = craft_idml::model::Spread::from_el(&crate::xml::to_craft(e)); + pub(super) fn spread_from_model(&mut self, model_spread: &craft_idml::model::Spread, id: SpreadId, master: bool) -> Spread { let facing = self.settings.facing_pages; // Page rectangles in IDML spread coordinates. - let pages = self.page_rects(&model_spread); + let pages = self.page_rects(model_spread); let min_x = pages.iter().map(|(r, _)| r.x0).fold(f64::INFINITY, f64::min); let min_y = pages.iter().map(|(r, _)| r.y0).fold(f64::INFINITY, f64::min); let (min_x, min_y) = if min_x.is_finite() { (min_x, min_y) } else { (0.0, 0.0) }; @@ -135,8 +134,9 @@ impl<'r> Importer<'r> { } let overrides: Vec> = pages.iter().map(|(_, p)| p.override_list().into_iter().map(str::to_string).collect()).collect(); let mut items = Vec::new(); - for c in e.elements() { - if let Some(it) = self.item(c, shift) { + for item in model_spread.items() { + let item_el = crate::xml::from_craft(item.to_el()); + if let Some(it) = self.item(&item_el, shift) { items.push(Arc::new(it)); } } diff --git a/crates/idml/src/import/story.rs b/crates/idml/src/import/story.rs index aa2066e27..302a33cca 100644 --- a/crates/idml/src/import/story.rs +++ b/crates/idml/src/import/story.rs @@ -11,6 +11,10 @@ impl<'r> Importer<'r> { pub(super) fn story_with_para(&mut self, id: StoryId, e: &El, default_para: ParaFormat) -> Story { let source = craft_idml::model::Story::from_el(&crate::xml::to_craft(e)); + self.story_from_model(id, source, default_para) + } + + pub(super) fn story_from_model(&mut self, id: StoryId, source: craft_idml::model::Story, default_para: ParaFormat) -> Story { let mut b = StoryBuilder { text: String::new(), paras: vec![default_para.clone()], diff --git a/crates/idml/src/import/styles.rs b/crates/idml/src/import/styles.rs index 4b574c032..d65f39441 100644 --- a/crates/idml/src/import/styles.rs +++ b/crates/idml/src/import/styles.rs @@ -1,19 +1,20 @@ use super::table::uniform_cell_stroke; use super::values::tint; use super::{ - CHAR_BUILTINS, CharacterStyle, El, Fill, Importer, OBJECT_BUILTINS, ObjectStyle, PARA_BUILTINS, ParagraphStyle, Rule, names, st, swatch, - unescape_id, + CHAR_BUILTINS, CharacterStyle, El, Fill, Importer, OBJECT_BUILTINS, ObjectStyle, PARA_BUILTINS, ParagraphStyle, Rule, TopKind, TopLevelNode, + names, st, swatch, top_el, unescape_id, }; type StyleElements = (Vec<(String, El)>, Vec<(String, El)>, Vec<(String, El)>, Vec<(String, El)>, Vec<(String, El)>); -fn style_elements(top: &[El]) -> StyleElements { +fn style_elements(top: &[TopLevelNode]) -> StyleElements { let mut paras = Vec::new(); let mut chars = Vec::new(); let mut objects = Vec::new(); let mut cell_styles = Vec::new(); let mut table_styles = Vec::new(); - for group in top.iter().filter_map(|el| craft_idml::model::StyleGroup::from_el(&crate::xml::to_craft(el))) { + let model_top: Vec<_> = top.iter().map(TopLevelNode::to_el).collect(); + for group in model_top.iter().filter_map(craft_idml::model::StyleGroup::from_el) { for (_, style) in group.styles() { let id = style.values.self_id().unwrap_or("").to_string(); let el = crate::xml::from_craft(style.to_el()); @@ -32,8 +33,8 @@ fn style_elements(top: &[El]) -> StyleElements { impl<'r> Importer<'r> { // ---------- styles ---------- - pub(super) fn styles(&mut self, top: &[El]) { - for e in top.iter().filter(|e| e.local() == "Condition") { + pub(super) fn styles(&mut self, top: &[TopLevelNode]) { + for e in top.iter().filter(|node| node.kind == TopKind::Condition).map(top_el) { let (Some(id), Some(name)) = (e.get("Self"), e.get("Name")) else { continue }; // Indicator colours: "r g b" (0–255) or a UI colour name (kept as the default blue). let nums: Vec = e @@ -47,7 +48,7 @@ impl<'r> Importer<'r> { self.condition_names.insert(id.to_string(), name.to_string()); self.conditions.push(designcraft_doc::Condition { name: name.to_string(), color, visible: e.get("Visible") != Some("false") }); } - for e in top.iter().filter(|e| e.local() == "NumberingList") { + for e in top.iter().filter(|node| node.kind == TopKind::NumberingList).map(top_el) { let name = e.get("Name").unwrap_or("").to_string(); if !name.is_empty() && !name.starts_with("$ID/") && !self.lists.iter().any(|l| l.name == name) { self.lists diff --git a/crates/idml/src/import/swatches.rs b/crates/idml/src/import/swatches.rs index 330019c1e..4fe358309 100644 --- a/crates/idml/src/import/swatches.rs +++ b/crates/idml/src/import/swatches.rs @@ -1,8 +1,8 @@ use super::frame::{Prefs, text_frame_options}; use super::values::lab_to_color; use super::{ - Color, ColorType, El, Gradient, GradientKind, GradientStop, HashMap, HashSet, Importer, Styles, Swatch, SwatchValue, TextFrameOptions, names, - swatch, + Color, ColorType, El, Gradient, GradientKind, GradientStop, HashMap, HashSet, Importer, Styles, Swatch, SwatchValue, TextFrameOptions, + TopLevelNode, names, swatch, }; impl<'r> Importer<'r> { @@ -30,8 +30,8 @@ impl<'r> Importer<'r> { } /// Custom stroke styles. - fn read_stroke_styles(&mut self, top: &[El]) { - let top: Vec<_> = top.iter().map(crate::xml::to_craft).collect(); + fn read_stroke_styles(&mut self, top: &[TopLevelNode]) { + let top: Vec<_> = top.iter().map(TopLevelNode::to_el).collect(); for e in craft_idml::model::stroke_styles(&top) { let (Some(id), Some(name)) = (e.values.self_id(), e.values.name()) else { continue }; let kind = match e.kind { @@ -47,8 +47,8 @@ impl<'r> Importer<'r> { } /// Ink Manager settings: inks converted to process and ink aliases. - fn read_inks(&mut self, top: &[El]) { - let model_top: Vec<_> = top.iter().map(crate::xml::to_craft).collect(); + fn read_inks(&mut self, top: &[TopLevelNode]) { + let model_top: Vec<_> = top.iter().map(TopLevelNode::to_el).collect(); for e in craft_idml::model::inks(&model_top) { let Some(name) = e.name().filter(|n| !n.starts_with("$ID/") && !["Process Cyan", "Process Magenta", "Process Yellow", "Process Black"].contains(n)) @@ -64,8 +64,8 @@ impl<'r> Importer<'r> { } } - pub(super) fn graphics(&mut self, top: &[El]) { - let model_top: Vec<_> = top.iter().map(crate::xml::to_craft).collect(); + pub(super) fn graphics(&mut self, top: &[TopLevelNode]) { + let model_top: Vec<_> = top.iter().map(TopLevelNode::to_el).collect(); let swatches = craft_idml::model::swatches(&model_top); let mut order: Vec<(String, Swatch)> = Vec::new(); // Colours.