Skip to content

Commit

Permalink
backport PR #2781
Browse files Browse the repository at this point in the history
  • Loading branch information
liborm85 committed Sep 7, 2024
1 parent 84517a6 commit da5798e
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 22 deletions.
73 changes: 58 additions & 15 deletions src/layoutBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,15 +442,31 @@ LayoutBuilder.prototype.processNode = function (node) {
}

if (margin) {
self.writer.context().moveDown(margin[1]);
self.writer.context().addMargin(margin[0], margin[2]);
const availableHeight = self.writer.context().availableHeight;
// If top margin is bigger than available space, move to next page
// Necessary for nodes inside tables
if (availableHeight - margin[1] < 0) {
self.writer.context().moveDown(availableHeight);
self.writer.moveToNextPage(node.pageOrientation);
} else {
self.writer.context().moveDown(margin[1]);
self.writer.context().addMargin(margin[0], margin[2]);
}
}

callback();

if (margin) {
self.writer.context().addMargin(-margin[0], -margin[2]);
self.writer.context().moveDown(margin[3]);
const availableHeight = self.writer.context().availableHeight;
// If bottom margin is bigger than available space, move to next page
// Necessary for nodes inside tables
if (availableHeight - margin[3] < 0) {
self.writer.context().moveDown(availableHeight);
self.writer.moveToNextPage(node.pageOrientation);
} else {
self.writer.context().addMargin(-margin[0], -margin[2]);
self.writer.context().moveDown(margin[3]);
}
}

if (node.pageBreak === 'after') {
Expand Down Expand Up @@ -491,7 +507,11 @@ LayoutBuilder.prototype.processColumns = function (columnNode) {
}

ColumnCalculator.buildColumnWidths(columns, availableWidth);
var result = this.processRow(false, columns, columns, gaps);
var result = this.processRow({
cells: columns,
widths: columns,
gaps
});
addAll(columnNode.positions, result.positions);


Expand Down Expand Up @@ -526,17 +546,25 @@ LayoutBuilder.prototype.findStartingSpanCell = function (arr, i) {
return null;
}

LayoutBuilder.prototype.processRow = function (dontBreakRows, columns, widths, gaps, tableBody, tableRow, height) {
LayoutBuilder.prototype.processRow = function ({dontBreakRows = false, rowsWithoutPageBreak = 0, cells, widths, gaps, tableBody, rowIndex, height}) {
var self = this;
var pageBreaks = [], positions = [];
var isUnbreakableRow = dontBreakRows || rowIndex <= rowsWithoutPageBreak - 1;
var pageBreaks = []
var positions = [];
var willBreakByHeight = false;

this.tracker.auto('pageChanged', storePageBreakData, function () {
widths = widths || columns;
// Check if row should break by height
if (!isUnbreakableRow && height > self.writer.context().availableHeight) {
willBreakByHeight = true;
}

widths = widths || cells;

self.writer.context().beginColumnGroup();

for (var i = 0, l = columns.length; i < l; i++) {
var column = columns[i];
for (var i = 0, l = cells.length; i < l; i++) {
var column = cells[i];
var width = widths[i]._calcWidth;
var leftOffset = colLeftOffset(i);

Expand All @@ -555,7 +583,7 @@ LayoutBuilder.prototype.processRow = function (dontBreakRows, columns, widths, g
}

// Check if exists and retrieve the cell that started the rowspan in case we are in the cell just after
var startingSpanCell = self.findStartingSpanCell(columns, i);
var startingSpanCell = self.findStartingSpanCell(cells, i);
var endingSpanCell = null;
if (startingSpanCell && startingSpanCell._endingCell) {
// Reference to the last cell of the rowspan
Expand Down Expand Up @@ -594,15 +622,15 @@ LayoutBuilder.prototype.processRow = function (dontBreakRows, columns, widths, g

// Check if last cell is part of a span
var endingSpanCell = null;
var lastColumn = columns.length > 0 ? columns[columns.length - 1] : null;
var lastColumn = cells.length > 0 ? cells[cells.length - 1] : null;
if (lastColumn) {
// Previous column cell has a rowspan
if (lastColumn._endingCell) {
endingSpanCell = lastColumn._endingCell;
// Previous column cell is part of a span
} else if (lastColumn._span === true) {
// We get the cell that started the span where we set a reference to the ending cell
var startingSpanCell = self.findStartingSpanCell(columns, columns.length);
var startingSpanCell = self.findStartingSpanCell(cells, cells.length);
if (startingSpanCell) {
// Context will be stored here (ending cell)
endingSpanCell = startingSpanCell._endingCell;
Expand All @@ -618,6 +646,12 @@ LayoutBuilder.prototype.processRow = function (dontBreakRows, columns, widths, g
// If there are page breaks in this row, update data with prevY of last cell
updatePageBreakData(self.writer.context().page, self.writer.context().y);

// If content did not break page, check if we should break by height
if (!isUnbreakableRow && pageBreaks.length === 0 && willBreakByHeight) {
self.writer.context().moveDown(this.writer.context().availableHeight);
self.writer.moveToNextPage();
}

self.writer.context().completeColumnGroup(height, endingSpanCell);
});

Expand Down Expand Up @@ -667,7 +701,7 @@ LayoutBuilder.prototype.processRow = function (dontBreakRows, columns, widths, g

function getEndingCell(column, columnIndex) {
if (column.rowSpan && column.rowSpan > 1) {
var endingRow = tableRow + column.rowSpan - 1;
var endingRow = rowIndex + column.rowSpan - 1;
if (endingRow >= tableBody.length) {
throw 'Row span for column ' + columnIndex + ' (with indexes starting from 0) exceeded row count';
}
Expand Down Expand Up @@ -753,7 +787,16 @@ LayoutBuilder.prototype.processTable = function (tableNode) {
height = undefined;
}

var result = this.processRow(processor.dontBreakRows, tableNode.table.body[i], tableNode.table.widths, tableNode._offsets.offsets, tableNode.table.body, i, height);
var result = this.processRow({
dontBreakRows: processor.dontBreakRows,
rowsWithoutPageBreak: processor.rowsWithoutPageBreak,
cells: tableNode.table.body[i],
widths: tableNode.table.widths,
gaps: tableNode._offsets.offsets,
tableBody: tableNode.table.body,
rowIndex: i,
height
});
addAll(tableNode.positions, result.positions);

processor.endRow(i, this.writer, result.pageBreaks);
Expand Down
56 changes: 49 additions & 7 deletions tests/layoutBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -1684,15 +1684,27 @@ describe('LayoutBuilder', function () {
it('should return an empty array if no page breaks occur', function () {
var doc = createTable(1, 0);

var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 0);
});

it('on page break should return an entry with ending/starting positions', function () {
var doc = createTable(0, 1, 10, 5, 5);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 1);
Expand All @@ -1702,7 +1714,13 @@ describe('LayoutBuilder', function () {

it('on page break should return an entry with ending/starting positions 2', function () {
var doc = createTable(0, 1, 10, 5);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 1);
Expand All @@ -1712,14 +1730,26 @@ describe('LayoutBuilder', function () {

it('on multi-pass page break (columns or table columns) should treat bottom-most page-break as the ending position ', function () {
var doc = createTable(0, 1, 10, 5, 7);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert.equal(result.pageBreaks[0].prevY, 40 + 12 * 7);
});

it('on multiple page breaks (more than 2 pages), should return all entries with ending/starting positions', function () {
var doc = createTable(0, 1, 100, 90, 90);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 2);
Expand All @@ -1731,7 +1761,13 @@ describe('LayoutBuilder', function () {

it('on multiple page breaks (more than 2 pages), should return all entries with ending/starting positions 2', function () {
var doc = createTable(0, 1, 100, 90);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 2);
Expand All @@ -1743,7 +1779,13 @@ describe('LayoutBuilder', function () {

it('on multiple and multi-pass page breaks should calculate bottom-most endings for every page', function () {
var doc = createTable(0, 1, 100, 90, 92);
var result = builder2.processRow(false, doc.table.body[0], doc.table.widths, doc._offsets.offsets, doc.table.body, 0);
var result = builder2.processRow({
cells: doc.table.body[0],
widths: doc.table.widths,
gaps: doc._offsets.offsets,
tableBody: doc.table.body,
rowIndex: 0
});

assert(result.pageBreaks instanceof Array);
assert.equal(result.pageBreaks.length, 2);
Expand Down

0 comments on commit da5798e

Please sign in to comment.