Use shared IDML document tree for import

This commit is contained in:
Dylan M. Taylor committed 2026-11-13 06:27:05 -05:00
1 parent e96849e2ef
commit dbc21ce1e9
9 files changed
+131 -112

No files matched your search

Generated
+26 -26
View File
@@ -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",
+2 -2
View File
@@ -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" }
+69 -56
View File
@@ -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<Item = El> + '_ {
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<Imported> {
let mut pkg = Package::open(bytes)?;
let package = pkg.document()?;
let root = crate::xml::from_craft(package.root);
let top: Vec<El> = 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<craft_idml::model::Spread> =
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<String> = 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<String>)> {
fn finish(mut self, root: &craft_idml::model::Values) -> Result<(Document, Vec<String>)> {
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()));
+6 -5
View File
@@ -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<designcraft_doc::Toc> {
pub(super) fn toc_of(&self, top: &[TopLevelNode]) -> Option<designcraft_doc::Toc> {
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.
+2 -2
View File
@@ -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<craft_idml::Document> {
self.inner.document().map_err(|e| match e {
pub(super) fn document(&mut self) -> Result<craft_idml::model::ModelDocument> {
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()),
+6 -6
View File
@@ -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<Vec<String>> = 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));
}
}
+4
View File
@@ -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()],
+8 -7
View File
@@ -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<u8> = 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
+8 -8
View File
@@ -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.