A bullet stored as a private-use code (U+F0xx) in a font that isn't
installed, and that isn't a mapped Symbol/Wingdings code, fell back to
any installed face with a glyph at that code - an icon font such as
Font Awesome / Nerd Fonts, where U+F081 is the Twitter logo. Such a
bullet now shows the level's default bullet (• ○ ▪), so level 2 is a
hollow circle.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A paragraph in a Thai font that isn't installed (TH Sarabun New, Angsana
New, Cordia New, the UPC families…) drew its Thai letters in one fallback
face and the Latin letters, digits and baht sign in a Latin substitute at
a visibly different size. Word substitutes one font (Cordia New) for the
whole run.
Thai families now have their own substitute lists (Cordia New and
Leelawadee UI on Windows, Thonburi on macOS, Noto Sans Thai and the TLWG
fonts on Linux; serif families prefer Angsana New, Sathu or Noto Serif
Thai), and the first listed face with Latin letters and digits as well
as Thai wins. When the substitute still lacks some of the run's Thai or
Latin text, the run moves to one face covering it through
FontDb::fallback_for_run, the generalised East Asian run fallback. Only
Thai fonts get this: a missing Latin font keeps Latin text in its own
substitute, a run with its own complex-script font keeps it for the Thai
letters, and a missing roman-classed Thai font is no longer drawn in
Cambria.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The legacy run properties w:outline, w:shadow, w:emboss and w:imprint were
read, resolved and saved but never drawn. Layout now turns them into text
effects (hollow outlined letters; a sharp grey copy down-right for shadow
and emboss, up-left for imprint, as Word's PDFs show them) and draws them
through the existing WordArt path, so screen and PDF both get them and the
PDF keeps the text. WordArt w14 effects on the same run take precedence.
Text drawn from outlines keeps synthetic bold (a widened outline, or one
in a solid fill's colour and transparency). Colour glyphs (emoji, no
outlines) and top-to-bottom runs with upright characters are drawn as
plain glyphs, and tracked insertions and deletions keep their legacy
effects.
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>
* 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>
split_row already keeps widow/orphan control in each cell paragraph.
When that moves all of a cell's lines on although its first line would
fit, the other cells stayed on the page and the row was split beside
an empty cell. Word moves the whole row on instead. Observed with
synthetic documents (exact 14 pt lines, a one-line cell next to a
longer one near the bottom of the page):
long cell | room for | Word | before | now
4 lines | 2 | 2 + 2 | 2 + 2 | 2 + 2
3 lines | 2 | row moves | short cell kept | row moves
3 lines | 1 | row moves | short cell kept | row moves
4 lines | 1 | row moves | short cell kept | row moves
5 lines | 3 | 3 + 2 | 3 + 2 | 3 + 2
3, control off | 2 | 2 + 1 | 2 + 1 | 2 + 1
Co-authored-by: Daniele Mori <Dinasty@hotmail.it>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Automatic text in a styled text box takes the shape style's font colour
A text box shape whose style has a:fontRef with a colour (Word's
default shape style uses lt1, white on the accent fill) shows its
automatic-colour text in that colour. WordCraft drew it black. Word,
observed with a synthetic document: only text whose resolved colour is
automatic takes the fontRef colour; a run's own colour, a paragraph or
character style colour and a colour from the document defaults all win
over it. A box without a fontRef keeps black.
- wordcraft-doc: TextBody gets `auto_color`.
- wordcraft-docx: read from wps:style/a:fontRef (theme colours resolved
as for SmartArt).
- wordcraft-layout: lines in a text box story resolve automatic colour
to it.
Saving does not write a shape style yet, so the colour is not kept
through a save; the reader and layout parts stand on their own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Remove stray doc-comment lines from the new test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Daniele Mori <Dinasty@hotmail.it>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.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>
* Tables: preserve row table border exceptions
* Tests: shorten the row border regression name
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.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>
A document typed in Vietnamese under the default editing language (en-US) was
covered in red underlines, every Vietnamese word checked as English. A
paragraph that reads as Vietnamese (words with Vietnamese-only letters: the
breve and horn letters, đ, ĩ ũ, the tone-marked vowels of Latin Extended
Additional, or stacked combining marks) is now treated like any language
without proofing tools: no spelling or grammar marks, as Word's automatic
language detection does. A Vietnamese name in English text (Nguyễn) is no
longer flagged either; French and Portuguese, which share â ê ô, are unaffected.
Automatic hyphenation also leaves Vietnamese paragraphs and words whole
(single syllables never take a hyphen); the English patterns happen not to
split these words today, and the guard keeps it so.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A table with repeated header rows that started near the bottom of a page left the header rows
there alone when the first row after them didn't fit, then repeated them on the next page above
that row. Word starts such a table on the next page.
place_table now checks, before the first row, whether the row after the header rows can start
under them (whole, or split when it may split). If it can't and the page already holds
something, the table starts on the next page. A table at the top of a page keeps its header
there as before.
Co-authored-by: dfgodvan <180286157+dfgodvan@users.noreply.github.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Word's cover pages are one paragraph holding a page break and then the
page-anchored text box with the title and the approval table. Word
draws a floating object on the page its anchor paragraph starts on;
WordCraft drew it with the line holding the anchor, which after the
break is the first line of page two, so the cover was blank and the
title box sat over the body text of page two.
`place_objects` now places a paragraph's floating objects from its first
piece, whichever of its lines holds the anchor, and none from later
pieces; inline objects still go with their own line. The wrap areas were
already registered from the paragraph's first page, so nothing changes
for text flowing around the object.
Co-authored-by: Daniele Mori <Dinasty@hotmail.it>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
WordCraft chose a substitute for a font that isn't installed from its
name alone, so an unknown brand font always came out sans. Word reads the
font table instead: measured with the same missing font, it draws it in
Cambria when w:family is roman and in Calibri when it is swiss or auto.
A report whose font table calls its brand font roman got a sans footer
where Word draws serif.
The font table's roman fonts are read into the settings, and layout looks
a missing one up as Cambria (Caladea where Cambria isn't installed). The
other classes keep the existing substitutes, which already start with
Calibri's metric clone.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.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>
A header or footer a section inherits (Same as Previous) keeps the
percentage widths of its tables relative to the section that defines it.
Measured in Word: a 100%-wide footer table defined by a portrait section
stays 451 pt wide, centred, on landscape pages that inherit it, and spans
the landscape width only when that section names the footer itself.
Paragraph alignment in the same footer follows the landscape page.
Found on a report whose landscape calculation pages drew their footer
table full width where Word draws it at the portrait width.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Layout: an empty section mark stays on a full page
An empty paragraph that carries a section break, when the next section
starts on a new page, needs no room of its own in Word. Measured: 50 lines
filling a page, then that paragraph, then the next section makes two pages
in Word; WordCraft made three, the middle one blank. A plain empty
paragraph in the same place still moves on, in both.
Found after a landscape drawing page in a 60-page report.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Layout: drop an unneeded mut in the section mark test
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>
* Tables: a row with less room than its minimum height moves on whole
Measured in Word with about 49 pt left on a page: a table row of eight
lines splits there, but the same row with an at-least height of 63.6 pt
goes to the next page whole, and so does one holding a nested table.
Without the height both split, as before. WordCraft split them all, so a
report's title row (a logo beside a small nested table) started at the
foot of its cover page.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tables: preserve splitting for oversized minimum-height rows
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Tables: text running past an exact-height row is cut off
A row with an exact height (w:trHeight w:hRule="exact") keeps that
height whatever its cells hold. Word cuts the text that doesn't fit at
the cell's edge; WordCraft drew it over the rows below, so a certificate's
identification block came out as overlapping lines.
The cell is marked as clipped in layout (Placed::Cell clip), and display
draws its lines inside that cell's clip, on screen and in PDF. Hit
testing is unchanged: the lines stay where they are in the layout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Tables: keep row clipping compatible with Rust 1.90
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A heading whose text opens with a page break had its list number drawn on
the line holding the break, so the number stood alone at the bottom of one
page and the heading text started the next. Word draws the number with the
text. The label now goes on the first line after a leading break.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Word writes the next heading's TOC bookmark start into the paragraph that
ends with a page break. The line after the break then held that marker,
so it wasn't the empty mark kept with the break (#932): it went onto the
next page with the paragraph's spacing and pushed the heading 17 pt down.
Lines holding only zero-width markers (InlineObject::is_marker) now count
as empty there.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
A paragraph holding only a page break keeps its mark on the page before
(#932), but its space after still went onto the new page, so a heading
with page break before no longer stood at the top and broke again: a
blank page. The space after now stays with the mark. A next-page section
break carried by such a paragraph also started a second page; the empty
page the break started is now used instead.
Found on a 60-page inspection report: two blank pages Word doesn't have.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Left of the left margin Word's next default tab stop is the first
multiple of the interval *at or after* the current position, not after
it: its arithmetic truncates toward zero. So a tab that already sits on
a stop, a second tab in a row or a leading tab on a line that starts at
-72 pt, doesn't advance; a tab preceded by text or a space, or a line
starting between stops, moves to the next multiple as usual, and right
of the margin nothing changes.
Measured on Word with synthetic documents (40 positions): "a\t\tX" at
-60 pt puts X at -36 pt where the old rule gave 0; "\tX" starting at
-72 pt leaves X at -72, at -60 moves it to -36; "\t \tX" at -60 reaches
0. Letterheads that line a footer up with spaces and tabs under a
negative indent rely on it: one had its registration number drawn 72 pt
too far right, over a vertical rule. It now lands within 0.2 pt of Word.
Co-authored-by: Daniele Mori <Dinasty@hotmail.it>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
w:pgNumType w:start="0" was read but laid out as 1: the page counter
was set to one less than the restart and could not go below zero. A
report numbering its cover 0 read "Page 2" on the page Word calls 1.
The restart is now the next page's number itself.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Layout: a table's percentage width past 100% is kept
Word keeps a preferred width over 100% of the text column (w:tblW
w:type="pct" above 5000). A cover-page footer table at 131% with the
left margin as a negative indent spans the page edge to edge in Word;
WordCraft capped it at 100%, so it ended three-quarters of the way across.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Contributors: add Fin Warman
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
russianLower/russianUpper showed 1), 2), 3). They now follow Word's 29-letter sequence (no ё, й, ъ or ь; ы kept), then repeat the letter (аа, бб, ааа), as observed black-box in Word.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
With room for two of its three lines at the bottom of a page, a paragraph was
split two and one, leaving a widow; taking a line along would leave an orphan,
so Word moves the paragraph whole. A paragraph continued from the page before
may still take one line along from two (no orphan there).
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>
* #1376: a word too wide for the strip beside a floating object moves on whole
Text in the narrow strip beside a square-wrapped picture was split mid-word
("docu" | "mentazione") when the strip was wider than the 20pt minimum but
narrower than the word. A span narrowed by a floating object is now used only
if the line's first word fits it; otherwise the word tries the row's next span,
or goes below the object. A word wider than the whole line still breaks in
place, and the 20pt minimum measured for floating tables is unchanged.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* #1376: a line after a skipped strip starts its row; word width skips hyphenation points
A line placed in a row's second span after the first was skipped was marked as
beside a line before it, so line numbering and pagination treated it as the
second half of a row. The word measured against the full line now runs to the
next real break, not the first hyphenation point, and a row with nothing on it
jumps below an object that actually crosses the column.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The index was a u16 clamped to u16::MAX while the style was still
appended, so every distinct format past the 65,536th in a paragraph
drew with the last one that fit: its font, size, link and tracked-change
marking. It is now a u32, like the glyph ranges beside it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
* Layout: inside/outside floats swap sides on even pages; Page Setup shows mirror margins (#1181)
Floats aligned inside or outside, or placed relative to the inside or
outside margin, were always put as on an odd page, so shapes Word puts
in a book's outside margin all came out on the right. They now follow
the page they're on (ECMA-376 ST_AlignH, ST_RelFromH): on an even page
the inside is the right side. Floating tables (w:tblpXSpec) too.
With mirrored margins, even pages are laid out as odd ones and then
shifted; float positions now allow for that shift, so floats placed
from the page edge stay put (the "known limit" in #452) and the left
and right margin areas are each page's own.
Mirrored margins read from a file were invisible in the UI: the Margins
menu ticks Mirrored when they're on, and Page Setup gets a Mirror
margins check box (labelling the margins Inside and Outside), applied
through a new `mirror` param of layout.margins.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* i18n: Mirror margins in every catalog
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: lloyd <lloyd@stackworx.io>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Windows Magnifier keeps the text cursor in view through UI Automation: the
caret's own box has no width, so it takes the box of the character after
the caret, and when that has none either, of the two characters before it.
The canvas described a line's end mark (the paragraph mark, a line break)
with no width, so on the empty line Enter or Shift+Enter makes Magnifier
looked at the end of the line above and stayed there until two more
letters were typed.
A line's end mark now takes the room a selection shows a paragraph mark
with: PARA_MARK_WIDTH (5 pt, now shared with selection_rects) at the line's
visual end (Line::mark_box). Checked live with Windows Magnifier, its view
read with MagGetFullscreenTransform: after Enter and Shift+Enter it moves
to the new line at once.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* Harden against hostile-document DoS and non-web link export
A security pass found several small files that make the app allocate or
compute without bound when opened (GUI, wordcraft-cli, or the MCP server),
and link targets leaving on export without the scheme check the HTML and
Markdown writers already apply. None lets a document run code or read files;
all are denial-of-service or credential-leak-on-click. Each fix bounds an
attacker-controlled size and lands with a regression test, per the
never-crash standard.
- layout: a table repeats its header rows on every page it spills onto, so
many tall header rows paginate to O(headers x pages) placed items. Cap the
total header-row repeats per table (lib.rs). 2 KB docx: 1.1 GB -> 124 MB.
- formats/model, html: an HTML table of many <tr> with large rowspan expanded
to rows x 64 covered cells, and `model::table` pre-allocated a full
rows x cols grid only to clear it. Cap rows at MAX_ROWS before
insert_covered, bound its total work, and build the grid template with one
row. 640 KB html: >1.5 GB -> 214 MB (a plain large table is faster too).
- docx/read/freeform: a custom-geometry Bezier segment took any number of
points, making de Casteljau flattening quadratic. Cap points per segment.
3 KB docx: 12 s -> 0.15 s.
- docbin: footnote/header/text-box story tables and the piece table can name
the same backing text many times. Hold the total characters materialised to
twice the WordDocument stream size (a ceiling no real file reaches, since
each char costs >=1 stream byte). 45 KB doc: >1.2 GB -> 14 MB.
- render, pdf, formats/rtf: document pictures were decoded with no dimension
limit, so a tiny file declaring a huge image could allocate before the size
check. Decode through image::Limits with a side cap first.
- doc/link, formats/rtf, odt, latex: route exported hyperlink targets through
is_safe_href (as HTML/Markdown already do), and extend it to reject
protocol-relative (//host) and UNC (\host) references. Keeps file:,
javascript:, ms-msdt: and UNC targets from being written into exported RTF,
ODT, LaTeX and PDF where a reader would follow them (UNC leaks NTLM on
Windows).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
* Align picture-decode limits with the bounds already in force
Review of the previous commit: `image::load_from_memory` and
`load_from_memory_with_format` already applied `Limits::default()`, whose
512 MB allocation cap bounded every picture decode. The PDF change had set
`max_alloc = None`, loosening that; restore the default. The render and RTF
side caps (16 384 px) newly rejected wide-but-short pictures that fit in
memory, so render now uses the pixmap's own `u16` side limit (what
`premul_pixmap` enforced after decoding, applied before it instead) and the
RTF re-encode keeps only the explicit allocation cap. Net effect: rejection
moves to header time with no change to the sizes accepted. Also fix a
comment: the header-row repeat cap is per table, not per document.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.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>
* #775: STYLEREF fields in headers and footers show each page's result
Running headers/footers with STYLEREF (e.g. the current chapter title) are
evaluated per page at layout time (ECMA-376 §17.16.5.59): the page's first
paragraph of the style (\l: last), else the nearest before, else after.
Style names/ids, heading levels (STYLEREF 1), character styles, and the
\n \r \w \s \t \p switches. Body STYLEREF fields update with the other
fields. STYLEREF added to Insert › Quick Parts › Field with its options.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #775: STYLEREF error text in our own words
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Review fixes for #882: translate the STYLEREF Field dialog strings
Adds the style picker label, the six STYLEREF switch labels and the
STYLEREF description to all 18 interface catalogs.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* STYLEREF: reuse the style index while the body and styles are unchanged
Headers with STYLEREF rebuilt and hashed the body's style index on every
layout pass (echelon's follow-up note on #882). The layout cache now keeps
the index with the body blocks it came from (shared, so an edited block is
a different pointer) and the styles/numbering hash, and rebuilds it only
when either changed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* vi: STYLEREF field strings
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>