@@ -46,6 +46,7 @@ public class MulticolRenderer extends AbstractRenderer {
4646 private int columnCount ;
4747 private float columnWidth ;
4848 private float approximateHeight ;
49+ private Float heightFromProperties ;
4950
5051 /**
5152 * Creates a DivRenderer from its corresponding layout object.
@@ -72,11 +73,14 @@ public final void setHeightCalculator(ColumnHeightCalculator heightCalculator) {
7273 @ Override
7374 public LayoutResult layout (LayoutContext layoutContext ) {
7475 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 );
7680 applyPaddings (actualBBox , false );
7781 applyBorderBox (actualBBox , false );
7882 applyMargins (actualBBox , false );
79-
83+ heightFromProperties = determineHeight ( actualBBox );
8084 columnCount = (int ) this .<Integer >getProperty (Property .COLUMN_COUNT );
8185 columnWidth = actualBBox .getWidth () / columnCount ;
8286 if (this .elementRenderer == null ) {
@@ -164,6 +168,45 @@ protected AbstractRenderer createOverflowRenderer(IRenderer overflowedContentRen
164168 return overflowRenderer ;
165169 }
166170
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+
167210 private float safelyRetrieveFloatProperty (int property ) {
168211 final Object value = this .<Object >getProperty (property );
169212 if (value instanceof UnitValue ) {
@@ -187,19 +230,44 @@ private MulticolLayoutResult balanceContentAndLayoutColumns(LayoutContext prelay
187230 isLastLayout = true ;
188231 approximateHeight = maxHeight ;
189232 }
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+
191247 if (result .getOverflowRenderer () == null || isLastLayout ) {
248+ clearOverFlowRendererIfNeeded (result );
192249 return result ;
193250 }
194251 additionalHeightPerIteration = heightCalculator .getAdditionalHeightOfEachColumn (this , result ).floatValue ();
195252 if (Math .abs (additionalHeightPerIteration ) <= ZERO_DELTA ) {
253+ clearOverFlowRendererIfNeeded (result );
196254 return result ;
197255 }
198256 approximateHeight += additionalHeightPerIteration ;
257+ clearOverFlowRendererIfNeeded (result );
199258 }
200259 return result ;
201260 }
202261
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+
203271 private LayoutArea calculateContainerOccupiedArea (LayoutContext layoutContext , boolean isFull ) {
204272 LayoutArea area = layoutContext .getArea ().clone ();
205273 float totalHeight = approximateHeight ;
@@ -221,6 +289,7 @@ private LayoutArea calculateContainerOccupiedArea(LayoutContext layoutContext, b
221289 area .getBBox ().setHeight (totalHeight );
222290 final Rectangle initialBBox = layoutContext .getArea ().getBBox ();
223291 area .getBBox ().setY (initialBBox .getY () + initialBBox .getHeight () - area .getBBox ().getHeight ());
292+ recalculateHeightWidthAfterLayouting (area .getBBox ());
224293 return area ;
225294 }
226295
@@ -232,16 +301,16 @@ private BlockRenderer getElementsRenderer() {
232301 }
233302
234303 private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer (LayoutContext preLayoutContext ,
235- Rectangle actualBBox ) {
304+ Rectangle actualBBox , float workingHeight ) {
236305 MulticolLayoutResult result = new MulticolLayoutResult ();
237306 IRenderer renderer = elementRenderer ;
307+
238308 for (int i = 0 ; i < columnCount && renderer != null ; i ++) {
239309 LayoutArea tempArea = preLayoutContext .getArea ().clone ();
240310 tempArea .getBBox ().setWidth (columnWidth );
241- tempArea .getBBox ().setHeight (approximateHeight );
311+ tempArea .getBBox ().setHeight (workingHeight );
242312 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 ());
245314
246315 LayoutContext columnContext = new LayoutContext (tempArea , preLayoutContext .getMarginsCollapseInfo (),
247316 preLayoutContext .getFloatRendererAreas (), preLayoutContext .isClippedHeight ());
@@ -252,6 +321,7 @@ private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer(LayoutContex
252321 result .setCauseOfNothing (tempResultColumn .getCauseOfNothing ());
253322 return result ;
254323 }
324+
255325 if (tempResultColumn .getSplitRenderer () == null ) {
256326 result .getSplitRenderers ().add (renderer );
257327 } else {
0 commit comments