Commit 70a2dbe
fix: correct spacing for paragraphs with borders/shades (#2586)
* fix: correct spacing for paragraphs with borders/shades
* fix(layout): overlap border expansion with paragraph spacing (SD-2106)
Per ECMA-376 §17.3.1.42, paragraph border space is measured from
the text edge "ignoring any spacing above/below". This means border
expansion should overlap with spacingBefore/After, not stack on top.
- Reduce top border expansion by the amount spacingBefore already covers
- Reduce effective spacingAfter by the bottom border expansion
- Subtract border expansion from sliceLines available height to prevent
page-bottom overflow
- Include border expansion in keepLines height calculation
* fix(layout): correct cursorY mismatch and continuation fragment overlap
Three fixes from self-review:
- fragment.y now uses extraTop (overlap-adjusted) instead of full
borderExpansion.top, so cursorY reaches the visual bottom exactly
- Track spacingAppliedThisFragment to avoid under-counting border
expansion on continuation fragments after page breaks
- keepLines fitsOnBlankPage uses overlap model (max instead of add)
to avoid unnecessary page breaks for bordered paragraphs
* fix(layout): hoist borderExpansion to function scope
borderExpansion was declared inside the while loop but referenced
in the spacingAfter block outside it, causing a ReferenceError.
Move it before the loop so it's accessible in both places.
* fix(layout,renderer): between-border group detection and spacing
Layout engine:
- Detect between-border groups by comparing adjacent paragraph border
hashes. When borders match, suppress top expansion and reclaim
previous paragraph's bottom expansion.
- Border expansion is additive with spacing for non-grouped paragraphs
(matches Word behavior).
- Add lastParagraphBorderHash to PageState for group tracking.
Renderer (group-analysis.ts):
- Remove requirement for `between` border element to be present for
grouping. Per ECMA-376 §17.3.1.5, grouping occurs when all border
properties are identical — a between border is optional.
- When no between border is defined, suppress bottom/top borders
and render as a single continuous box.
* test(painter-dom): update between-border test for grouping without between element
The test expected no grouping when `between` border is absent. Updated
to expect grouping with suppressBottomBorder per ECMA-376 §17.3.1.5:
identical borders form a group regardless of whether a between border
is defined.
* fix(layout): use local PX_PER_PT constant instead of pm-adapter import
layout-engine cannot import from pm-adapter (boundary removed in #2618).
Define PX_PER_PT locally, same as border-layer.ts does.
---------
Co-authored-by: Johannes Wilm <mail@johanneswilm.org>1 parent 357e593 commit 70a2dbe
4 files changed
Lines changed: 96 additions & 15 deletions
File tree
- packages/layout-engine
- layout-engine/src
- painters/dom/src
- features/paragraph-borders
Lines changed: 73 additions & 6 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
12 | 12 | | |
13 | 13 | | |
14 | 14 | | |
| 15 | + | |
15 | 16 | | |
16 | 17 | | |
17 | 18 | | |
| |||
24 | 25 | | |
25 | 26 | | |
26 | 27 | | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
27 | 31 | | |
28 | 32 | | |
29 | 33 | | |
| |||
89 | 93 | | |
90 | 94 | | |
91 | 95 | | |
| 96 | + | |
| 97 | + | |
92 | 98 | | |
93 | 99 | | |
94 | 100 | | |
| |||
162 | 168 | | |
163 | 169 | | |
164 | 170 | | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
| 188 | + | |
| 189 | + | |
| 190 | + | |
| 191 | + | |
| 192 | + | |
| 193 | + | |
| 194 | + | |
| 195 | + | |
| 196 | + | |
| 197 | + | |
| 198 | + | |
| 199 | + | |
| 200 | + | |
| 201 | + | |
| 202 | + | |
| 203 | + | |
165 | 204 | | |
166 | 205 | | |
167 | 206 | | |
| |||
589 | 628 | | |
590 | 629 | | |
591 | 630 | | |
| 631 | + | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
| 642 | + | |
| 643 | + | |
| 644 | + | |
| 645 | + | |
592 | 646 | | |
593 | 647 | | |
594 | 648 | | |
595 | 649 | | |
596 | 650 | | |
| 651 | + | |
| 652 | + | |
| 653 | + | |
| 654 | + | |
| 655 | + | |
| 656 | + | |
| 657 | + | |
597 | 658 | | |
598 | 659 | | |
599 | 660 | | |
| |||
635 | 696 | | |
636 | 697 | | |
637 | 698 | | |
| 699 | + | |
638 | 700 | | |
639 | 701 | | |
640 | 702 | | |
641 | 703 | | |
642 | 704 | | |
643 | | - | |
| 705 | + | |
| 706 | + | |
644 | 707 | | |
645 | 708 | | |
646 | 709 | | |
| |||
774 | 837 | | |
775 | 838 | | |
776 | 839 | | |
777 | | - | |
| 840 | + | |
| 841 | + | |
| 842 | + | |
| 843 | + | |
| 844 | + | |
778 | 845 | | |
779 | 846 | | |
780 | 847 | | |
| |||
785 | 852 | | |
786 | 853 | | |
787 | 854 | | |
788 | | - | |
789 | 855 | | |
790 | 856 | | |
791 | 857 | | |
792 | 858 | | |
793 | 859 | | |
794 | 860 | | |
795 | | - | |
| 861 | + | |
796 | 862 | | |
797 | 863 | | |
798 | 864 | | |
| |||
838 | 904 | | |
839 | 905 | | |
840 | 906 | | |
841 | | - | |
842 | 907 | | |
843 | | - | |
| 908 | + | |
| 909 | + | |
844 | 910 | | |
845 | 911 | | |
846 | 912 | | |
| |||
879 | 945 | | |
880 | 946 | | |
881 | 947 | | |
| 948 | + | |
882 | 949 | | |
883 | 950 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
18 | 18 | | |
19 | 19 | | |
20 | 20 | | |
| 21 | + | |
| 22 | + | |
21 | 23 | | |
22 | 24 | | |
23 | 25 | | |
| |||
Lines changed: 10 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
469 | 469 | | |
470 | 470 | | |
471 | 471 | | |
472 | | - | |
| 472 | + | |
| 473 | + | |
| 474 | + | |
473 | 475 | | |
474 | 476 | | |
475 | 477 | | |
476 | 478 | | |
477 | 479 | | |
478 | 480 | | |
479 | | - | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
480 | 488 | | |
481 | 489 | | |
482 | 490 | | |
| |||
Lines changed: 11 additions & 7 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
108 | 108 | | |
109 | 109 | | |
110 | 110 | | |
111 | | - | |
| 111 | + | |
112 | 112 | | |
113 | 113 | | |
| 114 | + | |
| 115 | + | |
| 116 | + | |
| 117 | + | |
114 | 118 | | |
115 | 119 | | |
116 | 120 | | |
| |||
134 | 138 | | |
135 | 139 | | |
136 | 140 | | |
137 | | - | |
138 | | - | |
139 | | - | |
| 141 | + | |
140 | 142 | | |
141 | 143 | | |
142 | 144 | | |
| |||
151 | 153 | | |
152 | 154 | | |
153 | 155 | | |
154 | | - | |
155 | | - | |
| 156 | + | |
| 157 | + | |
156 | 158 | | |
157 | 159 | | |
158 | 160 | | |
159 | 161 | | |
160 | 162 | | |
161 | 163 | | |
162 | | - | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
163 | 167 | | |
164 | 168 | | |
165 | 169 | | |
| |||
0 commit comments