mirror of
https://github.com/storytold/designcraft.git
synced 2026-11-14 14:22:39 +00:00
Use shared writer for IDML style groups
This commit is contained in:
4 files changed
+33
-83
No files matched your search
Generated
+10
-10
@@ -1242,10 +1242,10 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-idml"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=8345921af#8345921aff971504d55cc202b93d2ca6aa5932de"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c#3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c"
|
||||
dependencies = [
|
||||
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=8345921af)",
|
||||
"craft-zip 0.1.0 (git+https://github.com/storytold/craft-libs?rev=8345921af)",
|
||||
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"craft-zip 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"thiserror 2.0.21",
|
||||
]
|
||||
|
||||
@@ -1647,7 +1647,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-xml"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=40525913633942f84b06d4837a8d90534a55d63f#40525913633942f84b06d4837a8d90534a55d63f"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c#3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c"
|
||||
dependencies = [
|
||||
"quick-xml 0.41.0",
|
||||
"thiserror 2.0.21",
|
||||
@@ -1656,7 +1656,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-xml"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=8345921af#8345921aff971504d55cc202b93d2ca6aa5932de"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=40525913633942f84b06d4837a8d90534a55d63f#40525913633942f84b06d4837a8d90534a55d63f"
|
||||
dependencies = [
|
||||
"quick-xml 0.41.0",
|
||||
"thiserror 2.0.21",
|
||||
@@ -1730,7 +1730,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "craft-zip"
|
||||
version = "0.1.0"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=8345921af#8345921aff971504d55cc202b93d2ca6aa5932de"
|
||||
source = "git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c#3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c"
|
||||
dependencies = [
|
||||
"flate2",
|
||||
"thiserror 2.0.21",
|
||||
@@ -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=8345921af)",
|
||||
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"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=8345921af)",
|
||||
"craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"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=8345921af)",
|
||||
"craft-xml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"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=8345921af)",
|
||||
"craft-idml 0.1.0 (git+https://github.com/storytold/craft-libs?rev=3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c)",
|
||||
"craft-rtf",
|
||||
"craft-wordmodel",
|
||||
"craft-xlsx",
|
||||
|
||||
+2
-2
@@ -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 = "8345921af", version = "=0.1.0" }
|
||||
craft-idml = { git = "https://github.com/storytold/craft-libs", rev = "3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c", 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 = "8345921af", version = "=0.1.0" }
|
||||
craft-xml = { git = "https://github.com/storytold/craft-libs", rev = "3d82c75d5d0ffcbb7bb39aff687f69ce8c4a713c", 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" }
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
use super::common::{affine_s, bool_s, p, pct, uid, with_props};
|
||||
use super::{
|
||||
Affine, ColumnsKind, Content, El, Ex, HashSet, Item, Node, OBJECT_BUILTINS, PathData, Shape, TextFrameOptions, base64_encode, escape_id, names,
|
||||
num, pt,
|
||||
Affine, ColumnsKind, Content, El, Ex, HashSet, Item, Node, OBJECT_BUILTINS, PathData, Shape, TextFrameOptions, base64_encode, names, num, pt,
|
||||
};
|
||||
|
||||
impl<'a> Ex<'a> {
|
||||
@@ -324,49 +323,6 @@ impl<'a> Ex<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Most nested style folders one style name can create.
|
||||
const MAX_STYLE_GROUP_DEPTH: usize = 32;
|
||||
|
||||
/// Style folder tree (names `A/B/C` → groups A, B).
|
||||
#[derive(Default)]
|
||||
pub(super) struct Group {
|
||||
styles: Vec<El>,
|
||||
groups: Vec<(String, Group)>,
|
||||
}
|
||||
|
||||
impl Group {
|
||||
pub(super) fn insert(&mut self, name: &str, el: El) {
|
||||
let builtin = name.starts_with('[');
|
||||
let mut segs: Vec<&str> = if builtin { vec![name] } else { name.split('/').collect() };
|
||||
let _leaf = segs.pop();
|
||||
let mut g = self;
|
||||
// Deeper folders than this are not made (the style lands in the deepest one), so the recursive `emit` is bounded.
|
||||
for s in segs.into_iter().take(MAX_STYLE_GROUP_DEPTH) {
|
||||
let i = match g.groups.iter().position(|(n, _)| n == s) {
|
||||
Some(i) => i,
|
||||
None => {
|
||||
g.groups.push((s.to_string(), Group::default()));
|
||||
g.groups.len() - 1
|
||||
}
|
||||
};
|
||||
g = &mut g.groups[i].1;
|
||||
}
|
||||
g.styles.push(el);
|
||||
}
|
||||
|
||||
pub(super) fn emit(self, parent: &mut El, kind: &str, path: &str) {
|
||||
for s in self.styles {
|
||||
parent.push(s);
|
||||
}
|
||||
for (name, g) in self.groups {
|
||||
let full = if path.is_empty() { name.clone() } else { format!("{path}:{name}") };
|
||||
let mut ge = El::new(kind).attr("Self", format!("{kind}/{}", escape_id(&full))).attr("Name", &name);
|
||||
g.emit(&mut ge, kind, &full);
|
||||
parent.push(ge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `rule_color` is the IDML reference of the column rule's swatch.
|
||||
/// `TextWrapPreference` of a page item or a placed graphic.
|
||||
fn text_wrap_pref(w: &designcraft_doc::TextWrap) -> El {
|
||||
@@ -522,20 +478,20 @@ pub(crate) fn path_to_uri(path: &str) -> String {
|
||||
|
||||
#[cfg(test)]
|
||||
mod group_depth_tests {
|
||||
use super::*;
|
||||
use craft_idml::model::{StyleGroupWriter, StyleKind};
|
||||
|
||||
#[test]
|
||||
fn a_style_name_with_many_separators_makes_bounded_folders() {
|
||||
let mut g = Group::default();
|
||||
g.insert(&"a/".repeat(10_000), El::new("S"));
|
||||
let (mut depth, mut cur) = (0, &g);
|
||||
while let Some((_, next)) = cur.groups.first() {
|
||||
let mut group = StyleGroupWriter::new(StyleKind::Character, "root");
|
||||
let style = craft_idml::El::new("CharacterStyle");
|
||||
group.insert(&"a/".repeat(10_000), style);
|
||||
let root = group.to_el();
|
||||
let mut depth = 0;
|
||||
let mut current = root.elements().next();
|
||||
while let Some(el) = current.filter(|el| el.local() == "CharacterStyleGroup") {
|
||||
depth += 1;
|
||||
cur = next;
|
||||
current = el.elements().next();
|
||||
}
|
||||
assert_eq!(depth, MAX_STYLE_GROUP_DEPTH);
|
||||
assert_eq!(cur.styles.len(), 1);
|
||||
let mut root = El::new("Root");
|
||||
g.emit(&mut root, "K", "");
|
||||
assert_eq!(depth, 32);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::common::{bool_s, p, pct, pkg_root, with_props};
|
||||
use super::item::{Group, text_frame_pref};
|
||||
use super::item::text_frame_pref;
|
||||
use super::story::with_list_tab;
|
||||
use super::{
|
||||
CHAR_BUILTINS, El, Ex, NO_PARA_ID, OBJECT_BUILTINS, PARA_BUILTINS, Rule, TOC_STYLE_ID, TOC_STYLE_NAME, document, escape_id, names, num, st,
|
||||
@@ -14,7 +14,7 @@ impl<'a> Ex<'a> {
|
||||
let mut root = pkg_root("Styles");
|
||||
|
||||
// Character styles.
|
||||
let mut cg = Group::default();
|
||||
let mut cg = craft_idml::model::StyleGroupWriter::new(craft_idml::model::StyleKind::Character, self.fresh());
|
||||
for cs in &styles.character {
|
||||
let id = names::style_self("CharacterStyle", CHAR_BUILTINS, &cs.name);
|
||||
let mut el =
|
||||
@@ -32,14 +32,12 @@ impl<'a> Ex<'a> {
|
||||
if let Some(t) = styles.export_tag(&cs.name, true) {
|
||||
el.push(self.export_tag_map(t));
|
||||
}
|
||||
cg.insert(&cs.name, el);
|
||||
cg.insert(&cs.name, crate::xml::to_craft(&el));
|
||||
}
|
||||
let mut rc = El::new("RootCharacterStyleGroup").attr("Self", self.fresh());
|
||||
cg.emit(&mut rc, "CharacterStyleGroup", "");
|
||||
root.push(rc);
|
||||
root.push(crate::xml::from_craft(cg.to_el()));
|
||||
|
||||
// Paragraph styles.
|
||||
let mut pg = Group::default();
|
||||
let mut pg = craft_idml::model::StyleGroupWriter::new(craft_idml::model::StyleKind::Paragraph, self.fresh());
|
||||
for ps in &styles.paragraph {
|
||||
let id = names::style_self("ParagraphStyle", PARA_BUILTINS, &ps.name);
|
||||
let mut el =
|
||||
@@ -77,11 +75,9 @@ impl<'a> Ex<'a> {
|
||||
if let Some(t) = tag {
|
||||
el.push(self.export_tag_map(t));
|
||||
}
|
||||
pg.insert(&ps.name, el);
|
||||
pg.insert(&ps.name, crate::xml::to_craft(&el));
|
||||
}
|
||||
let mut rp = El::new("RootParagraphStyleGroup").attr("Self", self.fresh());
|
||||
pg.emit(&mut rp, "ParagraphStyleGroup", "");
|
||||
root.push(rp);
|
||||
root.push(crate::xml::from_craft(pg.to_el()));
|
||||
|
||||
self.append_cell_styles(&mut root, &styles);
|
||||
self.append_table_styles(&mut root, &styles);
|
||||
@@ -97,7 +93,7 @@ impl<'a> Ex<'a> {
|
||||
}
|
||||
|
||||
// Object styles.
|
||||
let mut og = Group::default();
|
||||
let mut og = craft_idml::model::StyleGroupWriter::new(craft_idml::model::StyleKind::Object, self.fresh());
|
||||
let mut have: Vec<&str> = styles.object.iter().map(|o| o.name.as_str()).collect();
|
||||
let defaults = designcraft_doc::Styles::default();
|
||||
let mut all: Vec<designcraft_doc::ObjectStyle> = styles.object.clone();
|
||||
@@ -157,11 +153,9 @@ impl<'a> Ex<'a> {
|
||||
.attr("EnableDirectionalFeather", "false")
|
||||
.attr("EnableGradientFeather", "false"),
|
||||
);
|
||||
og.insert(&os.name, el);
|
||||
og.insert(&os.name, crate::xml::to_craft(&el));
|
||||
}
|
||||
let mut ro = El::new("RootObjectStyleGroup").attr("Self", self.fresh());
|
||||
og.emit(&mut ro, "ObjectStyleGroup", "");
|
||||
root.push(ro);
|
||||
root.push(crate::xml::from_craft(og.to_el()));
|
||||
if let Some(toc) = d.toc.as_ref().filter(|t| d.story(t.story).is_some()) {
|
||||
root.push(self.toc_style_el(toc));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user