Read w:eastAsianLayout (ISO/IEC 29500-1 §17.3.2.10) into a new
CharProps::east_asian_layout and write it back after w:lang, in runs and
styles. Values outside the schema are left unset. Layout is unchanged.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* WIP for #1543
* DOCX: split mixed-direction runs and mark right-to-left pieces w:rtl so Word orders them as WordCraft does (#1543)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* DOCX: right-to-left pieces of split runs say their language (w:lang w:bidi) (#1543)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* DOCX: no phantom tracked formatting on split runs; typed text doesn't inherit run direction (#1543)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Engine: text typed or inserted anywhere takes its direction from its own letters, not the caret's run (#1543)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* track-move-options: WIP
* track-move-options: Moves options in Track Changes Options and w:doNotTrackMoves
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* track-move-options: Moved from Hidden leaves the layout; per-revision hiding
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* track-move-options: Word's mark lists, (none) moves are plain, no borders on collapsed paragraphs
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* track-move-options: hr and sv translations for Moved from:/Moved to:
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Shapes: preserve DrawingML outline dashes
* Shapes: scale dashes to effective path width (#380)
* Keep the outline dash with noFill; cap the raster dashed stroke width at 200 pt
Addresses the two CodeRabbit review notes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Use clamp for the dashed stroke width (clippy)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Found while testing crates/docx/src/write/story.rs:512-530 (InlineObject::NoteRef, the `current_note == Some(..)` branch)
Co-authored-by: Claude Haiku 5.5 <noreply@anthropic.com>
part that inherits its lines sends it, and the picker only shows No Border checked for it.
- CellProps::valign is Option<VAlign>: a cell's own Top (Align Top, w:vAlign="top") beats a
table style part's vertical alignment, and round-trips through .docx.
- tableStyle edit rejects Part fields at the top level without "part".
- "font": null or "" makes a part's font inherited; clearing the dialog's font box sends it.
- Document ui.dialog's optional "part" in docs/control-protocol.md.
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* #714: table style editor formats every table style part
Modify/New Table Style: "Apply formatting to" any of the 13 ECMA-376
§17.7.6 parts (whole table, header/total row, first/last column,
odd/even row and column bands, four corner cells), each with font,
size, bold, italic, underline, colour, fill, borders (line style,
width, colour; all/none/outside/inside/each edge) and the 9-way cell
alignment, over a live preview.
- doc: TablePart, PartFormat, PartSet; TableStyleParts::part/set_part
(new parts and per-part jc/vAlign in `regions`)
- layout: generic part resolution incl. band2, corner cells, alignment
- docx: every tblStylePr type read/written with pPr jc and tcPr vAlign
- engine: table.newStyle/modifyStyle take ECMA part names, `part`,
`parts`, per-edge `borders`, `underline`, `align`/`vAlign`/`cellAlign`
- ui: dialog moved to dialogs_table_style.rs; ui.dialog takes `part`
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: Hungarian and French strings for this change
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #887: Bulgarian strings for the table style parts
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #714: Vietnamese strings for the table style parts (main's new vi catalog)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* hr: match the catalog's word for banded
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A field begin marker flagged w:dirty by a producer that couldn't compute
its result (pandoc-style TOC placeholders) lost the flag on save, so Word
no longer refreshed the field on open. Mirror w:fldLock end to end:
FieldState, InlineObject::Field/FieldStart, the reader (fldChar and
fldSimple) and the writer (buffered, range and TOC-spanning begins).
Update Field/Update Table clear it on the fields they compute, like
Word's F9; untouched fields keep it. Round-trip and engine regression
tests, incl. a pin for #878 (imported TOC placeholder replaced in place,
fixed earlier by #617).
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
space after and the second's space before, as Word does by default. Word
adds them instead when the document's compatibility options include
w:doNotUseHTMLParagraphAutoSpacing. Measured in Word with five paragraphs
of 12 pt before and after: 24 pt between them with the option, 12 pt
without, the same in compatibility modes 14 and 15. A 60-page report with
the option lost 6 pt per paragraph, about 60 pt on its cover.
The option is read, laid out in the body and in boxes, and saved back.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
DrawingML's rtTriangle was read as an isosceles triangle, so a cover
page's white corner cut-outs pointed up into a peak instead of cutting a
V into the picture above them. It is now its own shape kind, drawn with
the right angle at the bottom left, wrapped and glued along that outline,
and saved back as rtTriangle. The .doc reader maps msosptRightTriangle (6)
to it too.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* #1290: read Word's VML text watermark from DOCX headers
Word's Design › Watermark is a VML shape with a v:textpath in the headers.
The reader dropped it, so screen and PDF showed no watermark. It now maps
it to the document's watermark model (text, font, fill colour,
semitransparent from v:fill opacity, diagonal when turned), which the
renderers already draw. Only Word's watermark shape (PowerPlusWaterMarkObject
id) or text centred on the page both ways counts; other header WordArt,
body WordArt and shapes inside text boxes are left alone. Writing it back
to DOCX is still missing (it was already lost on save).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1290: write the watermark to DOCX as a VML text shape in the headers
The DOCX writer dropped settings.watermark, so a watermark read from Word
(or set in WordCraft) was lost on save. Every header part now starts its
first paragraph with a VML shape (ECMA-376 Part 4) whose v:textpath carries
the text, font, fill colour, semitransparency (v:fill opacity) and diagonal
turn, centred on the margins behind the text, with the reader's
PowerPlusWaterMarkObject id so it reads back as the watermark, not a shape.
The shape type is our own: a straight path the text follows, fitted to the
box. Slots the pages show with no header of their own or linked from an
earlier section (default; first page with a title page; even pages with
even/odd headers) get a header holding only the watermark; linked sections
stay linked. A blank watermark isn't written. Check Compatibility no longer
warns about watermarks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1290: give the watermark's text path a top and a bottom edge so Word draws it
With a single line as the shape type's path, Word loaded the watermark as
WordArt (right text, size and turn) but drew nothing. Checked black-box in
Word: diagonal, horizontal and header-less documents now show it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1290: test the watermark through a Word-shaped file, table-only and even-page headers
Read → write → read of a file with Word's watermark keeps the watermark, the
headers' text and paragraphs and one shape per header; header WordArt that
isn't a watermark doesn't become one. A header holding only a table gains no
line; with odd and even pages an even header is added and later sections
stay linked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DOCX: read VML freeforms (v:shape with a path) as freeform shapes
Legacy VML shapes with their own `path` (ECMA-376 Part 4), such as rule
lines in headers, were dropped on open and lost on save. They are now
read as freeforms: m/t/l/r/c/v/x/e commands in the coordsize/coordorigin
space, nf/ns, v:fill and v:stroke opacity; arcs drawn straight, formula
references read as 0. Saved as DrawingML custom geometry.
Tests: header rule read and round-tripped; hostile paths and coordinate
spaces stay finite and never panic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DOCX: VML freeforms whose path uses formulas aren't drawn
Formulas (@n, from v:formulas) aren't evaluated; reading them as 0 drew stray lines. Parity row states the fill-opacity limit (none at 0, otherwise opaque, as for DrawingML fills).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DOCX: VML freeforms reuse the watermark's vml_fraction
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1290: move the VML freeform reader out of this PR
The three VML freeform commits (b7a6cc7, d8fa665, 945cbb4) aren't part of
#1290; they go to their own pull request so this one stays on the
watermark.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Word forms keep their legacy form fields and rows' skipped grid columns when saved (part of #1174)
* Tests: field initializers name the new form field
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* DOCX: merge settings.xml into the original instead of regenerating it (#1034)
A save regenerated word/settings.xml from the model, so every setting the
model doesn't hold was dropped: compatibility options (lost in 18 of 18
real-world Word files), rsids, document variables, proofing state and the
colour scheme mapping.
The reader now keeps the original part when it holds such settings, and
the writer merges into it: the original root and every unowned child stay
byte for byte; owned children follow the model in CT_Settings order; in
w:compat only compatibilityMode is replaced. The privacy options are the
model's since #1062, so they are owned too. Kept children that point at a
relationship (a mail-merge data source) are dropped. Anything unexpected
falls back to the generated part. Files WordCraft wrote itself keep
nothing extra.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* DOCX: carry unmodelled parts and keep comment ids, style defaults, latent styles, list ids and app props (#1034)
Builds on the settings.xml merge.
- Parts the package or main document relate to that WordCraft neither
models nor writes (webSettings, stylesWithEffects, people, add-in task
panes, the thumbnail, future parts) are carried verbatim with their
relationships and content types; relationship types the writer
produces, and any the body refers to by id, are not (HANDLED_RELS).
- commentsIds / commentsExtensible: durable ids and UTC dates are read
into the model and regenerated against the written paragraph ids.
- w:default on localized default styles, w:latentStyles, lists'
nsid/tmpl/multiLevelType, and app.xml Template/Company/Manager/
HyperlinkBase round-trip; counts are not carried, and Company/Manager
are dropped when the file asks to remove personal information.
- Comment reference marks use the document's "annotation reference"
style id instead of a hard-coded CommentReference.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: przemek-arch <263159043+przemek-arch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A save regenerated word/settings.xml from the model, so every setting the
model doesn't hold was dropped: compatibility options (lost in 18 of 18
real-world Word files), rsids, document variables, proofing state and the
colour scheme mapping.
The reader now keeps the original part when it holds such settings, and
the writer merges into it: the original root and every unowned child stay
byte for byte; owned children follow the model in CT_Settings order; in
w:compat only compatibilityMode is replaced. The privacy options are the
model's since #1062, so they are owned too. Kept children that point at a
relationship (a mail-merge data source) are dropped. Anything unexpected
falls back to the generated part. Files WordCraft wrote itself keep
nothing extra.
Co-authored-by: przemek-arch <263159043+przemek-arch@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
An mc:AlternateContent whose Choice holds a cx:chart is read as a read-only chart drawn from its fallback picture, keeping both branches and every part they reach (chartEx part, style, colours, workbook, picture). Saving writes the AlternateContent back with the chart's current frame on both branches, instead of only the fallback picture.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Lift equation color from run-level OMML to CharProps during read,
push it back to runs during write. Keep source OMML until the color
changes to preserve control properties the model can't hold.
* Shapes: rounded rectangles keep their own corner radius
A roundRect's adj (its corner in 100000ths of the shorter side) is read, kept
on the shape, saved back, and used for the screen, the PDF and Tight/Through
wrapping. Without one the corner stays at 16%.
* Render: test rounded rectangle corners through layout and rendering
* Docs: progress log and file-format parity for rounded rectangle corners
* Render: pass the shape's corner to the caret-background hit test (#299 code from main)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* #1062: honour Remove personal information / Remove date and time on save
w:removePersonalInformation and w:removeDateAndTime (ECMA-376 §17.15.1.69-70)
are read into Settings, written back in CT_Settings order, and honoured by the
DOCX writer: comment and revision authors saved as "Author" (initials "A"), no
dc:creator / cp:lastModifiedBy, no w:date on comments and tracked changes. The
open document keeps its real values. New file.privacyOptions command sets both.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1062: reading privacy options has no side effects; File › Options › Save check boxes
file.privacy reads the settings (a pure command: no undo step, no unsaved changes);
file.privacyOptions only changes them and refuses an empty call. File › Options › Save gets
a "Privacy for this document" section with the two check boxes, translated in every catalog.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Text boxes: VML text boxes keep their internal margins, fit to their text and alignment
A VML text box's inset ("l,t,r,b", ECMA-376 Part 4 §19.1.2.22) was ignored,
so its text sat Word's default 7.2 pt in and 3.6 pt down even where the file
says 0,0,0,0, which is how letterheads and form headers place address blocks
exactly. It's now read like DrawingML's lIns/tIns/rIns/bIns: each value left
out keeps the default, a bare number is in EMUs, o:insetmode="auto" leaves
the defaults. mso-fit-shape-to-text (VML's "Resize shape to fit text") is read
as auto-fit, like a:spAutoFit, and the shape's v-text-anchor as the text's
vertical alignment. In a group, a member's margins go with that member's
text.
The reader feeds layout, so the editor, PDF and page images all change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Drawings: hidden shapes and pictures are kept but not shown
A drawing marked hidden (VML visibility:hidden, floating or inline;
DrawingML wp:docPr/@hidden, or a group member's cNvPr/@hidden) was drawn,
took room and wrapped text. Word for Windows shows it in no view; it's now
kept and saved hidden, but left out of layout: not placed, no wrap area, no
room in its line, nothing drawn, its text box's notes not placed. Exports to
other formats and copies leave it out, the accessibility checker no longer
asks for its alt text, and the selection pane says it's hidden.
Word for Mac draws hidden VML shapes; Windows follows the markup.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Naxvog <4963183+naxvog@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Found by rendering 12 US government Word documents (NIH, EPA, MCC) in
Word for Windows and WordCraft and comparing the pages side by side,
then pinning each rule down with synthetic documents measured in Word.
- Kerning: the shaper kerned every run, so WordCraft's lines held more
text than Word's and broke differently. Word kerns only a run with
Kerning for fonts (w:kern) at or above that size; no w:kern and
w:kern="0" are unkerned. New documents keep kerning from 1 pt, like
Word's Normal template.
- Automatic paragraph spacing (w:beforeAutospacing/w:afterAutospacing,
common in text pasted from web pages) was ignored. It is 14 pt at
any size, none before the document's or a cell's first paragraph,
none after a cell's last, and the larger of two neighbouring spaces
counts. Read, written back, and settable through para.spacing
(beforeAuto/afterAuto); a number, Ctrl+0 and Remove Space After
replace it as in Word.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Found in NIH's monitoring-plan template compared with Word for Windows:
its footer puts the page number in a text frame (w:framePr: centred,
text wrapping around it), and Word draws "NCCIH DSMP Template" ending
just left of the number on the same line.
Before: frames other than drop caps were ignored on import, so the
number took a line of its own above the footer text (making every page
a line shorter), and the frame was lost on save.
After: a paragraph's text frame is read (size, anchors, alignment,
offsets, wrap, distances) and written back. In headers, footers, table
cells and text boxes it is placed like a floating object, sized to its
text unless it has a width, and the text after it wraps around it; the
DSMP footer now matches Word's. Frames in the body text still lay out
in line.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Read and write w:hideMark on table cells, and lay it out like Word: a cell's
empty last paragraph takes no room, spacing and all, so a row of only such
empty cells is just its borders; an ordinary empty cell keeps the row a line
tall. Measured in Word for Windows: 9 synthetic cases. NIH's Table A no
longer shows a blank row.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
A Word 365 cover page lost its look. The missing fills came from
theme-coloured shapes (scheme colours and wps:style fill references),
which the reporter's 0.5.0 build didn't read; #611 fixed that on main.
Two causes were still open on main:
- A freeform (a:custGeom) inside a wpg group was drawn as a rectangle.
read_wsp now reads custom geometry, so group members get it as well.
- Text boxes ignored wps:bodyPr lIns/tIns/rIns/bIns and a:spAutoFit.
Layout always used Word's default margins, so a title box with no
margins that was just tall enough for its text lost its second line.
TextBody now carries the box's own margins and auto_fit. Layout uses
those margins and doesn't cut the text of a box that resizes to fit.
Both are written back on save.
Co-authored-by: Dmitrii Khlapov <19991457+dkhlapov@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Keep inherited complex-script size, bold and italic independent from Latin
properties and retain explicit values during DOCX round trips. Preserve
ordinary formatting-command behavior and add regression coverage.
Resolve eight existing Clippy warnings without changing behavior so all
six required CI gates pass.
Co-authored-by: ChatGPT <noreply@openai.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* M8.1: Bibliography sources DOCX round-trip
Store bibliography sources in package-root custom XML (customXml/item1.xml) with datastore item properties (customXml/itemProps1.xml), relationships, root customXml relationship (_rels/.rels), and content type overrides per ECMA-376 §15.2.
Map internal source types to Word b:SourceType values (Book, BookSection, JournalArticle, ArticleInAPeriodical, InternetSite, DocumentFromInternetSite, ElectronicSource, Report, ConferenceProceedings, Case, Art, Film, Interview, Patent, Performance, SoundRecording, Standard, Thesis, Misc) and parse them back. Write SelectedStyle and StyleName attributes on b:Sources. Use safe slice indexing for author names parsing. Scan customXml relationships and customXml/item*.xml on read, extracting sources from b:Sources in the bibliography namespace.
Add roundtrip integration tests in crates/docx/tests/roundtrip.rs verifying all parts, relationships, and attributes, update second-generation kitchen sink stability test, add hostile-input tests in crates/docx/tests/malformed.rs, and verify integration with citation styles in engine citations test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
* Review fixes for #532: bounded source reading, real citation style
- Read at most 10,000 bibliography sources and dedupe them with hash sets, so a hostile
file with ~100k b:Source elements can't make opening quadratic; each custom XML part is
read at most once (64 parts at most). Test: hostile_bibliography_source_count_is_capped.
- Drop the rt::BIBLIOGRAPHY relationship branch (not an OPC relationship type) and the
stray comment in write_as.
- Write the document's citation style (References > Style) in b:Sources/@StyleName and
@SelectedStyle instead of always APA: Settings::bib_style records it, the style
command sets it, opening a file reads it back into the session.
- The b: namespace goes with the other non-body namespaces (it isn't declared on
document.xml), matching #612.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep the custom XML properties relationship apart from customXml
So #612, which adds the same rt::CUSTOM_XML line, merges with this branch without a
conflict.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* clippy: pass parse_persons by value (needless_borrows_for_generic_args)
* rustfmt after merging main
---------
Co-authored-by: yefan911 <yefan911@users.noreply.github.com>
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- docx: Flat OPC (`pkg:package`) read by unpacking the parts into an
in-memory package for the DOCX reader; written from the DOCX writer's
parts (XML inline, binary parts in base64). Part count, part size,
total size and base64 length are capped.
- docx: Word 2003 XML (`w:wordDocument`) imported by rewriting it as the
corresponding package (hyphenated names, w:hlink, w:listPr, w:lists,
inline headers/footers, notes, aml annotations, w:binData pictures,
o:DocumentProperties) and reading that with the DOCX reader.
- `.xml` told apart by root element; other XML is refused with
"not a Word XML document". File > Export gets "Word XML Document (*.xml)"
(all 9 catalogs); .xml saves keep the document like .docx.
- Tests: Flat OPC round trip equals DOCX round trip, hand-written Flat OPC
package, Word 2003 import, hostile inputs, engine io.
Fixes#548
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- Indents in characters (w:firstLineChars, w:hangingChars, w:leftChars,
w:rightChars; sprmPDxc* in .doc) are kept in the model, read and written,
and laid out in the paragraph mark's font size, winning over the points
as in Word. Indent commands cancel an inherited character indent.
- .doc: sprmPDxaLeft1 has a two-byte operand (was read as four, so every
first-line indent was lost); sprmPDxaLeft1_80 is read; LSPD line spacing
is decoded as signed dyaLine + fMultLinespace (exact 20pt read as 799pt,
a page per empty paragraph).
- A floating table placed on the page or margin that would cover the text
already on the page and doesn't fit below it moves to the next page.
- A line holding only a page break stays at the bottom of a full page
instead of leaving a blank page.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- Model (doc::smart_art): layout, items (text + level), colour variant; capped at 100 items,
255 characters, 8 levels.
- Layout algorithms of our own (docx::smart_art) place rounded rects, circles, bands, arrows and
connectors; WordCraft draws the graphic from the same dsp:drawing it saves.
- DOCX: data (dgm:dataModel points and connections), our own layout/quick-style/colour
definitions under the built-in identifiers, the drawing part, relationships and content types.
A diagram reads back editable only when its data part is exactly what WordCraft writes.
- Commands: insert.smartArt, smartArt.items/addShape/promote/demote/layout/colors/reset/textPane,
one undo step each; picture.size relays out a SmartArt graphic.
- UI: layout picker with previews drawn in code, SmartArt Design tab, Text Pane; strings in all
9 catalogs.
- Diagram reader draws `line` presets top-left to bottom-right (was the other diagonal).
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
- Model: SectionProps.text_direction (horizontal, tbRl, btLr); unknown
values read as horizontal.
- DOCX: w:textDirection in w:sectPr read and written in CT_SectPr order
(after w:titlePg, before w:bidi), also inside w:sectPrChange.
- Layout: a vertical section is laid out on its page turned on its side
(margins, page borders and columns turned with it) and each page is
turned onto the real page: tbRl lines run top to bottom stacking from
the right, btLr bottom to top from the left. Pictures, shapes and text
boxes stay upright; headers and footers stay horizontal; a section
turning the other way starts a new page.
- Display: in top-to-bottom text ideographs, kana, Hangul and full-width
forms stand upright (ideographic comma/full stop moved to the upper
right); Latin lies on its side. Raster and PDF draw it unchanged.
- Hit testing: clicks outside turned lines find the nearest turned line.
- Command layout.textDirection (Layout › Page Setup › Text Direction):
turns the selected cells or the text box the caret is in, else the
section; ribbon menu and keytip.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>