Skip to content

Commit 8bfe573

Browse files
committed
Fixes in overflow. Process long words correctly.
Distinguish x and y image overflow. Skip x overflow if there is already float in a line. Change long word's occupied area if it has x-overflow Distinguish whether area was clipped or not by setting clippedHeight value of LayoutArea. Apply overflow if area was clipped. DEVSIX-922
1 parent fc607f8 commit 8bfe573

File tree

8 files changed

+123
-39
lines changed

8 files changed

+123
-39
lines changed

layout/src/main/java/com/itextpdf/layout/layout/LayoutArea.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,31 @@ public class LayoutArea {
6767
*/
6868
protected boolean emptyArea = true;
6969

70+
/**
71+
* Indicates whether the height is clipped or not.
72+
*/
73+
protected boolean clippedHeight = false;
74+
7075
/**
7176
* Creates the area for content {@link com.itextpdf.layout.renderer.IRenderer#layout(LayoutContext) layouting}.
7277
*
7378
* @param pageNumber the number of page on which the area is located.
7479
* @param bBox the area's bounding box
7580
*/
7681
public LayoutArea(int pageNumber, Rectangle bBox) {
82+
this(pageNumber, bBox, false);
83+
}
84+
85+
/**
86+
* Creates the area for content {@link com.itextpdf.layout.renderer.IRenderer#layout(LayoutContext) layouting}.
87+
*
88+
* @param pageNumber the number of page on which the area is located.
89+
* @param bBox the area's bounding box
90+
*/
91+
public LayoutArea(int pageNumber, Rectangle bBox, boolean isClippedHeight) {
7792
this.pageNumber = pageNumber;
7893
this.bBox = bBox;
94+
this.clippedHeight = isClippedHeight;
7995
}
8096

8197
/**
@@ -119,6 +135,23 @@ public void setEmptyArea(boolean emptyArea) {
119135
this.emptyArea = emptyArea;
120136
}
121137

138+
/**
139+
* Indicates whether the height is clipped or not.
140+
*
141+
* @return whether the area is empty or not
142+
*/
143+
public boolean isClippedHeight() {
144+
return clippedHeight;
145+
}
146+
147+
/**
148+
* Defines whether the height is clipped or not.
149+
*/
150+
public void setClippedHeight(boolean clippedHeight) {
151+
this.clippedHeight = clippedHeight;
152+
}
153+
154+
122155
/**
123156
* {@inheritDoc}
124157
*/

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

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ protected BlockRenderer(IElement modelElement) {
9090
public LayoutResult layout(LayoutContext layoutContext) {
9191
overrideHeightProperties();
9292
boolean wasHeightClipped = false;
93+
boolean wasParentsHeightClipped = layoutContext.getArea().isClippedHeight();
9394
int pageNumber = layoutContext.getArea().getPageNumber();
9495

9596
boolean isPositioned = isPositioned();
@@ -132,18 +133,18 @@ public LayoutResult layout(LayoutContext layoutContext) {
132133
applyBordersPaddingsMargins(parentBBox, borders, paddings);
133134

134135
OverflowPropertyValue overflowX = this.<OverflowPropertyValue>getProperty(Property.OVERFLOW_X);
135-
OverflowPropertyValue overflowY = this.<OverflowPropertyValue>getProperty(Property.OVERFLOW_Y);
136+
Float blockMaxHeight = retrieveMaxHeight();
137+
OverflowPropertyValue overflowY = (null == blockMaxHeight || blockMaxHeight > parentBBox.getHeight()) && !wasParentsHeightClipped ? OverflowPropertyValue.FIT : this.<OverflowPropertyValue>getProperty(Property.OVERFLOW_Y);
136138

137139
if (blockWidth != null && (blockWidth < parentBBox.getWidth() || isPositioned || rotation != null || (null != overflowX && !OverflowPropertyValue.FIT.equals(overflowX)))) {
138140
// TODO DEVSIX-1174
139141
UnitValue widthVal = this.<UnitValue>getProperty(Property.WIDTH);
140-
if (widthVal != null && widthVal.isPercentValue() && widthVal.getValue() == 100 && (null == overflowX || OverflowPropertyValue.FIT.equals(overflowX))) {
142+
if (widthVal != null && widthVal.isPercentValue() && widthVal.getValue() == 100) {
141143
} else {
142144
parentBBox.setWidth((float) blockWidth);
143145
}
144146
}
145147

146-
Float blockMaxHeight = retrieveMaxHeight();
147148
if (!isFixedLayout() && null != blockMaxHeight && (blockMaxHeight < parentBBox.getHeight() || (null != overflowY && !OverflowPropertyValue.FIT.equals(overflowY)))
148149
&& !Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT))) {
149150
if (blockMaxHeight < parentBBox.getHeight()) {
@@ -156,8 +157,6 @@ public LayoutResult layout(LayoutContext layoutContext) {
156157
parentBBox.moveUp(heightDelta).setHeight((float) blockMaxHeight);
157158
}
158159

159-
Rectangle contentBoxToFit = parentBBox.clone();
160-
161160
List<Rectangle> areas;
162161
if (isPositioned) {
163162
areas = Collections.singletonList(parentBBox);
@@ -182,7 +181,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
182181
if (marginsCollapsingEnabled) {
183182
childMarginsInfo = marginsCollapseHandler.startChildMarginsHandling(childRenderer, layoutBox);
184183
}
185-
while ((result = childRenderer.setParent(this).layout(new LayoutContext(new LayoutArea(pageNumber, layoutBox), childMarginsInfo, floatRendererAreas)))
184+
while ((result = childRenderer.setParent(this).layout(new LayoutContext(new LayoutArea(pageNumber, layoutBox, wasHeightClipped || wasParentsHeightClipped), childMarginsInfo, floatRendererAreas)))
186185
.getStatus() != LayoutResult.FULL) {
187186
if (marginsCollapsingEnabled) {
188187
if (result.getStatus() != LayoutResult.NOTHING) {
@@ -196,7 +195,10 @@ public LayoutResult layout(LayoutContext layoutContext) {
196195
|| Boolean.TRUE.equals(getPropertyAsBoolean(Property.FILL_AVAILABLE_AREA))) {
197196
occupiedArea.setBBox(Rectangle.getCommonRectangle(occupiedArea.getBBox(), layoutBox));
198197
} else if (result.getOccupiedArea() != null && result.getStatus() != LayoutResult.NOTHING) {
199-
occupiedArea.setBBox(Rectangle.getCommonRectangle(occupiedArea.getBBox(), result.getOccupiedArea().getBBox()).setWidth(occupiedArea.getBBox().getWidth()));
198+
occupiedArea.setBBox(Rectangle.getCommonRectangle(occupiedArea.getBBox(), result.getOccupiedArea().getBBox()));
199+
if (occupiedArea.getBBox().getWidth() > layoutBox.getWidth()) {
200+
occupiedArea.getBBox().setWidth(layoutBox.getWidth());
201+
}
200202
}
201203

202204
if (FloatingHelper.isRendererFloating(this) || isCellRenderer) {
@@ -357,7 +359,10 @@ public LayoutResult layout(LayoutContext layoutContext) {
357359

358360
if (result.getOccupiedArea() != null) {
359361
if (!FloatingHelper.isRendererFloating(childRenderer)) { // this check is needed only if margins collapsing is enabled
360-
occupiedArea.setBBox(Rectangle.getCommonRectangle(occupiedArea.getBBox(), result.getOccupiedArea().getBBox()).setWidth(occupiedArea.getBBox().getWidth()));
362+
occupiedArea.setBBox(Rectangle.getCommonRectangle(occupiedArea.getBBox(), result.getOccupiedArea().getBBox()));
363+
if (occupiedArea.getBBox().getWidth() > layoutBox.getWidth()) {
364+
occupiedArea.getBBox().setWidth(layoutBox.getWidth());
365+
}
361366
}
362367
}
363368
if (marginsCollapsingEnabled) {
@@ -437,9 +442,17 @@ public LayoutResult layout(LayoutContext layoutContext) {
437442
correctPositionedLayout(layoutBox);
438443
}
439444

440-
float overflowPartHeight = getOverflowPartHeight(overflowY, contentBoxToFit);
445+
float overflowPartHeight = getOverflowPartHeight(overflowY, layoutBox);
441446
applyPaddings(occupiedArea.getBBox(), paddings, true);
442447
applyBorderBox(occupiedArea.getBBox(), borders, true);
448+
if (positionedRenderers.size() > 0) {
449+
LayoutArea area = new LayoutArea(occupiedArea.getPageNumber(), occupiedArea.getBBox().clone(), wasHeightClipped || wasParentsHeightClipped);
450+
applyBorderBox(area.getBBox(), false);
451+
for (IRenderer childPositionedRenderer : positionedRenderers) {
452+
childPositionedRenderer.setParent(this).layout(new LayoutContext(area));
453+
}
454+
applyBorderBox(area.getBBox(), true);
455+
}
443456
applyMargins(occupiedArea.getBBox(), true);
444457

445458
applyAbsolutePositionIfNeeded(layoutContext);
@@ -472,6 +485,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
472485
}
473486
}
474487
if (wasHeightClipped) {
488+
editedArea.getBBox().moveUp(overflowPartHeight).decreaseHeight(overflowPartHeight);
475489
occupiedArea.getBBox().moveUp(overflowPartHeight).decreaseHeight(overflowPartHeight);
476490
}
477491

@@ -823,7 +837,8 @@ protected MinMaxWidth getMinMaxWidth(float availableWidth) {
823837

824838
MinMaxWidth correctMinMaxWidth(MinMaxWidth minMaxWidth) {
825839
Float width = retrieveWidth(-1);
826-
if (width != null && width >= 0 && width >= minMaxWidth.getChildrenMinWidth()) {
840+
OverflowPropertyValue overflowX = this.<OverflowPropertyValue>getProperty(Property.OVERFLOW_X);
841+
if (width != null && width >= 0 && (width >= minMaxWidth.getChildrenMinWidth() || !OverflowPropertyValue.FIT.equals(overflowX))) {
827842
minMaxWidth.setChildrenMaxWidth((float) width);
828843
minMaxWidth.setChildrenMinWidth((float) width);
829844
}

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

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -123,8 +123,9 @@ public LayoutResult layout(LayoutContext layoutContext) {
123123
applyBorderBox(layoutBox, borders, false);
124124

125125
OverflowPropertyValue overflowX = this.parent.<OverflowPropertyValue>getProperty(Property.OVERFLOW_X);
126-
OverflowPropertyValue overflowY = this.parent.<OverflowPropertyValue>getProperty(Property.OVERFLOW_Y);
127-
boolean processOverflow = (null != overflowX && !OverflowPropertyValue.FIT.equals(overflowX)) || (null != overflowY && !OverflowPropertyValue.FIT.equals(overflowY));
126+
OverflowPropertyValue overflowY = (null == retrieveMaxHeight() || retrieveMaxHeight() > layoutBox.getHeight()) && !layoutContext.getArea().isClippedHeight() ? OverflowPropertyValue.FIT : this.parent.<OverflowPropertyValue>getProperty(Property.OVERFLOW_Y);
127+
boolean processOverflowX = (null != overflowX && !OverflowPropertyValue.FIT.equals(overflowX));
128+
boolean processOverflowY = (null != overflowY && !OverflowPropertyValue.FIT.equals(overflowY));
128129
if (isAbsolutePosition()) {
129130
applyAbsolutePosition(layoutBox);
130131
}
@@ -213,7 +214,7 @@ public LayoutResult layout(LayoutContext layoutContext) {
213214
// indicates whether the placement is forced
214215
boolean isPlacingForced = false;
215216
if (width > layoutBox.getWidth() || height > layoutBox.getHeight()) {
216-
if (Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT)) || processOverflow) {
217+
if (Boolean.TRUE.equals(getPropertyAsBoolean(Property.FORCED_PLACEMENT)) || (width > layoutBox.getWidth() && processOverflowX) || (height > layoutBox.getHeight() && processOverflowY)) {
217218
isPlacingForced = true;
218219
} else {
219220
return new MinMaxWidthLayoutResult(LayoutResult.NOTHING, occupiedArea, null, this, this);

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

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ This file is part of the iText (R) project.
6161
import com.itextpdf.layout.property.BaseDirection;
6262
import com.itextpdf.layout.property.FloatPropertyValue;
6363
import com.itextpdf.layout.property.Leading;
64+
import com.itextpdf.layout.property.OverflowPropertyValue;
6465
import com.itextpdf.layout.property.Property;
6566
import com.itextpdf.layout.property.TabAlignment;
6667
import com.itextpdf.layout.property.UnitValue;
@@ -92,10 +93,13 @@ public class LineRenderer extends AbstractRenderer {
9293
@Override
9394
public LineLayoutResult layout(LayoutContext layoutContext) {
9495
Rectangle layoutBox = layoutContext.getArea().getBBox().clone();
95-
96+
boolean wasParentsHeightClipped = layoutContext.getArea().isClippedHeight();
9697
List<Rectangle> floatRendererAreas = layoutContext.getFloatRendererAreas();
9798
if (floatRendererAreas != null) {
9899
FloatingHelper.adjustLineAreaAccordingToFloats(floatRendererAreas, layoutBox);
100+
if (0 != floatRendererAreas.size()) {
101+
setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT); // TODO
102+
}
99103
}
100104

101105
occupiedArea = new LayoutArea(layoutContext.getArea().getPageNumber(), layoutBox.clone().moveUp(layoutBox.getHeight()).setHeight(0).setWidth(0));
@@ -142,7 +146,7 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
142146
} else if (childRenderer instanceof TabRenderer) {
143147
if (hangingTabStop != null) {
144148
IRenderer tabRenderer = childRenderers.get(childPos - 1);
145-
tabRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), bbox)));
149+
tabRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), bbox, wasParentsHeightClipped)));
146150
curWidth += tabRenderer.getOccupiedArea().getBBox().getWidth();
147151
widthHandler.updateMaxChildWidth(tabRenderer.getOccupiedArea().getBBox().getWidth());
148152
}
@@ -193,10 +197,15 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
193197
// when floating span is split on other line;
194198
// TODO may be process floating spans as inline blocks always?
195199

200+
if (childPos > 0) {
201+
setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT);
202+
}
196203
if (overflowFloats.isEmpty() && (!anythingPlaced || floatingBoxFullWidth <= bbox.getWidth())) {
197-
childResult = childRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), layoutContext.getArea().getBBox().clone()), null, floatRendererAreas));
204+
childResult = childRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), layoutContext.getArea().getBBox().clone(), wasParentsHeightClipped), null, floatRendererAreas));
205+
}
206+
if (childPos > 0) {
207+
deleteOwnProperty(Property.OVERFLOW_X);
198208
}
199-
200209
// Get back child width so that it's not lost
201210
if (childWidthWasReplaced) {
202211
if (childRendererHasOwnWidthProperty) {
@@ -276,9 +285,15 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
276285
}
277286
}
278287

288+
if (childPos > 0) {
289+
setProperty(Property.OVERFLOW_X, OverflowPropertyValue.FIT);
290+
}
279291
if (childResult == null) {
280292
childResult = childRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), bbox)));
281293
}
294+
if (childPos > 0) {
295+
deleteOwnProperty(Property.OVERFLOW_X);
296+
}
282297

283298
// Get back child width so that it's not lost
284299
if (childWidthWasReplaced) {
@@ -344,7 +359,7 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
344359
affectedRenderers.addAll(childRenderers.subList(lastTabIndex + 1, childPos + 1));
345360
float tabWidth = calculateTab(layoutBox, curWidth, hangingTabStop, affectedRenderers, tabRenderer);
346361

347-
tabRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), bbox)));
362+
tabRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), bbox, wasParentsHeightClipped)));
348363
float sumOfAffectedRendererWidths = 0;
349364
for (IRenderer renderer : affectedRenderers) {
350365
renderer.getOccupiedArea().getBBox().moveRight(tabWidth + sumOfAffectedRendererWidths);
@@ -379,7 +394,7 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
379394

380395
boolean wordWasSplitAndItWillFitOntoNextLine = false;
381396
if (childResult instanceof TextLayoutResult && ((TextLayoutResult) childResult).isWordHasBeenSplit()) {
382-
LayoutResult newLayoutResult = childRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), layoutBox)));
397+
LayoutResult newLayoutResult = childRenderer.layout(new LayoutContext(new LayoutArea(layoutContext.getArea().getPageNumber(), layoutBox, wasParentsHeightClipped)));
383398
if (newLayoutResult instanceof TextLayoutResult && !((TextLayoutResult) newLayoutResult).isWordHasBeenSplit()) {
384399
wordWasSplitAndItWillFitOntoNextLine = true;
385400
}
@@ -602,6 +617,17 @@ public LineLayoutResult layout(LayoutContext layoutContext) {
602617
result.setMinMaxWidth(minMaxWidth);
603618
}
604619

620+
if (floatRendererAreas != null) {
621+
if (0 != floatRendererAreas.size()) {
622+
deleteOwnProperty(Property.OVERFLOW_X); // TODO
623+
if (null != result.getSplitRenderer()) {
624+
result.getSplitRenderer().deleteOwnProperty(Property.OVERFLOW_X);
625+
}
626+
if (null != result.getOverflowRenderer()) {
627+
result.getOverflowRenderer().deleteOwnProperty(Property.OVERFLOW_X);
628+
}
629+
}
630+
}
605631
return result;
606632
}
607633

0 commit comments

Comments
 (0)