blob: 51faaef84571ba96b12b957f19392f5dffb4f5bd [file] [log] [blame]
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001/*
2 * Copyright (C) 2013 Google Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#include "core/rendering/RenderBlockFlow.h"
33
34#include "core/page/FrameView.h"
35#include "core/rendering/LayoutRepainter.h"
36#include "core/rendering/RenderLayer.h"
37#include "core/rendering/RenderNamedFlowThread.h"
38#include "core/rendering/RenderView.h"
39
40using namespace std;
41
42namespace WebCore {
43
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +010044struct SameSizeAsMarginInfo {
45 uint16_t bitfields;
46 LayoutUnit margins[2];
47};
48
49COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
50
51class MarginInfo {
52 // Collapsing flags for whether we can collapse our margins with our children's margins.
53 bool m_canCollapseWithChildren : 1;
54 bool m_canCollapseMarginBeforeWithChildren : 1;
55 bool m_canCollapseMarginAfterWithChildren : 1;
56
57 // Whether or not we are a quirky container, i.e., do we collapse away top and bottom
58 // margins in our container. Table cells and the body are the common examples. We
59 // also have a custom style property for Safari RSS to deal with TypePad blog articles.
60 bool m_quirkContainer : 1;
61
62 // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block.
63 // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will
64 // always be collapsing with one another. This variable can remain set to true through multiple iterations
65 // as long as we keep encountering self-collapsing blocks.
66 bool m_atBeforeSideOfBlock : 1;
67
68 // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block.
69 bool m_atAfterSideOfBlock : 1;
70
71 // These variables are used to detect quirky margins that we need to collapse away (in table cells
72 // and in the body element).
73 bool m_hasMarginBeforeQuirk : 1;
74 bool m_hasMarginAfterQuirk : 1;
75 bool m_determinedMarginBeforeQuirk : 1;
76
77 bool m_discardMargin : 1;
78
79 // These flags track the previous maximal positive and negative margins.
80 LayoutUnit m_positiveMargin;
81 LayoutUnit m_negativeMargin;
82
83public:
84 MarginInfo(RenderBlockFlow*, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding);
85
86 void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; }
87 void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; }
88 void clearMargin()
89 {
90 m_positiveMargin = 0;
91 m_negativeMargin = 0;
92 }
93 void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; }
94 void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; }
95 void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; }
96 void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; }
97 void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; }
98 void setPositiveMarginIfLarger(LayoutUnit p)
99 {
100 ASSERT(!m_discardMargin);
101 if (p > m_positiveMargin)
102 m_positiveMargin = p;
103 }
104 void setNegativeMarginIfLarger(LayoutUnit n)
105 {
106 ASSERT(!m_discardMargin);
107 if (n > m_negativeMargin)
108 m_negativeMargin = n;
109 }
110
111 void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; }
112 void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; }
113 void setDiscardMargin(bool value) { m_discardMargin = value; }
114
115 bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; }
116 bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; }
117 bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; }
118 bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; }
119 bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; }
120 bool quirkContainer() const { return m_quirkContainer; }
121 bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; }
122 bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; }
123 bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; }
124 LayoutUnit positiveMargin() const { return m_positiveMargin; }
125 LayoutUnit negativeMargin() const { return m_negativeMargin; }
126 bool discardMargin() const { return m_discardMargin; }
127 LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; }
128};
129
130static bool inNormalFlow(RenderBox* child)
131{
132 RenderBlock* curr = child->containingBlock();
133 RenderView* renderView = child->view();
134 while (curr && curr != renderView) {
135 if (curr->hasColumns() || curr->isRenderFlowThread())
136 return true;
137 if (curr->isFloatingOrOutOfFlowPositioned())
138 return false;
139 curr = curr->containingBlock();
140 }
141 return true;
142}
143
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100144RenderBlockFlow::RenderBlockFlow(ContainerNode* node)
145 : RenderBlock(node)
146{
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100147 COMPILE_ASSERT(sizeof(MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100148}
149
150RenderBlockFlow::~RenderBlockFlow()
151{
152}
153
154void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
155{
156 ASSERT(needsLayout());
157
158 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can cause us to come in here. Bail.
159 return;
160
161 if (!relayoutChildren && simplifiedLayout())
162 return;
163
164 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
165
166 if (updateLogicalWidthAndColumnWidth())
167 relayoutChildren = true;
168
169 clearFloats();
170
171 LayoutUnit previousHeight = logicalHeight();
172 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
173 // for consistency with other render classes?
174 setLogicalHeight(0);
175
176 bool pageLogicalHeightChanged = false;
177 bool hasSpecifiedPageLogicalHeight = false;
178 checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight);
179
180 RenderView* renderView = view();
181 RenderStyle* styleToUse = style();
182 LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
183
184 // Regions changing widths can force us to relayout our children.
185 RenderFlowThread* flowThread = flowThreadContainingBlock();
186 if (logicalWidthChangedInRegions(flowThread))
187 relayoutChildren = true;
188 if (updateRegionsAndShapesLogicalSize(flowThread))
189 relayoutChildren = true;
190
191 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
192 // our current maximal positive and negative margins. These values are used when we
193 // are collapsed with adjacent blocks, so for example, if you have block A and B
194 // collapsing together, then you'd take the maximal positive margin from both A and B
195 // and subtract it from the maximal negative margin from both A and B to get the
196 // true collapsed margin. This algorithm is recursive, so when we finish layout()
197 // our block knows its current maximal positive/negative values.
198 //
199 // Start out by setting our margin values to our current margins. Table cells have
200 // no margins, so we don't fill in the values for table cells.
201 bool isCell = isTableCell();
202 if (!isCell) {
203 initMaxMarginValues();
204
205 setHasMarginBeforeQuirk(styleToUse->hasMarginBeforeQuirk());
206 setHasMarginAfterQuirk(styleToUse->hasMarginAfterQuirk());
207 setPaginationStrut(0);
208 }
209
210 SubtreeLayoutScope layoutScope(this);
211
212 LayoutUnit repaintLogicalTop = 0;
213 LayoutUnit repaintLogicalBottom = 0;
214 LayoutUnit maxFloatLogicalBottom = 0;
215 if (!firstChild() && !isAnonymousBlock())
216 setChildrenInline(true);
217 if (childrenInline())
218 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
219 else
220 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom, layoutScope);
221
222 if (frameView()->partialLayout().isStopping()) {
223 statePusher.pop();
224 return;
225 }
226
227 // Expand our intrinsic height to encompass floats.
228 LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
229 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
230 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
231
232 if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
233 return;
234
235 // Calculate our new height.
236 LayoutUnit oldHeight = logicalHeight();
237 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
238
239 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
240 // This ensures the size information is correctly computed for the last auto-height region receiving content.
241 if (isRenderFlowThread())
242 toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge);
243
244 updateLogicalHeight();
245 LayoutUnit newHeight = logicalHeight();
246 if (oldHeight != newHeight) {
247 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
248 // One of our children's floats may have become an overhanging float for us. We need to look for it.
249 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
250 if (child->isRenderBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) {
251 RenderBlock* block = toRenderBlock(child);
252 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
253 addOverhangingFloats(block, false);
254 }
255 }
256 }
257 }
258
259 bool heightChanged = (previousHeight != newHeight);
260 if (heightChanged)
261 relayoutChildren = true;
262
263 layoutPositionedObjects(relayoutChildren || isRoot());
264
265 updateRegionsAndShapesAfterChildLayout(flowThread, heightChanged);
266
267 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
268 computeOverflow(oldClientAfterEdge);
269
270 statePusher.pop();
271
272 fitBorderToLinesIfNeeded();
273
274 if (frameView()->partialLayout().isStopping())
275 return;
276
277 if (renderView->layoutState()->m_pageLogicalHeight)
278 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop()));
279
280 updateLayerTransform();
281
282 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
283 // we overflow or not.
284 updateScrollInfoAfterLayout();
285
286 // FIXME: This repaint logic should be moved into a separate helper function!
287 // Repaint with our new bounds if they are different from our old bounds.
288 bool didFullRepaint = repainter.repaintAfterLayout();
289 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
290 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
291 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
292 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
293 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
294 if (hasOverflowClip()) {
295 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
296 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
297 // layoutInlineChildren should be patched to compute the entire repaint rect.
298 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
299 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
300 }
301
302 LayoutRect repaintRect;
303 if (isHorizontalWritingMode())
304 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
305 else
306 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
307
308 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
309 adjustRectForColumns(repaintRect);
310
311 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
312
313 if (hasOverflowClip()) {
314 // Adjust repaint rect for scroll offset
315 repaintRect.move(-scrolledContentOffset());
316
317 // Don't allow this rect to spill out of our overflow box.
318 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
319 }
320
321 // Make sure the rect is still non-empty after intersecting for overflow above
322 if (!repaintRect.isEmpty()) {
323 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
324 if (hasReflection())
325 repaintRectangle(reflectedRect(repaintRect));
326 }
327 }
328
329 clearNeedsLayout();
330}
331
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100332void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
333{
334 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
335 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
336
337 // The child is a normal flow object. Compute the margins we will use for collapsing now.
338 child->computeAndSetBlockDirectionMargins(this);
339
340 // Try to guess our correct logical top position. In most cases this guess will
341 // be correct. Only if we're wrong (when we compute the real logical top position)
342 // will we have to potentially relayout.
343 LayoutUnit estimateWithoutPagination;
344 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
345
346 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
347 LayoutRect oldRect = child->frameRect();
348 LayoutUnit oldLogicalTop = logicalTopForChild(child);
349
350#if !ASSERT_DISABLED
351 LayoutSize oldLayoutDelta = view()->layoutDelta();
352#endif
353 // Go ahead and position the child as though it didn't collapse with the top.
354 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
355
356 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
357 bool markDescendantsWithFloats = false;
358 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats()) {
359 markDescendantsWithFloats = true;
360 } else if (UNLIKELY(logicalTopEstimate.mightBeSaturated())) {
361 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
362 // very large elements. If it does the comparison with oldLogicalTop might yield a
363 // false negative as adding and removing margins, borders etc from a saturated number
364 // might yield incorrect results. If this is the case always mark for layout.
365 markDescendantsWithFloats = true;
366 } else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
367 // If an element might be affected by the presence of floats, then always mark it for
368 // layout.
369 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
370 if (fb > logicalTopEstimate)
371 markDescendantsWithFloats = true;
372 }
373
374 if (childRenderBlock) {
375 if (markDescendantsWithFloats)
376 childRenderBlock->markAllDescendantsWithFloatsForLayout();
377 if (!child->isWritingModeRoot())
378 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
379 }
380
381 SubtreeLayoutScope layoutScope(child);
382 if (!child->needsLayout())
383 child->markForPaginationRelayoutIfNeeded(layoutScope);
384
385 bool childHadLayout = child->everHadLayout();
386 bool childNeededLayout = child->needsLayout();
387 if (childNeededLayout)
388 child->layout();
389
390 if (frameView()->partialLayout().isStopping())
391 return;
392
393 // Cache if we are at the top of the block right now.
394 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
395
396 // Now determine the correct ypos based off examination of collapsing margin
397 // values.
398 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
399
400 // Now check for clear.
401 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
402
403 bool paginated = view()->layoutState()->isPaginated();
404 if (paginated) {
405 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
406 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
407 }
408
409 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
410
411 // Now we have a final top position. See if it really does end up being different from our estimate.
412 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
413 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
414 if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) {
415 SubtreeLayoutScope layoutScope(child);
416 if (child->shrinkToAvoidFloats()) {
417 // The child's width depends on the line width.
418 // When the child shifts to clear an item, its width can
419 // change (because it has more available line width).
420 // So go ahead and mark the item as dirty.
421 layoutScope.setChildNeedsLayout(child);
422 }
423
424 if (childRenderBlock) {
425 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
426 childRenderBlock->markAllDescendantsWithFloatsForLayout();
427 if (!child->needsLayout())
428 child->markForPaginationRelayoutIfNeeded(layoutScope);
429 }
430
431 // Our guess was wrong. Make the child lay itself out again.
432 child->layoutIfNeeded();
433 }
434
435 // We are no longer at the top of the block if we encounter a non-empty child.
436 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
437 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
438 marginInfo.setAtBeforeSideOfBlock(false);
439
440 // Now place the child in the correct left position
441 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
442
Torne (Richard Coles)06f816c2013-09-26 13:25:12 +0100443 LayoutSize childOffset = child->location() - oldRect.location();
444 relayoutShapeDescendantIfMoved(childRenderBlock, childOffset);
445
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100446 // Update our height now that the child has been placed in the correct position.
447 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
448 if (mustSeparateMarginAfterForChild(child)) {
449 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
450 marginInfo.clearMargin();
451 }
452 // If the child has overhanging floats that intrude into following siblings (or possibly out
453 // of this block), then the parent gets notified of the floats now.
454 if (childRenderBlock && childRenderBlock->containsFloats())
455 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
456
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100457 if (childOffset.width() || childOffset.height()) {
458 view()->addLayoutDelta(childOffset);
459
460 // If the child moved, we have to repaint it as well as any floating/positioned
461 // descendants. An exception is if we need a layout. In this case, we know we're going to
462 // repaint ourselves (and the child) anyway.
463 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
464 child->repaintDuringLayoutIfMoved(oldRect);
465 }
466
467 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
468 child->repaint();
469 child->repaintOverhangingFloats(true);
470 }
471
472 if (paginated) {
473 // Check for an after page/column break.
474 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
475 if (newHeight != height())
476 setLogicalHeight(newHeight);
477 }
478
479 ASSERT(view()->layoutDeltaMatches(oldLayoutDelta));
480}
481
482LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
483{
484 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
485
486 if (estimateWithoutPagination != logicalTopAfterClear) {
487 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
488 // position.
489 setLogicalHeight(logicalTopAfterClear);
490 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
491
492 if (child->shrinkToAvoidFloats()) {
493 // The child's width depends on the line width.
494 // When the child shifts to clear an item, its width can
495 // change (because it has more available line width).
496 // So go ahead and mark the item as dirty.
497 child->setChildNeedsLayout(MarkOnlyThis);
498 }
499
500 SubtreeLayoutScope layoutScope(child);
501
502 if (childRenderBlock) {
503 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
504 childRenderBlock->markAllDescendantsWithFloatsForLayout();
505 if (!child->needsLayout())
506 child->markForPaginationRelayoutIfNeeded(layoutScope);
507 }
508
509 // Our guess was wrong. Make the child lay itself out again.
510 child->layoutIfNeeded();
511 }
512
513 LayoutUnit oldTop = logicalTopAfterClear;
514
515 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
516 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
517
518 if (pageLogicalHeightForOffset(result)) {
519 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
520 LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
521 if (spaceShortage > 0) {
522 // If the child crosses a column boundary, report a break, in case nothing inside it has already
523 // done so. The column balancer needs to know how much it has to stretch the columns to make more
524 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
525 // This should be improved, though, because here we just pretend that the child is
526 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
527 // where there's no child content, border or padding. In other words, we risk stretching more
528 // than necessary.
529 setPageBreak(result, spaceShortage);
530 }
531 }
532
533 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
534 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
535 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
536
537 LayoutUnit paginationStrut = 0;
538 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
539 if (unsplittableAdjustmentDelta)
540 paginationStrut = unsplittableAdjustmentDelta;
541 else if (childRenderBlock && childRenderBlock->paginationStrut())
542 paginationStrut = childRenderBlock->paginationStrut();
543
544 if (paginationStrut) {
545 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
546 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
547 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
548 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
549 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
550 // and pushes to the next page anyway, so not too concerned about it.
551 setPaginationStrut(result + paginationStrut);
552 if (childRenderBlock)
553 childRenderBlock->setPaginationStrut(0);
554 } else {
555 result += paginationStrut;
556 }
557 }
558
559 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
560 setLogicalHeight(logicalHeight() + (result - oldTop));
561
562 // Return the final adjusted logical top.
563 return result;
564}
565
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100566void RenderBlockFlow::clearFloats()
567{
568 if (m_floatingObjects)
569 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
570
571 HashSet<RenderBox*> oldIntrudingFloatSet;
572 if (!childrenInline() && m_floatingObjects) {
573 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
574 FloatingObjectSetIterator end = floatingObjectSet.end();
575 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
576 FloatingObject* floatingObject = *it;
577 if (!floatingObject->isDescendant())
578 oldIntrudingFloatSet.add(floatingObject->renderer());
579 }
580 }
581
582 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
583 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
584 if (m_floatingObjects) {
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100585 m_floatingObjects->clear();
586 }
587 if (!oldIntrudingFloatSet.isEmpty())
588 markAllDescendantsWithFloatsForLayout();
589 return;
590 }
591
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100592 RendererToFloatInfoMap floatMap;
593
594 if (m_floatingObjects) {
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100595 if (childrenInline())
596 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
597 else
598 m_floatingObjects->clear();
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +0100599 }
600
601 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
602 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
603 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
604 if (!parent() || !parent()->isRenderBlock())
605 return;
606
607 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
608 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
609 // to avoid floats.
610 RenderBlock* parentBlock = toRenderBlock(parent());
611 bool parentHasFloats = false;
612 RenderObject* prev = previousSibling();
613 while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
614 if (prev->isFloating())
615 parentHasFloats = true;
616 prev = prev->previousSibling();
617 }
618
619 // First add in floats from the parent.
620 LayoutUnit logicalTopOffset = logicalTop();
621 if (parentHasFloats)
622 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
623
624 LayoutUnit logicalLeftOffset = 0;
625 if (prev) {
626 logicalTopOffset -= toRenderBox(prev)->logicalTop();
627 } else {
628 prev = parentBlock;
629 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
630 }
631
632 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
633 RenderBlock* block = toRenderBlock(prev);
634 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
635 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
636
637 if (childrenInline()) {
638 LayoutUnit changeLogicalTop = LayoutUnit::max();
639 LayoutUnit changeLogicalBottom = LayoutUnit::min();
640 if (m_floatingObjects) {
641 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
642 FloatingObjectSetIterator end = floatingObjectSet.end();
643 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
644 FloatingObject* f = *it;
645 FloatingObject* oldFloatingObject = floatMap.get(f->renderer());
646 LayoutUnit logicalBottom = f->logicalBottom(isHorizontalWritingMode());
647 if (oldFloatingObject) {
648 LayoutUnit oldLogicalBottom = oldFloatingObject->logicalBottom(isHorizontalWritingMode());
649 if (f->logicalWidth(isHorizontalWritingMode()) != oldFloatingObject->logicalWidth(isHorizontalWritingMode()) || f->logicalLeft(isHorizontalWritingMode()) != oldFloatingObject->logicalLeft(isHorizontalWritingMode())) {
650 changeLogicalTop = 0;
651 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
652 } else {
653 if (logicalBottom != oldLogicalBottom) {
654 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
655 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
656 }
657 LayoutUnit logicalTop = f->logicalTop(isHorizontalWritingMode());
658 LayoutUnit oldLogicalTop = oldFloatingObject->logicalTop(isHorizontalWritingMode());
659 if (logicalTop != oldLogicalTop) {
660 changeLogicalTop = min(changeLogicalTop, min(logicalTop, oldLogicalTop));
661 changeLogicalBottom = max(changeLogicalBottom, max(logicalTop, oldLogicalTop));
662 }
663 }
664
665 floatMap.remove(f->renderer());
666 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
667 ASSERT(oldFloatingObject->originatingLine()->renderer() == this);
668 oldFloatingObject->originatingLine()->markDirty();
669 }
670 delete oldFloatingObject;
671 } else {
672 changeLogicalTop = 0;
673 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
674 }
675 }
676 }
677
678 RendererToFloatInfoMap::iterator end = floatMap.end();
679 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
680 FloatingObject* floatingObject = (*it).value;
681 if (!floatingObject->isDescendant()) {
682 changeLogicalTop = 0;
683 changeLogicalBottom = max(changeLogicalBottom, floatingObject->logicalBottom(isHorizontalWritingMode()));
684 }
685 }
686 deleteAllValues(floatMap);
687
688 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
689 } else if (!oldIntrudingFloatSet.isEmpty()) {
690 // If there are previously intruding floats that no longer intrude, then children with floats
691 // should also get layout because they might need their floating object lists cleared.
692 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size()) {
693 markAllDescendantsWithFloatsForLayout();
694 } else {
695 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
696 FloatingObjectSetIterator end = floatingObjectSet.end();
697 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
698 oldIntrudingFloatSet.remove((*it)->renderer());
699 if (!oldIntrudingFloatSet.isEmpty())
700 markAllDescendantsWithFloatsForLayout();
701 }
702 }
703}
704
705void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom, SubtreeLayoutScope& layoutScope)
706{
707 dirtyForLayoutFromPercentageHeightDescendants(layoutScope);
708
709 LayoutUnit beforeEdge = borderBefore() + paddingBefore();
710 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
711
712 setLogicalHeight(beforeEdge);
713
714 // Lay out our hypothetical grid line as though it occurs at the top of the block.
715 if (view()->layoutState()->lineGrid() == this)
716 layoutLineGridBox();
717
718 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
719 MarginInfo marginInfo(this, beforeEdge, afterEdge);
720
721 // Fieldsets need to find their legend and position it inside the border of the object.
722 // The legend then gets skipped during normal layout. The same is true for ruby text.
723 // It doesn't get included in the normal layout process but is instead skipped.
724 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren, layoutScope);
725
726 LayoutUnit previousFloatLogicalBottom = 0;
727 maxFloatLogicalBottom = 0;
728
729 RenderBox* next = firstChildBox();
730
731 while (next) {
732 RenderBox* child = next;
733 next = child->nextSiblingBox();
734
735 if (childToExclude == child)
736 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
737
738 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
739
740 if (child->isOutOfFlowPositioned()) {
741 child->containingBlock()->insertPositionedObject(child);
742 adjustPositionedBlock(child, marginInfo);
743 continue;
744 }
745 if (child->isFloating()) {
746 insertFloatingObject(child);
747 adjustFloatingBlock(marginInfo);
748 continue;
749 }
750
751 // Lay out the child.
752 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
753
754 // If doing a partial layout and the child was the target renderer, early exit here.
755 if (frameView()->partialLayout().checkPartialLayoutComplete(child))
756 break;
757 }
758
759 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
760 // determining the correct collapsed bottom margin information.
761 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
762}
763
Torne (Richard Coles)9bbd2f52013-09-19 22:37:05 +0100764// Our MarginInfo state used when laying out block children.
765MarginInfo::MarginInfo(RenderBlockFlow* blockFlow, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
766 : m_atBeforeSideOfBlock(true)
767 , m_atAfterSideOfBlock(false)
768 , m_hasMarginBeforeQuirk(false)
769 , m_hasMarginAfterQuirk(false)
770 , m_determinedMarginBeforeQuirk(false)
771 , m_discardMargin(false)
772{
773 RenderStyle* blockStyle = blockFlow->style();
774 ASSERT(blockFlow->isRenderView() || blockFlow->parent());
775 m_canCollapseWithChildren = !blockFlow->isRenderView() && !blockFlow->isRoot() && !blockFlow->isOutOfFlowPositioned()
776 && !blockFlow->isFloating() && !blockFlow->isTableCell() && !blockFlow->hasOverflowClip() && !blockFlow->isInlineBlockOrInlineTable()
777 && !blockFlow->isRenderFlowThread() && !blockFlow->isWritingModeRoot() && !blockFlow->parent()->isFlexibleBox()
778 && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
779
780 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
781
782 // If any height other than auto is specified in CSS, then we don't collapse our bottom
783 // margins with our children's margins. To do otherwise would be to risk odd visual
784 // effects when the children overflow out of the parent block and yet still collapse
785 // with it. We also don't collapse if we have any bottom border/padding.
786 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
787 && (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
788
789 m_quirkContainer = blockFlow->isTableCell() || blockFlow->isBody();
790
791 m_discardMargin = m_canCollapseMarginBeforeWithChildren && blockFlow->mustDiscardMarginBefore();
792
793 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mustDiscardMarginBefore()) ? blockFlow->maxPositiveMarginBefore() : LayoutUnit();
794 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mustDiscardMarginBefore()) ? blockFlow->maxNegativeMarginBefore() : LayoutUnit();
795}
796
797RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* child) const
798{
799 LayoutUnit childBeforePositive = 0;
800 LayoutUnit childBeforeNegative = 0;
801 LayoutUnit childAfterPositive = 0;
802 LayoutUnit childAfterNegative = 0;
803
804 LayoutUnit beforeMargin = 0;
805 LayoutUnit afterMargin = 0;
806
807 RenderBlockFlow* childRenderBlockFlow = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0;
808
809 // If the child has the same directionality as we do, then we can just return its
810 // margins in the same direction.
811 if (!child->isWritingModeRoot()) {
812 if (childRenderBlockFlow) {
813 childBeforePositive = childRenderBlockFlow->maxPositiveMarginBefore();
814 childBeforeNegative = childRenderBlockFlow->maxNegativeMarginBefore();
815 childAfterPositive = childRenderBlockFlow->maxPositiveMarginAfter();
816 childAfterNegative = childRenderBlockFlow->maxNegativeMarginAfter();
817 } else {
818 beforeMargin = child->marginBefore();
819 afterMargin = child->marginAfter();
820 }
821 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
822 // The child has a different directionality. If the child is parallel, then it's just
823 // flipped relative to us. We can use the margins for the opposite edges.
824 if (childRenderBlockFlow) {
825 childBeforePositive = childRenderBlockFlow->maxPositiveMarginAfter();
826 childBeforeNegative = childRenderBlockFlow->maxNegativeMarginAfter();
827 childAfterPositive = childRenderBlockFlow->maxPositiveMarginBefore();
828 childAfterNegative = childRenderBlockFlow->maxNegativeMarginBefore();
829 } else {
830 beforeMargin = child->marginAfter();
831 afterMargin = child->marginBefore();
832 }
833 } else {
834 // The child is perpendicular to us, which means its margins don't collapse but are on the
835 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
836 beforeMargin = marginBeforeForChild(child);
837 afterMargin = marginAfterForChild(child);
838 }
839
840 // Resolve uncollapsing margins into their positive/negative buckets.
841 if (beforeMargin) {
842 if (beforeMargin > 0)
843 childBeforePositive = beforeMargin;
844 else
845 childBeforeNegative = -beforeMargin;
846 }
847 if (afterMargin) {
848 if (afterMargin > 0)
849 childAfterPositive = afterMargin;
850 else
851 childAfterNegative = -afterMargin;
852 }
853
854 return RenderBlockFlow::MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
855}
856
857LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
858{
859 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
860 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
861 bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
862
863 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
864 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
865
866 // Get the four margin values for the child and cache them.
867 const RenderBlockFlow::MarginValues childMargins = marginValuesForChild(child);
868
869 // Get our max pos and neg top margins.
870 LayoutUnit posTop = childMargins.positiveMarginBefore();
871 LayoutUnit negTop = childMargins.negativeMarginBefore();
872
873 // For self-collapsing blocks, collapse our bottom margins into our
874 // top to get new posTop and negTop values.
875 if (childIsSelfCollapsing) {
876 posTop = max(posTop, childMargins.positiveMarginAfter());
877 negTop = max(negTop, childMargins.negativeMarginAfter());
878 }
879
880 // See if the top margin is quirky. We only care if this child has
881 // margins that will collapse with us.
882 bool topQuirk = hasMarginBeforeQuirk(child);
883
884 if (marginInfo.canCollapseWithMarginBefore()) {
885 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
886 // This child is collapsing with the top of the
887 // block. If it has larger margin values, then we need to update
888 // our own maximal values.
889 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
890 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
891
892 // The minute any of the margins involved isn't a quirk, don't
893 // collapse it away, even if the margin is smaller (www.webreference.com
894 // has an example of this, a <dt> with 0.8em author-specified inside
895 // a <dl> inside a <td>.
896 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
897 setHasMarginBeforeQuirk(false);
898 marginInfo.setDeterminedMarginBeforeQuirk(true);
899 }
900
901 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore()) {
902 // We have no top margin and our top child has a quirky margin.
903 // We will pick up this quirky margin and pass it through.
904 // This deals with the <td><div><p> case.
905 // Don't do this for a block that split two inlines though. You do
906 // still apply margins in this case.
907 setHasMarginBeforeQuirk(true);
908 }
909 } else {
910 // The before margin of the container will also discard all the margins it is collapsing with.
911 setMustDiscardMarginBefore();
912 }
913 }
914
915 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
916 if (childDiscardMarginBefore) {
917 marginInfo.setDiscardMargin(true);
918 marginInfo.clearMargin();
919 }
920
921 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
922 marginInfo.setHasMarginBeforeQuirk(topQuirk);
923
924 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
925 LayoutUnit logicalTop = beforeCollapseLogicalTop;
926 if (childIsSelfCollapsing) {
927 // For a self collapsing block both the before and after margins get discarded. The block doesn't contribute anything to the height of the block.
928 // Also, the child's top position equals the logical height of the container.
929 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
930 // This child has no height. We need to compute our
931 // position before we collapse the child's margins together,
932 // so that we can get an accurate position for the zero-height block.
933 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
934 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
935 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
936
937 // Now collapse the child's margins together, which means examining our
938 // bottom margin values as well.
939 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
940 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
941
942 if (!marginInfo.canCollapseWithMarginBefore()) {
943 // We need to make sure that the position of the self-collapsing block
944 // is correct, since it could have overflowing content
945 // that needs to be positioned correctly (e.g., a block that
946 // had a specified height of 0 but that actually had subcontent).
947 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
948 }
949 }
950 } else {
951 if (mustSeparateMarginBeforeForChild(child)) {
952 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
953 // If we are at the before side of the block and we collapse, ignore the computed margin
954 // and just add the child margin to the container height. This will correctly position
955 // the child inside the container.
956 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
957 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
958 logicalTop = logicalHeight();
959 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
960 || (!marginInfo.canCollapseMarginBeforeWithChildren()
961 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
962 // We're collapsing with a previous sibling's margins and not
963 // with the top of the block.
964 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
965 logicalTop = logicalHeight();
966 }
967
968 marginInfo.setDiscardMargin(childDiscardMarginAfter);
969
970 if (!marginInfo.discardMargin()) {
971 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
972 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
973 } else {
974 marginInfo.clearMargin();
975 }
976
977 if (marginInfo.margin())
978 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
979 }
980
981 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
982 // collapsed into the page edge.
983 LayoutState* layoutState = view()->layoutState();
984 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
985 && hasNextPage(beforeCollapseLogicalTop)) {
986 LayoutUnit oldLogicalTop = logicalTop;
987 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
988 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
989 }
990
991 // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
992 // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
993 // or clear it anyway, so don't worry about any floating children it may contain.
994 LayoutUnit oldLogicalHeight = logicalHeight();
995 setLogicalHeight(logicalTop);
996 RenderObject* prev = child->previousSibling();
997 if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
998 RenderBlockFlow* blockFlow = toRenderBlockFlow(prev);
999 if (blockFlow->containsFloats() && !blockFlow->avoidsFloats() && (blockFlow->logicalTop() + blockFlow->lowestFloatLogicalBottom()) > logicalTop)
1000 addOverhangingFloats(blockFlow, false);
1001 }
1002 setLogicalHeight(oldLogicalHeight);
1003
1004 return logicalTop;
1005}
1006
1007void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1008{
1009 bool isHorizontal = isHorizontalWritingMode();
1010 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1011
1012 LayoutUnit logicalTop = logicalHeight();
1013 updateStaticInlinePositionForChild(child, logicalTop);
1014
1015 if (!marginInfo.canCollapseWithMarginBefore()) {
1016 // Positioned blocks don't collapse margins, so add the margin provided by
1017 // the container now. The child's own margin is added later when calculating its logical top.
1018 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
1019 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
1020 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
1021 }
1022
1023 RenderLayer* childLayer = child->layer();
1024 if (childLayer->staticBlockPosition() != logicalTop) {
1025 childLayer->setStaticBlockPosition(logicalTop);
1026 if (hasStaticBlockPosition)
1027 child->setChildNeedsLayout(MarkOnlyThis);
1028 }
1029}
1030
1031LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
1032{
1033 LayoutUnit heightIncrease = getClearDelta(child, yPos);
1034 if (!heightIncrease)
1035 return yPos;
1036
1037 if (child->isSelfCollapsingBlock()) {
1038 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
1039
1040 // For self-collapsing blocks that clear, they can still collapse their
1041 // margins with following siblings. Reset the current margins to represent
1042 // the self-collapsing block's margins only.
1043 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
1044 if (!childDiscardMargin) {
1045 RenderBlockFlow::MarginValues childMargins = marginValuesForChild(child);
1046 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1047 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1048 } else {
1049 marginInfo.clearMargin();
1050 }
1051 marginInfo.setDiscardMargin(childDiscardMargin);
1052
1053 // CSS2.1 states:
1054 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
1055 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
1056 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
1057 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
1058 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
1059 for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
1060 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
1061 wouldCollapseMarginsWithParent = false;
1062 }
1063 if (wouldCollapseMarginsWithParent)
1064 marginInfo.setCanCollapseMarginAfterWithChildren(false);
1065
1066 // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top"
1067 // Move the top of the child box to the bottom of the float ignoring the child's top margin.
1068 LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
1069 setLogicalHeight(child->logicalTop() - collapsedMargin);
1070 // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
1071 heightIncrease -= max(LayoutUnit(), collapsedMargin);
1072 } else {
1073 // Increase our height by the amount we had to clear.
1074 setLogicalHeight(logicalHeight() + heightIncrease);
1075 }
1076
1077 if (marginInfo.canCollapseWithMarginBefore()) {
1078 // We can no longer collapse with the top of the block since a clear
1079 // occurred. The empty blocks collapse into the cleared block.
1080 // FIXME: This isn't quite correct. Need clarification for what to do
1081 // if the height the cleared block is offset by is smaller than the
1082 // margins involved.
1083 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1084 marginInfo.setAtBeforeSideOfBlock(false);
1085
1086 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
1087 setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
1088 }
1089
1090 LayoutUnit logicalTop = yPos + heightIncrease;
1091 // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it
1092 // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now.
1093 if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
1094 toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop);
1095
1096 return logicalTop;
1097}
1098
1099void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1100{
1101 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1102 // Update the after side margin of the container to discard if the after margin of the last child also discards and we collapse with it.
1103 // Don't update the max margin values because we won't need them anyway.
1104 if (marginInfo.discardMargin()) {
1105 setMustDiscardMarginAfter();
1106 return;
1107 }
1108
1109 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1110 // with our children.
1111 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1112
1113 if (!marginInfo.hasMarginAfterQuirk())
1114 setHasMarginAfterQuirk(false);
1115
1116 if (marginInfo.hasMarginAfterQuirk() && !marginAfter()) {
1117 // We have no bottom margin and our last child has a quirky margin.
1118 // We will pick up this quirky margin and pass it through.
1119 // This deals with the <td><div><p> case.
1120 setHasMarginAfterQuirk(true);
1121 }
1122 }
1123}
1124
1125void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
1126{
1127 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
1128 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
1129 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1130 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
1131 return;
1132
1133 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
1134 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
1135 if (child->style()->marginBeforeCollapse() == MDISCARD) {
1136 positiveMarginBefore = 0;
1137 negativeMarginBefore = 0;
1138 discardMarginBefore = true;
1139 return;
1140 }
1141
1142 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
1143 positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
1144 negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
1145
1146 if (!child->isRenderBlockFlow())
1147 return;
1148
1149 RenderBlockFlow* childBlockFlow = toRenderBlockFlow(child);
1150 if (childBlockFlow->childrenInline() || childBlockFlow->isWritingModeRoot())
1151 return;
1152
1153 MarginInfo childMarginInfo(childBlockFlow, childBlockFlow->borderBefore() + childBlockFlow->paddingBefore(), childBlockFlow->borderAfter() + childBlockFlow->paddingAfter());
1154 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
1155 return;
1156
1157 RenderBox* grandchildBox = childBlockFlow->firstChildBox();
1158 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
1159 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
1160 break;
1161 }
1162
1163 // Give up if there is clearance on the box, since it probably won't collapse into us.
1164 if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
1165 return;
1166
1167 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
1168 if (grandchildBox->needsLayout()) {
1169 grandchildBox->computeAndSetBlockDirectionMargins(this);
1170 if (grandchildBox->isRenderBlock()) {
1171 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
1172 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
1173 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
1174 }
1175 }
1176
1177 // Collapse the margin of the grandchild box with our own to produce an estimate.
1178 childBlockFlow->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1179}
1180
1181LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
1182{
1183 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1184 // relayout if there are intruding floats.
1185 LayoutUnit logicalTopEstimate = logicalHeight();
1186 if (!marginInfo.canCollapseWithMarginBefore()) {
1187 LayoutUnit positiveMarginBefore = 0;
1188 LayoutUnit negativeMarginBefore = 0;
1189 bool discardMarginBefore = false;
1190 if (child->selfNeedsLayout()) {
1191 // Try to do a basic estimation of how the collapse is going to go.
1192 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1193 } else {
1194 // Use the cached collapsed margin values from a previous layout. Most of the time they
1195 // will be right.
1196 RenderBlockFlow::MarginValues marginValues = marginValuesForChild(child);
1197 positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
1198 negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
1199 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1200 }
1201
1202 // Collapse the result with our current margins.
1203 if (!discardMarginBefore)
1204 logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
1205 }
1206
1207 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1208 // page.
1209 LayoutState* layoutState = view()->layoutState();
1210 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1211 && hasNextPage(logicalHeight()))
1212 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1213
1214 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1215
1216 estimateWithoutPagination = logicalTopEstimate;
1217
1218 if (layoutState->isPaginated()) {
1219 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1220 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1221
1222 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1223 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1224
1225 if (!child->selfNeedsLayout() && child->isRenderBlock())
1226 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1227 }
1228
1229 return logicalTopEstimate;
1230}
1231
1232void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
1233{
1234 // The float should be positioned taking into account the bottom margin
1235 // of the previous flow. We add that margin into the height, get the
1236 // float positioned properly, and then subtract the margin out of the
1237 // height again. In the case of self-collapsing blocks, we always just
1238 // use the top margins, since the self-collapsing block collapsed its
1239 // own bottom margin into its top margin.
1240 //
1241 // Note also that the previous flow may collapse its margin into the top of
1242 // our block. If this is the case, then we do not add the margin in to our
1243 // height when computing the position of the float. This condition can be tested
1244 // for by simply calling canCollapseWithMarginBefore. See
1245 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1246 // an example of this scenario.
1247 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1248 setLogicalHeight(logicalHeight() + marginOffset);
1249 positionNewFloats();
1250 setLogicalHeight(logicalHeight() - marginOffset);
1251}
1252
1253void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1254{
1255 marginInfo.setAtAfterSideOfBlock(true);
1256
1257 // If we can't collapse with children then go ahead and add in the bottom margin.
1258 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1259 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1260 setLogicalHeight(logicalHeight() + marginInfo.margin());
1261
1262 // Now add in our bottom border/padding.
1263 setLogicalHeight(logicalHeight() + afterSide);
1264
1265 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1266 // If this happens, ensure that the computed height is increased to the minimal height.
1267 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1268
1269 // Update our bottom collapsed margin info.
1270 setCollapsedBottomMargin(marginInfo);
1271}
1272
1273void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1274{
1275 if (style()->marginBeforeCollapse() == MDISCARD) {
1276 ASSERT(value);
1277 return;
1278 }
1279
1280 if (!m_rareData && !value)
1281 return;
1282
1283 if (!m_rareData)
1284 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1285
1286 m_rareData->m_discardMarginBefore = value;
1287}
1288
1289void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1290{
1291 if (style()->marginAfterCollapse() == MDISCARD) {
1292 ASSERT(value);
1293 return;
1294 }
1295
1296 if (!m_rareData && !value)
1297 return;
1298
1299 if (!m_rareData)
1300 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1301
1302 m_rareData->m_discardMarginAfter = value;
1303}
1304
1305bool RenderBlockFlow::mustDiscardMarginBefore() const
1306{
1307 return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
1308}
1309
1310bool RenderBlockFlow::mustDiscardMarginAfter() const
1311{
1312 return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
1313}
1314
1315bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox* child) const
1316{
1317 ASSERT(!child->selfNeedsLayout());
1318 if (!child->isWritingModeRoot())
1319 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
1320 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1321 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
1322
1323 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1324 // In case the boxes are perpendicular we assume the property is not specified.
1325 return false;
1326}
1327
1328bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox* child) const
1329{
1330 ASSERT(!child->selfNeedsLayout());
1331 if (!child->isWritingModeRoot())
1332 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
1333 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1334 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
1335
1336 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1337 return false;
1338}
1339
1340void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1341{
1342 if (!m_rareData) {
1343 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(this))
1344 return;
1345 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1346 }
1347 m_rareData->m_margins.setPositiveMarginBefore(pos);
1348 m_rareData->m_margins.setNegativeMarginBefore(neg);
1349}
1350
1351void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1352{
1353 if (!m_rareData) {
1354 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(this))
1355 return;
1356 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1357 }
1358 m_rareData->m_margins.setPositiveMarginAfter(pos);
1359 m_rareData->m_margins.setNegativeMarginAfter(neg);
1360}
1361
1362bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox* child) const
1363{
1364 ASSERT(!child->selfNeedsLayout());
1365 const RenderStyle* childStyle = child->style();
1366 if (!child->isWritingModeRoot())
1367 return childStyle->marginBeforeCollapse() == MSEPARATE;
1368 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1369 return childStyle->marginAfterCollapse() == MSEPARATE;
1370
1371 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1372 return false;
1373}
1374
1375bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) const
1376{
1377 ASSERT(!child->selfNeedsLayout());
1378 const RenderStyle* childStyle = child->style();
1379 if (!child->isWritingModeRoot())
1380 return childStyle->marginAfterCollapse() == MSEPARATE;
1381 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1382 return childStyle->marginBeforeCollapse() == MSEPARATE;
1383
1384 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1385 return false;
1386}
1387
1388LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
1389{
1390 // FIXME: Add page break checking here when we support printing.
1391 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
1392 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1393 RenderFlowThread* flowThread = flowThreadContainingBlock();
1394 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1395 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
1396 || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
1397 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1398 if (checkColumnBreaks)
1399 view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
1400 if (checkRegionBreaks) {
1401 LayoutUnit offsetBreakAdjustment = 0;
1402 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
1403 return logicalOffset + offsetBreakAdjustment;
1404 }
1405 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1406 }
1407 return logicalOffset;
1408}
1409
1410LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
1411{
1412 // FIXME: Add page break checking here when we support printing.
1413 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
1414 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1415 RenderFlowThread* flowThread = flowThreadContainingBlock();
1416 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1417 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
1418 || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
1419 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1420 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1421
1422 // So our margin doesn't participate in the next collapsing steps.
1423 marginInfo.clearMargin();
1424
1425 if (checkColumnBreaks)
1426 view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
1427 if (checkRegionBreaks) {
1428 LayoutUnit offsetBreakAdjustment = 0;
1429 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
1430 return logicalOffset + marginOffset + offsetBreakAdjustment;
1431 }
1432 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1433 }
1434 return logicalOffset;
1435}
1436
Torne (Richard Coles)8abfc582013-09-12 12:10:38 +01001437} // namespace WebCore