Old releases of heavy faces (the core-fonts Arial Black) claim weight 400 in
OS/2, so bold text in them was drawn with synthetic bold. Current releases say
900 and Word draws bold Arial Black unchanged. A static face whose file says less
than semibold now takes the weight its family's last word names: Black/Heavy 900,
ExtraBold/UltraBold 800. Files that already declare a heavy weight keep it.
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* WIP for #1609
* Equations: a script after _ or ^ is the whole run of letters and digits (#1609)
Word for Mac 16.113.4: V_dd and V_(dd) build up the same (dd is all
subscript), likewise x^ab, and Linear format shows V_dd bare.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Equations: bare scripts end at a space, digits continue a script run, upright function names (#1609)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Equations: a bare script also ends before a following period (#1609 review)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
* ROADMAP: drop three progress rows main already has
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 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* odt-sect-export: WIP
* Gap 19: ODT export writes sections
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Gap 19: ODT export writes sections — review fixes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ODT export: a list cut by a section continues with text:continue-list; drop duplicate parity rows
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 <noreply@anthropic.com>
* Spike: Ctrl+F3 collects cuts, Ctrl+Shift+F3 inserts them and empties it (gap #24)
* Search test: a lone INSERT's witness within the box's 14 results; Table checked past it
---------
Co-authored-by: Brandon Thomas <echelon@gmail.com>
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>
* Field results (STYLEREF, REF, PAGE text, note marks) shown as one atomic
cluster now place their inner clusters in UAX #9 visual order, in the
direction of the text around the field, so "פרק א" in a header no longer
draws reversed. Smart quotes already matched Word's logical-order result
in Hebrew (” in acronyms, not gershayim); pinned with a typing test.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1670: fix round 1: field results shaped per bidi run, so brackets mirror correctly
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>
* 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>
* WIP for #1480
* Web: an input method's DeleteSurrounding erases around the caret, so non-Latin typing no longer repeats (#1480)
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
* Web: input-method rewrites keep formatting and the typing undo group; AutoCorrect resets the web text field (#1480)
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>
* #1706: WIP
* #1706: Update Fields refreshes fields in headers, footers and text boxes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
# Conflicts:
# ROADMAP.md
# Conflicts:
# ROADMAP.md
* #1706: review fixes
Revision-history row, update_fields doc comment, test covers body field and locked header field.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1706: update the fields of the part being edited, as in Word
Word check: F9 with the caret in the body leaves header fields alone; with the caret in a header it updates that header. SEQ, citations and TOC run only from the body.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1706: printing updates every field in the document
references.updateFields takes {"all"?: bool}: the body (with SEQ, citations, TOC) plus every part story, wherever the caret is. Printing passes it.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1706: ROADMAP status line after rebase
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1706: tests build the field form value added on main
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* #1706: the test's fields take main's new dirty flag
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 <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>
* ink-arrows-2: WIP
* ink-arrows-2: Ink to Shape makes two-stroke arrows and closed-triangle heads
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* ink-arrows-2: review fixes — recognise each stroke once, drawing-order pairing, arrow rect
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 <noreply@anthropic.com>
Dialogs, the Read Aloud player and the file browser used egui's small close glyph: the hit area was the glyph alone and hovering only changed its stroke. The close control is now a box at the right end of the title bar, the full title-bar height and 1.6 times as wide, as a Windows caption button on a Word dialog. The whole box closes the window. It fills red with a white cross while the pointer is over it and darker red while pressed and still under the pointer, with colours from the theme tokens in both themes. The box is pointer-only, so Tab never lands on it; dragging from it does not move the window and Escape closes dialogs as before. Its accessibility name is translated like its tooltip.
docs/parity-checklist.md is the regenerated checklist.
Co-authored-by: Brandon Thomas <echelon@gmail.com>
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>
The web shell never loaded or saved the UiState the desktop app keeps in
ui.json, so a reload reset the theme and every other preference. It now
restores it from localStorage at startup and writes it back whenever it
changes (a reload runs no exit code).
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
The font box (ribbon and mini toolbar) opens with a Recently Used Fonts
section: the fonts applied from the box, the mini toolbar or the Font
dialog, most recent first, once each, ten at most, kept in ui.json. All
Fonts follows. The sections show while nothing is typed; a query lists
its matches only. Up/Down walk the recent entries then the list and Enter
applies the highlighted one; a click on a heading keeps the list open.
The typed list is sized again when its length changes, in a discarded
pass so it never blanks; it used to stay one row tall after a one-match
query. Names over 128 bytes are not kept, and reading a saved list stops
at ten names.
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>
With text selected, Layout > Columns used to change the whole section. As in
Word (observed black-box), a continuous section break now goes where the
selection starts and one where it ends, splitting a paragraph there, unless that
end already meets a section boundary (the document's start or end, or an
existing break); the columns go on the section between, in one undo step.
`layout.columns` gains `apply: "selection"`, its default when text is selected
in the main text. More Columns... offers "Selected text" and picks it then.
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>
With Different First Page on, page 1 shows the first-page header, but
Insert > Header/Footer/Page Number always wrote the default one (which
page 1 no longer shows), Edit Header without a page went to the default
too, and a double-click in page 1's header area was ignored while
another header was being edited (the usual case: edit the header, tick
Different First Page, double-click page 1). Now hf_part and edit_hf use
the slot of the caret's page, and a double-click in a header/footer
zone switches to the one that page shows even from another header.
Fixes#2826Fixes#2811
Claude-Session: https://claude.ai/code/session_013kKPnx8r1vcYumjyL3kcuz
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
LibreOffice puts a paragraph indented on both sides on the clipboard as
<blockquote>, its margins in the page's stylesheet. Paste mapped it to the
centred, italic Quote style. On paste only, it now becomes a Normal
paragraph indented by the blockquote's stylesheet margins (else 0.5 in each
side). Opening .html files still maps blockquote to Quote.
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>
A copy or cut of one equation on its own now also puts its MathML in the
platform's MathML clipboard formats, beside the HTML (with MathML, #816) and
the linear text: "MathML" and "MathML Presentation" (UTF-16LE) on Windows,
public.mathml.presentation and public.mathml on macOS. These are the names
W3C MathML 3 section 6.2.4 registers, and Microsoft's "MathML Support in
Microsoft 365" doc says Office checks them first when it pastes math. No
public clipboard format carries OMML. A copy with text around the equation
doesn't offer them, so Word keeps the text.
Not yet verified in Word: the parity docs say MathML clipboard formats, not
an editable paste.
Claude-Session: https://claude.ai/code/session_01P8veLveuUsJJm6UEcQPEuW
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Tab already follows reading order (next logical cell) and right-to-left
tables (w:bidiVisual) already lay the first cell out at the right. The
bug was that insert.table ignored the caret paragraph's direction, so a
table made while writing RTL text was a left-to-right table and Tab went
rightwards. Like Word, insert.table now makes a right-to-left table when
the caret's paragraph reads right to left.
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
Indonesian spelling reads the installed Hunspell id_ID dictionary at runtime
(Debian/Ubuntu hunspell-id, LibreOffice dict-id, the Dictionaries folder or
WORDCRAFT_DICTIONARIES), like Czech, Polish and Portuguese: nothing is bundled,
and without a dictionary Indonesian text gets no spelling marks.
- ProofLang::Id for id, id-ID, ind and the legacy in tag
- suggestions reuse the dictionary-driven Czech ranking (MAP/REP/TRY/KEY of
the loaded dictionary), nothing Indonesian hard-coded
- hyphenated reduplication accepted whole or by parts (kupu-kupu, anak-anak);
hyphenated clitics after capitals/abbreviations (KTP-nya, se-Indonesia)
- generic grammar only: repeated word (offers anak-anak first), space before
punctuation, double space, with Indonesian messages
- Review > Language, status bar, Set Proofing Language, File > Options >
Proofing list Indonesian; name translated in every catalog
- tests use a hand-written synthetic dictionary; engine end-to-end test
Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>
* fix(ui): draw Arabic and other non-Latin comment text in balloons
Comment balloons and the Comments pane draw comment text and author
names with the interface faces (Inter, Source Sans, CJK), which have no
Arabic, Hebrew, Thai and so on: every such letter was a box. The app now
borrows a document fallback face that covers the comments, as the window
caption does (#840), checked once per document revision.
egui also lays bidi runs and words out left to right, so a right-to-left
comment read backwards. Read-only balloons now wrap the text by word
widths, put each row in display order (Unicode bidi runs, words of a
right-to-left run reversed, brackets mirrored) and set right-to-left
paragraphs against the right edge. Text without right-to-left letters is
laid out exactly as before. The editable fields (the selected balloon and
the Comments pane) keep logical order.
Also adds my contributor entry (sync_github_name).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* One contributor entry each
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Mohamed Youssef <ms.rightsteps@gmail.com>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: Brandon Thomas <echelon@gmail.com>