Skip to content

Commit 8c80775

Browse files
Fix issues with returned LayoutResult, split renderer children and RootRenderer float kids splitting
DEVSIX-1267
1 parent 2a2555f commit 8c80775

File tree

3 files changed

+121
-94
lines changed

3 files changed

+121
-94
lines changed

layout/src/main/java/com/itextpdf/layout/renderer/BlockRenderer.java

Lines changed: 72 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,9 @@ This file is part of the iText (R) project.
7676
import java.util.ArrayList;
7777
import java.util.Collections;
7878
import java.util.HashMap;
79+
import java.util.LinkedHashMap;
7980
import java.util.List;
81+
import java.util.Map;
8082

8183
public abstract class BlockRenderer extends AbstractRenderer {
8284

@@ -87,8 +89,8 @@ protected BlockRenderer(IElement modelElement) {
8789
@Override
8890
public LayoutResult layout(LayoutContext layoutContext) {
8991
overrideHeightProperties();
92+
Map<Integer, IRenderer> waitingFloatsSplitRenderers = new LinkedHashMap<>();
9093
List<IRenderer> waitingOverflowFloatRenderers = new ArrayList<>();
91-
List<IRenderer> waitingSplitFloatRenderers = new ArrayList<>();
9294
boolean wasHeightClipped = false;
9395
int pageNumber = layoutContext.getArea().getPageNumber();
9496

@@ -166,19 +168,18 @@ public LayoutResult layout(LayoutContext layoutContext) {
166168
// the first renderer (one of childRenderers or their children) to produce LayoutResult.NOTHING
167169
IRenderer causeOfNothing = null;
168170
boolean anythingPlaced = false;
169-
List<IRenderer> ignoredChildRenderers = new ArrayList<>();
170171
for (int childPos = 0; childPos < childRenderers.size(); childPos++) {
171172
IRenderer childRenderer = childRenderers.get(childPos);
172173
LayoutResult result;
173174
childRenderer.setParent(this);
174175
MarginsCollapseInfo childMarginsInfo = null;
175-
if (!waitingOverflowFloatRenderers.isEmpty() &&
176-
FloatingHelper.isFloatAffectedByClear(waitingOverflowFloatRenderers.get(waitingOverflowFloatRenderers.size() - 1).<FloatPropertyValue>getProperty(Property.FLOAT),
177-
childRenderer.<ClearPropertyValue>getProperty(Property.CLEAR))) {
178-
return splitIfClearRendererIsPresentAfterFloatRendererWasSplitted(childPos, waitingSplitFloatRenderers,
176+
177+
// TODO process correctly for floats with clear
178+
if (!waitingOverflowFloatRenderers.isEmpty() && FloatingHelper.isClearanceApplied(waitingOverflowFloatRenderers, childRenderer.<ClearPropertyValue>getProperty(Property.CLEAR))) {
179+
return splitIfClearRendererIsPresentAfterFloatRendererWasSplit(childPos, waitingFloatsSplitRenderers,
179180
waitingOverflowFloatRenderers, blockMaxHeight, wasHeightClipped, marginsCollapseHandler,
180181
layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled, isCellRenderer,
181-
paddings, borders, layoutContext.getFloatRendererAreas(), causeOfNothing);
182+
paddings, borders, layoutContext.getFloatRendererAreas(), causeOfNothing, layoutBox);
182183
}
183184
if (marginsCollapsingEnabled) {
184185
childMarginsInfo = marginsCollapseHandler.startChildMarginsHandling(childRenderer, layoutBox);
@@ -236,17 +237,15 @@ public LayoutResult layout(LayoutContext layoutContext) {
236237
if (result.getStatus() == LayoutResult.PARTIAL) {
237238
if (currentAreaPos + 1 == areas.size()) {
238239

239-
AbstractRenderer[] splitAndOverflowRenderers = createSplitAndOverflowRenderers(childPos, ignoredChildRenderers,
240-
result, childRenderer, floatRendererAreas, layoutContext.getArea().getBBox(), clearHeightCorrection,
241-
marginsCollapsingEnabled, waitingSplitFloatRenderers, waitingOverflowFloatRenderers, LayoutResult.PARTIAL);
242-
AbstractRenderer splitRenderer = splitAndOverflowRenderers[0];
243-
splitRenderer.childRenderers.add(result.getSplitRenderer());
244-
FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(childRenderer, floatRendererAreas, parentBBox, clearHeightCorrection, marginsCollapsingEnabled);
245-
if(splitAndOverflowRenderers.length == 1) {
246-
waitingSplitFloatRenderers = splitRenderer.childRenderers;
240+
AbstractRenderer[] splitAndOverflowRenderers = createSplitAndOverflowRenderers(childPos, waitingFloatsSplitRenderers,
241+
result, childRenderer, waitingOverflowFloatRenderers, LayoutResult.PARTIAL);
242+
if (splitAndOverflowRenderers == null) {
243+
waitingFloatsSplitRenderers.put(childPos, result.getSplitRenderer());
247244
break;
248245
}
249246

247+
AbstractRenderer splitRenderer = splitAndOverflowRenderers[0];
248+
splitRenderer.childRenderers.add(result.getSplitRenderer());
250249
AbstractRenderer overflowRenderer = splitAndOverflowRenderers[1];
251250
overflowRenderer.deleteOwnProperty(Property.FORCED_PLACEMENT);
252251

@@ -270,11 +269,11 @@ public LayoutResult layout(LayoutContext layoutContext) {
270269
applyBorderBox(occupiedArea.getBBox(), borders, true);
271270
applyMargins(occupiedArea.getBBox(), true);
272271

272+
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
273273
if (wasHeightClipped) {
274-
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
275274
return new LayoutResult(LayoutResult.FULL, editedArea, splitRenderer, null);
276275
} else {
277-
return new LayoutResult(LayoutResult.PARTIAL, occupiedArea, splitRenderer, overflowRenderer, causeOfNothing);
276+
return new LayoutResult(LayoutResult.PARTIAL, editedArea, splitRenderer, overflowRenderer, causeOfNothing);
278277
}
279278
} else {
280279
childRenderers.set(childPos, result.getSplitRenderer());
@@ -286,16 +285,14 @@ public LayoutResult layout(LayoutContext layoutContext) {
286285
boolean keepTogether = isKeepTogether();
287286
int layoutResult = anythingPlaced && !keepTogether ? LayoutResult.PARTIAL : LayoutResult.NOTHING;
288287

289-
AbstractRenderer[] splitAndOverflowRenderers = createSplitAndOverflowRenderers(childPos, ignoredChildRenderers,
290-
result, childRenderer, floatRendererAreas, layoutContext.getArea().getBBox(), clearHeightCorrection,
291-
marginsCollapsingEnabled, waitingSplitFloatRenderers, waitingOverflowFloatRenderers, layoutResult);
288+
AbstractRenderer[] splitAndOverflowRenderers = createSplitAndOverflowRenderers(childPos, waitingFloatsSplitRenderers,
289+
result, childRenderer, waitingOverflowFloatRenderers, layoutResult);
292290

293-
AbstractRenderer splitRenderer = splitAndOverflowRenderers[0];
294-
waitingSplitFloatRenderers = splitRenderer.childRenderers;
295-
if(splitAndOverflowRenderers.length == 1) {
296-
ignoredChildRenderers.add(childRenderer);
291+
if (splitAndOverflowRenderers == null) {
292+
waitingFloatsSplitRenderers.put(childPos, null);
297293
break;
298294
}
295+
AbstractRenderer splitRenderer = splitAndOverflowRenderers[0];
299296
AbstractRenderer overflowRenderer = splitAndOverflowRenderers[1];
300297

301298
if (isRelativePosition() && positionedRenderers.size() > 0) {
@@ -335,11 +332,14 @@ public LayoutResult layout(LayoutContext layoutContext) {
335332
applyBorderBox(occupiedArea.getBBox(), borders, true);
336333
applyMargins(occupiedArea.getBBox(), true);
337334

335+
338336
if (Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT)) || wasHeightClipped) {
339-
return new LayoutResult(LayoutResult.FULL, occupiedArea, splitRenderer, null, null);
337+
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
338+
return new LayoutResult(LayoutResult.FULL, editedArea, splitRenderer, null, null);
340339
} else {
341340
if (layoutResult != LayoutResult.NOTHING) {
342-
return new LayoutResult(layoutResult, occupiedArea, splitRenderer, overflowRenderer, null).setAreaBreak(result.getAreaBreak());
341+
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
342+
return new LayoutResult(layoutResult, editedArea, splitRenderer, overflowRenderer, null).setAreaBreak(result.getAreaBreak());
343343
} else {
344344
return new LayoutResult(layoutResult, null, null, overflowRenderer, result.getCauseOfNothing()).setAreaBreak(result.getAreaBreak());
345345
}
@@ -357,7 +357,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
357357
if (marginsCollapsingEnabled) {
358358
marginsCollapseHandler.endChildMarginsHandling(layoutBox);
359359
}
360-
if (result.getStatus() == LayoutResult.FULL && (waitingOverflowFloatRenderers.isEmpty() || !FloatingHelper.isRendererFloating(childRenderer))) {
360+
if (result.getStatus() == LayoutResult.FULL) {
361361
layoutBox.setHeight(result.getOccupiedArea().getBBox().getY() - layoutBox.getY());
362362
if (childRenderer.getOccupiedArea() != null) {
363363
// Use occupied area's bbox width so that for absolutely positioned renderers we do not align using full width
@@ -445,19 +445,35 @@ public LayoutResult layout(LayoutContext layoutContext) {
445445
overflowRenderer = createOverflowRenderer(LayoutResult.PARTIAL);
446446
overflowRenderer.getChildRenderers().addAll(waitingOverflowFloatRenderers);
447447
}
448-
IRenderer splitRenderer;
449-
if (!waitingSplitFloatRenderers.isEmpty()) {
448+
AbstractRenderer splitRenderer = this;
449+
if (!waitingFloatsSplitRenderers.isEmpty()) {
450450
splitRenderer = createSplitRenderer(LayoutResult.PARTIAL);
451-
splitRenderer.getChildRenderers().addAll(waitingSplitFloatRenderers);
452-
} else {
453-
splitRenderer = this;
451+
splitRenderer.childRenderers = new ArrayList<>(childRenderers);
452+
replaceSplitRendererKidFloats(waitingFloatsSplitRenderers, splitRenderer);
454453
}
455454

456-
if (null == overflowRenderer) {
457-
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
455+
LayoutArea editedArea = FloatingHelper.adjustResultOccupiedAreaForFloatAndClear(this, layoutContext.getFloatRendererAreas(), layoutContext.getArea().getBBox(), clearHeightCorrection, marginsCollapsingEnabled);
456+
if (overflowRenderer == null) {
458457
return new LayoutResult(LayoutResult.FULL, editedArea, splitRenderer, null, causeOfNothing);
459458
} else {
460-
return new LayoutResult(LayoutResult.PARTIAL, occupiedArea, splitRenderer, overflowRenderer, causeOfNothing);
459+
// assert splitRenderer != this; // TODO review
460+
return new LayoutResult(LayoutResult.PARTIAL, editedArea, splitRenderer, overflowRenderer, causeOfNothing);
461+
}
462+
}
463+
464+
private void replaceSplitRendererKidFloats(Map<Integer, IRenderer> waitingFloatsSplitRenderers, IRenderer splitRenderer) {
465+
for (Map.Entry<Integer, IRenderer> waitingSplitRenderer : waitingFloatsSplitRenderers.entrySet()) {
466+
if (waitingSplitRenderer.getValue() != null) {
467+
splitRenderer.getChildRenderers().set(waitingSplitRenderer.getKey(), waitingSplitRenderer.getValue());
468+
} else{
469+
// splitRenderer.getChildRenderers().remove((int)waitingSplitRenderer.getKey());
470+
splitRenderer.getChildRenderers().set((int)waitingSplitRenderer.getKey(), null);
471+
}
472+
}
473+
for (int i = splitRenderer.getChildRenderers().size() - 1; i >= 0; --i) {
474+
if (splitRenderer.getChildRenderers().get(i) == null) {
475+
splitRenderer.getChildRenderers().remove(i);
476+
}
461477
}
462478
}
463479

@@ -778,22 +794,29 @@ MinMaxWidth correctMinMaxWidth(MinMaxWidth minMaxWidth) {
778794
return minMaxWidth;
779795
}
780796

781-
private LayoutResult splitIfClearRendererIsPresentAfterFloatRendererWasSplitted(int childPos, List<IRenderer> waitingSplitRenderers,
782-
List<IRenderer> waitingOverflowRenderers,
783-
Float blockMaxHeight, boolean wasHeightClipped,
784-
MarginsCollapseHandler marginsCollapseHandler,
785-
Rectangle parentBBox, float clearHeightCorrection,
786-
boolean marginsCollapsingEnabled, boolean isCellRenderer,
787-
float[] paddings, Border[] borders,
788-
List<Rectangle> floatRendererAreas, IRenderer causeOfNothing) {
797+
private LayoutResult splitIfClearRendererIsPresentAfterFloatRendererWasSplit(int childPos, Map<Integer, IRenderer> waitingFloatsSplitRenderers,
798+
List<IRenderer> waitingFloatsOverflowRenderers,
799+
Float blockMaxHeight, boolean wasHeightClipped,
800+
MarginsCollapseHandler marginsCollapseHandler,
801+
Rectangle parentBBox, float clearHeightCorrection,
802+
boolean marginsCollapsingEnabled, boolean isCellRenderer,
803+
float[] paddings, Border[] borders,
804+
List<Rectangle> floatRendererAreas, IRenderer causeOfNothing, Rectangle layoutBox) {
805+
806+
if (marginsCollapsingEnabled && !isCellRenderer) {
807+
marginsCollapseHandler.endMarginsCollapse(layoutBox);
808+
}
789809
AbstractRenderer splitRenderer = createSplitRenderer(LayoutResult.PARTIAL);
810+
Rectangle splitRendererOccupiedArea = splitRenderer.getOccupiedArea().getBBox();
811+
splitRendererOccupiedArea.increaseHeight(splitRendererOccupiedArea.getY() - layoutBox.getY()).setY(layoutBox.getY());
790812
splitRenderer.childRenderers = new ArrayList<>(childRenderers.subList(0, childPos));
791-
splitRenderer.childRenderers = waitingSplitRenderers;
813+
814+
replaceSplitRendererKidFloats(waitingFloatsSplitRenderers, splitRenderer);
792815

793816
AbstractRenderer overflowRenderer = createOverflowRenderer(LayoutResult.PARTIAL);
794817
// Apply forced placement only on split renderer
795818
overflowRenderer.deleteOwnProperty(Property.FORCED_PLACEMENT);
796-
overflowRenderer.childRenderers.addAll(waitingOverflowRenderers);
819+
overflowRenderer.childRenderers.addAll(waitingFloatsOverflowRenderers);
797820
overflowRenderer.childRenderers.addAll(childRenderers.subList(childPos, childRenderers.size()));
798821

799822

@@ -813,9 +836,6 @@ private LayoutResult splitIfClearRendererIsPresentAfterFloatRendererWasSplitted(
813836
.moveDown((float) blockMaxHeight - occupiedArea.getBBox().getHeight())
814837
.setHeight((float) blockMaxHeight);
815838
}
816-
if (marginsCollapsingEnabled && !isCellRenderer) {
817-
marginsCollapseHandler.endMarginsCollapse(occupiedArea.getBBox());
818-
}
819839

820840
applyPaddings(occupiedArea.getBBox(), paddings, true);
821841
applyBorderBox(occupiedArea.getBBox(), borders, true);
@@ -830,25 +850,20 @@ private LayoutResult splitIfClearRendererIsPresentAfterFloatRendererWasSplitted(
830850
}
831851
}
832852

833-
private AbstractRenderer[] createSplitAndOverflowRenderers(int childPos, List<IRenderer> ignoredChildRenderers, LayoutResult result,
834-
IRenderer childRenderer, List<Rectangle> floatRendererAreas, Rectangle parentBBox,
835-
float clearHeightCorrection, boolean marginsCollapsingEnabled,
836-
List<IRenderer> waitingSplitFloatRenderers, List<IRenderer> waitingOverflowFloatRenderers,
853+
private AbstractRenderer[] createSplitAndOverflowRenderers(int childPos, Map<Integer, IRenderer> waitingFloatsSplitRenderers, LayoutResult result,
854+
IRenderer childRenderer, List<IRenderer> waitingOverflowFloatRenderers,
837855
int layoutStatus) {
838856
AbstractRenderer splitRenderer = createSplitRenderer(layoutStatus);
839857
splitRenderer.childRenderers = new ArrayList<>(childRenderers.subList(0, childPos));
840858

841-
for(IRenderer ignoredRenderer : ignoredChildRenderers) {
842-
splitRenderer.childRenderers.remove(ignoredRenderer);
843-
}
859+
replaceSplitRendererKidFloats(waitingFloatsSplitRenderers, splitRenderer);
844860
for (IRenderer renderer : splitRenderer.childRenderers) {
845861
renderer.setParent(splitRenderer);
846862
}
847863

848864
if (FloatingHelper.isRendererFloating(childRenderer)) {
849-
// ignoredChildRenderers.add(childRenderer);
850865
waitingOverflowFloatRenderers.add(result.getOverflowRenderer());
851-
return new AbstractRenderer[]{splitRenderer};
866+
return null;
852867
}
853868
AbstractRenderer overflowRenderer = createOverflowRenderer(layoutStatus);
854869
overflowRenderer.childRenderers.addAll(waitingOverflowFloatRenderers);

0 commit comments

Comments
 (0)