Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions packages/layout-engine/contracts/src/column-layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export function cloneColumnLayout(columns?: ColumnLayout): ColumnLayout {
gap: columns.gap,
...(Array.isArray(columns.widths) ? { widths: [...columns.widths] } : {}),
...(columns.equalWidth !== undefined ? { equalWidth: columns.equalWidth } : {}),
...(columns.lineBetween !== undefined ? { lineBetween: columns.lineBetween } : {}),
}
: { count: 1, gap: 0 };
}
Expand Down Expand Up @@ -70,6 +71,7 @@ export function normalizeColumnLayout(
gap,
...(widths.length > 0 ? { widths } : {}),
...(input?.equalWidth !== undefined ? { equalWidth: input.equalWidth } : {}),
...(input?.lineBetween !== undefined ? { lineBetween: input.lineBetween } : {}),
width,
};
}
7 changes: 7 additions & 0 deletions packages/layout-engine/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -990,6 +990,7 @@ export type SectionBreakBlock = {
gap: number;
widths?: number[];
equalWidth?: boolean;
lineBetween?: boolean;
};
/**
* Vertical alignment of content within the section's pages.
Expand Down Expand Up @@ -1478,6 +1479,7 @@ export type ColumnLayout = {
gap: number;
widths?: number[];
equalWidth?: boolean;
lineBetween?: boolean;
};

/** A measured line within a block, output by the measurer. */
Expand Down Expand Up @@ -1698,6 +1700,11 @@ export type Page = {
* where headers/footers don't affect vertical alignment.
*/
baseMargins?: { top: number; bottom: number };
/**
* Column layout for this page, if multi-column.
* Carried from the active section so the painter can render column separator lines.
*/
columns?: ColumnLayout;
/**
* Index of the section this page belongs to.
* Used for section-aware page numbering and header/footer selection.
Expand Down
4 changes: 4 additions & 0 deletions packages/layout-engine/layout-engine/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1071,6 +1071,10 @@ export function layoutDocument(blocks: FlowBlock[], measures: Measure[], options
bottom: activeSectionBaseBottomMargin,
};
}
// Carry column layout to the page for the painter (e.g. inter-column separator lines)
if (activeColumns && activeColumns.count > 1) {
page.columns = activeColumns;
Comment on lines +1075 to +1076
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve lineBetween when attaching columns to page

page.columns = activeColumns assumes the new lineBetween flag survives section-state cloning, but cloneColumnLayout currently drops that field (packages/layout-engine/contracts/src/column-layout.ts, function cloneColumnLayout). As a result, page.columns.lineBetween is typically undefined even when <w:cols w:sep="1"> is parsed, so the separator rendering path never activates. Please propagate lineBetween through the column clone/state pipeline before assigning it to the page.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch — fixed in 42aea30. Both cloneColumnLayout and normalizeColumnLayout now propagate the field, so page.columns.lineBetween survives the section-state pipeline.

}
return page;
};

Expand Down
53 changes: 53 additions & 0 deletions packages/layout-engine/painters/dom/src/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2227,9 +2227,61 @@
);
});
this.renderDecorationsForPage(el, page, pageIndex);
this.renderColumnSeparators(el, page, width, height);

return el;
}

/**
* Append vertical separator lines between columns when the page's column
* layout has `lineBetween` enabled (OOXML `<w:cols w:sep="1">`).
*
* Shared by `renderPage` (book/horizontal flow) and `createPageState`
* (vertical/virtualized flow) so the feature shows up in both paths.
*
* Safe to call unconditionally: it no-ops when the flag is off, when there
* are fewer than 2 columns, or when margins/document are missing.
*/
private renderColumnSeparators(el: HTMLElement, page: Page, width: number, height: number): void {
if (!page.columns?.lineBetween || page.columns.count <= 1 || !page.margins || !this.doc) {
return;
}
const cols = page.columns;
const margins = page.margins;
const pageHeight = page.size?.h ?? height;
const contentTop = margins.top;
const contentBottom = pageHeight - margins.bottom;
const lineHeight = contentBottom - contentTop;

if (lineHeight <= 0) return;

Check failure on line 2256 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'margins.bottom' is possibly 'undefined'.

Check failure on line 2256 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'margins.bottom' is possibly 'undefined'.

Check failure on line 2256 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'margins.bottom' is possibly 'undefined'.

Check failure on line 2256 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'margins.bottom' is possibly 'undefined'.

Check failure on line 2257 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'contentTop' is possibly 'undefined'.

Check failure on line 2257 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'contentTop' is possibly 'undefined'.

Check failure on line 2257 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'contentTop' is possibly 'undefined'.

Check failure on line 2257 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'contentTop' is possibly 'undefined'.
const colWidths = Array.isArray(cols.widths) && cols.widths.length > 0 ? cols.widths : null;
for (let c = 0; c < cols.count - 1; c++) {
let lineX: number;
if (colWidths) {
let x = margins.left;
for (let j = 0; j <= c; j++) {
x += colWidths[j] ?? 0;
if (j < c) x += cols.gap;
}
lineX = x + cols.gap / 2;

Check failure on line 2267 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'x' is possibly 'undefined'.

Check failure on line 2267 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'x' is possibly 'undefined'.

Check failure on line 2267 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'x' is possibly 'undefined'.

Check failure on line 2267 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'x' is possibly 'undefined'.
} else {

Check failure on line 2268 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'x' is possibly 'undefined'.

Check failure on line 2268 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'x' is possibly 'undefined'.

Check failure on line 2268 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'x' is possibly 'undefined'.

Check failure on line 2268 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'x' is possibly 'undefined'.
const colWidth = (width - margins.left - margins.right - (cols.count - 1) * cols.gap) / cols.count;
lineX = margins.left + (c + 1) * colWidth + (c + 0.5) * cols.gap;

Check failure on line 2270 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'x' is possibly 'undefined'.

Check failure on line 2270 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'x' is possibly 'undefined'.

Check failure on line 2270 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'x' is possibly 'undefined'.

Check failure on line 2270 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'x' is possibly 'undefined'.
}

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'margins.right' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'margins.left' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'margins.right' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'margins.left' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'margins.right' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'margins.left' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'margins.right' is possibly 'undefined'.

Check failure on line 2272 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'margins.left' is possibly 'undefined'.
const line = this.doc.createElement('div');

Check failure on line 2273 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (2)

'margins.left' is possibly 'undefined'.

Check failure on line 2273 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (1)

'margins.left' is possibly 'undefined'.

Check failure on line 2273 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / test (3)

'margins.left' is possibly 'undefined'.

Check failure on line 2273 in packages/layout-engine/painters/dom/src/renderer.ts

View workflow job for this annotation

GitHub Actions / build

'margins.left' is possibly 'undefined'.
line.style.position = 'absolute';
line.style.left = `${lineX}px`;
line.style.top = `${contentTop}px`;
line.style.width = '0px';
line.style.height = `${lineHeight}px`;
line.style.borderLeft = '1px solid #000';
line.style.pointerEvents = 'none';
el.appendChild(line);
}
}

/**
* Render a ruler element for a page.
*
Expand Down Expand Up @@ -2811,6 +2863,7 @@
});

this.renderDecorationsForPage(el, page, pageIndex);
this.renderColumnSeparators(el, page, pageSize.w, pageSize.h);
return { element: el, fragments: fragmentStates };
}

Expand Down
8 changes: 7 additions & 1 deletion packages/layout-engine/pm-adapter/src/sections/extraction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ function extractPageNumbering(elements: SectionElement[]):
*/
function extractColumns(
elements: SectionElement[],
): { count: number; gap: number; widths?: number[]; equalWidth?: boolean } | undefined {
): { count: number; gap: number; widths?: number[]; equalWidth?: boolean; lineBetween?: boolean } | undefined {
const cols = elements.find((el) => el?.name === 'w:cols');
if (!cols?.attributes) return undefined;

Expand All @@ -233,11 +233,17 @@ function extractColumns(
.filter((widthTwips) => Number.isFinite(widthTwips) && widthTwips > 0)
.map((widthTwips) => (widthTwips / 1440) * PX_PER_INCH);

const sepAttr = cols.attributes['w:sep'];
const hasSepChild = Array.isArray(cols.elements) && cols.elements.some((child) => child?.name === 'w:sep');
const lineBetween =
sepAttr === '1' || sepAttr === 1 || sepAttr === true || sepAttr === 'true' || hasSepChild ? true : undefined;

const result = {
count,
gap: gapInches * PX_PER_INCH,
...(widths.length > 0 ? { widths } : {}),
...(equalWidth !== undefined ? { equalWidth } : {}),
...(lineBetween !== undefined ? { lineBetween } : {}),
};

return result;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,17 @@ export function getSectPrColumns(sectPr) {
result.gap = twipsToInches(a['w:space']);
}

// w:sep = line between columns (attribute on w:cols)
if (a['w:sep'] === '1' || a['w:sep'] === 'true') {
result.lineBetween = true;
}

// Also check for w:sep child element (alternative OOXML form)
const sepChild = cols.elements?.find((el) => el?.name === 'w:sep');
if (sepChild) {
result.lineBetween = true;
}

return Object.keys(result).length > 0 ? result : undefined;
}

Expand Down
Loading