diff --git a/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/InlineBoxing.java b/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/InlineBoxing.java index 1f398bfc5..bc7362925 100644 --- a/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/InlineBoxing.java +++ b/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/InlineBoxing.java @@ -45,6 +45,7 @@ import org.xhtmlrenderer.render.MarkerData; import org.xhtmlrenderer.render.StrutMetrics; import org.xhtmlrenderer.render.TextDecoration; +import org.xhtmlrenderer.util.XRRuntimeException; /** * This class is responsible for flowing inline content into lines. Block @@ -52,6 +53,9 @@ * here as well as floating and absolutely positioned content. */ public class InlineBoxing { + + private static final int MAX_ITERATION_COUNT = 100000; + private InlineBoxing() { } @@ -161,7 +165,12 @@ public static void layoutContent(LayoutContext c, BlockBox box, int initialY, in lbContext.setMaster(iB.getContentFunction().getLayoutReplacementText()); } + int q = 0; do { + if (q++ > MAX_ITERATION_COUNT) { + throw new XRRuntimeException("Too many iterations (" + q + ") in InlineBoxing, giving up."); + } + lbContext.reset(); int fit = 0; diff --git a/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/breaker/Breaker.java b/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/breaker/Breaker.java index cf7263713..8da05cebf 100644 --- a/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/breaker/Breaker.java +++ b/flying-saucer-core/src/main/java/org/xhtmlrenderer/layout/breaker/Breaker.java @@ -179,14 +179,14 @@ private static void doBreakText(LayoutContext c, } context.setNeedsNewLine(true); - if (right < 0 && style.getWordWrap() == IdentValue.BREAK_WORD) { + if (right <= 0 && style.getWordWrap() == IdentValue.BREAK_WORD) { if (!tryToBreakAnywhere) { doBreakText(c, context, avail, style, true); return; } } - if (right >= 0) { // found a place to wrap + if (right > 0) { // found a place to wrap context.setEnd(context.getStart() + right); context.setWidth(getWidth(c, f, context.getMaster().substring(context.getStart(), context.getStart() + right))); return; diff --git a/flying-saucer-pdf/src/test/java/org/xhtmlrenderer/pdf/bug/EndlessLoopTest.java b/flying-saucer-pdf/src/test/java/org/xhtmlrenderer/pdf/bug/EndlessLoopTest.java new file mode 100644 index 000000000..bbe9c457c --- /dev/null +++ b/flying-saucer-pdf/src/test/java/org/xhtmlrenderer/pdf/bug/EndlessLoopTest.java @@ -0,0 +1,19 @@ +package org.xhtmlrenderer.pdf.bug; + +import org.junit.Test; +import org.xhtmlrenderer.pdf.ITextRenderer; + +import java.io.File; +import java.net.URL; + +public class EndlessLoopTest { + + @Test(timeout = 3000L) + public void testWordwrap() throws Exception { + URL htmlUrl = getClass().getResource("EndlessLoopTest_wordwrap.html"); + File htmlFile = new File(htmlUrl.toURI()); + ITextRenderer renderer = new ITextRenderer(); + renderer.setDocument(htmlFile); + renderer.layout(); + } +} diff --git a/flying-saucer-pdf/src/test/resources/org/xhtmlrenderer/pdf/bug/EndlessLoopTest_wordwrap.html b/flying-saucer-pdf/src/test/resources/org/xhtmlrenderer/pdf/bug/EndlessLoopTest_wordwrap.html new file mode 100644 index 000000000..50d44ed26 --- /dev/null +++ b/flying-saucer-pdf/src/test/resources/org/xhtmlrenderer/pdf/bug/EndlessLoopTest_wordwrap.html @@ -0,0 +1,4 @@ + +
floated
+
word wrapped
+