@@ -46,6 +46,7 @@ public class MulticolRenderer extends AbstractRenderer {
46
46
private int columnCount ;
47
47
private float columnWidth ;
48
48
private float approximateHeight ;
49
+ private Float heightFromProperties ;
49
50
50
51
/**
51
52
* Creates a DivRenderer from its corresponding layout object.
@@ -72,11 +73,14 @@ public final void setHeightCalculator(ColumnHeightCalculator heightCalculator) {
72
73
@ Override
73
74
public LayoutResult layout (LayoutContext layoutContext ) {
74
75
this .setProperty (Property .TREAT_AS_CONTINUOUS_CONTAINER , Boolean .TRUE );
75
- final Rectangle actualBBox = layoutContext .getArea ().getBBox ().clone ();
76
+
77
+ Rectangle actualBBox = layoutContext .getArea ().getBBox ().clone ();
78
+ float originalWidth = actualBBox .getWidth ();
79
+ applyWidth (actualBBox , originalWidth );
76
80
applyPaddings (actualBBox , false );
77
81
applyBorderBox (actualBBox , false );
78
82
applyMargins (actualBBox , false );
79
-
83
+ heightFromProperties = determineHeight ( actualBBox );
80
84
columnCount = (int ) this .<Integer >getProperty (Property .COLUMN_COUNT );
81
85
columnWidth = actualBBox .getWidth () / columnCount ;
82
86
if (this .elementRenderer == null ) {
@@ -164,6 +168,45 @@ protected AbstractRenderer createOverflowRenderer(IRenderer overflowedContentRen
164
168
return overflowRenderer ;
165
169
}
166
170
171
+ private void applyWidth (Rectangle parentBbox , float originalWidth ) {
172
+ final Float blockWidth = retrieveWidth (originalWidth );
173
+ if (blockWidth != null ) {
174
+ parentBbox .setWidth ((float ) blockWidth );
175
+ } else {
176
+ final Float minWidth = retrieveMinWidth (parentBbox .getWidth ());
177
+ if (minWidth != null && minWidth > parentBbox .getWidth ()) {
178
+ parentBbox .setWidth ((float ) minWidth );
179
+ }
180
+ }
181
+ }
182
+
183
+ private Float determineHeight (Rectangle parentBBox ) {
184
+ Float height = retrieveHeight ();
185
+ final Float minHeight = retrieveMinHeight ();
186
+ final Float maxHeight = retrieveMaxHeight ();
187
+ if (height == null || (minHeight != null && height < minHeight )) {
188
+ if ((minHeight != null ) && parentBBox .getHeight () < minHeight ) {
189
+ height = minHeight ;
190
+ }
191
+ }
192
+ if (height != null && maxHeight != null && height > maxHeight ) {
193
+ height = maxHeight ;
194
+ }
195
+ return height ;
196
+ }
197
+
198
+
199
+ private void recalculateHeightWidthAfterLayouting (Rectangle parentBBox ) {
200
+ Float height = determineHeight (parentBBox );
201
+ if (height != null ) {
202
+ float heightDelta = parentBBox .getHeight () - (float ) height ;
203
+ parentBBox .moveUp (heightDelta );
204
+ parentBBox .setHeight ((float ) height );
205
+ }
206
+ applyWidth (parentBBox , parentBBox .getWidth ());
207
+ }
208
+
209
+
167
210
private float safelyRetrieveFloatProperty (int property ) {
168
211
final Object value = this .<Object >getProperty (property );
169
212
if (value instanceof UnitValue ) {
@@ -187,19 +230,44 @@ private MulticolLayoutResult balanceContentAndLayoutColumns(LayoutContext prelay
187
230
isLastLayout = true ;
188
231
approximateHeight = maxHeight ;
189
232
}
190
- result = layoutColumnsAndReturnOverflowRenderer (prelayoutContext , actualBbox );
233
+ // height calcultion
234
+ float workingHeight = approximateHeight ;
235
+ if (heightFromProperties != null ) {
236
+ workingHeight = Math .min ((float ) heightFromProperties , (float ) approximateHeight );
237
+ workingHeight -= safelyRetrieveFloatProperty (Property .PADDING_TOP );
238
+ workingHeight -= safelyRetrieveFloatProperty (Property .PADDING_BOTTOM );
239
+ workingHeight -= safelyRetrieveFloatProperty (Property .BORDER_TOP );
240
+ workingHeight -= safelyRetrieveFloatProperty (Property .BORDER_BOTTOM );
241
+ workingHeight -= safelyRetrieveFloatProperty (Property .BORDER ) * 2 ;
242
+ workingHeight -= safelyRetrieveFloatProperty (Property .MARGIN_TOP );
243
+ workingHeight -= safelyRetrieveFloatProperty (Property .MARGIN_BOTTOM );
244
+ }
245
+ result = layoutColumnsAndReturnOverflowRenderer (prelayoutContext , actualBbox , workingHeight );
246
+
191
247
if (result .getOverflowRenderer () == null || isLastLayout ) {
248
+ clearOverFlowRendererIfNeeded (result );
192
249
return result ;
193
250
}
194
251
additionalHeightPerIteration = heightCalculator .getAdditionalHeightOfEachColumn (this , result ).floatValue ();
195
252
if (Math .abs (additionalHeightPerIteration ) <= ZERO_DELTA ) {
253
+ clearOverFlowRendererIfNeeded (result );
196
254
return result ;
197
255
}
198
256
approximateHeight += additionalHeightPerIteration ;
257
+ clearOverFlowRendererIfNeeded (result );
199
258
}
200
259
return result ;
201
260
}
202
261
262
+ private void clearOverFlowRendererIfNeeded (MulticolLayoutResult result ) {
263
+ //When we have a height set on the element but the content doesn't fit in the given height
264
+ //we don't want to render the overflow renderer as it would be rendered in the next area
265
+ if (heightFromProperties != null && heightFromProperties < approximateHeight ) {
266
+ result .setOverflowRenderer (null );
267
+ }
268
+ }
269
+
270
+
203
271
private LayoutArea calculateContainerOccupiedArea (LayoutContext layoutContext , boolean isFull ) {
204
272
LayoutArea area = layoutContext .getArea ().clone ();
205
273
float totalHeight = approximateHeight ;
@@ -221,6 +289,7 @@ private LayoutArea calculateContainerOccupiedArea(LayoutContext layoutContext, b
221
289
area .getBBox ().setHeight (totalHeight );
222
290
final Rectangle initialBBox = layoutContext .getArea ().getBBox ();
223
291
area .getBBox ().setY (initialBBox .getY () + initialBBox .getHeight () - area .getBBox ().getHeight ());
292
+ recalculateHeightWidthAfterLayouting (area .getBBox ());
224
293
return area ;
225
294
}
226
295
@@ -232,16 +301,16 @@ private BlockRenderer getElementsRenderer() {
232
301
}
233
302
234
303
private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer (LayoutContext preLayoutContext ,
235
- Rectangle actualBBox ) {
304
+ Rectangle actualBBox , float workingHeight ) {
236
305
MulticolLayoutResult result = new MulticolLayoutResult ();
237
306
IRenderer renderer = elementRenderer ;
307
+
238
308
for (int i = 0 ; i < columnCount && renderer != null ; i ++) {
239
309
LayoutArea tempArea = preLayoutContext .getArea ().clone ();
240
310
tempArea .getBBox ().setWidth (columnWidth );
241
- tempArea .getBBox ().setHeight (approximateHeight );
311
+ tempArea .getBBox ().setHeight (workingHeight );
242
312
tempArea .getBBox ().setX (actualBBox .getX () + columnWidth * i );
243
- tempArea .getBBox ().setY (actualBBox .getY () + actualBBox .getHeight () - tempArea .getBBox ()
244
- .getHeight ());
313
+ tempArea .getBBox ().setY (actualBBox .getY () + actualBBox .getHeight () - tempArea .getBBox ().getHeight ());
245
314
246
315
LayoutContext columnContext = new LayoutContext (tempArea , preLayoutContext .getMarginsCollapseInfo (),
247
316
preLayoutContext .getFloatRendererAreas (), preLayoutContext .isClippedHeight ());
@@ -252,6 +321,7 @@ private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer(LayoutContex
252
321
result .setCauseOfNothing (tempResultColumn .getCauseOfNothing ());
253
322
return result ;
254
323
}
324
+
255
325
if (tempResultColumn .getSplitRenderer () == null ) {
256
326
result .getSplitRenderers ().add (renderer );
257
327
} else {
0 commit comments