@@ -40,11 +40,9 @@ This file is part of the iText (R) project.
40
40
*/
41
41
public class MulticolRenderer extends AbstractRenderer {
42
42
43
- private static final int MAX_RELAYOUT_COUNT = 4 ;
44
43
private static final float ZERO_DELTA = 0.0001F ;
45
-
44
+ private ColumnHeightCalculator heightCalculator ;
46
45
private BlockRenderer elementRenderer ;
47
- private final HeightEnhancer heightCalculator = new HeightEnhancer ();
48
46
private int columnCount ;
49
47
private float columnWidth ;
50
48
private float approximateHeight ;
@@ -56,6 +54,16 @@ public class MulticolRenderer extends AbstractRenderer {
56
54
*/
57
55
public MulticolRenderer (MulticolContainer modelElement ) {
58
56
super (modelElement );
57
+ setHeightCalculator (new LayoutInInfiniteHeightCalculator ());
58
+ }
59
+
60
+ /**
61
+ * Sets the height calculator to be used by this renderer.
62
+ *
63
+ * @param heightCalculator the height calculator to be used by this renderer.
64
+ */
65
+ public final void setHeightCalculator (ColumnHeightCalculator heightCalculator ) {
66
+ this .heightCalculator = heightCalculator ;
59
67
}
60
68
61
69
/**
@@ -78,15 +86,8 @@ public LayoutResult layout(LayoutContext layoutContext) {
78
86
}
79
87
//It is necessary to set parent, because during relayout elementRenderer's parent gets cleaned up
80
88
elementRenderer .setParent (this );
81
- LayoutResult prelayoutResult = elementRenderer .layout (
82
- new LayoutContext (new LayoutArea (1 , new Rectangle (columnWidth , INF ))));
83
- if (prelayoutResult .getStatus () != LayoutResult .FULL ) {
84
- return new LayoutResult (LayoutResult .NOTHING , null , null , this , prelayoutResult .getCauseOfNothing ());
85
- }
86
-
87
- approximateHeight = prelayoutResult .getOccupiedArea ().getBBox ().getHeight () / columnCount ;
88
89
89
- MulticolLayoutResult layoutResult = balanceContentAndLayoutColumns (layoutContext , actualBBox );
90
+ final MulticolLayoutResult layoutResult = layoutInColumns (layoutContext , actualBBox );
90
91
91
92
if (layoutResult .getSplitRenderers ().isEmpty ()) {
92
93
return new LayoutResult (LayoutResult .NOTHING , null , null , this , layoutResult .getCauseOfNothing ());
@@ -112,6 +113,18 @@ public IRenderer getNextRenderer() {
112
113
return new MulticolRenderer ((MulticolContainer ) modelElement );
113
114
}
114
115
116
+ protected MulticolLayoutResult layoutInColumns (LayoutContext layoutContext , Rectangle actualBBox ) {
117
+ LayoutResult inifiniteHeighOneColumnLayoutResult = elementRenderer .layout (
118
+ new LayoutContext (new LayoutArea (1 , new Rectangle (columnWidth , INF ))));
119
+ if (inifiniteHeighOneColumnLayoutResult .getStatus () != LayoutResult .FULL ) {
120
+ final MulticolLayoutResult result = new MulticolLayoutResult ();
121
+ result .setCauseOfNothing (inifiniteHeighOneColumnLayoutResult .getCauseOfNothing ());
122
+ return result ;
123
+ }
124
+
125
+ approximateHeight = inifiniteHeighOneColumnLayoutResult .getOccupiedArea ().getBBox ().getHeight () / columnCount ;
126
+ return balanceContentAndLayoutColumns (layoutContext , actualBBox );
127
+ }
115
128
116
129
/**
117
130
* Creates a split renderer.
@@ -162,10 +175,11 @@ private float safelyRetrieveFloatProperty(int property) {
162
175
return 0F ;
163
176
}
164
177
165
- private MulticolLayoutResult balanceContentAndLayoutColumns (LayoutContext prelayoutContext , Rectangle actualBbox ) {
178
+ private MulticolLayoutResult balanceContentAndLayoutColumns (LayoutContext prelayoutContext ,
179
+ Rectangle actualBbox ) {
166
180
float additionalHeightPerIteration ;
167
181
MulticolLayoutResult result = new MulticolLayoutResult ();
168
- int counter = MAX_RELAYOUT_COUNT + 1 ;
182
+ int counter = heightCalculator . maxAmountOfRelayouts () + 1 ;
169
183
float maxHeight = actualBbox .getHeight ();
170
184
boolean isLastLayout = false ;
171
185
while (counter -- > 0 ) {
@@ -177,7 +191,7 @@ private MulticolLayoutResult balanceContentAndLayoutColumns(LayoutContext prelay
177
191
if (result .getOverflowRenderer () == null || isLastLayout ) {
178
192
return result ;
179
193
}
180
- additionalHeightPerIteration = heightCalculator .apply (this , result ).floatValue ();
194
+ additionalHeightPerIteration = heightCalculator .getAdditionalHeightOfEachColumn (this , result ).floatValue ();
181
195
if (Math .abs (additionalHeightPerIteration ) <= ZERO_DELTA ) {
182
196
return result ;
183
197
}
@@ -217,7 +231,8 @@ private BlockRenderer getElementsRenderer() {
217
231
return (BlockRenderer ) getChildRenderers ().get (0 );
218
232
}
219
233
220
- private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer (LayoutContext preLayoutContext , Rectangle actualBBox ) {
234
+ private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer (LayoutContext preLayoutContext ,
235
+ Rectangle actualBBox ) {
221
236
MulticolLayoutResult result = new MulticolLayoutResult ();
222
237
IRenderer renderer = elementRenderer ;
223
238
for (int i = 0 ; i < columnCount && renderer != null ; i ++) {
@@ -244,17 +259,37 @@ private MulticolLayoutResult layoutColumnsAndReturnOverflowRenderer(LayoutContex
244
259
}
245
260
renderer = tempResultColumn .getOverflowRenderer ();
246
261
}
247
- result .setOverflowRenderer ((AbstractRenderer )renderer );
262
+ result .setOverflowRenderer ((AbstractRenderer ) renderer );
248
263
return result ;
249
264
}
250
265
251
266
267
+ /**
268
+ * Interface which used for additional height calculation
269
+ */
270
+ public interface ColumnHeightCalculator {
271
+
272
+
273
+ /**
274
+ * Calculate height, by which current height of given {@code MulticolRenderer} should be increased so
275
+ * {@code MulticolLayoutResult#getOverflowRenderer} could be lauded
276
+ *
277
+ * @param renderer multicol renderer for which height needs to be increased
278
+ * @param result result of one iteration of {@code MulticolRenderer} layouting
279
+ *
280
+ * @return height by which current height of given multicol renderer should be increased
281
+ */
282
+ Float getAdditionalHeightOfEachColumn (MulticolRenderer renderer , MulticolLayoutResult result );
283
+
284
+ int maxAmountOfRelayouts ();
285
+ }
286
+
252
287
/**
253
288
* Represents result of one iteration of MulticolRenderer layouting
254
289
* It contains split renderers which were lauded on a given height and overflow renderer
255
290
* for which height should be increased, so it can be lauded.
256
291
*/
257
- private static class MulticolLayoutResult {
292
+ public static class MulticolLayoutResult {
258
293
private List <IRenderer > splitRenderers = new ArrayList <>();
259
294
private AbstractRenderer overflowRenderer ;
260
295
private IRenderer causeOfNothing ;
@@ -267,34 +302,25 @@ public AbstractRenderer getOverflowRenderer() {
267
302
return overflowRenderer ;
268
303
}
269
304
270
- public IRenderer getCauseOfNothing () {
271
- return causeOfNothing ;
272
- }
273
-
274
305
public void setOverflowRenderer (AbstractRenderer overflowRenderer ) {
275
306
this .overflowRenderer = overflowRenderer ;
276
307
}
277
308
309
+ public IRenderer getCauseOfNothing () {
310
+ return causeOfNothing ;
311
+ }
312
+
278
313
public void setCauseOfNothing (IRenderer causeOfNothing ) {
279
314
this .causeOfNothing = causeOfNothing ;
280
315
}
281
316
}
282
317
283
- /**
284
- * Class which used for additional height calculation
285
- */
286
- private static class HeightEnhancer {
318
+ public static class LayoutInInfiniteHeightCalculator implements ColumnHeightCalculator {
319
+
320
+ protected int maxRelayoutCount = 4 ;
287
321
private Float height = null ;
288
322
289
- /**
290
- * Calculate height, by which current height of given {@code MulticolRenderer} should be increased so
291
- * {@code MulticolLayoutResult#getOverflowRenderer} could be lauded
292
- *
293
- * @param renderer multicol renderer for which height needs to be increased
294
- * @param result result of one iteration of {@code MulticolRenderer} layouting
295
- * @return height by which current height of given multicol renderer should be increased
296
- */
297
- public Float apply (MulticolRenderer renderer , MulticolLayoutResult result ) {
323
+ public Float getAdditionalHeightOfEachColumn (MulticolRenderer renderer , MulticolLayoutResult result ) {
298
324
if (height != null ) {
299
325
return height ;
300
326
}
@@ -303,8 +329,16 @@ public Float apply(MulticolRenderer renderer, MulticolLayoutResult result) {
303
329
}
304
330
LayoutResult overflowResult = result .getOverflowRenderer ().layout (
305
331
new LayoutContext (new LayoutArea (1 , new Rectangle (renderer .columnWidth , INF ))));
306
- height = overflowResult .getOccupiedArea ().getBBox ().getHeight () / MAX_RELAYOUT_COUNT ;
332
+ height = overflowResult .getOccupiedArea ().getBBox ().getHeight () / maxRelayoutCount ;
307
333
return height ;
308
334
}
335
+
336
+ /**
337
+ * @return maximum amount of relayouts which can be done by this height enhancer
338
+ */
339
+ @ Override
340
+ public int maxAmountOfRelayouts () {
341
+ return maxRelayoutCount ;
342
+ }
309
343
}
310
344
}
0 commit comments