* Add craft-drawingml: units, colours, preset shapes, custom geometry and text warps The parts of DrawingML that need no document model, moved from DeckCraft (60f91f78): crates/color, crates/geom (preset, warp, Xfrm and the EMU conversions) and crates/pptx/src/custgeom.rs with CustomPath from crates/model. The code is unchanged except that custgeom reads craft-xml trees and writes to a craft-xml Writer instead of DeckCraft's own XML helper, and matches elements by local name. The 59 tests of the moved code come with it; six more cover the custom geometry limits. * drawingml: evaluate a custom geometry's guide lists once per coordinate space read_cust_geom rebuilt Guides and evaluated avLst and gdLst again for every path: up to 1,000 paths times up to 10,000 guides, each name copied and hashed. Guides are now cached per path coordinate space (w, h). At most 16 spaces and 4 MiB of guide names are kept per geometry; paths in further spaces are left out. The first space is always kept, and a geometry without guides is not capped. Ported from storytold/deckcraft#1789. A list counts as having guides only when it has gd children, as that PR's review asked. * drawingml: the model types for fills, lines, text, tables, charts and diagrams Moved from DeckCraft (60f91f78) crates/model/src: style.rs, text.rs, table.rs, chart.rs, numfmt.rs and trendline.rs, plus Diagram, DiagramNode and the MediaId and SlideId newtypes from lib.rs. The files are unchanged except that deckcraft_color:: is crate::color:: and Fill and TableBorder allow clippy::large_enum_variant. Their 60 tests come with them. Readers and writers follow. * drawingml: the theme model (colour, font and format schemes) Moved from DeckCraft crates/model/src/theme.rs at 60f91f78: FontSet, ScriptFont, FontScheme, FormatScheme, Theme and default_format. The app's theme gallery, its variants and its own default theme stay in the app. Theme::default() is a plain theme built in place, so nothing here depends on a gallery. * drawingml: readers and writers for fills, lines, text, charts, themes, table styles and diagrams Moved from DeckCraft crates/pptx/src at 60f91f78: read/dml.rs, write/dml.rs, read/chart.rs, read/chartex.rs, write/chart.rs, read/theme.rs, write/theme.rs, tables.rs and dgm.rs, onto craft-xml. Package lookups (Imp, Part, Exp, Out) are the caller's part::Source and part::Sink. The chart frame budget and kept-part capture stay with the presentation reader. * drawingml xmlx: copy only used, bounded namespace declarations onto kept fragments and mc branches From storytold/deckcraft#1740 (988a4920), which landed after the extraction commit 60f91f78.
craft-drawingml
The parts of DrawingML (ECMA-376 part 1, chapter 20) that presentations, word-processing
documents and spreadsheets share. A .pptx slide, a .docx drawing and an .xlsx drawing all
hold the same a: elements; this crate is the one place that knows what they mean.
Nothing here opens a package. Readers take a craft_xml::El and writers a craft_xml::Writer,
so the caller decides which part the markup comes from. Lengths are points (1/72 inch) as f64;
files store EMU (12 700 per point).
| Module | What | Markup |
|---|---|---|
| crate root | emu_to_pt, pt_to_emu, Xfrm (offset, extent, rotation, flips, as an affine), group_child_affine |
a:xfrm, a:chOff, a:chExt |
color |
Rgba, SchemeSlot and ColorScheme (the twelve theme colours and their bg1/tx1 aliases), ColorTransform with apply, the preset and system colour names |
a:srgbClr, a:schemeClr, a:prstClr, a:sysClr, a:lumMod, a:tint, a:alpha … |
preset |
build(name, w, h, adjusts): the outline of a preset shape as fill and stroke sub-paths, its text rectangle, adjust handles and connection sites; CATALOG with labels, categories and default adjusts |
a:prstGeom |
custgeom |
read_cust_geom / write_cust_geom between a:custGeom and CustomPath (an M L C Q Z path string per sub-path), and Guides, the shape guide formula evaluator |
a:custGeom, a:gd |
warp |
warp(name, adjusts, rect): the bands and guide curves of a preset text warp, and the mapping of laid-out lines onto them |
a:prstTxWarp |
The model
These modules hold types only; their readers and writers are not here yet.
| Module | Types | Markup they stand for |
|---|---|---|
style |
ColorRef (a base colour plus transforms, resolved against a ColorScheme), Fill, Gradient, PictureFill, Line, Effects, ShapeStyle |
a:solidFill, a:gradFill, a:blipFill, a:pattFill, a:ln, a:effectLst, p:style |
text |
TextBody, Paragraph, ParaProps, Run, RunProps, ListStyle, hyperlinks and actions |
a:txBody, a:bodyPr, a:lstStyle, a:p, a:r |
table |
Table, Row, Cell, TableStyleDef and the built-in table styles |
a:tbl, a:tblStyleLst |
chart |
Chart, Series, axes, data labels, trendlines and error bars, with the values they compute |
c:chartSpace, cx:chartSpace |
numfmt |
format(code, value, lang): number format codes as charts and cells use them |
c:numFmt |
diagram |
Diagram, DiagramNode |
dgm:dataModel |
A picture or sound is a MediaId; whoever owns the package keeps the bytes. Themes are not here yet.
Preset shapes and text warps
Preset names are the file's (roundRect, rightArrow, textArchUp) so files round-trip. The
outlines are constructed in Rust from what each shape looks like and from the meaning of its
adjust values; no geometry table is copied. Adjust values use the file convention: ratios in
1/100 000 of the shorter side (or of the width or height), angles in 1/60 000 degree.
let g = craft_drawingml::preset::build("roundRect", 200.0, 100.0, &[25_000.0]).unwrap();
assert!(!g.paths.is_empty());
assert!(g.text_rect.width() < 200.0);
Hostile input
read_cust_geom reads at most 1 000 paths per geometry, 100 000 commands per path and 5 000
guides per list, keeps at most 10 000 guide values, and evaluates the guide lists once per
coordinate space, for at most 16 spaces and 4 MiB of guide names. Every evaluated value is finite and within
±1e15; a division by zero is 0. An arc that sweeps a full turn or more draws one turn. preset::build and
warp::warp take any f64 and return None or a finite outline. Each limit has a test.
The types derive serde traits with the field names the apps' own document files already use.