blob: f66ac8ff4245e8ca0888963d951eec929313e3d6 [file] [log] [blame]
hyatt@apple.com5388e672013-09-06 20:54:47 +00001/*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003-2013 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24#include "config.h"
25#include "RenderBlockFlow.h"
26
bjonesbe@adobe.com67478092013-09-09 22:18:17 +000027#include "FloatingObjects.h"
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000028#include "HitTestLocation.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000029#include "LayoutRepainter.h"
30#include "RenderFlowThread.h"
31#include "RenderLayer.h"
32#include "RenderView.h"
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000033#include "VerticalPositionCache.h"
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +000034
35using namespace std;
36
hyatt@apple.com5388e672013-09-06 20:54:47 +000037namespace WebCore {
38
bjonesbe@adobe.com24199752013-10-08 23:20:42 +000039bool RenderBlock::s_canPropagateFloatIntoSibling = false;
40
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000041struct SameSizeAsMarginInfo {
42 uint32_t bitfields : 16;
43 LayoutUnit margins[2];
44};
45
46COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
akling@apple.com42e10632013-10-14 17:55:52 +000047COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +000048
49// Our MarginInfo state used when laying out block children.
50RenderBlockFlow::MarginInfo::MarginInfo(RenderBlockFlow* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
51 : m_atBeforeSideOfBlock(true)
52 , m_atAfterSideOfBlock(false)
53 , m_hasMarginBeforeQuirk(false)
54 , m_hasMarginAfterQuirk(false)
55 , m_determinedMarginBeforeQuirk(false)
56 , m_discardMargin(false)
57{
58 RenderStyle* blockStyle = block->style();
59 ASSERT(block->isRenderView() || block->parent());
60 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
61 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
62 && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox()
63 && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan();
64
65 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
66
67 // If any height other than auto is specified in CSS, then we don't collapse our bottom
68 // margins with our children's margins. To do otherwise would be to risk odd visual
69 // effects when the children overflow out of the parent block and yet still collapse
70 // with it. We also don't collapse if we have any bottom border/padding.
71 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding
72 && (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
73
74 m_quirkContainer = block->isTableCell() || block->isBody();
75
76 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore();
77
78 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit();
79 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit();
80}
81
akling@apple.com42e10632013-10-14 17:55:52 +000082RenderBlockFlow::RenderBlockFlow(Element& element)
antti@apple.come7f589e2013-10-01 22:29:34 +000083 : RenderBlock(element, RenderBlockFlowFlag)
hyatt@apple.com5388e672013-09-06 20:54:47 +000084{
akling@apple.com42e10632013-10-14 17:55:52 +000085}
86
87RenderBlockFlow::RenderBlockFlow(Document& document)
88 : RenderBlock(document, RenderBlockFlowFlag)
89{
hyatt@apple.com5388e672013-09-06 20:54:47 +000090}
91
92RenderBlockFlow::~RenderBlockFlow()
93{
94}
95
hyatt@apple.com3cd5c772013-09-27 18:22:50 +000096void RenderBlockFlow::willBeDestroyed()
97{
98 if (lineGridBox())
99 lineGridBox()->destroy(renderArena());
100
101 RenderBlock::willBeDestroyed();
102}
103
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000104void RenderBlockFlow::clearFloats()
105{
106 if (m_floatingObjects)
107 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
108
109 HashSet<RenderBox*> oldIntrudingFloatSet;
110 if (!childrenInline() && m_floatingObjects) {
111 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000112 auto end = floatingObjectSet.end();
113 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
114 FloatingObject* floatingObject = it->get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000115 if (!floatingObject->isDescendant())
darin@apple.com7cad7042013-09-24 05:53:55 +0000116 oldIntrudingFloatSet.add(&floatingObject->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000117 }
118 }
119
120 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
121 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
122 if (m_floatingObjects) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000123 m_floatingObjects->clear();
124 }
125 if (!oldIntrudingFloatSet.isEmpty())
126 markAllDescendantsWithFloatsForLayout();
127 return;
128 }
129
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000130 RendererToFloatInfoMap floatMap;
131
132 if (m_floatingObjects) {
bjonesbe@adobe.com0434768a2013-09-16 22:01:38 +0000133 if (childrenInline())
134 m_floatingObjects->moveAllToFloatInfoMap(floatMap);
135 else
136 m_floatingObjects->clear();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000137 }
138
139 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
140 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
141 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000142 if (!parent() || !parent()->isRenderBlockFlow())
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000143 return;
144
145 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
146 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
147 // to avoid floats.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000148 RenderBlockFlow* parentBlock = toRenderBlockFlow(parent());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000149 bool parentHasFloats = false;
150 RenderObject* prev = previousSibling();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000151 while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlockFlow() || toRenderBlockFlow(prev)->avoidsFloats())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000152 if (prev->isFloating())
153 parentHasFloats = true;
154 prev = prev->previousSibling();
155 }
156
157 // First add in floats from the parent.
158 LayoutUnit logicalTopOffset = logicalTop();
159 if (parentHasFloats)
160 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
161
162 LayoutUnit logicalLeftOffset = 0;
163 if (prev)
164 logicalTopOffset -= toRenderBox(prev)->logicalTop();
165 else {
166 prev = parentBlock;
167 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
168 }
169
170 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000171 RenderBlockFlow* block = toRenderBlockFlow(prev);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000172 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
173 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
174
175 if (childrenInline()) {
176 LayoutUnit changeLogicalTop = LayoutUnit::max();
177 LayoutUnit changeLogicalBottom = LayoutUnit::min();
178 if (m_floatingObjects) {
179 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000180 auto end = floatingObjectSet.end();
181 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000182 FloatingObject* floatingObject = it->get();
183 std::unique_ptr<FloatingObject> oldFloatingObject = floatMap.take(&floatingObject->renderer());
184 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000185 if (oldFloatingObject) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000186 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject.get());
187 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject.get()) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject.get())) {
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000188 changeLogicalTop = 0;
189 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
190 } else {
191 if (logicalBottom != oldLogicalBottom) {
192 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
193 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
194 }
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000195 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
196 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject.get());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000197 if (logicalTop != oldLogicalTop) {
198 changeLogicalTop = min(changeLogicalTop, min(logicalTop, oldLogicalTop));
199 changeLogicalBottom = max(changeLogicalBottom, max(logicalTop, oldLogicalTop));
200 }
201 }
202
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000203 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) {
204 ASSERT(&oldFloatingObject->originatingLine()->renderer() == this);
205 oldFloatingObject->originatingLine()->markDirty();
206 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000207 } else {
208 changeLogicalTop = 0;
209 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
210 }
211 }
212 }
213
darin@apple.com7cad7042013-09-24 05:53:55 +0000214 auto end = floatMap.end();
215 for (auto it = floatMap.begin(); it != end; ++it) {
216 FloatingObject* floatingObject = it->value.get();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000217 if (!floatingObject->isDescendant()) {
218 changeLogicalTop = 0;
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +0000219 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000220 }
221 }
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000222
223 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
224 } else if (!oldIntrudingFloatSet.isEmpty()) {
225 // If there are previously intruding floats that no longer intrude, then children with floats
226 // should also get layout because they might need their floating object lists cleared.
227 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
228 markAllDescendantsWithFloatsForLayout();
229 else {
230 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
darin@apple.com7cad7042013-09-24 05:53:55 +0000231 auto end = floatingObjectSet.end();
232 for (auto it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
233 oldIntrudingFloatSet.remove(&(*it)->renderer());
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000234 if (!oldIntrudingFloatSet.isEmpty())
235 markAllDescendantsWithFloatsForLayout();
236 }
237 }
238}
239
240void RenderBlockFlow::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
241{
242 ASSERT(needsLayout());
243
244 if (!relayoutChildren && simplifiedLayout())
245 return;
246
247 LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
248
249 if (updateLogicalWidthAndColumnWidth())
250 relayoutChildren = true;
251
252 clearFloats();
253
254 LayoutUnit previousHeight = logicalHeight();
255 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(),
256 // for consistency with other render classes?
257 setLogicalHeight(0);
258
259 bool pageLogicalHeightChanged = false;
260 bool hasSpecifiedPageLogicalHeight = false;
261 checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight);
262
263 RenderStyle* styleToUse = style();
264 LayoutStateMaintainer statePusher(&view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
265
266 // Regions changing widths can force us to relayout our children.
267 RenderFlowThread* flowThread = flowThreadContainingBlock();
268 if (logicalWidthChangedInRegions(flowThread))
269 relayoutChildren = true;
270 if (updateShapesBeforeBlockLayout())
271 relayoutChildren = true;
272
273 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
274 // our current maximal positive and negative margins. These values are used when we
275 // are collapsed with adjacent blocks, so for example, if you have block A and B
276 // collapsing together, then you'd take the maximal positive margin from both A and B
277 // and subtract it from the maximal negative margin from both A and B to get the
278 // true collapsed margin. This algorithm is recursive, so when we finish layout()
279 // our block knows its current maximal positive/negative values.
280 //
281 // Start out by setting our margin values to our current margins. Table cells have
282 // no margins, so we don't fill in the values for table cells.
283 bool isCell = isTableCell();
284 if (!isCell) {
285 initMaxMarginValues();
286
287 setHasMarginBeforeQuirk(styleToUse->hasMarginBeforeQuirk());
288 setHasMarginAfterQuirk(styleToUse->hasMarginAfterQuirk());
289 setPaginationStrut(0);
290 }
291
292 LayoutUnit repaintLogicalTop = 0;
293 LayoutUnit repaintLogicalBottom = 0;
294 LayoutUnit maxFloatLogicalBottom = 0;
295 if (!firstChild() && !isAnonymousBlock())
296 setChildrenInline(true);
297 if (childrenInline())
298 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
299 else
300 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
301
302 // Expand our intrinsic height to encompass floats.
303 LayoutUnit toAdd = borderAndPaddingAfter() + scrollbarLogicalHeight();
304 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
305 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
306
307 if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher) || relayoutToAvoidWidows(statePusher)) {
308 ASSERT(!shouldBreakAtLineToAvoidWidow());
309 return;
310 }
311
312 // Calculate our new height.
313 LayoutUnit oldHeight = logicalHeight();
314 LayoutUnit oldClientAfterEdge = clientLogicalBottom();
315
316 // Before updating the final size of the flow thread make sure a forced break is applied after the content.
317 // This ensures the size information is correctly computed for the last auto-height region receiving content.
318 if (isRenderFlowThread())
319 toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge);
320
321 updateLogicalHeight();
322 LayoutUnit newHeight = logicalHeight();
323 if (oldHeight != newHeight) {
324 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
325 // One of our children's floats may have become an overhanging float for us. We need to look for it.
326 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
327 if (child->isRenderBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000328 RenderBlockFlow* block = toRenderBlockFlow(child);
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000329 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
330 addOverhangingFloats(block, false);
331 }
332 }
333 }
334 }
335
336 bool heightChanged = (previousHeight != newHeight);
337 if (heightChanged)
338 relayoutChildren = true;
339
340 layoutPositionedObjects(relayoutChildren || isRoot());
341
342 updateShapesAfterBlockLayout(heightChanged);
343
344 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
345 computeOverflow(oldClientAfterEdge);
346
347 statePusher.pop();
348
349 fitBorderToLinesIfNeeded();
350
351 if (view().layoutState()->m_pageLogicalHeight)
352 setPageLogicalOffset(view().layoutState()->pageLogicalOffset(this, logicalTop()));
353
354 updateLayerTransform();
355
356 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
357 // we overflow or not.
358 updateScrollInfoAfterLayout();
359
360 // FIXME: This repaint logic should be moved into a separate helper function!
361 // Repaint with our new bounds if they are different from our old bounds.
362 bool didFullRepaint = repainter.repaintAfterLayout();
363 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
364 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
365 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
366 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
367 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
368 if (hasOverflowClip()) {
369 // 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.
370 // 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.
371 // layoutInlineChildren should be patched to compute the entire repaint rect.
372 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
373 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
374 }
375
376 LayoutRect repaintRect;
377 if (isHorizontalWritingMode())
378 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
379 else
380 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
381
382 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
383 adjustRectForColumns(repaintRect);
384
385 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
386
387 if (hasOverflowClip()) {
388 // Adjust repaint rect for scroll offset
389 repaintRect.move(-scrolledContentOffset());
390
391 // Don't allow this rect to spill out of our overflow box.
392 repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
393 }
394
395 // Make sure the rect is still non-empty after intersecting for overflow above
396 if (!repaintRect.isEmpty()) {
397 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
398 if (hasReflection())
399 repaintRectangle(reflectedRect(repaintRect));
400 }
401 }
402
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000403 clearNeedsLayout();
hyatt@apple.comc9b1aef2013-09-09 20:23:21 +0000404}
405
406void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
407{
408 dirtyForLayoutFromPercentageHeightDescendants();
409
410 LayoutUnit beforeEdge = borderAndPaddingBefore();
411 LayoutUnit afterEdge = borderAndPaddingAfter() + scrollbarLogicalHeight();
412
413 setLogicalHeight(beforeEdge);
414
415 // Lay out our hypothetical grid line as though it occurs at the top of the block.
416 if (view().layoutState()->lineGrid() == this)
417 layoutLineGridBox();
418
419 // The margin struct caches all our current margin collapsing state.
420 MarginInfo marginInfo(this, beforeEdge, afterEdge);
421
422 // Fieldsets need to find their legend and position it inside the border of the object.
423 // The legend then gets skipped during normal layout. The same is true for ruby text.
424 // It doesn't get included in the normal layout process but is instead skipped.
425 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
426
427 LayoutUnit previousFloatLogicalBottom = 0;
428 maxFloatLogicalBottom = 0;
429
430 RenderBox* next = firstChildBox();
431
432 while (next) {
433 RenderBox* child = next;
434 next = child->nextSiblingBox();
435
436 if (childToExclude == child)
437 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
438
439 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child);
440
441 if (child->isOutOfFlowPositioned()) {
442 child->containingBlock()->insertPositionedObject(child);
443 adjustPositionedBlock(child, marginInfo);
444 continue;
445 }
446 if (child->isFloating()) {
447 insertFloatingObject(child);
448 adjustFloatingBlock(marginInfo);
449 continue;
450 }
451
452 // Lay out the child.
453 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
454 }
455
456 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
457 // determining the correct collapsed bottom margin information.
458 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
459}
460
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000461void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
462{
463 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
464 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
465
466 // The child is a normal flow object. Compute the margins we will use for collapsing now.
467 child->computeAndSetBlockDirectionMargins(this);
468
469 // Try to guess our correct logical top position. In most cases this guess will
470 // be correct. Only if we're wrong (when we compute the real logical top position)
471 // will we have to potentially relayout.
472 LayoutUnit estimateWithoutPagination;
473 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
474
475 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
476 LayoutRect oldRect = child->frameRect();
477 LayoutUnit oldLogicalTop = logicalTopForChild(child);
478
479#if !ASSERT_DISABLED
480 LayoutSize oldLayoutDelta = view().layoutDelta();
481#endif
482 // Go ahead and position the child as though it didn't collapse with the top.
483 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
484 estimateRegionRangeForBoxChild(child);
485
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000486 RenderBlockFlow* childBlockFlow = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0;
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000487 bool markDescendantsWithFloats = false;
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000488 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childBlockFlow && childBlockFlow->containsFloats())
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000489 markDescendantsWithFloats = true;
490#if ENABLE(SUBPIXEL_LAYOUT)
491 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated()))
492 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for
493 // very large elements. If it does the comparison with oldLogicalTop might yield a
494 // false negative as adding and removing margins, borders etc from a saturated number
495 // might yield incorrect results. If this is the case always mark for layout.
496 markDescendantsWithFloats = true;
497#endif
498 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
499 // If an element might be affected by the presence of floats, then always mark it for
500 // layout.
501 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
502 if (fb > logicalTopEstimate)
503 markDescendantsWithFloats = true;
504 }
505
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000506 if (childBlockFlow) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000507 if (markDescendantsWithFloats)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000508 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000509 if (!child->isWritingModeRoot())
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000510 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childBlockFlow->lowestFloatLogicalBottom());
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000511 }
512
513 if (!child->needsLayout())
514 child->markForPaginationRelayoutIfNeeded();
515
516 bool childHadLayout = child->everHadLayout();
517 bool childNeededLayout = child->needsLayout();
518 if (childNeededLayout)
519 child->layout();
520
521 // Cache if we are at the top of the block right now.
522 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
523
524 // Now determine the correct ypos based off examination of collapsing margin
525 // values.
526 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
527
528 // Now check for clear.
529 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
530
531 bool paginated = view().layoutState()->isPaginated();
532 if (paginated)
533 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
534 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
535
536 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
537
538 // Now we have a final top position. See if it really does end up being different from our estimate.
539 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
540 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000541 if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childBlockFlow && childBlockFlow->shouldBreakAtLineToAvoidWidow())) {
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000542 if (child->shrinkToAvoidFloats()) {
543 // The child's width depends on the line width.
544 // When the child shifts to clear an item, its width can
545 // change (because it has more available line width).
546 // So go ahead and mark the item as dirty.
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000547 child->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000548 }
549
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000550 if (childBlockFlow) {
551 if (!child->avoidsFloats() && childBlockFlow->containsFloats())
552 childBlockFlow->markAllDescendantsWithFloatsForLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000553 if (!child->needsLayout())
554 child->markForPaginationRelayoutIfNeeded();
555 }
556
557 // Our guess was wrong. Make the child lay itself out again.
558 child->layoutIfNeeded();
559 }
560
561 if (updateRegionRangeForBoxChild(child)) {
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000562 child->setNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000563 child->layoutIfNeeded();
564 }
565
566 // We are no longer at the top of the block if we encounter a non-empty child.
567 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
568 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
569 marginInfo.setAtBeforeSideOfBlock(false);
570
571 // Now place the child in the correct left position
572 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta);
573
574 LayoutSize childOffset = child->location() - oldRect.location();
575#if ENABLE(CSS_SHAPES)
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000576 relayoutShapeDescendantIfMoved(child->isRenderBlock() ? toRenderBlock(child) : 0, childOffset);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000577#endif
578
579 // Update our height now that the child has been placed in the correct position.
580 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
581 if (mustSeparateMarginAfterForChild(child)) {
582 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
583 marginInfo.clearMargin();
584 }
585 // If the child has overhanging floats that intrude into following siblings (or possibly out
586 // of this block), then the parent gets notified of the floats now.
hyatt@apple.com2ea59882013-09-17 16:41:42 +0000587 if (childBlockFlow && childBlockFlow->containsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000588 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlockFlow(child), !childNeededLayout));
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000589
590 if (childOffset.width() || childOffset.height()) {
591 view().addLayoutDelta(childOffset);
592
593 // If the child moved, we have to repaint it as well as any floating/positioned
594 // descendants. An exception is if we need a layout. In this case, we know we're going to
595 // repaint ourselves (and the child) anyway.
596 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
597 child->repaintDuringLayoutIfMoved(oldRect);
598 }
599
600 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
601 child->repaint();
602 child->repaintOverhangingFloats(true);
603 }
604
605 if (paginated) {
606 // Check for an after page/column break.
607 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
608 if (newHeight != height())
609 setLogicalHeight(newHeight);
610 }
611
612 ASSERT(view().layoutDeltaMatches(oldLayoutDelta));
613}
614
615void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
616{
617 bool isHorizontal = isHorizontalWritingMode();
618 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
619
620 LayoutUnit logicalTop = logicalHeight();
621 updateStaticInlinePositionForChild(child, logicalTop);
622
623 if (!marginInfo.canCollapseWithMarginBefore()) {
624 // Positioned blocks don't collapse margins, so add the margin provided by
625 // the container now. The child's own margin is added later when calculating its logical top.
626 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
627 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
628 logicalTop += collapsedBeforePos - collapsedBeforeNeg;
629 }
630
631 RenderLayer* childLayer = child->layer();
632 if (childLayer->staticBlockPosition() != logicalTop) {
633 childLayer->setStaticBlockPosition(logicalTop);
634 if (hasStaticBlockPosition)
antti@apple.comca2a8ff2013-10-04 04:04:35 +0000635 child->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000636 }
637}
638
639void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo)
640{
641 // The float should be positioned taking into account the bottom margin
642 // of the previous flow. We add that margin into the height, get the
643 // float positioned properly, and then subtract the margin out of the
644 // height again. In the case of self-collapsing blocks, we always just
645 // use the top margins, since the self-collapsing block collapsed its
646 // own bottom margin into its top margin.
647 //
648 // Note also that the previous flow may collapse its margin into the top of
649 // our block. If this is the case, then we do not add the margin in to our
650 // height when computing the position of the float. This condition can be tested
651 // for by simply calling canCollapseWithMarginBefore. See
652 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
653 // an example of this scenario.
654 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
655 setLogicalHeight(logicalHeight() + marginOffset);
656 positionNewFloats();
657 setLogicalHeight(logicalHeight() - marginOffset);
658}
659
660RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* child) const
661{
662 LayoutUnit childBeforePositive = 0;
663 LayoutUnit childBeforeNegative = 0;
664 LayoutUnit childAfterPositive = 0;
665 LayoutUnit childAfterNegative = 0;
666
667 LayoutUnit beforeMargin = 0;
668 LayoutUnit afterMargin = 0;
669
670 RenderBlockFlow* childRenderBlock = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0;
671
672 // If the child has the same directionality as we do, then we can just return its
673 // margins in the same direction.
674 if (!child->isWritingModeRoot()) {
675 if (childRenderBlock) {
676 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
677 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
678 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
679 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
680 } else {
681 beforeMargin = child->marginBefore();
682 afterMargin = child->marginAfter();
683 }
684 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
685 // The child has a different directionality. If the child is parallel, then it's just
686 // flipped relative to us. We can use the margins for the opposite edges.
687 if (childRenderBlock) {
688 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
689 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
690 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
691 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
692 } else {
693 beforeMargin = child->marginAfter();
694 afterMargin = child->marginBefore();
695 }
696 } else {
697 // The child is perpendicular to us, which means its margins don't collapse but are on the
698 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
699 beforeMargin = marginBeforeForChild(child);
700 afterMargin = marginAfterForChild(child);
701 }
702
703 // Resolve uncollapsing margins into their positive/negative buckets.
704 if (beforeMargin) {
705 if (beforeMargin > 0)
706 childBeforePositive = beforeMargin;
707 else
708 childBeforeNegative = -beforeMargin;
709 }
710 if (afterMargin) {
711 if (afterMargin > 0)
712 childAfterPositive = afterMargin;
713 else
714 childAfterNegative = -afterMargin;
715 }
716
717 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
718}
719
720LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
721{
722 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child);
723 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child);
724 bool childIsSelfCollapsing = child->isSelfCollapsingBlock();
725
726 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block.
727 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing);
728
729 // Get the four margin values for the child and cache them.
730 const MarginValues childMargins = marginValuesForChild(child);
731
732 // Get our max pos and neg top margins.
733 LayoutUnit posTop = childMargins.positiveMarginBefore();
734 LayoutUnit negTop = childMargins.negativeMarginBefore();
735
736 // For self-collapsing blocks, collapse our bottom margins into our
737 // top to get new posTop and negTop values.
738 if (childIsSelfCollapsing) {
739 posTop = max(posTop, childMargins.positiveMarginAfter());
740 negTop = max(negTop, childMargins.negativeMarginAfter());
741 }
742
743 // See if the top margin is quirky. We only care if this child has
744 // margins that will collapse with us.
745 bool topQuirk = hasMarginBeforeQuirk(child);
746
747 if (marginInfo.canCollapseWithMarginBefore()) {
748 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
749 // This child is collapsing with the top of the
750 // block. If it has larger margin values, then we need to update
751 // our own maximal values.
752 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
753 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
754
755 // The minute any of the margins involved isn't a quirk, don't
756 // collapse it away, even if the margin is smaller (www.webreference.com
757 // has an example of this, a <dt> with 0.8em author-specified inside
758 // a <dl> inside a <td>.
759 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
760 setHasMarginBeforeQuirk(false);
761 marginInfo.setDeterminedMarginBeforeQuirk(true);
762 }
763
764 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
765 // We have no top margin and our top child has a quirky margin.
766 // We will pick up this quirky margin and pass it through.
767 // This deals with the <td><div><p> case.
768 // Don't do this for a block that split two inlines though. You do
769 // still apply margins in this case.
770 setHasMarginBeforeQuirk(true);
771 } else
772 // The before margin of the container will also discard all the margins it is collapsing with.
773 setMustDiscardMarginBefore();
774 }
775
776 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard.
777 if (childDiscardMarginBefore) {
778 marginInfo.setDiscardMargin(true);
779 marginInfo.clearMargin();
780 }
781
782 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
783 marginInfo.setHasMarginBeforeQuirk(topQuirk);
784
785 LayoutUnit beforeCollapseLogicalTop = logicalHeight();
786 LayoutUnit logicalTop = beforeCollapseLogicalTop;
787 if (childIsSelfCollapsing) {
788 // 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.
789 // Also, the child's top position equals the logical height of the container.
790 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) {
791 // This child has no height. We need to compute our
792 // position before we collapse the child's margins together,
793 // so that we can get an accurate position for the zero-height block.
794 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
795 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
796 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
797
798 // Now collapse the child's margins together, which means examining our
799 // bottom margin values as well.
800 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
801 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
802
803 if (!marginInfo.canCollapseWithMarginBefore())
804 // We need to make sure that the position of the self-collapsing block
805 // is correct, since it could have overflowing content
806 // that needs to be positioned correctly (e.g., a block that
807 // had a specified height of 0 but that actually had subcontent).
808 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
809 }
810 } else {
811 if (mustSeparateMarginBeforeForChild(child)) {
812 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin()));
813 // If we are at the before side of the block and we collapse, ignore the computed margin
814 // and just add the child margin to the container height. This will correctly position
815 // the child inside the container.
816 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0);
817 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child));
818 logicalTop = logicalHeight();
819 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock()
820 || (!marginInfo.canCollapseMarginBeforeWithChildren()
821 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) {
822 // We're collapsing with a previous sibling's margins and not
823 // with the top of the block.
824 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
825 logicalTop = logicalHeight();
826 }
827
828 marginInfo.setDiscardMargin(childDiscardMarginAfter);
829
830 if (!marginInfo.discardMargin()) {
831 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
832 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
833 } else
834 marginInfo.clearMargin();
835
836 if (marginInfo.margin())
837 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child));
838 }
839
840 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
841 // collapsed into the page edge.
842 LayoutState* layoutState = view().layoutState();
843 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
844 && hasNextPage(beforeCollapseLogicalTop)) {
845 LayoutUnit oldLogicalTop = logicalTop;
846 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
847 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
848 }
849
850 // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
851 // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
852 // or clear it anyway, so don't worry about any floating children it may contain.
853 LayoutUnit oldLogicalHeight = logicalHeight();
854 setLogicalHeight(logicalTop);
855 RenderObject* prev = child->previousSibling();
856 if (prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000857 RenderBlockFlow* block = toRenderBlockFlow(prev);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000858 if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
859 addOverhangingFloats(block, false);
860 }
861 setLogicalHeight(oldLogicalHeight);
862
863 return logicalTop;
864}
865
866LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
867{
868 LayoutUnit heightIncrease = getClearDelta(child, yPos);
869 if (!heightIncrease)
870 return yPos;
871
872 if (child->isSelfCollapsingBlock()) {
873 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child);
874
875 // For self-collapsing blocks that clear, they can still collapse their
876 // margins with following siblings. Reset the current margins to represent
877 // the self-collapsing block's margins only.
878 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values.
879 if (!childDiscardMargin) {
880 MarginValues childMargins = marginValuesForChild(child);
881 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
882 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
883 } else
884 marginInfo.clearMargin();
885 marginInfo.setDiscardMargin(childDiscardMargin);
886
887 // CSS2.1 states:
888 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
889 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
890 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
891 // for a block with height - if none is found then don't allow the margins to collapse with the parent.
892 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
893 for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
894 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
895 wouldCollapseMarginsWithParent = false;
896 }
897 if (wouldCollapseMarginsWithParent)
898 marginInfo.setCanCollapseMarginAfterWithChildren(false);
899
900 // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top"
901 // Move the top of the child box to the bottom of the float ignoring the child's top margin.
902 LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
903 setLogicalHeight(child->logicalTop() - collapsedMargin);
904 // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above.
905 heightIncrease -= max(LayoutUnit(), collapsedMargin);
906 } else
907 // Increase our height by the amount we had to clear.
908 setLogicalHeight(logicalHeight() + heightIncrease);
909
910 if (marginInfo.canCollapseWithMarginBefore()) {
911 // We can no longer collapse with the top of the block since a clear
912 // occurred. The empty blocks collapse into the cleared block.
913 // FIXME: This isn't quite correct. Need clarification for what to do
914 // if the height the cleared block is offset by is smaller than the
915 // margins involved.
916 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
917 marginInfo.setAtBeforeSideOfBlock(false);
918
919 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value.
920 setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD);
921 }
922
923 LayoutUnit logicalTop = yPos + heightIncrease;
924 // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it
925 // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +0000926 if (containsFloats() && child->isRenderBlockFlow() && !toRenderBlockFlow(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
927 toRenderBlockFlow(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +0000928
929 return logicalTop;
930}
931
932void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const
933{
934 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
935 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing.
936 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
937 if ((document().inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE)
938 return;
939
940 // The margins are discarded by a child that specified -webkit-margin-collapse: discard.
941 // FIXME: Use writing mode independent accessor for marginBeforeCollapse.
942 if (child->style()->marginBeforeCollapse() == MDISCARD) {
943 positiveMarginBefore = 0;
944 negativeMarginBefore = 0;
945 discardMarginBefore = true;
946 return;
947 }
948
949 LayoutUnit beforeChildMargin = marginBeforeForChild(child);
950 positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
951 negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
952
953 if (!child->isRenderBlockFlow())
954 return;
955
956 RenderBlockFlow* childBlock = toRenderBlockFlow(child);
957 if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
958 return;
959
960 MarginInfo childMarginInfo(childBlock, childBlock->borderAndPaddingBefore(), childBlock->borderAndPaddingAfter());
961 if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
962 return;
963
964 RenderBox* grandchildBox = childBlock->firstChildBox();
965 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
966 if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
967 break;
968 }
969
970 // Give up if there is clearance on the box, since it probably won't collapse into us.
971 if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
972 return;
973
974 // Make sure to update the block margins now for the grandchild box so that we're looking at current values.
975 if (grandchildBox->needsLayout()) {
976 grandchildBox->computeAndSetBlockDirectionMargins(this);
977 if (grandchildBox->isRenderBlock()) {
978 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox);
979 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk());
980 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk());
981 }
982 }
983
984 // Collapse the margin of the grandchild box with our own to produce an estimate.
985 childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
986}
987
988LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
989{
990 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
991 // relayout if there are intruding floats.
992 LayoutUnit logicalTopEstimate = logicalHeight();
993 if (!marginInfo.canCollapseWithMarginBefore()) {
994 LayoutUnit positiveMarginBefore = 0;
995 LayoutUnit negativeMarginBefore = 0;
996 bool discardMarginBefore = false;
997 if (child->selfNeedsLayout()) {
998 // Try to do a basic estimation of how the collapse is going to go.
999 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore);
1000 } else {
1001 // Use the cached collapsed margin values from a previous layout. Most of the time they
1002 // will be right.
1003 MarginValues marginValues = marginValuesForChild(child);
1004 positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
1005 negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
1006 discardMarginBefore = mustDiscardMarginBeforeForChild(child);
1007 }
1008
1009 // Collapse the result with our current margins.
1010 if (!discardMarginBefore)
1011 logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
1012 }
1013
1014 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1015 // page.
1016 LayoutState* layoutState = view().layoutState();
1017 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
1018 && hasNextPage(logicalHeight()))
1019 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1020
1021 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1022
1023 estimateWithoutPagination = logicalTopEstimate;
1024
1025 if (layoutState->isPaginated()) {
1026 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1027 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1028
1029 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1030 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1031
1032 if (!child->selfNeedsLayout() && child->isRenderBlock())
1033 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1034 }
1035
1036 return logicalTopEstimate;
1037}
1038
1039void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1040{
1041 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1042 // 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.
1043 // Don't update the max margin values because we won't need them anyway.
1044 if (marginInfo.discardMargin()) {
1045 setMustDiscardMarginAfter();
1046 return;
1047 }
1048
1049 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1050 // with our children.
1051 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1052
1053 if (!marginInfo.hasMarginAfterQuirk())
1054 setHasMarginAfterQuirk(false);
1055
1056 if (marginInfo.hasMarginAfterQuirk() && !marginAfter())
1057 // We have no bottom margin and our last child has a quirky margin.
1058 // We will pick up this quirky margin and pass it through.
1059 // This deals with the <td><div><p> case.
1060 setHasMarginAfterQuirk(true);
1061 }
1062}
1063
1064void RenderBlockFlow::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
1065{
1066 marginInfo.setAtAfterSideOfBlock(true);
1067
1068 // If we can't collapse with children then go ahead and add in the bottom margin.
1069 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1070 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk())))
1071 setLogicalHeight(logicalHeight() + marginInfo.margin());
1072
1073 // Now add in our bottom border/padding.
1074 setLogicalHeight(logicalHeight() + afterSide);
1075
1076 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1077 // If this happens, ensure that the computed height is increased to the minimal height.
1078 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1079
1080 // Update our bottom collapsed margin info.
1081 setCollapsedBottomMargin(marginInfo);
1082}
1083
1084void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
1085{
1086 if (!m_rareData) {
1087 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(this))
1088 return;
1089 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1090 }
1091 m_rareData->m_margins.setPositiveMarginBefore(pos);
1092 m_rareData->m_margins.setNegativeMarginBefore(neg);
1093}
1094
1095void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
1096{
1097 if (!m_rareData) {
1098 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(this))
1099 return;
1100 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1101 }
1102 m_rareData->m_margins.setPositiveMarginAfter(pos);
1103 m_rareData->m_margins.setNegativeMarginAfter(neg);
1104}
1105
1106void RenderBlockFlow::setMustDiscardMarginBefore(bool value)
1107{
1108 if (style()->marginBeforeCollapse() == MDISCARD) {
1109 ASSERT(value);
1110 return;
1111 }
1112
1113 if (!m_rareData && !value)
1114 return;
1115
1116 if (!m_rareData)
1117 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1118
1119 m_rareData->m_discardMarginBefore = value;
1120}
1121
1122void RenderBlockFlow::setMustDiscardMarginAfter(bool value)
1123{
1124 if (style()->marginAfterCollapse() == MDISCARD) {
1125 ASSERT(value);
1126 return;
1127 }
1128
1129 if (!m_rareData && !value)
1130 return;
1131
1132 if (!m_rareData)
1133 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
1134
1135 m_rareData->m_discardMarginAfter = value;
1136}
1137
1138bool RenderBlockFlow::mustDiscardMarginBefore() const
1139{
1140 return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore);
1141}
1142
1143bool RenderBlockFlow::mustDiscardMarginAfter() const
1144{
1145 return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter);
1146}
1147
1148bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox* child) const
1149{
1150 ASSERT(!child->selfNeedsLayout());
1151 if (!child->isWritingModeRoot())
1152 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
1153 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1154 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
1155
1156 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end.
1157 // In case the boxes are perpendicular we assume the property is not specified.
1158 return false;
1159}
1160
1161bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox* child) const
1162{
1163 ASSERT(!child->selfNeedsLayout());
1164 if (!child->isWritingModeRoot())
1165 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD);
1166 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1167 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD);
1168
1169 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1170 return false;
1171}
1172
1173bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox* child) const
1174{
1175 ASSERT(!child->selfNeedsLayout());
1176 const RenderStyle* childStyle = child->style();
1177 if (!child->isWritingModeRoot())
1178 return childStyle->marginBeforeCollapse() == MSEPARATE;
1179 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1180 return childStyle->marginAfterCollapse() == MSEPARATE;
1181
1182 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1183 return false;
1184}
1185
1186bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) const
1187{
1188 ASSERT(!child->selfNeedsLayout());
1189 const RenderStyle* childStyle = child->style();
1190 if (!child->isWritingModeRoot())
1191 return childStyle->marginAfterCollapse() == MSEPARATE;
1192 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
1193 return childStyle->marginBeforeCollapse() == MSEPARATE;
1194
1195 // FIXME: See |mustDiscardMarginBeforeForChild| above.
1196 return false;
1197}
1198
1199static bool inNormalFlow(RenderBox* child)
1200{
1201 RenderBlock* curr = child->containingBlock();
1202 while (curr && curr != &child->view()) {
1203 if (curr->hasColumns() || curr->isRenderFlowThread())
1204 return true;
1205 if (curr->isFloatingOrOutOfFlowPositioned())
1206 return false;
1207 curr = curr->containingBlock();
1208 }
1209 return true;
1210}
1211
1212LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
1213{
1214 // FIXME: Add page break checking here when we support printing.
1215 bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
1216 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1217 RenderFlowThread* flowThread = flowThreadContainingBlock();
1218 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1219 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
1220 || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
1221 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1222 if (checkColumnBreaks)
1223 view().layoutState()->addForcedColumnBreak(child, logicalOffset);
1224 if (checkRegionBreaks) {
1225 LayoutUnit offsetBreakAdjustment = 0;
1226 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
1227 return logicalOffset + offsetBreakAdjustment;
1228 }
1229 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1230 }
1231 return logicalOffset;
1232}
1233
1234LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
1235{
1236 // FIXME: Add page break checking here when we support printing.
1237 bool checkColumnBreaks = view().layoutState()->isPaginatingColumns();
1238 bool checkPageBreaks = !checkColumnBreaks && view().layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
1239 RenderFlowThread* flowThread = flowThreadContainingBlock();
1240 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
1241 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
1242 || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
1243 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
1244 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1245
1246 // So our margin doesn't participate in the next collapsing steps.
1247 marginInfo.clearMargin();
1248
1249 if (checkColumnBreaks)
1250 view().layoutState()->addForcedColumnBreak(child, logicalOffset);
1251 if (checkRegionBreaks) {
1252 LayoutUnit offsetBreakAdjustment = 0;
1253 if (flowThread->addForcedRegionBreak(this, offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
1254 return logicalOffset + marginOffset + offsetBreakAdjustment;
1255 }
1256 return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
1257 }
1258 return logicalOffset;
1259}
1260
1261LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
1262{
1263 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
1264
1265 if (estimateWithoutPagination != logicalTopAfterClear) {
1266 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
1267 // position.
1268 setLogicalHeight(logicalTopAfterClear);
1269 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
1270
1271 if (child->shrinkToAvoidFloats()) {
1272 // The child's width depends on the line width.
1273 // When the child shifts to clear an item, its width can
1274 // change (because it has more available line width).
1275 // So go ahead and mark the item as dirty.
antti@apple.comca2a8ff2013-10-04 04:04:35 +00001276 child->setChildNeedsLayout(MarkOnlyThis);
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001277 }
1278
1279 if (childRenderBlock) {
1280 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001281 toRenderBlockFlow(childRenderBlock)->markAllDescendantsWithFloatsForLayout();
hyatt@apple.com1807b5b2013-09-11 19:50:03 +00001282 if (!child->needsLayout())
1283 child->markForPaginationRelayoutIfNeeded();
1284 }
1285
1286 // Our guess was wrong. Make the child lay itself out again.
1287 child->layoutIfNeeded();
1288 }
1289
1290 LayoutUnit oldTop = logicalTopAfterClear;
1291
1292 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1293 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
1294
1295 if (pageLogicalHeightForOffset(result)) {
1296 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary);
1297 LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight;
1298 if (spaceShortage > 0) {
1299 // If the child crosses a column boundary, report a break, in case nothing inside it has already
1300 // done so. The column balancer needs to know how much it has to stretch the columns to make more
1301 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME:
1302 // This should be improved, though, because here we just pretend that the child is
1303 // unsplittable. A splittable child, on the other hand, has break opportunities at every position
1304 // where there's no child content, border or padding. In other words, we risk stretching more
1305 // than necessary.
1306 setPageBreak(result, spaceShortage);
1307 }
1308 }
1309
1310 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1311 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
1312 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
1313
1314 LayoutUnit paginationStrut = 0;
1315 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
1316 if (unsplittableAdjustmentDelta)
1317 paginationStrut = unsplittableAdjustmentDelta;
1318 else if (childRenderBlock && childRenderBlock->paginationStrut())
1319 paginationStrut = childRenderBlock->paginationStrut();
1320
1321 if (paginationStrut) {
1322 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
1323 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
1324 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
1325 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
1326 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
1327 // and pushes to the next page anyway, so not too concerned about it.
1328 setPaginationStrut(result + paginationStrut);
1329 if (childRenderBlock)
1330 childRenderBlock->setPaginationStrut(0);
1331 } else
1332 result += paginationStrut;
1333 }
1334
1335 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
1336 setLogicalHeight(logicalHeight() + (result - oldTop));
1337
1338 // Return the final adjusted logical top.
1339 return result;
1340}
1341
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001342static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
1343{
1344 // We may require a certain minimum number of lines per page in order to satisfy
1345 // orphans and widows, and that may affect the minimum page height.
1346 unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
1347 if (lineCount > 1) {
1348 RootInlineBox* line = lastLine;
1349 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
1350 line = line->prevRootBox();
1351
1352 // FIXME: Paginating using line overflow isn't all fine. See FIXME in
1353 // adjustLinePositionForPagination() for more details.
1354 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
1355 lineTop = min(line->lineTopWithLeading(), overflow.y());
1356 }
1357 return lineBottom - lineTop;
1358}
1359
1360void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
1361{
1362 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
1363 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
1364 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
1365 // of the first column.
1366 //
1367 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
1368 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
1369 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
1370 // for overflow to occur), and then cache visible overflow for each column rect.
1371 //
1372 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
1373 // content that paints in a previous column (and content that paints in the following column).
1374 //
1375 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
1376 // at least make positive leading work in typical cases.
1377 //
1378 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
1379 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
1380 // line and all following lines.
1381 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
1382 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
1383 LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
1384 LayoutUnit lineHeight = logicalBottom - logicalOffset;
1385 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
1386 logicalOffset += delta;
1387 lineBox->setPaginationStrut(0);
1388 lineBox->setIsFirstAfterPageBreak(false);
1389 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
1390 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
1391 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
1392 // still going to add a strut, so that the visible overflow fits on a single page.
1393 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
1394 || !hasNextPage(logicalOffset))
abucur@adobe.comd40287b2013-10-08 17:33:05 +00001395 // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
1396 // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001397 return;
1398 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
1399
1400 int lineIndex = lineCount(lineBox);
1401 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
abucur@adobe.comfc497132013-10-04 08:49:21 +00001402 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001403 clearShouldBreakAtLineToAvoidWidow();
abucur@adobe.comfc497132013-10-04 08:49:21 +00001404 setDidBreakAtLineToAvoidWidow();
1405 }
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001406 // If we have a non-uniform page height, then we have to shift further possibly.
1407 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
1408 return;
1409 if (lineHeight > pageLogicalHeight) {
1410 // Split the top margin in order to avoid splitting the visible part of the line.
1411 remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
1412 }
1413 LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
1414 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
1415 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
1416 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineIndex))
1417 && !isOutOfFlowPositioned() && !isTableCell())
1418 setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
1419 else {
1420 delta += remainingLogicalHeight;
1421 lineBox->setPaginationStrut(remainingLogicalHeight);
1422 lineBox->setIsFirstAfterPageBreak(true);
1423 }
1424 } else if (remainingLogicalHeight == pageLogicalHeight && lineBox != firstRootBox())
1425 lineBox->setIsFirstAfterPageBreak(true);
1426}
1427
1428void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak)
1429{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001430 ASSERT(lineToBreak >= 0);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001431 if (!m_rareData)
1432 m_rareData = adoptPtr(new RenderBlockFlowRareData(this));
abucur@adobe.comfc497132013-10-04 08:49:21 +00001433
1434 ASSERT(!m_rareData->m_didBreakAtLineToAvoidWidow);
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001435 m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
1436}
1437
abucur@adobe.comfc497132013-10-04 08:49:21 +00001438void RenderBlockFlow::setDidBreakAtLineToAvoidWidow()
1439{
1440 ASSERT(!shouldBreakAtLineToAvoidWidow());
1441 if (!m_rareData)
1442 return;
1443
1444 m_rareData->m_didBreakAtLineToAvoidWidow = true;
1445}
1446
1447void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow()
1448{
1449 if (!m_rareData)
1450 return;
1451
1452 m_rareData->m_didBreakAtLineToAvoidWidow = false;
1453}
1454
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001455void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const
1456{
abucur@adobe.comfc497132013-10-04 08:49:21 +00001457 ASSERT(shouldBreakAtLineToAvoidWidow());
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001458 if (!m_rareData)
1459 return;
abucur@adobe.comfc497132013-10-04 08:49:21 +00001460
hyatt@apple.com2ea59882013-09-17 16:41:42 +00001461 m_rareData->m_lineBreakToAvoidWidow = -1;
1462}
1463
1464bool RenderBlockFlow::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
1465{
1466 if (!shouldBreakAtLineToAvoidWidow())
1467 return false;
1468
1469 statePusher.pop();
1470 setEverHadLayout(true);
1471 layoutBlock(false);
1472 return true;
1473}
1474
hyatt@apple.com3cd5c772013-09-27 18:22:50 +00001475void RenderBlockFlow::layoutLineGridBox()
1476{
1477 if (style()->lineGrid() == RenderStyle::initialLineGrid()) {
1478 setLineGridBox(0);
1479 return;
1480 }
1481
1482 setLineGridBox(0);
1483
1484 RootInlineBox* lineGridBox = new (renderArena()) RootInlineBox(*this);
1485 lineGridBox->setHasTextChildren(); // Needed to make the line ascent/descent actually be honored in quirks mode.
1486 lineGridBox->setConstructed();
1487 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1488 VerticalPositionCache verticalPositionCache;
1489 lineGridBox->alignBoxesInBlockDirection(logicalHeight(), textBoxDataMap, verticalPositionCache);
1490
1491 setLineGridBox(lineGridBox);
1492
1493 // FIXME: If any of the characteristics of the box change compared to the old one, then we need to do a deep dirtying
1494 // (similar to what happens when the page height changes). Ideally, though, we only do this if someone is actually snapping
1495 // to this grid.
1496}
1497
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001498bool RenderBlockFlow::containsFloat(RenderBox* renderer) const
1499{
1500 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox&, FloatingObjectHashTranslator>(*renderer);
1501}
1502
1503void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
1504{
1505 RenderBlock::styleDidChange(diff, oldStyle);
1506
1507 // After our style changed, if we lose our ability to propagate floats into next sibling
1508 // blocks, then we need to find the top most parent containing that overhanging float and
1509 // then mark its descendants with floats for layout and clear all floats from its next
1510 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
1511 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
1512 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
1513 RenderBlockFlow* parentBlock = this;
1514 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1515 auto end = floatingObjectSet.end();
1516
akling@apple.com14141552013-10-14 07:58:09 +00001517 for (auto curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001518 if (curr->isRenderBlockFlow()) {
1519 RenderBlockFlow* currBlock = toRenderBlockFlow(curr);
1520
1521 if (currBlock->hasOverhangingFloats()) {
1522 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1523 RenderBox& renderer = (*it)->renderer();
1524 if (currBlock->hasOverhangingFloat(&renderer)) {
1525 parentBlock = currBlock;
1526 break;
1527 }
1528 }
1529 }
1530 }
1531 }
1532
1533 parentBlock->markAllDescendantsWithFloatsForLayout();
1534 parentBlock->markSiblingsWithFloatsForLayout();
1535 }
1536}
1537
1538void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
1539{
1540 RenderStyle* oldStyle = style();
1541 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
1542
1543 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
1544 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
1545 markAllDescendantsWithFloatsForLayout();
1546 }
1547
1548 RenderBlock::styleWillChange(diff, newStyle);
1549}
1550
1551void RenderBlockFlow::deleteLineBoxTree()
1552{
1553 if (containsFloats())
1554 m_floatingObjects->clearLineBoxTreePointers();
1555 RenderBlock::deleteLineBoxTree();
1556}
1557
1558void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert)
1559{
1560 RenderBlockFlow* toBlockFlow = toRenderBlockFlow(toBlock);
1561 moveAllChildrenTo(toBlockFlow, fullRemoveInsert);
1562
1563 // When a portion of the render tree is being detached, anonymous blocks
1564 // will be combined as their children are deleted. In this process, the
1565 // anonymous block later in the tree is merged into the one preceeding it.
1566 // It can happen that the later block (this) contains floats that the
1567 // previous block (toBlockFlow) did not contain, and thus are not in the
1568 // floating objects list for toBlockFlow. This can result in toBlockFlow
1569 // containing floats that are not in it's floating objects list, but are in
1570 // the floating objects lists of siblings and parents. This can cause
1571 // problems when the float itself is deleted, since the deletion code
1572 // assumes that if a float is not in it's containing block's floating
1573 // objects list, it isn't in any floating objects list. In order to
1574 // preserve this condition (removing it has serious performance
1575 // implications), we need to copy the floating objects from the old block
1576 // (this) to the new block (toBlockFlow). The float's metrics will likely
1577 // all be wrong, but since toBlockFlow is already marked for layout, this
1578 // will get fixed before anything gets displayed.
1579 // See bug https://bugs.webkit.org/show_bug.cgi?id=115566
1580 if (m_floatingObjects) {
1581 if (!toBlockFlow->m_floatingObjects)
1582 toBlockFlow->createFloatingObjects();
1583
1584 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set();
1585 auto end = fromFloatingObjectSet.end();
1586
1587 for (auto it = fromFloatingObjectSet.begin(); it != end; ++it) {
1588 FloatingObject* floatingObject = it->get();
1589
1590 // Don't insert the object again if it's already in the list
1591 if (toBlockFlow->containsFloat(&floatingObject->renderer()))
1592 continue;
1593
1594 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone());
1595 }
1596 }
1597}
1598
1599void RenderBlockFlow::addOverflowFromFloats()
1600{
1601 if (!m_floatingObjects)
1602 return;
1603
1604 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1605 auto end = floatingObjectSet.end();
1606 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1607 FloatingObject* r = it->get();
1608 if (r->isDescendant())
1609 addOverflowFromChild(&r->renderer(), IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1610 }
1611}
1612
1613void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1614{
1615 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats);
1616
1617 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1618 addOverflowFromFloats();
1619}
1620
1621void RenderBlockFlow::repaintOverhangingFloats(bool paintAllDescendants)
1622{
1623 // Repaint any overhanging floats (if we know we're the one to paint them).
1624 // Otherwise, bail out.
1625 if (!hasOverhangingFloats())
1626 return;
1627
1628 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
1629 // in this block. Better yet would be to push extra state for the containers of other floats.
1630 LayoutStateDisabler layoutStateDisabler(&view());
1631 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1632 auto end = floatingObjectSet.end();
1633 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1634 FloatingObject* floatingObject = it->get();
1635 // Only repaint the object if it is overhanging, is not in its own layer, and
1636 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
1637 // condition is replaced with being a descendant of us.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001638 if (logicalBottomForFloat(floatingObject) > logicalHeight()
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001639 && !floatingObject->renderer().hasSelfPaintingLayer()
1640 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer().isDescendantOf(this)))) {
1641 floatingObject->renderer().repaint();
1642 floatingObject->renderer().repaintOverhangingFloats(false);
1643 }
1644 }
1645}
1646
1647void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
1648{
1649 if (!m_floatingObjects)
1650 return;
1651
1652 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1653 auto end = floatingObjectSet.end();
1654 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1655 FloatingObject* r = it->get();
1656 // Only paint the object if our m_shouldPaint flag is set.
1657 if (r->shouldPaint() && !r->renderer().hasSelfPaintingLayer()) {
1658 PaintInfo currentPaintInfo(paintInfo);
1659 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
1660 // FIXME: LayoutPoint version of xPositionForFloatIncludingMargin would make this much cleaner.
1661 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->renderer().x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->renderer().y()));
1662 r->renderer().paint(currentPaintInfo, childPoint);
1663 if (!preservePhase) {
1664 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
1665 r->renderer().paint(currentPaintInfo, childPoint);
1666 currentPaintInfo.phase = PaintPhaseFloat;
1667 r->renderer().paint(currentPaintInfo, childPoint);
1668 currentPaintInfo.phase = PaintPhaseForeground;
1669 r->renderer().paint(currentPaintInfo, childPoint);
1670 currentPaintInfo.phase = PaintPhaseOutline;
1671 r->renderer().paint(currentPaintInfo, childPoint);
1672 }
1673 }
1674 }
1675}
1676
1677
1678void RenderBlockFlow::clipOutFloatingObjects(RenderBlock* rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock)
1679{
1680 if (m_floatingObjects) {
1681 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1682 auto end = floatingObjectSet.end();
1683 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
1684 FloatingObject* floatingObject = it->get();
1685 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject),
1686 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject),
1687 floatingObject->renderer().width(), floatingObject->renderer().height());
1688 rootBlock->flipForWritingMode(floatBox);
1689 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
1690 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox));
1691 }
1692 }
1693}
1694
1695void RenderBlockFlow::createFloatingObjects()
1696{
1697 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
1698}
1699
1700void RenderBlockFlow::removeFloatingObjects()
1701{
1702 if (!m_floatingObjects)
1703 return;
1704
1705 m_floatingObjects->clear();
1706}
1707
1708FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox* floatBox)
1709{
1710 ASSERT(floatBox->isFloating());
1711
1712 // Create the list of special objects if we don't aleady have one
1713 if (!m_floatingObjects)
1714 createFloatingObjects();
1715 else {
1716 // Don't insert the floatingObject again if it's already in the list
1717 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1718 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(*floatBox);
1719 if (it != floatingObjectSet.end())
1720 return it->get();
1721 }
1722
1723 // Create the special floatingObject entry & append it to the list
1724
1725 std::unique_ptr<FloatingObject> floatingObject = FloatingObject::create(*floatBox);
1726
1727 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
1728 // Just go ahead and lay out the float.
1729 bool isChildRenderBlock = floatBox->isRenderBlock();
1730 if (isChildRenderBlock && !floatBox->needsLayout() && view().layoutState()->pageLogicalHeightChanged())
1731 floatBox->setChildNeedsLayout(MarkOnlyThis);
1732
1733 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view().layoutState()->needsBlockDirectionLocationSetBeforeLayout();
1734 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
1735 floatBox->layoutIfNeeded();
1736 else {
1737 floatBox->updateLogicalWidth();
1738 floatBox->computeAndSetBlockDirectionMargins(this);
1739 }
1740
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001741 setLogicalWidthForFloat(floatingObject.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001742
1743#if ENABLE(CSS_SHAPES)
1744 if (ShapeOutsideInfo* shapeOutside = floatBox->shapeOutsideInfo())
1745 shapeOutside->setShapeSize(logicalWidthForChild(floatBox), logicalHeightForChild(floatBox));
1746#endif
1747
1748 return m_floatingObjects->add(std::move(floatingObject));
1749}
1750
1751void RenderBlockFlow::removeFloatingObject(RenderBox* floatBox)
1752{
1753 if (m_floatingObjects) {
1754 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1755 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(*floatBox);
1756 if (it != floatingObjectSet.end()) {
1757 FloatingObject* floatingObject = it->get();
1758 if (childrenInline()) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001759 LayoutUnit logicalTop = logicalTopForFloat(floatingObject);
1760 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001761
1762 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
1763 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
1764 logicalBottom = LayoutUnit::max();
1765 else {
1766 // Special-case zero- and less-than-zero-height floats: those don't touch
1767 // the line that they're on, but it still needs to be dirtied. This is
1768 // accomplished by pretending they have a height of 1.
1769 logicalBottom = max(logicalBottom, logicalTop + 1);
1770 }
1771 if (floatingObject->originatingLine()) {
1772 if (!selfNeedsLayout()) {
1773 ASSERT(&floatingObject->originatingLine()->renderer() == this);
1774 floatingObject->originatingLine()->markDirty();
1775 }
1776#if !ASSERT_DISABLED
1777 floatingObject->setOriginatingLine(0);
1778#endif
1779 }
1780 markLinesDirtyInBlockRange(0, logicalBottom);
1781 }
1782 m_floatingObjects->remove(floatingObject);
1783 }
1784 }
1785}
1786
1787void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
1788{
1789 if (!containsFloats())
1790 return;
1791
1792 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1793 FloatingObject* curr = floatingObjectSet.last().get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001794 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001795 m_floatingObjects->remove(curr);
1796 if (floatingObjectSet.isEmpty())
1797 break;
1798 curr = floatingObjectSet.last().get();
1799 }
1800}
1801
1802LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
1803{
1804 RenderBox* childBox = &floatingObject->renderer();
1805 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
1806 LayoutUnit logicalRightOffset; // Constant part of right offset.
1807#if ENABLE(CSS_SHAPES)
1808 // FIXME Bug 102948: This only works for shape outside directly set on this block.
1809 ShapeInsideInfo* shapeInsideInfo = this->layoutShapeInsideInfo();
1810 // FIXME: Implement behavior for right floats.
1811 if (shapeInsideInfo) {
zoltan@webkit.orgb64932a2013-10-11 21:01:40 +00001812 LayoutSize floatLogicalSize = logicalSizeForFloat(floatingObject);
1813 // floatingObject's logicalSize doesn't contain the actual height at this point, so we need to calculate it
1814 floatLogicalSize.setHeight(logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
1815
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001816 // FIXME: If the float doesn't fit in the shape we should push it under the content box
1817 logicalTopOffset = shapeInsideInfo->computeFirstFitPositionForFloat(floatLogicalSize);
1818 if (logicalHeight() > logicalTopOffset)
1819 logicalTopOffset = logicalHeight();
1820
zoltan@webkit.orgb64932a2013-10-11 21:01:40 +00001821 SegmentList segments = shapeInsideInfo->computeSegmentsForLine(logicalTopOffset, floatLogicalSize.height());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001822 // FIXME Bug 102949: Add support for shapes with multiple segments.
1823 if (segments.size() == 1) {
1824 // The segment offsets are relative to the content box.
1825 logicalRightOffset = logicalLeftOffset + segments[0].logicalRight;
1826 logicalLeftOffset += segments[0].logicalLeft;
1827 }
1828 } else
1829#endif
1830 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset);
1831
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001832 LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001833
1834 LayoutUnit floatLogicalLeft;
1835
1836 bool insideFlowThread = flowThreadContainingBlock();
1837
1838 if (childBox->style()->floating() == LeftFloat) {
1839 LayoutUnit heightRemainingLeft = 1;
1840 LayoutUnit heightRemainingRight = 1;
1841 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
1842 while (logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
1843 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
1844 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
1845 if (insideFlowThread) {
1846 // Have to re-evaluate all of our offsets, since they may have changed.
1847 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
1848 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001849 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001850 }
1851 }
1852 floatLogicalLeft = max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
1853 } else {
1854 LayoutUnit heightRemainingLeft = 1;
1855 LayoutUnit heightRemainingRight = 1;
1856 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
1857 while (floatLogicalLeft - logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
1858 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
1859 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
1860 if (insideFlowThread) {
1861 // Have to re-evaluate all of our offsets, since they may have changed.
1862 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
1863 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001864 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001865 }
1866 }
1867 // Use the original width of the float here, since the local variable
1868 // |floatLogicalWidth| was capped to the available line width. See
1869 // fast/block/float/clamped-right-float.html.
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001870 floatLogicalLeft -= logicalWidthForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001871 }
1872
1873 return LayoutPoint(floatLogicalLeft, logicalTopOffset);
1874}
1875
1876bool RenderBlockFlow::positionNewFloats()
1877{
1878 if (!m_floatingObjects)
1879 return false;
1880
1881 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1882 if (floatingObjectSet.isEmpty())
1883 return false;
1884
1885 // If all floats have already been positioned, then we have no work to do.
1886 if (floatingObjectSet.last()->isPlaced())
1887 return false;
1888
1889 // Move backwards through our floating object list until we find a float that has
1890 // already been positioned. Then we'll be able to move forward, positioning all of
1891 // the new floats that need it.
1892 auto it = floatingObjectSet.end();
1893 --it; // Go to last item.
1894 auto begin = floatingObjectSet.begin();
1895 FloatingObject* lastPlacedFloatingObject = 0;
1896 while (it != begin) {
1897 --it;
1898 if ((*it)->isPlaced()) {
1899 lastPlacedFloatingObject = it->get();
1900 ++it;
1901 break;
1902 }
1903 }
1904
1905 LayoutUnit logicalTop = logicalHeight();
1906
1907 // The float cannot start above the top position of the last positioned float.
1908 if (lastPlacedFloatingObject)
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001909 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001910
1911 auto end = floatingObjectSet.end();
1912 // Now walk through the set of unpositioned floats and place them.
1913 for (; it != end; ++it) {
1914 FloatingObject* floatingObject = it->get();
1915 // The containing block is responsible for positioning floats, so if we have floats in our
1916 // list that come from somewhere else, do not attempt to position them.
1917 if (floatingObject->renderer().containingBlock() != this)
1918 continue;
1919
1920 RenderBox* childBox = &floatingObject->renderer();
1921
1922 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
1923
1924 LayoutRect oldRect = childBox->frameRect();
1925
1926 if (childBox->style()->clear() & CLEFT)
1927 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
1928 if (childBox->style()->clear() & CRIGHT)
1929 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
1930
1931 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
1932
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001933 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001934
1935 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
1936 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
1937
1938 estimateRegionRangeForBoxChild(childBox);
1939
1940 LayoutState* layoutState = view().layoutState();
1941 bool isPaginated = layoutState->isPaginated();
1942 if (isPaginated && !childBox->needsLayout())
1943 childBox->markForPaginationRelayoutIfNeeded();
1944
1945 childBox->layoutIfNeeded();
1946
1947 if (isPaginated) {
1948 // If we are unsplittable and don't fit, then we need to move down.
1949 // We include our margins as part of the unsplittable area.
1950 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
1951
1952 // See if we have a pagination strut that is making us move down further.
1953 // Note that an unsplittable child can't also have a pagination strut, so this is
1954 // exclusive with the case above.
1955 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
1956 if (childBlock && childBlock->paginationStrut()) {
1957 newLogicalTop += childBlock->paginationStrut();
1958 childBlock->setPaginationStrut(0);
1959 }
1960
1961 if (newLogicalTop != floatLogicalLocation.y()) {
1962 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y());
1963
1964 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001965 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001966
1967 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
1968 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
1969
1970 if (childBlock)
1971 childBlock->setChildNeedsLayout(MarkOnlyThis);
1972 childBox->layoutIfNeeded();
1973 }
1974
1975 if (updateRegionRangeForBoxChild(childBox)) {
1976 childBox->setNeedsLayout(MarkOnlyThis);
1977 childBox->layoutIfNeeded();
1978 }
1979 }
1980
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001981 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001982
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00001983 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00001984
1985 m_floatingObjects->addPlacedObject(floatingObject);
1986
1987 // If the child moved, we have to repaint it.
1988 if (childBox->checkForRepaintDuringLayout())
1989 childBox->repaintDuringLayoutIfMoved(oldRect);
1990 }
1991 return true;
1992}
1993
1994void RenderBlockFlow::newLine(EClear clear)
1995{
1996 positionNewFloats();
1997 // set y position
1998 LayoutUnit newY = 0;
1999 switch (clear) {
2000 case CLEFT:
2001 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2002 break;
2003 case CRIGHT:
2004 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2005 break;
2006 case CBOTH:
2007 newY = lowestFloatLogicalBottom();
2008 default:
2009 break;
2010 }
2011 if (height() < newY)
2012 setLogicalHeight(newY);
2013}
2014
2015LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
2016{
2017 if (m_floatingObjects && m_floatingObjects->hasLeftObjects())
2018 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight, offsetMode, heightRemaining);
2019
2020 return fixedOffset;
2021}
2022
2023LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
2024{
2025 if (m_floatingObjects && m_floatingObjects->hasRightObjects())
2026 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight, offsetMode, heightRemaining);
2027
2028 return fixedOffset;
2029}
2030
2031LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const
2032{
2033 if (!m_floatingObjects)
2034 return logicalHeight;
2035
2036 LayoutUnit bottom = LayoutUnit::max();
2037 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2038 auto end = floatingObjectSet.end();
2039 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2040 FloatingObject* floatingObject = it->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002041 LayoutUnit floatBottom = logicalBottomForFloat(floatingObject);
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002042#if ENABLE(CSS_SHAPES)
2043 ShapeOutsideInfo* shapeOutside = floatingObject->renderer().shapeOutsideInfo();
bjonesbe@adobe.com10472b72013-10-09 21:45:44 +00002044 if (offsetMode == ShapeOutsideFloatShapeOffset && shapeOutside) {
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002045 LayoutUnit shapeBottom = logicalTopForFloat(floatingObject) + marginBeforeForChild(&(floatingObject->renderer())) + shapeOutside->shapeLogicalBottom();
bjonesbe@adobe.com10472b72013-10-09 21:45:44 +00002046 // Use the shapeBottom unless it extends outside of the margin box, in which case it is clipped.
2047 if (shapeBottom < floatBottom)
2048 floatBottom = shapeBottom;
2049 }
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002050#endif
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002051 if (floatBottom > logicalHeight)
2052 bottom = min(floatBottom, bottom);
2053 }
2054
2055 return bottom == LayoutUnit::max() ? LayoutUnit() : bottom;
2056}
2057
2058LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
2059{
2060 if (!m_floatingObjects)
2061 return 0;
2062 LayoutUnit lowestFloatBottom = 0;
2063 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2064 auto end = floatingObjectSet.end();
2065 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2066 FloatingObject* floatingObject = it->get();
2067 if (floatingObject->isPlaced() && floatingObject->type() & floatType)
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002068 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(floatingObject));
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002069 }
2070 return lowestFloatBottom;
2071}
2072
2073LayoutUnit RenderBlockFlow::addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats)
2074{
2075 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
2076 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
2077 return 0;
2078
2079 LayoutUnit childLogicalTop = child->logicalTop();
2080 LayoutUnit childLogicalLeft = child->logicalLeft();
2081 LayoutUnit lowestFloatLogicalBottom = 0;
2082
2083 // Floats that will remain the child's responsibility to paint should factor into its
2084 // overflow.
2085 auto childEnd = child->m_floatingObjects->set().end();
2086 for (auto childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
2087 FloatingObject* floatingObject = childIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002088 LayoutUnit floatLogicalBottom = min(logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop);
2089 LayoutUnit logicalBottom = childLogicalTop + floatLogicalBottom;
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002090 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
2091
2092 if (logicalBottom > logicalHeight()) {
2093 // If the object is not in the list, we add it now.
2094 if (!containsFloat(&floatingObject->renderer())) {
2095 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
2096 bool shouldPaint = false;
2097
2098 // The nearest enclosing layer always paints the float (so that zindex and stacking
2099 // behaves properly). We always want to propagate the desire to paint the float as
2100 // far out as we can, to the outermost block that overlaps the float, stopping only
2101 // if we hit a self-painting layer boundary.
2102 if (floatingObject->renderer().enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) {
2103 floatingObject->setShouldPaint(false);
2104 shouldPaint = true;
2105 }
2106 // We create the floating object list lazily.
2107 if (!m_floatingObjects)
2108 createFloatingObjects();
2109
2110 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true));
2111 }
2112 } else {
2113 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()
2114 && floatingObject->renderer().isDescendantOf(child) && floatingObject->renderer().enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
2115 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
2116 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
2117 // layer.
2118 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
2119 // it should paint.
2120 floatingObject->setShouldPaint(true);
2121 }
2122
2123 // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the
2124 // child now.
2125 if (floatingObject->isDescendant())
2126 child->addOverflowFromChild(&floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject)));
2127 }
2128 }
2129 return lowestFloatLogicalBottom;
2130}
2131
2132bool RenderBlockFlow::hasOverhangingFloat(RenderBox* renderer)
2133{
2134 if (!m_floatingObjects || hasColumns() || !parent())
2135 return false;
2136
2137 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2138 auto it = floatingObjectSet.find<RenderBox&, FloatingObjectHashTranslator>(*renderer);
2139 if (it == floatingObjectSet.end())
2140 return false;
2141
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002142 return logicalBottomForFloat(it->get()) > logicalHeight();
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002143}
2144
2145void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
2146{
2147 ASSERT(!avoidsFloats());
2148
2149 // If the parent or previous sibling doesn't have any floats to add, don't bother.
2150 if (!prev->m_floatingObjects)
2151 return;
2152
2153 logicalLeftOffset += marginLogicalLeft();
2154
2155 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
2156 auto prevEnd = prevSet.end();
2157 for (auto prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
2158 FloatingObject* floatingObject = prevIt->get();
bjonesbe@adobe.com1ccd3a12013-10-10 00:35:38 +00002159 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) {
bjonesbe@adobe.com24199752013-10-08 23:20:42 +00002160 if (!m_floatingObjects || !m_floatingObjects->set().contains<FloatingObject&, FloatingObjectHashTranslator>(*floatingObject)) {
2161 // We create the floating object list lazily.
2162 if (!m_floatingObjects)
2163 createFloatingObjects();
2164
2165 // Applying the child's margin makes no sense in the case where the child was passed in.
2166 // since this margin was added already through the modification of the |logicalLeftOffset| variable
2167 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
2168 // into account. Only apply this code if prev is the parent, since otherwise the left margin
2169 // will get applied twice.
2170 LayoutSize offset = isHorizontalWritingMode()
2171 ? LayoutSize(logicalLeftOffset - (prev != parent() ? prev->marginLeft() : LayoutUnit()), logicalTopOffset)
2172 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != parent() ? prev->marginTop() : LayoutUnit()));
2173
2174 m_floatingObjects->add(floatingObject->copyToNewContainer(offset));
2175 }
2176 }
2177 }
2178}
2179
2180void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
2181{
2182 if (!everHadLayout() && !containsFloats())
2183 return;
2184
2185 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
2186 setChildNeedsLayout(markParents);
2187
2188 if (floatToRemove)
2189 removeFloatingObject(floatToRemove);
2190
2191 // Iterate over our children and mark them as needed.
2192 if (!childrenInline()) {
2193 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
2194 if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isRenderBlock())
2195 continue;
2196 if (!child->isRenderBlockFlow()) {
2197 RenderBlock* childBlock = toRenderBlock(child);
2198 if (childBlock->shrinkToAvoidFloats() && childBlock->everHadLayout())
2199 childBlock->setChildNeedsLayout(markParents);
2200 continue;
2201 }
2202 RenderBlockFlow* childBlock = toRenderBlockFlow(child);
2203 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
2204 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
2205 }
2206 }
2207}
2208
2209void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
2210{
2211 if (!m_floatingObjects)
2212 return;
2213
2214 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2215 auto end = floatingObjectSet.end();
2216
2217 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
2218 if (!next->isRenderBlockFlow() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlock(next)->avoidsFloats())
2219 continue;
2220
2221 RenderBlockFlow* nextBlock = toRenderBlockFlow(next);
2222 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2223 RenderBox* floatingBox = &(*it)->renderer();
2224 if (floatToRemove && floatingBox != floatToRemove)
2225 continue;
2226 if (nextBlock->containsFloat(floatingBox))
2227 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox);
2228 }
2229 }
2230}
2231
2232LayoutUnit RenderBlockFlow::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
2233{
2234 // There is no need to compute clearance if we have no floats.
2235 if (!containsFloats())
2236 return 0;
2237
2238 // At least one float is present. We need to perform the clearance computation.
2239 bool clearSet = child->style()->clear() != CNONE;
2240 LayoutUnit logicalBottom = 0;
2241 switch (child->style()->clear()) {
2242 case CNONE:
2243 break;
2244 case CLEFT:
2245 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
2246 break;
2247 case CRIGHT:
2248 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
2249 break;
2250 case CBOTH:
2251 logicalBottom = lowestFloatLogicalBottom();
2252 break;
2253 }
2254
2255 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default).
2256 LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
2257 if (!result && child->avoidsFloats()) {
2258 LayoutUnit newLogicalTop = logicalTop;
2259 while (true) {
2260 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
2261 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
2262 return newLogicalTop - logicalTop;
2263
2264 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
2265 LayoutRect borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
2266 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2267
2268 // FIXME: None of this is right for perpendicular writing-mode children.
2269 LayoutUnit childOldLogicalWidth = child->logicalWidth();
2270 LayoutUnit childOldMarginLeft = child->marginLeft();
2271 LayoutUnit childOldMarginRight = child->marginRight();
2272 LayoutUnit childOldLogicalTop = child->logicalTop();
2273
2274 child->setLogicalTop(newLogicalTop);
2275 child->updateLogicalWidth();
2276 region = regionAtBlockOffset(logicalTopForChild(child));
2277 borderBox = child->borderBoxRectInRegion(region, DoNotCacheRenderBoxRegionInfo);
2278 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
2279
2280 child->setLogicalTop(childOldLogicalTop);
2281 child->setLogicalWidth(childOldLogicalWidth);
2282 child->setMarginLeft(childOldMarginLeft);
2283 child->setMarginRight(childOldMarginRight);
2284
2285 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
2286 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
2287 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
2288 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
2289 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
2290 child->setChildNeedsLayout(MarkOnlyThis);
2291 return newLogicalTop - logicalTop;
2292 }
2293
2294 newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop);
2295 ASSERT(newLogicalTop >= logicalTop);
2296 if (newLogicalTop < logicalTop)
2297 break;
2298 }
2299 ASSERT_NOT_REACHED();
2300 }
2301 return result;
2302}
2303
2304bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
2305{
2306 if (!m_floatingObjects)
2307 return false;
2308
2309 LayoutPoint adjustedLocation = accumulatedOffset;
2310 if (isRenderView())
2311 adjustedLocation += toLayoutSize(toRenderView(*this).frameView().scrollPosition());
2312
2313 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2314 auto begin = floatingObjectSet.begin();
2315 for (auto it = floatingObjectSet.end(); it != begin;) {
2316 --it;
2317 FloatingObject* floatingObject = it->get();
2318 if (floatingObject->shouldPaint() && !floatingObject->renderer().hasSelfPaintingLayer()) {
2319 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().x();
2320 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer().y();
2321 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
2322 if (floatingObject->renderer().hitTest(request, result, locationInContainer, childPoint)) {
2323 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
2324 return true;
2325 }
2326 }
2327 }
2328
2329 return false;
2330}
2331
2332void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
2333{
2334 RenderBlock::adjustForBorderFit(x, left, right);
2335
2336 if (style()->visibility() == VISIBLE) {
2337 if (m_floatingObjects) {
2338 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2339 auto end = floatingObjectSet.end();
2340 for (auto it = floatingObjectSet.begin(); it != end; ++it) {
2341 FloatingObject* r = it->get();
2342 // Only examine the object if our m_shouldPaint flag is set.
2343 if (r->shouldPaint()) {
2344 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->renderer().x();
2345 LayoutUnit floatRight = floatLeft + r->renderer().width();
2346 left = min(left, floatLeft);
2347 right = max(right, floatRight);
2348 }
2349 }
2350 }
2351 }
2352}
2353
2354
hyatt@apple.com5388e672013-09-06 20:54:47 +00002355} // namespace WebCore