352 Commits
Author SHA1 Message Date
Dylan M. Taylor 42a5df5f94 chore: cut over image codecs and zip to craft-libs (#6661)
* chore: cut over image codecs and zip to craft-libs, fix main test regressions

* tests: store ODS mimetype and use standard ODF namespaces in mailings test

* Remove unused quick-xml workspace dependency

* fix: use standard ODF namespaces in file_dialogs test and preserve trailing line in markdown import_on_with_lines

* fix(geom): use png_chunks for PNG dimensions and p.fits(budget) in decode_for_drawing
2026-11-14 14:51:35 -05:00
Dylan M. Taylor 33afe69094 fix(docx): bump craft-docx/wordmodel, fix missing_pictures total, and dedup Arc<Graphic> 2026-11-14 06:16:12 +00:00
Dylan M. Taylor beae4b82fa Fix formatting and clippy lints in docx and formats adapters 2026-11-14 05:14:05 +00:00
Dylan M. Taylor fbd6c7f133 Migrate crates/docx and crates/formats RTF to craft-libs (#778)
- Wire craft-wordmodel, craft-docx, craft-rtf (doc), and craft-doc-binary into workspace
- Delete ~26,300 lines of app-owned DOCX parser/serializer in crates/docx
- Implement zero-copy media transfer and FitState custom XML round-trip via craft_wordmodel bridge
- Delete ~5,400 lines of app-owned RTF parser/serializer in crates/formats/src/rtf
- Delegate RTF import, export, parse, and esc to craft-rtf
- Add cfb_guard DIFAT validation and float sanitization on model bridge
- Net reduction: 31,697 deletions, 818 insertions (-30,879 LOC)
2026-11-14 01:55:21 +00:00
batistalucasv 0294f81d83 Merge branch 'main' into feat/fit-one-page-upstream 2026-11-12 23:49:35 -03:00
batistalucasv 2bda4e5a41 M2.1: Resolve Fit One Page stores by marker, reserve path, and location provenance (#6433)
- Recognize a marked Fit One Page custom XML store across package and document
  relationships, skipping passthrough only after loading successfully.
- Reserve the Fit One Page part path in EmbedWriter taken paths to prevent collisions.
- Track typography provenance per formatting location rather than sorted multisets.
- Validate stepPt parameter and reject non-positive or non-finite values.
- Report "already fits on one page" before an exhausted cumulative budget.
2026-11-12 23:44:54 -03:00
FredApps fab8793ce7 Merge pull request #2703 from vangel76/feat/style-pr-change-2697
Track style property changes (#2697)
2026-11-13 02:29:33 +01:00
batistalucasv 2e185a6a74 docx: ignore w:lnNumType without w:countBy (#6209) (#6231)
* docx: ignore w:lnNumType without w:countBy (#6209)

* DOCX: record the w:lnNumType rule in the parity docs (#6209)

A row for `w:lnNumType` (§17.6.8), its status line and a revision entry in
`docs/file-format-parity.md`, the progress-log bullet in `ROADMAP.md`, a comment in
the reader saying why a missing `w:countBy` leaves numbering off, and a save check in
the zero-interval test.
2026-11-13 01:38:40 +01:00
batistalucasv 3f7bff9204 M2.1: Only inspect the Fit One Page DOCX part by name (#6433)
Check the fixed custom XML part name before parsing, so unrelated custom XML
stores are not read twice just to look for the fit budget.
2026-11-12 19:35:12 -03:00
batistalucasv d30a8392f9 M2.1: Harden Fit One Page budget provenance and DOCX persistence (#6433)
- Record original and reduced font sizes, line spacings and paragraph
  spacings as multisets, so restoring neighbouring sizes clears the
  exhausted budget, and paragraph spacing keeps the budget when line
  spacing rounds back to its original.
- Resolve font and spacing budgets independently, letting the remaining
  component be used instead of refusing the whole command.
- Persist FitState in a namespaced DOCX custom XML part and restore it on
  read; add a DOCX round-trip regression.
2026-11-12 19:32:10 -03:00
FredApps 118eb8af1f Merge pull request #6033 from batistalucasv/fix/6011-docx-equation-revision-marks
DOCX: save and load tracked revision marks around equations (#6011)
2026-11-11 07:59:24 +01:00
FredApps f936270317 Merge pull request #6049 from vangel76/fix/6018-line-numbers-columns
Line numbers appear beside every column and keep their Word formatting
2026-11-11 07:56:26 +01:00
Martin BallandClaude Opus 5.5 d40d1b2718 CLI: --strict on convert and render refuses missing glyphs and pictures (#6039)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-09 20:16:05 +01:00
vangel76andClaude Opus 5.5 bce47689ad Line numbers: number every column, and use a localised Line Number style
In a multi-column section every line number was drawn left of the page
margin, so the second column's numbers sat on top of the first column's.
Each column now has its numbers left of its own edge, as in Word.

Word in other languages saves the built-in "line number" style under a
localised id (German: Zeilennummer); the numbers now find it by its
built-in name when there is no LineNumber id, so its formatting applies.

Fixes #6018.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 22:40:14 +01:00
batistalucasv 0b7cfa86fe #6011: docx: strengthen tracked equation roundtrip assertions 2026-11-08 15:50:29 -03:00
batistalucasv 85eb8bb92e #6011: docx: write and read revision marks around equations 2026-11-08 15:13:02 -03:00
vangel76andClaude Opus 5.5 dbbc43a89a Merge upstream/main into PR #2703
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 17:18:43 +01:00
Dylan M. TaylorandMartin Ball 04217419b6 DOCX save: collect an embedded object's relationship ids in a set (#5414)
* fix(docx): collect an embedded object's relationship ids in a set on save

* style: rustfmt

---------

Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 07:59:33 +01:00
Dylan M. TaylorandMartin Ball 7592d1440e fix(docx): refuse to carry parts named like WordCraft's bookkeeping (#5411)
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 06:48:33 +01:00
d34e341d75 Charts: an automatic series colour follows the series' c:idx (#5963) (#5975)
* Charts: an automatic series colour follows the series' c:idx (#5963)

A series without its own colour took the accent for its place in the
file. Word picks it by the series' c:idx (c:order doesn't matter), so a
chart whose series aren't numbered 0, 1, 2... in file order, such as a
lone series with idx 2 after a deletion, got different colours.

c:idx is read strictly as the unsignedInt the schema says; a missing or
invalid value falls back to the place in the file.

* Charts: the renumbered test helper fails if ser's layout changes (#5963)

---------

Co-authored-by: kiwi4boy <kiwi4boy@gmail.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 06:41:38 +01:00
535b675e8a DOCX: paragraph indents and spacing beyond 16 bits wrap as in Word (#5655)
## What changed

Word stores paragraph indents (`w:ind` left/start, right/end, hanging, firstLine) in 16 signed bits and paragraph
spacing (`w:spacing` before/after) in 16 unsigned bits. A file that writes a larger plain integer is read by Word
modulo 2^16: `w:left="66256"` is a 720-twip (0.5") indent in Word. We read the full value, so such a paragraph was
indented by about 46 inches and its text was pushed off the page.

- `crates/docx/src/units.rs`: new `tw_i16` / `tw_u16` readers. A plain integer keeps its low 16 bits (two's
  complement for indents, so 66256 -> 720 and 65535 -> -1); values with a unit or a fraction read as before.
- `crates/docx/src/read/props.rs` and `read/styles.rs` use them for `w:ind` and `w:spacing` before/after, in direct
  and style formatting.
- In-range values read exactly as before.

## Testing

- `crates/docx/tests/it/twips_wrap.rs`: synthetic documents with out-of-range indents and spacing in paragraph and
  style properties check the wrapped values; in-range values and values with units are unchanged.
- Unit tests for the two readers; `cargo xtask ci` passes.

Found by a real-file corpus comparison against Word's own PDFs: a file whose indents exceed 16 bits shows its text on
the page in Word and off the page here.

Co-authored-by: tpawley2001 <268951182+tpawley2001@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 06:39:22 +01:00
Dylan M. TaylorandMartin Ball c8618d3e05 fix(docx): look relationships up by id through an index (#5410)
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 06:34:27 +01:00
cd4f755dcf DOCX: nested block-level content controls stay block-level when a bookmark follows them, so Word opens the file (#5811)
## What changed

The DOCX writer's content-control planner (`crates/docx/src/write/sdt.rs`) decides whether a control that
covers a whole paragraph is written block-level (`w:sdt` around `w:p`) or run-level (inside the paragraph).
It only treated the control as covering the whole paragraph when nothing but control-end markers followed
its end. Bookmark, comment and permission range markers after the end now count as "nothing" too, so the
control stays block-level and the markers stay at the end of its paragraph.

## Why

Word writes a body-level `_GoBack` bookmark (`<w:bookmarkStart w:name="_GoBack"/><w:bookmarkEnd/>` directly in
`w:body`) in nearly every file it saves. When the last body-level content control was followed by it, the
reader put the bookmark at the end of the control's paragraph, and the writer then turned the control (and
any controls nested in it) into run-level `w:sdt`s inside that paragraph. For a repeating section
(`w15:repeatingSection` / `w15:repeatingSectionItem`), which must wrap whole paragraphs or rows, Microsoft
365 Word then refuses to open the saved file ("the file appears to be corrupted"). Plain nested block
controls changed what they cover the same way.

Found by the real-file corpus: Word reported our saved copy of a form with a repeating section as corrupted.

## How it was tested

- New tests in `crates/docx/tests/it/nested_block_controls.rs` (synthetic packages): a repeating section around
  one paragraph, plain nested block controls, nested block controls in a table cell, a run-level control that
  must stay in its paragraph, and repeating sections / block controls followed by a body-level bookmark (with
  and without data bindings) all round-trip with the controls at the same level and the text kept.
- `cargo xtask ci` passes.

Co-authored-by: tpawley2001 <268951182+tpawley2001@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:59:51 +01:00
batistalucasv c4d5f70c1d DOCX: resolve LibreOffice font fallback lists to first installed family (#5843) (#5851)
* #5843: resolve LibreOffice semicolon-separated font fallback lists to first installed family

* #5843: address review comments on font fallback list resolution

* #5843: verify fallback list text on cache hit and accept Times New Roman in tests

* #5843: bound the fallback lists read from a DOCX and reuse their classification

A document could name thousands of fallback families in `w:ascii`/`w:hAnsi`.
Nothing bounded that value, and the name-based rules (roman classification,
Thai family, named substitutes) then scanned every candidate for each shaped
piece, so opening the document took seconds.

`w:ascii` and `w:hAnsi` now keep the leading families within MAX_FONT_NAME
bytes, cut at a `;` so no name is split, as `w:cs`/`w:eastAsia` already bound
their names. The family a real list would pick is kept: a LibreOffice list
names a few families, well under the bound.

The Thai-family and named-substitute answers are worked out once per list and
kept in the fallback-list cache, keyed by the list text, so shaping no longer
rescans candidates for every piece. Resolution still reads every candidate.

A 500-paragraph document whose font names 20,000 candidates laid out in 10.8 s;
bounded on read it takes 17 ms.

Tests:
- a hostile fallback list keeps its leading families, cut on a `;`
- a real LibreOffice list is read whole
- a later Thai or named fallback still classifies, and lists are cached
2026-11-08 05:55:24 +01:00
neilcawse b8a7e2acdb docx: normalize TOCHeading gallery content controls with trailing FieldEnd paragraph (#5952)
* docx: normalize TOCHeading gallery content controls with trailing FieldEnd paragraph

* test(docx): assert TOC entries survive round-trip in section-break TOC control test
2026-11-08 05:50:41 +01:00
Jhong-Ken ChenandMartin Ball f0fb31c0c9 XML: normalise line ends in text and CDATA (XML 1.0 §2.11) (#5897) (#5898)
Text nodes were decoded without line-end normalisation, so a file
saved with Windows line ends kept the CR of each CR LF: a line break
inside w:t read as two spaces. Text and CDATA now go through
quick-xml's xml_content, which reads CR LF and a lone CR as one line
feed; a CR written as &#13; stays a CR. Attribute values were already
normalised.

Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 05:48:20 +01:00
vangel76andClaude Opus 5.5 5d139d0f0e Merge upstream/main into PR #2703
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 05:19:14 +01:00
c40719f431 Layout: a turned inline picture with no recorded room for the turn keeps its line to its frame, as in Word (#5448)
A file that turns an inline picture but writes no wp:effectExtent (or a zero
one), as other tools do, makes Word keep the picture's line to its frame and
let the turn overhang it, cut at the line's top and bottom: the frame as it
is in Word 2007 layout (compatibilityMode < 15), with width and height
exchanged from 45 to 135 and 225 to 315 degrees in Word 2013+ layout.
WordCraft always reserved the exact rotated bounds (Float::spin_pad), which
is what Word's own files encode through their effect extents, so the text
after such a picture sat up to 34 pt too low (docxide-pdf
standalone-picture-compat12-* / compat15-angle45/135).

The docx reader now marks such objects (Float::bare_turn, cleared when the
object is turned again); the inline room comes from Float::line_pad, which
display uses too to place the frame in it, and the line clips the picture's
overhang. The writer keeps writing no turn overhang for them, so a save
round-trips. Word-saved pictures are unchanged.

Co-authored-by: Naxvog <4963183+naxvog@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-08 04:34:00 +01:00
Harrison Booth 6d0bd73127 Preserve paragraph text direction in DOCX (#5392)
* WC6-07: preserve paragraph text direction

* Resolve gaps summary merge

* WC6-07: retain paragraph direction variants

* WC6-07: preserve strict paragraph direction

* Update lockfile for DOCX test dependency

* Close paragraph direction implementation

* Format paragraph direction imports
2026-11-08 04:31:23 +01:00
b7c2fe8dff DOCX: a VML text box keeps its text direction (layout-flow) (#5193) (#5346)
Compatibility-mode documents store text boxes as VML only. The reader
ignored v:textbox's text direction, so a header text box turned 270
degrees was drawn level. It now reads it as Word for Windows does:
mso-layout-flow-alt:bottom-to-top is vert270 whatever layout-flow says;
otherwise layout-flow:vertical or vertical-ideographic is vert; anything
else stays horizontal.

Co-authored-by: Naxvog <4963183+naxvog@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 04:28:39 +01:00
caeb87c754 Shapes in Strict Open XML documents open (#3548) (#5697)
A Strict document opened with its text and no shapes at all. Strict puts
shapes, groups and canvases (wsp, wgp, wpc) and their parts in its one
WordprocessingDrawing namespace, which the reader maps to wp:, while the
drawing reader looks for Word 2010's wps:, wpg: and wpc: names. Word also
writes a Strict text box's text in wne:txbxContent.

The XML reader now names those elements as Transitional documents do,
from the element and its parent (xml::element_prefix), and reads a text
box's content from wne:txbxContent and from the schema's own
txbxContent. Saving writes them as Transitional.


Claude-Session: https://claude.ai/code/session_01LvG6E1XTfHtZDbfYwfREhR

Co-authored-by: Filip Strajnar <filip.strajnar@proton.me>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 04:08:36 +01:00
d2a2709e14 Pictures: a linked picture shows its link on hover and follows it on Ctrl+click; DOCX keeps the link on the drawing (#5267) (#5295)
* #5267: a linked picture shows and follows its link; DOCX keeps it on the drawing

A link put on a picture from its context menu was stored, but nothing showed
it: hovering the picture gave no tip, and Ctrl+click picked the picture for a
copy instead of following the link. Now the hover tip and Ctrl/Cmd+click work
on a linked picture, shape or text box, in line or floating, as on linked text.

DOCX: Word keeps a picture's hyperlink on the drawing (wp:docPr/a:hlinkClick,
ECMA-376 Part 1 20.4.2.5). It is now read (a w:hyperlink around the run wins)
and written beside the w:hyperlink, sharing one relationship. A link to a place
in the document stays the w:hyperlink w:anchor only.

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

* #5267: ink and Office 2016 charts take their drawing's link; Ctrl+click over text on a Behind Text picture stays a text click

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

* #5267: rustfmt

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

* #5267: a chart or ink takes the link of the choice it was read from; Ctrl/⌘+click in the docs

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

* #5267: the decoy choice in the chart-link fixture needs a namespace no reader knows

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

* #5267: inside a linked text box, hover and Ctrl/⌘+click take the box's link

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

* #5267: the picture-link test sets the image's fx after merging main

Main gave InlineObject::Image picture effects (fx); the round-trip test this PR adds built
an image without them and no longer compiled.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 03:50:38 +01:00
9b6e9564a2 Lists: a numFmt none level shows its literal text, so RESPONSE: labels the paragraph (#4985) (#5055)
* #4985: a numFmt none list level shows its literal text

Word labels a paragraph whose level has numFmt none and lvlText RESPONSE:
with RESPONSE:. Counters::next_label returned no label for any none level;
now only a none level of placeholders shows nothing. Its own %n stays
empty, and it still doesn't count. Numbering::shows_label agrees.

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

* #4985: rustfmt

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

* #4985: a "none" list level counts, and only its own number is empty

Taken from MeHail-02's numbering-literal-none branch (46405e66), checked in Word
for Windows: a none level is an ordinary level whose own number reads as
nothing. It counts and restarts the levels below it, stays empty in legal
numbering, and an empty label still tabs the text to the indent unless it
already ends there (the Chapter 1 list's Heading 2 stays at the margin).

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

* #4985: STYLEREF in full context keeps a none-level heading's parent

Review: a none level now has a label, so its headings reach the style index,
which leaves the none level out of the levels it keeps; \w and \r took the last
kept level for the heading's own and dropped the parent. Levels now carry their
index, and the levels above are picked by it.

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

* #4985: STYLEREF number switches on a none-level heading

Review: in full context an empty label of its own added a trailing period (3.),
and the suppress switch gave a none level's label (Note), which holds no number,
back whole. An empty own part is left out, and a none level's label with no
number is suppressed to nothing.

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

* #4985: STYLEREF \s and \t on none-level labels

Review: \s took a none level's label (Note) for a chapter number; the heading's
count stands in, as for an unnumbered heading. \t matched any ancestor's number
inside a word (the a of Chapter); only the numbers the label's template shows
count now.

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

* #4985: STYLEREF takes a label's numbers by their spans

Review: \s took the last word of a label (Response of "3 Response") and fell
back on the heading count for a none level showing its parent's number (%1);
\t kept text attached to a number (Section3). A label's numbers are now the
spans of the values its template shows, with their delimiters (a letter number
only standing apart from other letters); \s takes the last of them.

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

* #4985: tests edit the numbering through Arc::make_mut after merging main

Main shares the numbering between undo steps (#2694), so `Document::numbering` is an
`Arc<Numbering>`; the tests this PR adds wrote to it directly and no longer built.

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

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: MeHail <mihailsmetanin15@gmail.com>
Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 03:20:49 +01:00
Harrison BoothandMartin Ball 7855a2d814 fix(fields): quoted-argument backslash escapes; body PAGE in a cardinal-text section (#4579)
* fix(fields): quoted-argument backslash escapes and body PAGE in a cardinal-text section

A backslash inside a quoted field argument makes the next character literal, so TITLE "x \* Upper" shows x * Upper as Word does. A body PAGE field now uses the section's page number format (cardinal text shows words), as headers and footers already did.

* Fields: PAGE in a body table follows the section number format; parity docs

* fmt

* docs: clarify quoted field escape rule

* Fix page fields in fitted text boxes

* Move fitted cache test after layout helpers

---------

Co-authored-by: Martin Ball <martin.ball@ucscaregroup.co.uk>
2026-11-08 02:08:54 +01:00
NetterSilverandClaude Opus 5.5 334494a39f Cap equation matrix size when writing OMML (#4000)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 21:41:27 +01:00
Harrison Booth 737bab404f Preserve text frame anchor locks (#5382)
* Preserve text frame anchor locks

* Update lockfile for DOCX test dependency

* Assert frame geometry survives document round trips

* Preserve text frame locks on paragraph updates

* Remove duplicate DOCX test dependency
2026-11-05 11:39:30 +01:00
Harrison Booth 9c5b54a1a1 Preserve paragraph grid indent settings in DOCX (#5384)
* WC6-06: preserve adjustRightInd in DOCX

* WC6-06: honor grid indent defaults and XML order

* Update lockfile for DOCX test dependency

* Format DOCX ordering assertion

* Keep main lockfile for paragraph property PR

* PR 5384: tighten grid indent docs and regression

* PR 5384: match paragraph check formatting
2026-11-05 11:39:25 +01:00
Harrison Booth 12a840f653 Preserve section settings when saving DOCX (#5311)
* DOCX: preserve section print and note settings

* docs: record chapter style byte range

* fix: accept XML integer syntax for tray codes

* fix: preserve automatic footnote columns
2026-11-05 09:14:03 +01:00
vangel76andClaude Sonnet 5.5 097cddbd03 Resolve and test style changes through Arc::make_mut after the shared-stylesheet change on main
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 03:32:58 +01:00
vangel76andClaude Sonnet 5.5 7814450d0a Merge upstream/main into feat/style-pr-change-2697
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 03:27:01 +01:00
entropybeaterandBrian 4123bdc09f docx: keep a paragraph's text alignment (#5498)
* docx: keep a paragraph's text alignment

w:textAlignment (ECMA-376 17.3.1.39) was not read, so a save dropped it. Word sizes a line by it when a
list's bullet is larger than the text: without it, those lines grow and every page after them moves.
ParaProps gains text_alignment, read and carried through styles, and written back after w:jc. Kept for
the file only; the layout does not use it yet.

* contributors: add entropybeater

---------

Co-authored-by: Brian <255903314+entropybeater@users.noreply.github.com>
2026-11-05 02:09:55 +01:00
Joseph AngladaandClaude Sonnet 5.5 208facfb92 SmartArt: custom colours per item from the Text Pane (#3123)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:47:56 +01:00
entropybeaterandBrian 811a847e86 doc, docx: keep the compound border lines (#5499)
* doc, docx: keep the compound border lines

The nine thin and thick compound lines (thinThickSmallGap to thinThickThinLargeGap, ECMA-376 17.18.2)
were read as a single line and written back as one, on paragraphs, tables, cells and pages. BorderStyle
gains them; they are written back by name and drawn as a single line of the border's width, as before.
RTF export and import carry them too (the importer read four of them as double).

* contributors: add entropybeater

---------

Co-authored-by: Brian <255903314+entropybeater@users.noreply.github.com>
2026-11-05 01:40:16 +01:00
Dmitrii KhlapovandClaude Sonnet 5.5 1c7b5013fa Drop Cap follow-ups: whole selection, script fonts, margin gap, menu keeps options (#4077)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
2026-11-05 01:26:57 +01:00
mmazzieriandClaude Opus 5.5 75fc50fb77 DOCX: picture brightness, contrast and transparency (VML washout, a:lum, a:alphaModFix) (#1961)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 21:47:44 +01:00
FredApps 3c7aa5df90 Merge branch 'main' of https://github.com/storytold/wordcraft into pr-5559
# Conflicts:
#	crates/formats/src/odt/import.rs
2026-11-04 15:24:27 +01:00
Bryan MarkandClaude Opus 5.5 b2734c28f4 Undo: steps share the style sheet and list definitions (1.2 GB → 21 MB at the limit) (#2694)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-04 15:03:13 +01:00
FredApps 8b9f726ea7 Merge main (688cce47) into ODT PR 2026-11-04 13:44:24 +01:00
VoiceLessQ fd1c5efe6c Format readers: one border-type table for .doc, one HYPERLINK parser for DOCX, RTF and .doc (#4222) 2026-11-04 12:13:39 +01:00
VoiceLessQ 655b4312d3 DOCX: nil shading paints no fill, border theme colours win (part of #1991) (#4705) 2026-11-04 11:58:06 +01:00