Commit Graph
196 Commits
Author SHA1 Message Date
Dylan M. Taylor c9bf4a34a6 Merge pull request #1242 from alehel/claude/issue-1230-c0c8eb
craft-audio: write AAC, ALAC, MP3, AC-3 and E-AC-3 files
2026-11-14 11:46:38 -05:00
Dylan M. Taylor 29fb8f8e86 Merge pull request #1216 from dotCooCoo/feat/craft-texture-planes
craft-texture: add bounded float image planes and texture sampling
2026-11-14 11:28:44 -05:00
41fb227542 feat(ps): add bounded shared PostScript EPS reader (#1276)
* feat(ps): add craft-ps with an EPS reader (read feature)

The reading half of craft-ps (#115): a clean-room PostScript interpreter
that runs an EPS and returns what it paints as a one-page vector PDF of
its bounding box, colours kept, so apps can draw and export EPS as a
placed PDF. Moved from DesignCraft (storytold/designcraft, where it was
written for placed EPS), with its app-specific names made neutral.

Written from the PostScript Language Reference (3rd ed.), the EPS
specification, the Type 1 Font Format and Adobe TN 5012/5176/5177.
Covers the language, paths, clipping, strokepath, device/Separation/
DeviceN/Indexed/ICCBased/Lab colour, images with lazily decoded filters,
shadings 1-7 and patterns, and Type 1/3/42/CFF/CID text through CMaps,
horizontal and vertical.

Bounded: each operator charges work proportional to its operands
against the step limit as it goes, every byte read or decoded counts,
copies count against the memory cap; defaults 50 M steps / 1 GiB, and
20 M / 256 MiB on wasm32. No panics (deny lints, fuzzed in debug
builds). 34 tests, the Type 42 one on a TrueType font built in the
test. No new external crates: pdf-writer, miniz_oxide, weezl, skrifa
and kurbo are already locked at these versions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* clippy(ps): document stateful decoder complexity

* fix(ps): bound huge arc angle normalization

* fix(ps): preserve EffectCraft EPS text and limits parity

* fix(ps): address interpreter review findings

* fix(ps): preserve composite glyph paint order

* fix(ps): address interpreter review findings

* fix(ps): bound filter buffers and preserve file aliases

* fix(ps): make predictor allocation fallible

---------

Co-authored-by: markus.doebele <markus.doebele@top21.sh>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-14 06:10:27 -05:00
dotCooCoo abcfe7ddc3 Merge main into feat/craft-texture-planes 2026-11-14 02:45:18 -08:00
Dylan M. Taylor b77af389f3 Merge pull request #1245 from storytold/codex/anicraft-envelope
feat(anicraft-format): extract native JSON envelope
2026-11-13 23:01:08 -05:00
Dylan M. Taylor 840d156fbf Merge current main into image codec extraction 2026-11-14 03:10:53 +00:00
Dylan M. Taylor 427fa15899 Merge pull request #1223 from storytold/codex/anicraft-xfl-format
Add bounded XFL FLA package reader
2026-11-13 22:01:31 -05:00
Dylan M. Taylor 5df4b49f8c feat(anicraft-format): extract versioned JSON envelope 2026-11-14 02:46:10 +00:00
alehel 63712c33e6 craft-audio: review round 2 for the coded formats
- craft-media: Mp4Writer counts chunk offsets from the first byte of the
  file, not from position 0 of the writer, so a file begun mid-writer is
  valid. This replaces the seek adapter the M4A writer wrapped its sink in.
- Tests pin the bytes of the roll sample group and each format's feature.
- Docs: ALAC's length comes from the sample durations, not an edit list;
  which readers take an empty AAC file; speaker names as the errors print
  them; craft-media's README lists roll_distance.
- Error messages for a layout a format has not no longer suggest setting
  a layout that was set.

Refs #1230
2026-11-14 03:16:51 +01:00
alehel eee76c3fc2 craft-audio: AAC, ALAC, MP3, AC-3 and E-AC-3 as formats of encode and FileEncoder
EncodeFormat gains Aac and Alac (M4A through craft-media's MP4 muxer) and
Mp3, Ac3 and Eac3 (raw streams), so one call writes any of them from
WAV-order f32 audio and EncodeOptions.

- EncodeOptions::rate_control (with_bitrate, with_quality): a bit rate is
  moved to the nearest one the stream can carry; quality is AAC's VBR.
- Channels are mapped onto the codec's order by speaker, from
  EncodeOptions::layout. A layout the format has not is Unsupported
  instead of reaching the wrong speakers.
- M4A: the edit list skips the AAC priming, and the last sample's duration
  is cut so the track ends at the last frame written.
- encode_format_for, ENCODE_EXTENSIONS and EncodeFormat::ALL list the new
  formats; aac-encode and alac-encode now turn on craft-media's isobmff.

Refs #1230
2026-11-14 03:16:51 +01:00
Dylan M. Taylor 6d620e971e Merge pull request #1229 from storytold/codex/craft-jxl-extraction
Add shared JPEG XL decoder and encoder
2026-11-13 19:39:17 -05:00
Dylan M. Taylor 4d3e920954 Add shared JPEG XL decoder and encoder 2026-11-13 22:47:47 +00:00
Dylan M. Taylor 888bffcbb3 Add shared DWG-DXF byte bridge 2026-11-13 22:45:07 +00:00
Dylan M. Taylor b4d1e249d9 Add bounded XFL FLA package reader 2026-11-13 22:05:11 +00:00
dotCooCoo 3c3a83151d craft-texture: add bounded float image planes and texture sampling
Adds crates/texture (craft-texture), the first step of RFC-0032
(storytold/craft-contrib#50). The code comes from MaterialCraft
crates/image/src/lib.rs at 31330629, with its six tests unchanged. No app
uses the crate yet.

Changes from the source:
- Image fields are private; from_data checks the size and the buffer
  length, so a zero side can no longer reach a panic and a short buffer
  is rejected instead of read with defaults.
- Limits caps the side, pixels and bytes; the try_ constructors and
  try_map, try_to_kind, try_resize and try_to_rgba8_display reserve
  memory first and return an error.
- Repeat sampling reduces the coordinate to its fractional part, so the
  period holds at large coordinates.
- Bilinear sampling sums the four weighted texels and skips zero weights;
  box shrinking sums in f64.
- generate_uv clamps the size before computing pixel centers.
- linear_to_srgb(NaN) returns NaN.
- rayon is behind the parallel feature.
2026-11-13 13:14:55 -08:00
Dylan M. Taylor 8ebdc499a5 Merge pull request #1186 from dylanmtaylor/codex/stencilcraft-file-import-registry
Add shared neutral file import and writer registry
2026-11-13 09:04:29 -05:00
Dylan M. Taylor 93d0998383 Merge pull request #1184 from storytold/codex/designcraft-native-format
Add shared DesignCraft native format codec
2026-11-13 08:05:30 -05:00
Dylan M. Taylor 62e2328905 Add shared neutral file import and writer registry 2026-11-13 07:36:18 -05:00
Dylan M. Taylor 59c52ac1dc Merge pull request #1174 from dylanmtaylor/codex/vector-file-imports
Add shared vector path import APIs
2026-11-13 07:35:46 -05:00
Dylan M. Taylor 58ae17473c Merge pull request #1179 from dylanmtaylor/codex/stencilcraft-typed-format
StencilCraft: share the native document model and codec
2026-11-13 05:33:43 -05:00
Dylan M. Taylor 65b2a68df0 Add shared DesignCraft native format codec 2026-11-13 05:12:58 -05:00
Dylan M. Taylor 68ad072e4a Merge remote-tracking branch 'origin/main' into codex/soundcraft-format 2026-11-13 09:12:20 +00:00
Dylan M. Taylor 915fc54458 Merge pull request #1164 from storytold/codex/craft-time-soundcraft
craft-time: preserve SoundCraft sample-time APIs
2026-11-13 04:10:26 -05:00
Dylan M. Taylor 59eccec4ff Merge remote-tracking branch 'upstream/main' into HEAD
# Conflicts:
#	Cargo.lock
2026-11-13 04:06:48 -05:00
Dylan M. Taylor 7c56d282a2 Merge pull request #1170 from dylanmtaylor/codex/designcraft-format-migration
Add reusable document bundle and SVG preflight APIs
2026-11-13 04:03:23 -05:00
Dylan M. Taylor b373553e98 Add shared vector path import APIs 2026-11-13 03:58:21 -05:00
Dylan M. Taylor 686b5478ea Merge pull request #1173 from dylanmtaylor/codex/file-formats-api
Add shared file format detection
2026-11-13 03:55:21 -05:00
Dylan M. Taylor 166d0d2127 craft-stencilcraft-document: share the native document model 2026-11-13 03:46:47 -05:00
Dylan M. Taylor 4d709b5e0e Merge remote-tracking branch 'upstream/main' into HEAD
# Conflicts:
#	Cargo.lock
#	crates/raster-codecs/Cargo.toml
#	crates/raster-codecs/src/common.rs
2026-11-13 03:30:22 -05:00
Dylan M. Taylor fd5133174b Add shared pcraft bundle storage 2026-11-13 02:23:08 -05:00
Dylan M. Taylor e2cab3f651 Merge pull request #1158 from storytold/feat/stencilcraft-format
Add versioned flattened JSON format schema
2026-11-13 02:13:29 -05:00
Dylan M. Taylor c5d1e937ae feat(materialx): add bounded reader and OpenPBR writer (#1167)
* feat(materialx): add bounded document reader and OpenPBR writer

* proof, video, latex, cms: satisfy the clippy lints that ship with Rust 1.100

The newer clippy flags needless bool guards and range loops whose index
only indexes one slice; express both with the equivalent iterators so
the workspace lint stays green on every platform.

* cms: index the ink loops instead of a range loop, which newer clippy rejects

* feat(materialx): resolve shader graphs and write OpenPBR materials

* feat(materialx): resolve shader graphs and write OpenPBR materials
2026-11-13 02:03:31 -05:00
Dylan M. Taylor 96c8487984 Add shared InDesign conversion facade 2026-11-13 01:30:54 -05:00
Dylan M. Taylor 79c2003ac9 Add shared file format detection 2026-11-13 00:30:56 -05:00
Dylan M. Taylor 9430f2807e Add shared image codec facade 2026-11-13 00:17:04 -05:00
Dylan M. Taylor 4ecdcd78da Export common raster codec facade 2026-11-13 00:03:41 -05:00
Dylan M. Taylor 8c41139369 Add shared raster codec facade and versioned JSON headers 2026-11-13 00:01:32 -05:00
Dylan M. Taylor 88aa0bed6a Add shared SoundCraft session format 2026-11-13 04:07:08 +00:00
Dylan M. Taylor f29cb7076f Merge remote-tracking branch 'origin/main' into codex/craft-time-soundcraft
# Conflicts:
#	Cargo.lock
#	Cargo.toml
#	README.md
2026-11-13 03:46:49 +00:00
Dylan M. Taylor c7fb7544c2 craft-stencilcraft-format: add native JSON schema 2026-11-13 02:23:04 +00:00
Dylan M. Taylor ef01d69f7d Shared document bundle package IO 2026-11-12 19:11:55 -05:00
Dylan M. TaylorandDylan Taylor f92a91afa4 plotter: add TB54 registration-mark offset command (#1139)
* plotter: add TB54 registration-mark offset command with py_silhouette citation

The full Silhouette registration sequence (TB99 through TB55, plus
TB123/TB124 for search and TB23 for manual positioning) is documented
in the community driver py_silhouette (zero_on_registration_mark()),
which reverse-engineered the protocol from public behaviour — not from
any proprietary binary.

TB54,0,0 sets the registration-mark offset to zero (mark at expected
position). Without it the machine may use a non-zero default offset.

* workspace: allow unused_workspace_dependencies lint

The root Cargo.toml declares many workspace dependencies that are not
referenced by any crate's Cargo.toml (e.g. craft-aep, craft-ai-core,
craft-cms, etc.). This is intentional — they are available for apps to
use. Suppress the clippy warning so CI passes.

* workspace: allow unused_workspace_dependencies (cargo lint)

This is a cargo-level lint (not clippy) that fires when workspace
dependencies declared in [workspace.dependencies] are not referenced
by any crate's Cargo.toml. Many entries are intentionally available
for apps to use.

* cms, prepress, proof: allow unused_workspace_dependencies lint

These crates are built individually by CI (cargo clippy -p <crate>)
which does not inherit workspace lints. Add per-crate suppression.

* cms, prepress, proof: inherit workspace lints

Add [lints] workspace = true so these crates pick up the
unused_workspace_dependencies suppression from the root Cargo.toml.

* revert: remove duplicate [lints] sections

The cms, prepress, and proof crates already had [lints] workspace = true.
My previous commits accidentally added duplicate sections.

* cargo: suppress unused_workspace_dependencies lint via config

This is a cargo-level lint (not clippy) that fires when workspace
dependencies declared in [workspace.dependencies] are not referenced
by any crate's Cargo.toml. Many entries are intentionally available
for apps to use.

---------

Co-authored-by: Dylan Taylor <dylanmtaylor@gmail.com>
2026-11-12 15:44:47 -05:00
David Mann 86d6e8c5b0 feat(flags): shared feature flags for the Craft apps and the launcher
craft-flags keeps one per-user file, ArtCraft/flags.toml beside the AI
layer's ArtCraft/ai, that the launcher and every app read; CRAFT_FLAGS
overrides it for one run. Every flag is off by default. The first two:
AI-MCP (AI agents through MCP) and AI-MODELS (AI models and services).

Loading never fails: a missing or damaged file means defaults, with the
reason in Flags::problems. set() changes one flag atomically and keeps
everything else in the file, and never overwrites a file it can't read.
In the browser every flag is at its default.

Closes #1118

---------

Co-authored-by: David Mann <daaavid.mann@gmail.com>
2026-11-12 10:05:07 -05:00
Dylan M. Taylorandjonathanwxh-cell 1c5c8a4e14 Add craft-pkcs7: DER, X.509, CMS SignedData, PKCS #12, RFC 3161 and revocation from PdfCraft
* Add craft-pkcs7: DER, X.509, CMS SignedData, PKCS #12, RFC 3161 and revocation from PdfCraft

Moved from PdfCraft's crates/sign at 1d7a9f9f: der, x509, cms, pkcs12, timestamp,
revocation, keys, rsa_pad and ec512, with their unit tests, the integration tests
that need no PDF, and the test keys.

x509 no longer returns PdfCraft's worded sentences: signing_problem gives a
SigningProblem and build_chain_noted a Refused (reason and the two certificates).
The checks behind them are unchanged. Error is SignError without its PDF variants.

* craft-pkcs7: write the certificate serial verbatim in SignerInfo and ESSCertIDv2

A serial with its high bit set and no leading zero was written with one added, so
the signer identifier and the signing-certificate attribute named a different
number than the certificate has.

Ported from storytold/pdfcraft#6868. The test uses a certificate that really has
such a serial and also checks that the signer's certificate is found.

* craft-pkcs7: note why RIPEMD-160 is supported

---------

Co-authored-by: jonathanwxh-cell <jonathanwxh@gmail.com>
2026-11-12 09:45:31 -05:00
Dylan M. Taylor 373c242ad7 Add craft-openpgp: OpenPGP signature checking and key reading from MailCraft
Moved from MailCraft's crates/openpgp at a44a45013d1c. Built on rPGP 0.21.0 as
there. The one code change: the Unicode format-character test the From address
check used from mailcraft-names is now a private function here, with a test.
2026-11-12 09:10:41 -05:00
Dylan M. Taylor d516b44691 Add craft-doc-binary: WordCraft's .doc reader on craft-wordmodel and craft-cfb
Add craft-doc-binary: WordCraft's .doc reader on craft-wordmodel and craft-cfb

* craft-doc-binary: WordCraft's crates/docbin as it is at wordcraft 07f97737

The source, unchanged, so the next commit shows only what the move changes.
It has no manifest yet, so it is not built.

* craft-doc-binary: on craft-wordmodel, craft-cfb and craft-codepage

- The compound file is read with craft-cfb (bounded directory, streams refused
  above 1 GiB before anything is allocated), in place of the cfb crate and
  WordCraft's cfb_guard precheck; an oversized stream is DocbinError::Limit.
- 8-bit text uses craft-codepage in place of wordcraft_doc::encoding.
- wordcraft-doc is craft-wordmodel; wordcraft-geom's helpers are its geom.

The tests keep building their files with the cfb crate (a dev-dependency), so
craft-cfb's reader is checked against another implementation's writer. The
repeating-DIFAT regression is craft-cfb's own; the guard asserts in the
valid-files test go with the guard.
2026-11-11 22:43:11 -05:00
Dylan M. Taylorandbflatastic 428541a512 craft-sf2: SoundFont 2 reader from LoopCraft (#1076)
The SoundFont 2 reader of LoopCraft's loopcraft-audiofile crate (sf2.rs at
storytold/loopcraft@0d150c1), over a neutral model of its own: the sample
pool, presets and resolved key/velocity regions with tuning, loop points,
pan, gain and volume envelope. The fixture writer its tests use is the
test-support feature, so readers in other crates can test with real files.

Co-authored-by: bflatastic <bombayapirat@gmail.com>
2026-11-11 21:58:16 -05:00
Dylan M. TaylorandJordi Altayó 5538d8a0d7 Add craft-pptx: the PresentationML model (from DeckCraft) (#1044)
* 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: what WordCraft and GridCraft read that DeckCraft's copy did not

Every ST_PresetColorVal name has its colour, in any case and with the dk/lt/med abbreviations;
a sysClr without lastClr takes the usual value of its name; a Strict percentage (50%) reads
anywhere a percentage does; a chart series keeps its c:f formulas and the writer uses them.

* craft-drawingml: extra named theme colours and explicit tint rows

Ported from the format part of storytold/deckcraft#1746 by @jagjordi: ColorScheme::{extra, tints,
computed_tints}, ExtraColor, GalleryVariant, variants_of, and the a:clrScheme extension that
keeps them in a file.

* 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.

* Add craft-pptx: the PresentationML model (from DeckCraft)

Presentation, masters, layouts, slides, shapes, placeholders, media,
comments, sections, show settings, properties, embedded fonts, kept parts
and drawing guides from DeckCraft's crates/model/src/lib.rs, and
transitions and animations from anim.rs. The DrawingML types come from
craft-drawingml. The placeholder matching from DeckCraft's resolve.rs
moves as placeholder::parents, without the rest of resolve.

Presentation::default() is now an empty 16:9 deck with no masters; the
starting deck stays with the application.

---------

Co-authored-by: Jordi Altayó <jordiag@kth.se>
2026-11-11 21:04:26 -05:00
Dylan M. Taylorandshuff57 bdf06f1029 Add craft-latex: LaTeX documents read and written, on craft-flow (stacked) (#1038)
* Add craft-wordmodel: WordCraft's document model without its editing code

WordCraft's crates/doc (wordcraft-doc, at 07f97737) moved as it is, so the DOCX,
RTF, ODT and other text-format crates can read into and write from one model.
Module paths, type names and serde attributes are unchanged: an app that
re-exports the crate keeps its native file format.

Left in the app: range editing (edit.rs), IME text and equation editing. Not
model, and already in craft-libs: code pages (craft-rtf), the ZIP entry-count
check (craft-opc), the compound-file guard (craft-cfb). The paragraph walks
moved to walk.rs and the unit helpers of wordcraft-geom to geom.rs.

* craft-wordmodel: math_tree, the arguments of an equation node and a walk over its runs

The DOCX reader and writer walk an equation's runs. The walk and the child
accessors it uses were in WordCraft's equation editor (math_edit.rs), which
stays in the app; they are structure, not editing.

* craft-mime: detect, for bytes that name no character set

is_text, decode (BOM, unmarked UTF-16, UTF-8, else the legacy encoding
the bytes look like), legacy and legacy_label, behind a detect feature
that brings in chardetng. Moved from WordCraft's crates/formats/src/txt.rs
at 06c2ae6f with its text-sniffing tests. Also charset::is_known, so a
caller can tell a label decode would read as UTF-8 from one it knows.

* craft-wordmodel: keep the document operations (edit.rs) with the model

The DOCX and RTF readers use them: alternative-format chunks are merged into
a document with adopt_blocks, and a reader formats ranges with format_range
and inserts objects. They operate on the document, not on a view, so they
belong beside it. The tests that drove them come back with them; the
paragraph walks stay in walk.rs and edit re-exports them.

base64 0.23, as WordCraft and craft-offcrypto use.

* Add craft-math: the equation tree with OMML, MathML, LaTeX and UnicodeMath

The math tree, LaTeX, linear-format, symbol and tree-walk modules come
from craft-wordmodel (storytold/craft-libs#963, WordCraft's crates/doc at
07f97737) unchanged, with the run colour (Rgb) and the symbol-font tables
they use. MathML is WordCraft's crates/formats/src/mathml.rs and OMML is
WordCraft's crates/docx/src/read/math.rs and write/math.rs (06c2ae6f /
07f97737), moved onto craft-xml. The HTML-specific MathML tests stay in
WordCraft; the rest moved with the code.

mathml::parse and omml::parse/read_str/write_str are new: string entry
points for callers that have no tree of their own.

* craft-math: read MathLive's and other spellings of LaTeX math commands

\abs{...} (an absolute value), \lvert \rvert \lVert \rVert, \nparallel,
\backprime, \infinity, \cross, \differentialD, \exponentialE and
\imaginaryI (MathLive's d, upright e and i), \emph, \textsf, \hbox,
\mathnormal and \underleftarrow / \underrightarrow /
\underleftrightarrow were unknown and read as literal text. They are read
as equaSHion's typed-input parser reads them (storytold/craft-libs#29).

* craft-math: equaSHion's equation corpus as test data

corpus/equations.tsv, corpus/latex.tsv and the OMML samples of
storytold/craft-libs#29 (7a6ef6b9), unmodified.

* craft-math: corpus round trips, GridCraft's OMML cases, entry points and limits tested; README

The corpus equations go through OMML, MathML and LaTeX and back; the OMML
samples are written back as kept and from the tree. GridCraft's OMML to
LaTeX test cases (crates/xlsx/src/omml.rs) give LaTeX that reads back the
same through the tree. omml::parse and read_str are tested against other
prefixes, the strict namespace, kept OMML, junk, the element cap and deep
nesting.

* Add craft-flow: the flow model the text formats map to, on craft-wordmodel

WordCraft's crates/formats/src/model (07f97737) moved as it is: Flow,
FBlock, Para, Inline, Fmt, tables and cells, pictures, to_doc and
from_doc, picture sniffing, colours, base64 and the Dropped report. Only
the paths changed (wordcraft_doc is craft_wordmodel); the report helpers
are public so the format crates can call them; the image re-encoding
helper stays with WordCraft's RTF writer.

* Add craft-markdown: Markdown read and written, on craft-flow

WordCraft's crates/formats/src/markdown (07f97737) with its 35 tests,
moved onto craft-flow and craft-wordmodel. Character references come from
craft-html. The table cell budget lives in craft-flow, which names it in
its warning. Two test lines that wrote plain text through WordCraft's txt
module stay in WordCraft.

* WIP: craft-latex sources from WordCraft (unmodified)

* Add craft-latex: LaTeX documents read and written, on craft-flow

WordCraft's crates/formats/src/latex (07f97737) with its 21 tests, moved
onto craft-flow and craft-wordmodel; bytes are decoded by craft-mime's
detect. The LaTeX parts of WordCraft's cross-format tests (nesting,
column specs, labels, no TeX commands from the document, the fuzz and
round-trip properties) come along as tests/hostile.rs. The ligature test
builds its three-font paragraph as a flow instead of reading HTML.

* craft-math: latex_text, LaTeX math and the linear format converted as text

WordCraft's crates/formats/src/latex/math.rs (07f97737): the converter its
LaTeX document reader and writer use, which keeps the source's spacing.
It moves here so craft-math is the one place that converts LaTeX math;
craft-latex calls it, and its output does not change. Its tests (from
WordCraft's latex tests and cross-format tests) come along.

* craft-math: latex_text's group finders are public, for craft-latex's length parser

* craft-latex: math through craft_math::latex_text; label timing test by ratio

The document math converter moved to craft-math (#1040) unchanged; this
crate calls it there (and its length parser uses its group finders), so
export output is the same. The label test compared one read with a
ten-second wall clock and failed on a loaded machine; it now compares the
fastest of three reads of 25,000 and 100,000 labels, which a linear read
keeps near 4x and a quadratic one near 16x.

---------

Co-authored-by: shuff57 <62350898+shuff57@users.noreply.github.com>
2026-11-11 20:58:36 -05:00
Dylan M. TaylorandMartin Ball d197b1e72f Add craft-dav: WebDAV multistatus reader from MailCraft (#975)
MailCraft crates/dav/src/xml.rs at a44a450, re-based onto craft-xml: a
multistatus read fail-closed into a bounded tree with fixed prefixes for
the DAV, CalDAV, CardDAV and related namespaces, and the properties of a
response's successful propstats. Its tests come along.

Co-authored-by: Martin Ball <98639962+benandez@users.noreply.github.com>
2026-11-11 20:51:12 -05:00