diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/BlockFormattingContext.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/BlockFormattingContext.java
index ebe747b5e..65f4c0e2a 100755
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/BlockFormattingContext.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/BlockFormattingContext.java
@@ -84,6 +84,7 @@ public void clear(LayoutContext c, Box current) {
getFloatManager().clear(c, this, current);
}
+ @Override
public String toString() {
return "BlockFormattingContext: (" + _x + "," + _y + ")";
}
diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/FloatManager.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/FloatManager.java
index 4faace32f..36d7dc3fe 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/FloatManager.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/layout/FloatManager.java
@@ -23,8 +23,10 @@
import java.awt.Rectangle;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.stream.Stream;
import com.openhtmltopdf.css.style.CssContext;
import com.openhtmltopdf.render.BlockBox;
@@ -37,55 +39,63 @@
* non-floated (block) boxes.
*/
public class FloatManager {
- public static final int LEFT = 1;
- public static final int RIGHT = 2;
+ public enum FloatDirection {
+ LEFT,
+ RIGHT;
+ }
/* Lazily created for performance. */
private List _leftFloats = Collections.emptyList();
private List _rightFloats = Collections.emptyList();
-
+
private final Box _master;
public FloatManager(Box master) {
this._master = master;
}
- private List getAddableFloats(int direction) {
+ private List getAddableFloats(FloatDirection direction) {
if (getFloats(direction).isEmpty()) {
setFloats(direction, new ArrayList<>());
}
return getFloats(direction);
}
-
- private void setFloats(int direction, List list) {
- if (direction == LEFT) {
+
+ private void setFloats(FloatDirection direction, List list) {
+ if (direction == FloatDirection.LEFT) {
_leftFloats = list;
} else {
+ assert direction == FloatDirection.RIGHT;
_rightFloats = list;
}
}
-
+
public void floatBox(LayoutContext c, Layer layer, BlockFormattingContext bfc, BlockBox box) {
if (box.getStyle().isFloatedLeft()) {
- position(c, bfc, box, LEFT);
- save(box, layer, bfc, LEFT);
+ position(c, bfc, box, FloatDirection.LEFT);
+ save(box, layer, bfc, FloatDirection.LEFT);
} else if (box.getStyle().isFloatedRight()) {
- position(c, bfc, box, RIGHT);
- save(box, layer, bfc, RIGHT);
+ position(c, bfc, box, FloatDirection.RIGHT);
+ save(box, layer, bfc, FloatDirection.RIGHT);
}
}
public void clear(CssContext cssCtx, BlockFormattingContext bfc, Box box) {
if (box.getStyle().isClearLeft()) {
- moveClear(cssCtx, bfc, box, getFloats(LEFT));
+ moveClear(cssCtx, bfc, box, getFloats(FloatDirection.LEFT));
}
if (box.getStyle().isClearRight()) {
- moveClear(cssCtx, bfc, box, getFloats(RIGHT));
+ moveClear(cssCtx, bfc, box, getFloats(FloatDirection.RIGHT));
}
}
- private void save(BlockBox current, Layer layer, BlockFormattingContext bfc, int direction) {
+ private void save(
+ BlockBox current,
+ Layer layer,
+ BlockFormattingContext bfc,
+ FloatDirection direction) {
+
Point p = bfc.getOffset();
getAddableFloats(direction).add(new BoxOffset(current, p.x, p.y));
layer.addFloat(current, bfc);
@@ -96,7 +106,7 @@ private void save(BlockBox current, Layer layer, BlockFormattingContext bfc, int
}
private void position(CssContext cssCtx, BlockFormattingContext bfc,
- BlockBox current, int direction) {
+ BlockBox current, FloatDirection direction) {
moveAllTheWayOver(current, direction);
alignToLastOpposingFloat(cssCtx, bfc, current, direction);
@@ -115,25 +125,32 @@ private void position(CssContext cssCtx, BlockFormattingContext bfc,
}
if (current.getStyle().isCleared()) {
- if (current.getStyle().isClearLeft() && direction == LEFT) {
- moveAllTheWayOver(current, LEFT);
- } else if (current.getStyle().isClearRight() && direction == RIGHT) {
- moveAllTheWayOver(current, RIGHT);
+ if (current.getStyle().isClearLeft() && direction == FloatDirection.LEFT) {
+ moveAllTheWayOver(current, FloatDirection.LEFT);
+ } else if (current.getStyle().isClearRight() && direction == FloatDirection.RIGHT) {
+ moveAllTheWayOver(current, FloatDirection.RIGHT);
}
moveFloatBelow(cssCtx, bfc, current, getFloats(direction));
}
}
-
- public List getFloats(int direction) {
- return direction == LEFT ? _leftFloats : _rightFloats;
+
+ public List getFloats(FloatDirection direction) {
+ return direction == FloatDirection.LEFT ? _leftFloats : _rightFloats;
}
- private List getOpposingFloats(int direction) {
- return direction == LEFT ? _rightFloats : _leftFloats;
+ public Stream getFloatStream(FloatDirection direction) {
+ return getFloats(direction).stream();
}
- private void alignToLastFloat(CssContext cssCtx,
- BlockFormattingContext bfc, BlockBox current, int direction) {
+ private List getOpposingFloats(FloatDirection direction) {
+ return direction == FloatDirection.LEFT ? _rightFloats : _leftFloats;
+ }
+
+ private void alignToLastFloat(
+ CssContext cssCtx,
+ BlockFormattingContext bfc,
+ BlockBox current,
+ FloatDirection direction) {
List floats = getFloats(direction);
if (floats.size() > 0) {
@@ -157,9 +174,9 @@ private void alignToLastFloat(CssContext cssCtx,
}
if (moveOver) {
- if (direction == LEFT) {
+ if (direction == FloatDirection.LEFT) {
currentBounds.x = lastBounds.x + last.getWidth();
- } else if (direction == RIGHT) {
+ } else if (direction == FloatDirection.RIGHT) {
currentBounds.x = lastBounds.x - current.getWidth();
}
@@ -171,11 +188,12 @@ private void alignToLastFloat(CssContext cssCtx,
}
}
- private void alignToLastOpposingFloat(CssContext cssCtx,
- BlockFormattingContext bfc, BlockBox current, int direction) {
+ private void alignToLastOpposingFloat(
+ CssContext cssCtx,
+ BlockFormattingContext bfc, BlockBox current, FloatDirection direction) {
List floats = getOpposingFloats(direction);
- if (floats.size() > 0) {
+ if (!floats.isEmpty()) {
Point offset = bfc.getOffset();
BoxOffset lastOffset = floats.get(floats.size() - 1);
@@ -194,10 +212,10 @@ private void alignToLastOpposingFloat(CssContext cssCtx,
}
}
- private void moveAllTheWayOver(BlockBox current, int direction) {
- if (direction == LEFT) {
+ private void moveAllTheWayOver(BlockBox current, FloatDirection direction) {
+ if (direction == FloatDirection.LEFT) {
current.setX(0);
- } else if (direction == RIGHT) {
+ } else if (direction == FloatDirection.RIGHT) {
current.setX(current.getContainingBlock().getContentWidth() - current.getWidth());
}
}
@@ -208,22 +226,17 @@ private boolean fitsInContainingBlock(BlockBox current) {
}
private int findLowestY(CssContext cssCtx, List floats) {
- int result = 0;
-
- for (BoxOffset floater : floats) {
- Rectangle bounds = floater.getBox().getMarginEdge(
- cssCtx, -floater.getX(), -floater.getY());
- if (bounds.y + bounds.height > result) {
- result = bounds.y + bounds.height;
- }
- }
-
- return result;
+ return floats
+ .stream()
+ .map(floater -> floater.getBox().getMarginEdge(cssCtx, -floater.getX(), -floater.getY()))
+ .mapToInt(bounds -> bounds.y + bounds.height)
+ .max()
+ .orElse(0);
}
public int getClearDelta(CssContext cssCtx, int bfcRelativeY) {
- int lowestLeftY = findLowestY(cssCtx, getFloats(LEFT));
- int lowestRightY = findLowestY(cssCtx, getFloats(RIGHT));
+ int lowestLeftY = findLowestY(cssCtx, getFloats(FloatDirection.LEFT));
+ int lowestRightY = findLowestY(cssCtx, getFloats(FloatDirection.RIGHT));
int lowestY = Math.max(lowestLeftY, lowestRightY);
@@ -235,21 +248,15 @@ private boolean overlaps(CssContext cssCtx, BlockFormattingContext bfc,
Point offset = bfc.getOffset();
Rectangle bounds = current.getMarginEdge(cssCtx, -offset.x, -offset.y);
- for (BoxOffset floater : floats) {
- Rectangle floaterBounds = floater.getBox().getMarginEdge(cssCtx,
- -floater.getX(), -floater.getY());
-
- if (floaterBounds.intersects(bounds)) {
- return true;
- }
- }
-
- return false;
+ return floats
+ .stream()
+ .map(floater -> floater.getBox().getMarginEdge(cssCtx, -floater.getX(), -floater.getY()))
+ .anyMatch(floaterBounds -> floaterBounds.intersects(bounds));
}
private void moveFloatBelow(CssContext cssCtx, BlockFormattingContext bfc,
Box current, List floats) {
- if (floats.size() == 0) {
+ if (floats.isEmpty()) {
return;
}
@@ -264,7 +271,7 @@ private void moveFloatBelow(CssContext cssCtx, BlockFormattingContext bfc,
private void moveClear(CssContext cssCtx, BlockFormattingContext bfc,
Box current, List floats) {
- if (floats.size() == 0) {
+ if (floats.isEmpty()) {
return;
}
@@ -287,8 +294,8 @@ private void moveClear(CssContext cssCtx, BlockFormattingContext bfc,
}
public void removeFloat(BlockBox floater) {
- removeFloat(floater, getFloats(LEFT));
- removeFloat(floater, getFloats(RIGHT));
+ removeFloat(floater, getFloats(FloatDirection.LEFT));
+ removeFloat(floater, getFloats(FloatDirection.RIGHT));
}
private void removeFloat(BlockBox floater, List floats) {
@@ -302,8 +309,8 @@ private void removeFloat(BlockBox floater, List floats) {
}
public void calcFloatLocations() {
- calcFloatLocations(getFloats(LEFT));
- calcFloatLocations(getFloats(RIGHT));
+ calcFloatLocations(getFloats(FloatDirection.LEFT));
+ calcFloatLocations(getFloats(FloatDirection.RIGHT));
}
private void calcFloatLocations(List floats) {
@@ -324,23 +331,11 @@ private void applyLineHeightHack(CssContext cssCtx, Box line, Rectangle bounds)
public int getNextLineBoxDelta(CssContext cssCtx, BlockFormattingContext bfc,
LineBox line, int containingBlockContentWidth) {
- BoxDistance left = getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(LEFT), LEFT);
- BoxDistance right = getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(RIGHT), RIGHT);
-
- int leftDelta;
- int rightDelta;
-
- if (left.getBox() != null) {
- leftDelta = calcDelta(cssCtx, line, left);
- } else {
- leftDelta = 0;
- }
+ BoxDistance left = getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(FloatDirection.LEFT), FloatDirection.LEFT);
+ BoxDistance right = getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(FloatDirection.RIGHT), FloatDirection.RIGHT);
- if (right.getBox() != null) {
- rightDelta = calcDelta(cssCtx, line, right);
- } else {
- rightDelta = 0;
- }
+ int leftDelta = left.getBox() != null ? calcDelta(cssCtx, line, left) : 0;
+ int rightDelta = right.getBox() != null ? calcDelta(cssCtx, line, right) : 0;
return Math.max(leftDelta, rightDelta);
}
@@ -354,18 +349,23 @@ private int calcDelta(CssContext cssCtx, LineBox line, BoxDistance boxDistance)
public int getLeftFloatDistance(CssContext cssCtx, BlockFormattingContext bfc,
LineBox line, int containingBlockContentWidth) {
- return getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(LEFT), LEFT).getDistance();
+ return getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(FloatDirection.LEFT), FloatDirection.LEFT).getDistance();
}
public int getRightFloatDistance(CssContext cssCtx, BlockFormattingContext bfc,
LineBox line, int containingBlockContentWidth) {
- return getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(RIGHT), RIGHT).getDistance();
+ return getFloatDistance(cssCtx, bfc, line, containingBlockContentWidth, getFloats(FloatDirection.RIGHT), FloatDirection.RIGHT).getDistance();
}
- private BoxDistance getFloatDistance(CssContext cssCtx, BlockFormattingContext bfc,
- LineBox line, int containingBlockContentWidth,
- List floatsList, int direction) {
- if (floatsList.size() == 0) {
+ private BoxDistance getFloatDistance(
+ CssContext cssCtx,
+ BlockFormattingContext bfc,
+ LineBox line,
+ int containingBlockContentWidth,
+ List floatsList,
+ FloatDirection direction) {
+
+ if (floatsList.isEmpty()) {
return new BoxDistance(null, 0);
}
@@ -373,27 +373,30 @@ private BoxDistance getFloatDistance(CssContext cssCtx, BlockFormattingContext b
Rectangle lineBounds = line.getMarginEdge(cssCtx, -offset.x, -offset.y);
lineBounds.width = containingBlockContentWidth;
- int farthestOver = direction == LEFT ? lineBounds.x : lineBounds.x + lineBounds.width;
+ int farthestOver = direction == FloatDirection.LEFT ? lineBounds.x : lineBounds.x + lineBounds.width;
applyLineHeightHack(cssCtx, line, lineBounds);
+
BlockBox farthestOverBox = null;
- for (int i = 0; i < floatsList.size(); i++) {
- BoxOffset floater = floatsList.get(i);
+
+ for (BoxOffset floater : floatsList) {
Rectangle fr = floater.getBox().getMarginEdge(cssCtx, -floater.getX(), -floater.getY());
+
if (lineBounds.intersects(fr)) {
- if (direction == LEFT && fr.x + fr.width > farthestOver) {
+ if (direction == FloatDirection.LEFT && fr.x + fr.width > farthestOver) {
farthestOver = fr.x + fr.width;
- } else if (direction == RIGHT && fr.x < farthestOver) {
+ } else if (direction == FloatDirection.RIGHT && fr.x < farthestOver) {
farthestOver = fr.x;
}
+
farthestOverBox = floater.getBox();
}
}
- if (direction == LEFT) {
+ if (direction == FloatDirection.LEFT) {
return new BoxDistance(farthestOverBox, farthestOver - lineBounds.x);
} else {
- return new BoxDistance(farthestOverBox,lineBounds.x + lineBounds.width - farthestOver);
+ return new BoxDistance(farthestOverBox, lineBounds.x + lineBounds.width - farthestOver);
}
}
@@ -403,20 +406,15 @@ public Box getMaster() {
public Point getOffset(BlockBox floater) {
// FIXME inefficient (but probably doesn't matter)
- return getOffset(floater,
- floater.getStyle().isFloatedLeft() ? getFloats(LEFT) : getFloats(RIGHT));
+ return getOffset(floater,
+ getFloatStream(floater.getStyle().isFloatedLeft() ? FloatDirection.LEFT : FloatDirection.RIGHT));
}
- private Point getOffset(BlockBox floater, List floats) {
- for (BoxOffset boxOffset : floats) {
- BlockBox box = boxOffset.getBox();
-
- if (box.equals(floater)) {
- return new Point(boxOffset.getX(), boxOffset.getY());
- }
- }
-
- return null;
+ private Point getOffset(BlockBox floater, Stream floats) {
+ return floats.filter(boxOffset -> boxOffset.getBox().equals(floater))
+ .findFirst()
+ .map(boxOffset -> new Point(boxOffset.getX(), boxOffset.getY()))
+ .orElse(null);
}
private void performFloatOperation(FloatOperation op, List floats) {
@@ -431,8 +429,8 @@ private void performFloatOperation(FloatOperation op, List floats) {
}
public void performFloatOperation(FloatOperation op) {
- performFloatOperation(op, getFloats(LEFT));
- performFloatOperation(op, getFloats(RIGHT));
+ performFloatOperation(op, getFloats(FloatDirection.LEFT));
+ performFloatOperation(op, getFloats(FloatDirection.RIGHT));
}
public static class BoxOffset {
@@ -475,8 +473,14 @@ BlockBox getBox() {
int getDistance() {
return _distance;
}
+
+ @Override
+ public String toString() {
+ return "BoxDistance [_box=" + _box + ", _distance=" + _distance + "]";
+ }
}
+ @FunctionalInterface
public interface FloatOperation {
public void operate(Box floater);
}
diff --git a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/FlowingColumnContainerBox.java b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/FlowingColumnContainerBox.java
index 88c12f824..a5b829935 100644
--- a/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/FlowingColumnContainerBox.java
+++ b/openhtmltopdf-core/src/main/java/com/openhtmltopdf/render/FlowingColumnContainerBox.java
@@ -136,8 +136,8 @@ private void layoutFloats(TreeMap columns, List columnMap, PersistentBFC bfc, int columnCount, int colWidth, int colGap) {
- List floatsL = this.getPersistentBFC().getFloatManager().getFloats(FloatManager.LEFT);
- List floatsR = this.getPersistentBFC().getFloatManager().getFloats(FloatManager.RIGHT);
+ List floatsL = this.getPersistentBFC().getFloatManager().getFloats(FloatManager.FloatDirection.LEFT);
+ List floatsR = this.getPersistentBFC().getFloatManager().getFloats(FloatManager.FloatDirection.RIGHT);
layoutFloats(columnMap, floatsL, columnCount, colWidth, colGap);
layoutFloats(columnMap, floatsR, columnCount, colWidth, colGap);
@@ -173,8 +173,8 @@ private int adjustUnbalanced(LayoutContext c, Box child, int colGap, int colWidt
final List pages = c.getRootLayer().getPages();
final boolean haveFloats =
- !this.getPersistentBFC().getFloatManager().getFloats(FloatManager.LEFT).isEmpty() ||
- !this.getPersistentBFC().getFloatManager().getFloats(FloatManager.RIGHT).isEmpty();
+ !this.getPersistentBFC().getFloatManager().getFloats(FloatManager.FloatDirection.LEFT).isEmpty() ||
+ !this.getPersistentBFC().getFloatManager().getFloats(FloatManager.FloatDirection.RIGHT).isEmpty();
// We only need the tree map if we have floats.
final TreeMap columnMap = haveFloats ? new TreeMap<>() : null;
diff --git a/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-615-infinite-loop-break-word.html b/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-615-infinite-loop-break-word.html
index 83856f626..491c72ee9 100644
--- a/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-615-infinite-loop-break-word.html
+++ b/openhtmltopdf-examples/src/main/resources/visualtest/html/issue-615-infinite-loop-break-word.html
@@ -1,6 +1,17 @@
+
+
+
-
+
a