Commit ed74cbb1 authored by Fred Chasen's avatar Fred Chasen

Add check for looping breakTokens

parent 50fb6cf2
Pipeline #503 passed with stage
in 3 minutes and 46 seconds
......@@ -30,16 +30,6 @@ const plugins = [
];
export default [
{
input: pkg.module,
output: {
name: 'Paged',
file: pkg.browser,
format: 'umd'
},
plugins: plugins
},
{
input: "./src/polyfill/polyfill.js",
output: {
......
......@@ -76,8 +76,7 @@
<section>
<p>Nam eros tellus, hendrerit ut rhoncus sed, aliquet et felis. Cras a ex malesuada, fringilla magna elementum, cursus purus. Etiam fringilla leo non diam congue tempor. Ut laoreet, est eget blandit congue, mauris magna cursus sapien, dictum tempus sapien diam et dolor. Vestibulum vel egestas velit. Pellentesque vel consectetur urna, eu consequat odio. Sed ac pretium magna, ut ultrices tortor.</p>
<p>Nam eros tellus, hendrerit ut rhoncus sed, aliquet et felis. Cras a ex malesuada, fringilla magna elementum, cursus purus. Etiam fringilla leo non diam congue tempor. Ut laoreet, est eget blandit congue, mauris magna cursus sapien, dictum tempus sapien diam et dolor. Vestibulum vel egestas velit. Pellentesque vel consectetur urna, eu consequat odio. Sed ac pretium magna, ut ultrices tortor.</p>
<h1>Cras ut augue condimentum, egestas nisi in, dictum erat. Nullam tincidunt tincidunt tempor. Sed in eleifend nibh, sit amet feugiat nisi. Cras at ante ut urna sagittis dictum ut nec elit. In feugiat euismod massa sagittis dictum. Nullam eu nisl eu elit laoreet tincidunt id sed ligula. Praesent vulputate faucibus nibh, ut ultrices nunc aliquam nec. Mauris et condimentum ligula. Vestibulum nec tortor quis urna dictum luctus. Cras quis suscipit metus. Ut dignissim ullamcorper aliquam. Donec condimentum eu tellus at interdum.</h1>
<p>Morbi a lacus eget augue sagittis euismod. Aliquam non leo quis dui bibendum viverra eu vel erat. Fusce iaculis vulputate leo, sit amet laoreet eros aliquam a. Sed id tellus at ligula porttitor pharetra. Morbi non fringilla augue. Cras sodales egestas mi, et porta orci ultricies sed. Sed et nulla a ligula aliquet accumsan non eleifend quam. Aliquam pellentesque, justo vel interdum accumsan, purus ipsum porttitor lectus, ac luctus risus lectus nec lectus. Cras ut augue condimentum, egestas nisi in, dictum erat. Nullam tincidunt tincidunt tempor. Sed in eleifend nibh, sit amet feugiat nisi. Cras at ante ut urna sagittis dictum ut nec elit. In feugiat euismod massa sagittis dictum. Nullam eu nisl eu elit laoreet tincidunt id sed ligula. Praesent vulputate faucibus nibh, ut ultrices nunc aliquam nec. Mauris et condimentum ligula. Vestibulum nec tortor quis urna dictum luctus. Cras quis suscipit metus. Ut dignissim ullamcorper aliquam. Donec condimentum eu tellus at interdum.</p>
<p>Pellentesque pulvinar, justo eget tincidunt semper, augue massa placerat enim, non tempus quam erat eu orci. Suspendisse auctor consectetur lectus, a mattis odio. Pellentesque id sem sit amet justo fringilla bibendum id sit amet quam. Vivamus ex est, ultrices non pharetra eu, facilisis nec quam. Etiam molestie sed orci sed suscipit. Donec ipsum est, venenatis ut nisl ut, viverra auctor diam. Cras vestibulum lacus vel nunc dapibus aliquam. Aliquam accumsan lorem rhoncus tortor rhoncus, ut euismod sapien ullamcorper. Vivamus et dictum lacus, eu pellentesque dolor. Suspendisse potenti. Mauris vitae volutpat odio. Duis vitae purus nec enim posuere efficitur at vitae nisl. Etiam enim nisl, rutrum in vestibulum nec, dapibus ut dui. Pellentesque imperdiet molestie ante quis feugiat. Sed nec felis congue, cursus ligula eget, bibendum est. Proin mattis, tortor non lobortis lobortis, nibh quam aliquam neque, sed tristique nibh ex aliquet felis. Phasellus non augue ac ante efficitur consectetur at at est. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam dui enim, iaculis et felis ac, porta ullamcorper justo. Suspendisse potenti.</p>
......
const TIMEOUT = 10000; // Some book might take longer than this to renderer
describe.skip("infinite-loop", () => {
describe("infinite-loop", () => {
let page;
beforeAll(async () => {
page = await loadPage("infinite-loop/infinite-loop.html");
......@@ -13,15 +13,13 @@ describe.skip("infinite-loop", () => {
}
});
// TODO: the following test will produce an infinite loop (the element cannot fit on a page)
// this issue can be reproduced on v0.1.40
it.skip("should render 1 page", async () => {
it("should render 1 page", async () => {
let pages = await page.$$eval(".pagedjs_page", (r) => r.length);
expect(pages).toBe(1);
});
if (!DEBUG) {
it.skip("should create a pdf", async () => {
it("should create a pdf", async () => {
let pdf = await page.pdf(PDF_SETTINGS);
expect(pdf).toMatchPDFSnapshot(1);
});
......
/**
* Layout
* @class
*/
class BreakToken {
constructor(node, offset) {
this.node = node;
this.offset = offset;
}
equals(otherBreakToken) {
if (!otherBreakToken) {
return false;
}
if (this["node"] && otherBreakToken["node"] &&
this["node"] !== otherBreakToken["node"]) {
return false;
}
if (this["offset"] && otherBreakToken["offset"] &&
this["offset"] !== otherBreakToken["offset"]) {
return false;
}
return true;
}
}
export default BreakToken;
\ No newline at end of file
......@@ -14,13 +14,14 @@ import {
needsPageBreak,
needsPreviousBreakAfter,
nodeAfter,
nodeBefore, previousSignificantNode,
displayedElementBefore, previousSignificantNode,
prevValidNode,
rebuildAncestors,
validNode,
walk,
words
} from "../utils/dom";
import BreakToken from "./breaktoken";
import EventEmitter from "event-emitter";
import Hook from "../utils/hook";
......@@ -59,6 +60,7 @@ class Layout {
let walker = walk(start, source);
let node;
let prevNode;
let done;
let next;
......@@ -67,10 +69,11 @@ class Layout {
let length = 0;
let prevBreakToken = breakToken || { node: start, offset: 0 };
let prevBreakToken = breakToken || new BreakToken(start);
while (!done && !newBreakToken) {
next = walker.next();
prevNode = node;
node = next.value;
done = next.done;
......@@ -84,7 +87,8 @@ class Layout {
newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken);
if(this.equalTokens(newBreakToken, prevBreakToken)) {
if (newBreakToken && newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", prevNode);
return undefined;
}
return newBreakToken;
......@@ -103,14 +107,15 @@ class Layout {
newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken);
if(this.equalTokens(newBreakToken, prevBreakToken)) {
return undefined;
}
if (!newBreakToken) {
newBreakToken = this.breakAt(node);
}
if (newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", node);
return undefined;
}
length = 0;
break;
......@@ -145,7 +150,8 @@ class Layout {
newBreakToken = this.findBreakToken(wrapper, source, bounds, prevBreakToken);
if(this.equalTokens(newBreakToken, prevBreakToken)) {
if (newBreakToken && newBreakToken.equals(prevBreakToken)) {
console.warn("Unable to layout item: ", node);
return undefined;
}
......@@ -160,10 +166,10 @@ class Layout {
}
breakAt(node, offset = 0) {
return {
return new BreakToken(
node,
offset
};
);
}
shouldBreak(node) {
......@@ -326,8 +332,14 @@ class Layout {
parent = findElement(renderedNode, source);
index = indexOfTextNode(temp, parent);
node = child(parent, index);
offset = 0;
// No seperatation for the first textNode of an element
if(index === 0) {
node = parent;
offset = 0;
} else {
node = child(parent, index);
offset = 0;
}
}
} else {
renderedNode = findElement(container.parentNode, rendered);
......@@ -352,10 +364,10 @@ class Layout {
return;
}
return {
return new BreakToken(
node,
offset
};
);
}
......@@ -372,7 +384,6 @@ class Layout {
if (overflow) {
breakToken = this.createBreakToken(overflow, rendered, source);
// breakToken is nullable
let breakHooks = this.hooks.onBreakToken.triggerSync(breakToken, overflow, rendered, this);
breakHooks.forEach((newToken) => {
......@@ -382,7 +393,7 @@ class Layout {
});
// Stop removal if we are in a loop
if (this.equalTokens(breakToken, prevBreakToken)) {
if (breakToken.equals(prevBreakToken)) {
return breakToken;
}
......@@ -441,25 +452,25 @@ class Layout {
isFloat = styles.getPropertyValue("float") !== "none";
skip = styles.getPropertyValue("break-inside") === "avoid";
breakAvoid = node.dataset.breakBefore === "avoid" || node.dataset.previousBreakAfter === "avoid";
prev = breakAvoid && nodeBefore(node, rendered);
prev = breakAvoid && displayedElementBefore(node, rendered);
br = node.tagName === "BR" || node.tagName === "WBR";
}
if (prev) {
range = document.createRange();
range.setStartBefore(prev);
range.selectNode(prev);
break;
}
if (!br && !isFloat && isElement(node)) {
range = document.createRange();
range.setStartBefore(node);
range.selectNode(node);
break;
}
if (isText(node) && node.textContent.trim().length) {
range = document.createRange();
range.setStartBefore(node);
range.selectNode(node);
break;
}
......
import Handler from "../handler";
import csstree from "css-tree";
import { displayedElementAfter } from "../../utils/dom";
import { displayedElementAfter, displayedElementBefore } from "../../utils/dom";
class Breaks extends Handler {
constructor(chunker, polisher, caller) {
......@@ -90,6 +90,14 @@ class Breaks extends Handler {
if (nodeAfter) {
nodeAfter.setAttribute("data-previous-break-after", prop.value);
}
} else if (prop.property === "break-before") {
let nodeBefore = displayedElementBefore(elements[i], parsed);
elements[i].setAttribute("data-break-before", prop.value);
if (nodeBefore) {
nodeBefore.setAttribute("data-next-break-before", prop.value);
}
} else if (prop.property === "page") {
elements[i].setAttribute("data-page", prop.value);
......
......@@ -81,27 +81,27 @@ export function nodeBefore(node, limiter) {
}
export function elementAfter(node, limiter) {
let after = nodeAfter(node);
let after = nodeAfter(node, limiter);
while (after && after.nodeType !== 1) {
after = nodeAfter(after);
after = nodeAfter(after, limiter);
}
return after;
}
export function elementBefore(node, limiter) {
let before = nodeAfter(node);
let before = nodeBefore(node, limiter);
while (before && before.nodeType !== 1) {
before = nodeAfter(before);
before = nodeBefore(before, limiter);
}
return before;
}
export function displayedElementAfter(node, limiter) {
let after = elementAfter(node);
let after = elementAfter(node, limiter);
while (after && after.dataset.undisplayed) {
after = elementAfter(after);
......@@ -110,6 +110,16 @@ export function displayedElementAfter(node, limiter) {
return after;
}
export function displayedElementBefore(node, limiter) {
let before = elementBefore(node, limiter);
while (before && before.dataset.undisplayed) {
before = elementBefore(before);
}
return before;
}
export function stackChildren(currentNode, stacked) {
let stack = stacked || [];
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment