Commit f229576
feat(math): implement m:box and m:borderBox converters (#2750)
* feat(math): implement m:box and m:borderBox converters (closes #2605)
Made-with: Cursor
* fix(math): parse full ST_OnOff values in borderBox converter
Made-with: Cursor
* fix(math): fall back to mrow when borderBox hides all sides with no strikes
Made-with: Cursor
* fix(math): address review findings for m:box/m:borderBox
- isOn now checks m:val === undefined instead of !el.attributes so
elements with namespace-only attributes are still treated as on,
matching the ST_OnOff default per §22.9.2.7.
- convertBorderBox returns null for empty m:e, consistent with
convertBox and convertFunction (no empty <menclose> wrappers).
- m:box JSDoc now reflects that boxPr semantics (opEmu, noBreak,
aln, diff, argSz) are silently dropped — not "purely a grouping
mechanism".
- Registry comment drift fixed: m:box and m:borderBox moved into
the Implemented block.
- Tests: strike direction mapping (BLTR→up, TLBR→down, V), full
ST_OnOff matrix (1/true/on/bare/0/false), tightened assertions to
exact-string equality, pinned the current boxPr-drop behavior.
* feat(math): polyfill MathML <menclose> via CSS
MathML Core (Chrome 109+, 2023) dropped <menclose> — no browser paints
it natively. Without this, m:borderBox content imports correctly but
renders invisibly. Ship a small CSS polyfill that maps every notation
token to borders or pseudo-element strike overlays:
- box / top / bottom / left / right → CSS border sides
- horizontalstrike / verticalstrike → ::after gradient layer (H or V)
- updiagonalstrike / downdiagonalstrike → layered gradients via CSS
custom properties so X patterns stack correctly
Wired through the existing ensure*Styles pattern in renderer.ts. Zero
bundle cost, no runtime polling, fully semantic (the DOM still says
<menclose notation="box">).
* fix(math): correct diagonal strike directions in menclose polyfill
CSS linear-gradient direction keywords confusingly produce stripes
perpendicular to the direction vector:
- "to top right" progresses toward the top-right corner, which makes
the visible color stripe run top-left to bottom-right ("\")
- "to bottom right" progresses toward the bottom-right corner, which
makes the stripe run bottom-left to top-right ("/")
The polyfill had them swapped, so updiagonalstrike rendered as "\"
and downdiagonalstrike as "/" — the opposite of what Word shows and
what MathML 3 specifies. Swap the direction keywords and add a
comment so the next reader doesn't re-flip them.
* fix(math): wrap borderBox content in <mrow> for horizontal row layout
MathML Core does not define <menclose>, so Chrome treats it as an
unknown element and does not run the row-layout algorithm on its
children. Each child rendered with display: block math and stacked
vertically — a multi-element expression inside a borderBox (e.g.
Annex L.6.1.3's a² = b² + c²) became a column of letters.
Wrap the content in an inner <mrow> before appending to <menclose>.
<mrow> is in MathML Core, so the row layout runs on its children and
everything stays inline. The outer <menclose> remains the polyfill
target for borders and strikes.
* test(behavior): cover m:borderBox + menclose polyfill end-to-end
Loads the 30-scenario fixture (sd-2750-borderbox.docx) and asserts:
- every scenario produces the expected notation attribute in DOM order
- multi-child content (Annex L.6.1.3: a² = b² + c²) renders as a
horizontal row — width > 1.5× height, inner <mrow> present, 5 children
- ST_OnOff variants (1/true/on/bare/0/false) resolve correctly through
the full import path, not just the unit converter
- m:box silently drops boxPr (opEmu/noBreak/aln/diff) and emits <mrow>
- the menclose CSS polyfill stylesheet is injected into the document
Runs across chromium/firefox/webkit. Complements the 53 unit tests by
exercising the cross-package path: OMML import → pm-adapter →
painter-dom → rendered MathML.
---------
Co-authored-by: Caio Pizzol <caio@harbourshare.com>1 parent 9c05a6f commit f229576
8 files changed
Lines changed: 703 additions & 3 deletions
File tree
- packages/layout-engine/painters/dom/src
- features/math
- converters
- tests/behavior/tests/importing
- fixtures
Lines changed: 122 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
| 71 | + | |
| 72 | + | |
| 73 | + | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
| 83 | + | |
| 84 | + | |
| 85 | + | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
| 89 | + | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
| 101 | + | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
| 113 | + | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
| 119 | + | |
| 120 | + | |
| 121 | + | |
| 122 | + | |
Lines changed: 1 addition & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
24 | 24 | | |
25 | 25 | | |
26 | 26 | | |
| 27 | + | |
0 commit comments