@@ -41,7 +41,7 @@ This file is part of the iText (R) project.
41
41
/**
42
42
* Represents a renderer for a grid.
43
43
*/
44
- public class GridContainerRenderer extends DivRenderer {
44
+ public class GridContainerRenderer extends BlockRenderer {
45
45
private boolean isFirstLayout = true ;
46
46
47
47
/**
@@ -110,7 +110,33 @@ public LayoutResult layout(LayoutContext layoutContext) {
110
110
public void addChild (IRenderer renderer ) {
111
111
renderer .setProperty (Property .OVERFLOW_X , OverflowPropertyValue .VISIBLE );
112
112
renderer .setProperty (Property .OVERFLOW_Y , OverflowPropertyValue .VISIBLE );
113
- super .addChild (renderer );
113
+ renderer .setProperty (Property .COLLAPSING_MARGINS , determineCollapsingMargins (renderer ));
114
+
115
+ GridItemRenderer itemRenderer = new GridItemRenderer ();
116
+ itemRenderer .setProperty (Property .COLLAPSING_MARGINS , Boolean .FALSE );
117
+ itemRenderer .addChild (renderer );
118
+
119
+ super .addChild (itemRenderer );
120
+ }
121
+
122
+ /**
123
+ * Calculates collapsing margins value. It's based on browser behavior.
124
+ * Always returning true somehow also almost works.
125
+ */
126
+ private static Boolean determineCollapsingMargins (IRenderer renderer ) {
127
+ IRenderer currentRenderer = renderer ;
128
+ while (!currentRenderer .getChildRenderers ().isEmpty ()) {
129
+ if (currentRenderer .getChildRenderers ().size () > 1 ) {
130
+ return Boolean .TRUE ;
131
+ } else {
132
+ currentRenderer = currentRenderer .getChildRenderers ().get (0 );
133
+ }
134
+ }
135
+ if (currentRenderer instanceof TableRenderer ) {
136
+ return Boolean .TRUE ;
137
+ }
138
+
139
+ return Boolean .FALSE ;
114
140
}
115
141
116
142
private AbstractRenderer createSplitRenderer (List <IRenderer > children ) {
@@ -126,12 +152,13 @@ private AbstractRenderer createSplitRenderer(List<IRenderer> children) {
126
152
}
127
153
128
154
private AbstractRenderer createOverflowRenderer (List <IRenderer > children ) {
129
- // TODO DEVSIX-8340 - We put the original amount of rows into overflow container.
130
155
GridContainerRenderer overflowRenderer = (GridContainerRenderer ) getNextRenderer ();
131
156
overflowRenderer .isFirstLayout = false ;
132
157
overflowRenderer .parent = parent ;
133
158
overflowRenderer .modelElement = modelElement ;
134
159
overflowRenderer .addAllProperties (getOwnProperties ());
160
+ overflowRenderer .setProperty (Property .GRID_TEMPLATE_ROWS , null );
161
+ overflowRenderer .setProperty (Property .GRID_AUTO_ROWS , null );
135
162
overflowRenderer .setChildRenderers (children );
136
163
ContinuousContainer .clearPropertiesFromOverFlowRenderer (overflowRenderer );
137
164
return overflowRenderer ;
@@ -141,54 +168,91 @@ private AbstractRenderer createOverflowRenderer(List<IRenderer> children) {
141
168
private GridLayoutResult layoutGrid (LayoutContext layoutContext , Rectangle actualBBox , Grid grid ) {
142
169
GridLayoutResult layoutResult = new GridLayoutResult ();
143
170
171
+ int notLayoutedRow = grid .getNumberOfRows ();
144
172
for (GridCell cell : grid .getUniqueGridCells (Grid .GridOrder .ROW )) {
145
173
// Calculate cell layout context by getting actual x and y on parent layout area for it
146
174
LayoutContext cellContext = getCellLayoutContext (layoutContext , actualBBox , cell );
147
-
175
+ Rectangle cellBBox = cellContext . getArea (). getBBox ();
148
176
IRenderer cellToRender = cell .getValue ();
149
- cellToRender .setProperty (Property .COLLAPSING_MARGINS , Boolean .FALSE );
150
177
151
178
// Now set the height for the individual items
152
179
// We know cell height upfront and this way we tell the element what it can occupy
153
- Rectangle cellBBox = cellContext .getArea ().getBBox ();
154
- if (!cellToRender .hasProperty (Property .HEIGHT )) {
155
- final Rectangle rectangleWithoutBordersMarginsPaddings = cellBBox .clone ();
156
- if (cellToRender instanceof AbstractRenderer ) {
157
- final AbstractRenderer abstractCellRenderer = ((AbstractRenderer ) cellToRender );
158
- // We subtract margins/borders/paddings because we should take into account that
159
- // borders/paddings/margins should also fit into a cell.
160
- if (AbstractRenderer .isBorderBoxSizing (cellToRender )) {
161
- abstractCellRenderer .applyMargins (rectangleWithoutBordersMarginsPaddings , false );
162
- } else {
163
- abstractCellRenderer .applyMarginsBordersPaddings (rectangleWithoutBordersMarginsPaddings , false );
164
- }
165
- }
180
+ final float itemHeight = ((GridItemRenderer ) cellToRender ).calculateHeight (cellBBox .getHeight ());
166
181
167
- cellToRender .setProperty (Property .HEIGHT ,
168
- UnitValue .createPointValue (rectangleWithoutBordersMarginsPaddings .getHeight ()));
169
- }
182
+ cellToRender .setProperty (Property .HEIGHT , UnitValue .createPointValue (itemHeight ));
170
183
171
184
// Adjust cell BBox to the remaining part of the layout bbox
172
185
// This way we can layout elements partially
173
186
cellBBox .setHeight (cellBBox .getTop () - actualBBox .getBottom ())
174
187
.setY (actualBBox .getY ());
175
188
189
+ cellToRender .setProperty (Property .FILL_AVAILABLE_AREA , Boolean .TRUE );
176
190
LayoutResult cellResult = cellToRender .layout (cellContext );
191
+ notLayoutedRow = Math .min (notLayoutedRow , processLayoutResult (layoutResult , cell , cellResult ));
192
+ }
177
193
178
- if (cellResult .getStatus () == LayoutResult .NOTHING ) {
179
- layoutResult .getOverflowRenderers ().add (cellToRender );
180
- layoutResult .getCauseOfNothing ().add (cellResult .getCauseOfNothing ());
181
- } else {
182
- // PARTIAL + FULL result handling
183
- layoutResult .getSplitRenderers ().add (cellToRender );
184
- if (cellResult .getStatus () == LayoutResult .PARTIAL ) {
185
- layoutResult .getOverflowRenderers ().add (cellResult .getOverflowRenderer ());
186
- }
194
+ for (IRenderer overflowRenderer : layoutResult .getOverflowRenderers ()) {
195
+ if (overflowRenderer .<Integer >getProperty (Property .GRID_ROW_START ) != null ) {
196
+ overflowRenderer .setProperty (Property .GRID_ROW_START ,
197
+ (int ) overflowRenderer .<Integer >getProperty (Property .GRID_ROW_START ) - notLayoutedRow );
198
+ overflowRenderer .setProperty (Property .GRID_ROW_END ,
199
+ (int ) overflowRenderer .<Integer >getProperty (Property .GRID_ROW_END ) - notLayoutedRow );
187
200
}
188
201
}
202
+
189
203
return layoutResult ;
190
204
}
191
205
206
+ private static int processLayoutResult (GridLayoutResult layoutResult , GridCell cell , LayoutResult cellResult ) {
207
+ IRenderer cellToRenderer = cell .getValue ();
208
+ if (cellResult .getStatus () == LayoutResult .NOTHING ) {
209
+ cellToRenderer .setProperty (Property .GRID_COLUMN_START , cell .getColumnStart () + 1 );
210
+ cellToRenderer .setProperty (Property .GRID_COLUMN_END , cell .getColumnEnd () + 1 );
211
+ cellToRenderer .setProperty (Property .GRID_ROW_START , cell .getRowStart () + 1 );
212
+ cellToRenderer .setProperty (Property .GRID_ROW_END , cell .getRowEnd () + 1 );
213
+ layoutResult .getOverflowRenderers ().add (cellToRenderer );
214
+ layoutResult .getCauseOfNothing ().add (cellResult .getCauseOfNothing ());
215
+
216
+ return cell .getRowStart ();
217
+ }
218
+
219
+ // PARTIAL + FULL result handling
220
+ layoutResult .getSplitRenderers ().add (cellToRenderer );
221
+ if (cellResult .getStatus () == LayoutResult .PARTIAL ) {
222
+ IRenderer overflowRenderer = cellResult .getOverflowRenderer ();
223
+ overflowRenderer .setProperty (Property .GRID_COLUMN_START , cell .getColumnStart () + 1 );
224
+ overflowRenderer .setProperty (Property .GRID_COLUMN_END , cell .getColumnEnd () + 1 );
225
+ int rowStart = cell .getRowStart () + 1 ;
226
+ int rowEnd = cell .getRowEnd () + 1 ;
227
+ layoutResult .getOverflowRenderers ().add (overflowRenderer );
228
+ // Now let's find out where we split exactly
229
+ float accumulatedRowSize = 0 ;
230
+ final float layoutedHeight = cellResult .getOccupiedArea ().getBBox ().getHeight ();
231
+ int notLayoutedRow = rowStart - 1 ;
232
+ for (int i = 0 ; i < cell .getRowSizes ().length ; ++i ) {
233
+ accumulatedRowSize += cell .getRowSizes ()[i ];
234
+ if (accumulatedRowSize < layoutedHeight ) {
235
+ ++rowStart ;
236
+ ++notLayoutedRow ;
237
+ } else {
238
+ break ;
239
+ }
240
+ }
241
+
242
+ // We don't know what to do if rowStart is equal or more than rowEnd
243
+ // Let's not try to guess by just take the 1st available space in a column
244
+ // by leaving nulls for grid-row-start/end
245
+ if (rowEnd > rowStart ) {
246
+ overflowRenderer .setProperty (Property .GRID_ROW_START , rowStart );
247
+ overflowRenderer .setProperty (Property .GRID_ROW_END , rowEnd );
248
+ }
249
+
250
+ return notLayoutedRow ;
251
+ }
252
+
253
+ return Integer .MAX_VALUE ;
254
+ }
255
+
192
256
//Init cell layout context based on a parent context and calculated cell layout area from grid sizing algorithm.
193
257
private static LayoutContext getCellLayoutContext (LayoutContext layoutContext , Rectangle actualBBox , GridCell cell ) {
194
258
LayoutArea tempArea = layoutContext .getArea ().clone ();
@@ -209,10 +273,12 @@ private static LayoutContext getCellLayoutContext(LayoutContext layoutContext, R
209
273
private LayoutArea calculateContainerOccupiedArea (LayoutContext layoutContext , Grid grid , boolean isFull ) {
210
274
LayoutArea area = layoutContext .getArea ().clone ();
211
275
final float totalHeight = updateOccupiedHeight (grid .getHeight (), isFull );
212
- area .getBBox ().setHeight (totalHeight );
213
- final Rectangle initialBBox = layoutContext .getArea ().getBBox ();
214
- area .getBBox ().setY (initialBBox .getY () + initialBBox .getHeight () - area .getBBox ().getHeight ());
215
- recalculateHeightAndWidthAfterLayout (area .getBBox (), isFull );
276
+ if (totalHeight < area .getBBox ().getHeight () || isFull ) {
277
+ area .getBBox ().setHeight (totalHeight );
278
+ final Rectangle initialBBox = layoutContext .getArea ().getBBox ();
279
+ area .getBBox ().setY (initialBBox .getY () + initialBBox .getHeight () - area .getBBox ().getHeight ());
280
+ recalculateHeightAndWidthAfterLayout (area .getBBox (), isFull );
281
+ }
216
282
return area ;
217
283
}
218
284
@@ -300,7 +366,6 @@ private static Grid constructGrid(GridContainerRenderer renderer, Rectangle actu
300
366
return grid ;
301
367
}
302
368
303
-
304
369
private final static class GridLayoutResult {
305
370
private final List <IRenderer > splitRenderers = new ArrayList <>();
306
371
private final List <IRenderer > overflowRenderers = new ArrayList <>();
0 commit comments