1 /* 2 * Copyright (C) 2013 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "core/rendering/RenderBlockFlow.h" 33 34 #include "core/accessibility/AXObjectCache.h" 35 #include "core/frame/FrameView.h" 36 #include "core/frame/LocalFrame.h" 37 #include "core/frame/Settings.h" 38 #include "core/html/HTMLDialogElement.h" 39 #include "core/paint/BlockFlowPainter.h" 40 #include "core/rendering/HitTestLocation.h" 41 #include "core/rendering/RenderFlowThread.h" 42 #include "core/rendering/RenderLayer.h" 43 #include "core/rendering/RenderMultiColumnFlowThread.h" 44 #include "core/rendering/RenderPagedFlowThread.h" 45 #include "core/rendering/RenderText.h" 46 #include "core/rendering/RenderView.h" 47 #include "core/rendering/TextAutosizer.h" 48 #include "core/rendering/line/LineWidth.h" 49 #include "core/rendering/svg/SVGTextRunRenderingContext.h" 50 #include "platform/text/BidiTextRun.h" 51 52 namespace blink { 53 54 bool RenderBlockFlow::s_canPropagateFloatIntoSibling = false; 55 56 struct SameSizeAsMarginInfo { 57 uint16_t bitfields; 58 LayoutUnit margins[2]; 59 }; 60 61 COMPILE_ASSERT(sizeof(RenderBlockFlow::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small); 62 63 class MarginInfo { 64 // Collapsing flags for whether we can collapse our margins with our children's margins. 65 bool m_canCollapseWithChildren : 1; 66 bool m_canCollapseMarginBeforeWithChildren : 1; 67 bool m_canCollapseMarginAfterWithChildren : 1; 68 bool m_canCollapseMarginAfterWithLastChild: 1; 69 70 // Whether or not we are a quirky container, i.e., do we collapse away top and bottom 71 // margins in our container. Table cells and the body are the common examples. We 72 // also have a custom style property for Safari RSS to deal with TypePad blog articles. 73 bool m_quirkContainer : 1; 74 75 // This flag tracks whether we are still looking at child margins that can all collapse together at the beginning of a block. 76 // They may or may not collapse with the top margin of the block (|m_canCollapseTopWithChildren| tells us that), but they will 77 // always be collapsing with one another. This variable can remain set to true through multiple iterations 78 // as long as we keep encountering self-collapsing blocks. 79 bool m_atBeforeSideOfBlock : 1; 80 81 // This flag is set when we know we're examining bottom margins and we know we're at the bottom of the block. 82 bool m_atAfterSideOfBlock : 1; 83 84 // These variables are used to detect quirky margins that we need to collapse away (in table cells 85 // and in the body element). 86 bool m_hasMarginBeforeQuirk : 1; 87 bool m_hasMarginAfterQuirk : 1; 88 bool m_determinedMarginBeforeQuirk : 1; 89 90 bool m_discardMargin : 1; 91 92 // These flags track the previous maximal positive and negative margins. 93 LayoutUnit m_positiveMargin; 94 LayoutUnit m_negativeMargin; 95 96 public: 97 MarginInfo(RenderBlockFlow*, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding); 98 99 void setAtBeforeSideOfBlock(bool b) { m_atBeforeSideOfBlock = b; } 100 void setAtAfterSideOfBlock(bool b) { m_atAfterSideOfBlock = b; } 101 void clearMargin() 102 { 103 m_positiveMargin = 0; 104 m_negativeMargin = 0; 105 } 106 void setHasMarginBeforeQuirk(bool b) { m_hasMarginBeforeQuirk = b; } 107 void setHasMarginAfterQuirk(bool b) { m_hasMarginAfterQuirk = b; } 108 void setDeterminedMarginBeforeQuirk(bool b) { m_determinedMarginBeforeQuirk = b; } 109 void setPositiveMargin(LayoutUnit p) { ASSERT(!m_discardMargin); m_positiveMargin = p; } 110 void setNegativeMargin(LayoutUnit n) { ASSERT(!m_discardMargin); m_negativeMargin = n; } 111 void setPositiveMarginIfLarger(LayoutUnit p) 112 { 113 ASSERT(!m_discardMargin); 114 if (p > m_positiveMargin) 115 m_positiveMargin = p; 116 } 117 void setNegativeMarginIfLarger(LayoutUnit n) 118 { 119 ASSERT(!m_discardMargin); 120 if (n > m_negativeMargin) 121 m_negativeMargin = n; 122 } 123 124 void setMargin(LayoutUnit p, LayoutUnit n) { ASSERT(!m_discardMargin); m_positiveMargin = p; m_negativeMargin = n; } 125 void setCanCollapseMarginAfterWithChildren(bool collapse) { m_canCollapseMarginAfterWithChildren = collapse; } 126 void setCanCollapseMarginAfterWithLastChild(bool collapse) { m_canCollapseMarginAfterWithLastChild = collapse; } 127 void setDiscardMargin(bool value) { m_discardMargin = value; } 128 129 bool atBeforeSideOfBlock() const { return m_atBeforeSideOfBlock; } 130 bool canCollapseWithMarginBefore() const { return m_atBeforeSideOfBlock && m_canCollapseMarginBeforeWithChildren; } 131 bool canCollapseWithMarginAfter() const { return m_atAfterSideOfBlock && m_canCollapseMarginAfterWithChildren; } 132 bool canCollapseMarginBeforeWithChildren() const { return m_canCollapseMarginBeforeWithChildren; } 133 bool canCollapseMarginAfterWithChildren() const { return m_canCollapseMarginAfterWithChildren; } 134 bool canCollapseMarginAfterWithLastChild() const { return m_canCollapseMarginAfterWithLastChild; } 135 bool quirkContainer() const { return m_quirkContainer; } 136 bool determinedMarginBeforeQuirk() const { return m_determinedMarginBeforeQuirk; } 137 bool hasMarginBeforeQuirk() const { return m_hasMarginBeforeQuirk; } 138 bool hasMarginAfterQuirk() const { return m_hasMarginAfterQuirk; } 139 LayoutUnit positiveMargin() const { return m_positiveMargin; } 140 LayoutUnit negativeMargin() const { return m_negativeMargin; } 141 bool discardMargin() const { return m_discardMargin; } 142 LayoutUnit margin() const { return m_positiveMargin - m_negativeMargin; } 143 }; 144 static bool inNormalFlow(RenderBox* child) 145 { 146 RenderBlock* curr = child->containingBlock(); 147 RenderView* renderView = child->view(); 148 while (curr && curr != renderView) { 149 if (curr->hasColumns() || curr->isRenderFlowThread()) 150 return true; 151 if (curr->isFloatingOrOutOfFlowPositioned()) 152 return false; 153 curr = curr->containingBlock(); 154 } 155 return true; 156 } 157 158 void RenderBlockFlow::RenderBlockFlowRareData::trace(Visitor* visitor) 159 { 160 visitor->trace(m_multiColumnFlowThread); 161 } 162 163 RenderBlockFlow::RenderBlockFlow(ContainerNode* node) 164 : RenderBlock(node) 165 { 166 COMPILE_ASSERT(sizeof(MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small); 167 setChildrenInline(true); 168 } 169 170 RenderBlockFlow::~RenderBlockFlow() 171 { 172 } 173 174 void RenderBlockFlow::trace(Visitor* visitor) 175 { 176 visitor->trace(m_rareData); 177 RenderBlock::trace(visitor); 178 } 179 180 RenderBlockFlow* RenderBlockFlow::createAnonymous(Document* document) 181 { 182 RenderBlockFlow* renderer = new RenderBlockFlow(0); 183 renderer->setDocumentForAnonymous(document); 184 return renderer; 185 } 186 187 RenderObject* RenderBlockFlow::layoutSpecialExcludedChild(bool relayoutChildren, SubtreeLayoutScope& layoutScope) 188 { 189 RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread(); 190 if (!flowThread) 191 return 0; 192 setLogicalTopForChild(flowThread, borderBefore() + paddingBefore()); 193 flowThread->layoutColumns(relayoutChildren, layoutScope); 194 determineLogicalLeftPositionForChild(flowThread); 195 return flowThread; 196 } 197 198 bool RenderBlockFlow::updateLogicalWidthAndColumnWidth() 199 { 200 bool relayoutChildren = RenderBlock::updateLogicalWidthAndColumnWidth(); 201 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { 202 if (flowThread->needsNewWidth()) 203 return true; 204 } 205 return relayoutChildren; 206 } 207 208 void RenderBlockFlow::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) 209 { 210 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { 211 LogicalExtentComputedValues computedValues; 212 computeLogicalHeight(LayoutUnit(), logicalTop(), computedValues); 213 LayoutUnit columnHeight = computedValues.m_extent - borderAndPaddingLogicalHeight() - scrollbarLogicalHeight(); 214 pageLogicalHeightChanged = columnHeight != flowThread->columnHeightAvailable(); 215 flowThread->setColumnHeightAvailable(std::max<LayoutUnit>(columnHeight, 0)); 216 } else if (hasColumns()) { 217 ColumnInfo* colInfo = columnInfo(); 218 219 if (!pageLogicalHeight) { 220 LayoutUnit oldLogicalHeight = logicalHeight(); 221 setLogicalHeight(0); 222 // We need to go ahead and set our explicit page height if one exists, so that we can 223 // avoid doing two layout passes. 224 updateLogicalHeight(); 225 LayoutUnit columnHeight = contentLogicalHeight(); 226 if (columnHeight > 0) { 227 pageLogicalHeight = columnHeight; 228 hasSpecifiedPageLogicalHeight = true; 229 } 230 setLogicalHeight(oldLogicalHeight); 231 } 232 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) { 233 colInfo->setColumnHeight(pageLogicalHeight); 234 pageLogicalHeightChanged = true; 235 } 236 237 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight) 238 colInfo->clearForcedBreaks(); 239 } else if (isRenderFlowThread()) { 240 RenderFlowThread* flowThread = toRenderFlowThread(this); 241 242 // FIXME: This is a hack to always make sure we have a page logical height, if said height 243 // is known. The page logical height thing in LayoutState is meaningless for flow 244 // thread-based pagination (page height isn't necessarily uniform throughout the flow 245 // thread), but as long as it is used universally as a means to determine whether page 246 // height is known or not, we need this. Page height is unknown when column balancing is 247 // enabled and flow thread height is still unknown (i.e. during the first layout pass). When 248 // it's unknown, we need to prevent the pagination code from assuming page breaks everywhere 249 // and thereby eating every top margin. It should be trivial to clean up and get rid of this 250 // hack once the old multicol implementation is gone. 251 pageLogicalHeight = flowThread->isPageLogicalHeightKnown() ? LayoutUnit(1) : LayoutUnit(0); 252 253 pageLogicalHeightChanged = flowThread->pageLogicalSizeChanged(); 254 } 255 } 256 257 bool RenderBlockFlow::shouldRelayoutForPagination(LayoutUnit& pageLogicalHeight, LayoutUnit layoutOverflowLogicalBottom) const 258 { 259 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what 260 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall. 261 ColumnInfo* colInfo = columnInfo(); 262 LayoutUnit columnHeight = pageLogicalHeight; 263 const int minColumnCount = colInfo->forcedBreaks() + 1; 264 const int desiredColumnCount = colInfo->desiredColumnCount(); 265 if (minColumnCount >= desiredColumnCount) { 266 // The forced page breaks are in control of the balancing. Just set the column height to the 267 // maximum page break distance. 268 if (!pageLogicalHeight) { 269 LayoutUnit distanceBetweenBreaks = std::max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(), 270 view()->layoutState()->pageLogicalOffset(*this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset()); 271 columnHeight = std::max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); 272 } 273 } else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) { 274 // Now that we know the intrinsic height of the columns, we have to rebalance them. 275 columnHeight = std::max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf(layoutOverflowLogicalBottom.toFloat() / desiredColumnCount)); 276 } 277 278 if (columnHeight && columnHeight != pageLogicalHeight) { 279 pageLogicalHeight = columnHeight; 280 return true; 281 } 282 283 return false; 284 } 285 286 void RenderBlockFlow::setColumnCountAndHeight(unsigned count, LayoutUnit pageLogicalHeight) 287 { 288 ColumnInfo* colInfo = columnInfo(); 289 if (pageLogicalHeight) 290 colInfo->setColumnCountAndHeight(count, pageLogicalHeight); 291 292 if (columnCount(colInfo)) { 293 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); 294 m_overflow.clear(); 295 } 296 } 297 298 void RenderBlockFlow::setBreakAtLineToAvoidWidow(int lineToBreak) 299 { 300 ASSERT(lineToBreak >= 0); 301 ensureRareData(); 302 ASSERT(!m_rareData->m_didBreakAtLineToAvoidWidow); 303 m_rareData->m_lineBreakToAvoidWidow = lineToBreak; 304 } 305 306 void RenderBlockFlow::setDidBreakAtLineToAvoidWidow() 307 { 308 ASSERT(!shouldBreakAtLineToAvoidWidow()); 309 310 // This function should be called only after a break was applied to avoid widows 311 // so assert |m_rareData| exists. 312 ASSERT(m_rareData); 313 314 m_rareData->m_didBreakAtLineToAvoidWidow = true; 315 } 316 317 void RenderBlockFlow::clearDidBreakAtLineToAvoidWidow() 318 { 319 if (!m_rareData) 320 return; 321 322 m_rareData->m_didBreakAtLineToAvoidWidow = false; 323 } 324 325 void RenderBlockFlow::clearShouldBreakAtLineToAvoidWidow() const 326 { 327 ASSERT(shouldBreakAtLineToAvoidWidow()); 328 if (!m_rareData) 329 return; 330 331 m_rareData->m_lineBreakToAvoidWidow = -1; 332 } 333 334 bool RenderBlockFlow::isSelfCollapsingBlock() const 335 { 336 m_hasOnlySelfCollapsingChildren = RenderBlock::isSelfCollapsingBlock(); 337 return m_hasOnlySelfCollapsingChildren; 338 } 339 340 void RenderBlockFlow::layoutBlock(bool relayoutChildren) 341 { 342 ASSERT(needsLayout()); 343 ASSERT(isInlineBlockOrInlineTable() || !isInline()); 344 345 // If we are self-collapsing with self-collapsing descendants this will get set to save us burrowing through our 346 // descendants every time in |isSelfCollapsingBlock|. We reset it here so that |isSelfCollapsingBlock| attempts to burrow 347 // at least once and so that it always gives a reliable result reflecting the latest layout. 348 m_hasOnlySelfCollapsingChildren = false; 349 350 if (!relayoutChildren && simplifiedLayout()) 351 return; 352 353 SubtreeLayoutScope layoutScope(*this); 354 355 // Multiple passes might be required for column and pagination based layout 356 // In the case of the old column code the number of passes will only be two 357 // however, in the newer column code the number of passes could equal the 358 // number of columns. 359 bool done = false; 360 LayoutUnit pageLogicalHeight = 0; 361 while (!done) 362 done = layoutBlockFlow(relayoutChildren, pageLogicalHeight, layoutScope); 363 364 fitBorderToLinesIfNeeded(); 365 366 RenderView* renderView = view(); 367 if (renderView->layoutState()->pageLogicalHeight()) 368 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(*this, logicalTop())); 369 370 updateLayerTransformAfterLayout(); 371 372 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 373 // we overflow or not. 374 updateScrollInfoAfterLayout(); 375 376 if (m_paintInvalidationLogicalTop != m_paintInvalidationLogicalBottom) { 377 bool hasVisibleContent = style()->visibility() == VISIBLE; 378 if (!hasVisibleContent) { 379 RenderLayer* layer = enclosingLayer(); 380 layer->updateDescendantDependentFlags(); 381 hasVisibleContent = layer->hasVisibleContent(); 382 } 383 if (hasVisibleContent) 384 setShouldInvalidateOverflowForPaint(true); 385 } 386 387 if (isHTMLDialogElement(node()) && isOutOfFlowPositioned()) 388 positionDialog(); 389 390 clearNeedsLayout(); 391 } 392 393 inline bool RenderBlockFlow::layoutBlockFlow(bool relayoutChildren, LayoutUnit &pageLogicalHeight, SubtreeLayoutScope& layoutScope) 394 { 395 LayoutUnit oldLeft = logicalLeft(); 396 bool logicalWidthChanged = updateLogicalWidthAndColumnWidth(); 397 relayoutChildren |= logicalWidthChanged; 398 399 rebuildFloatsFromIntruding(); 400 401 bool pageLogicalHeightChanged = false; 402 bool hasSpecifiedPageLogicalHeight = false; 403 checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight); 404 if (pageLogicalHeightChanged) 405 relayoutChildren = true; 406 407 LayoutState state(*this, locationOffset(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo(), logicalWidthChanged); 408 409 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 410 // our current maximal positive and negative margins. These values are used when we 411 // are collapsed with adjacent blocks, so for example, if you have block A and B 412 // collapsing together, then you'd take the maximal positive margin from both A and B 413 // and subtract it from the maximal negative margin from both A and B to get the 414 // true collapsed margin. This algorithm is recursive, so when we finish layout() 415 // our block knows its current maximal positive/negative values. 416 // 417 // Start out by setting our margin values to our current margins. Table cells have 418 // no margins, so we don't fill in the values for table cells. 419 if (!isTableCell()) { 420 initMaxMarginValues(); 421 setHasMarginBeforeQuirk(style()->hasMarginBeforeQuirk()); 422 setHasMarginAfterQuirk(style()->hasMarginAfterQuirk()); 423 setPaginationStrut(0); 424 } 425 426 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); 427 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 428 LayoutUnit previousHeight = logicalHeight(); 429 setLogicalHeight(beforeEdge); 430 431 m_paintInvalidationLogicalTop = 0; 432 m_paintInvalidationLogicalBottom = 0; 433 if (!firstChild() && !isAnonymousBlock()) 434 setChildrenInline(true); 435 436 TextAutosizer::LayoutScope textAutosizerLayoutScope(this); 437 438 if (childrenInline()) 439 layoutInlineChildren(relayoutChildren, m_paintInvalidationLogicalTop, m_paintInvalidationLogicalBottom, afterEdge); 440 else 441 layoutBlockChildren(relayoutChildren, layoutScope, beforeEdge, afterEdge); 442 443 // Expand our intrinsic height to encompass floats. 444 if (lowestFloatLogicalBottom() > (logicalHeight() - afterEdge) && createsBlockFormattingContext()) 445 setLogicalHeight(lowestFloatLogicalBottom() + afterEdge); 446 447 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { 448 if (flowThread->recalculateColumnHeights()) { 449 setChildNeedsLayout(MarkOnlyThis); 450 return false; 451 } 452 } else if (hasColumns()) { 453 OwnPtr<RenderOverflow> savedOverflow = m_overflow.release(); 454 if (childrenInline()) 455 addOverflowFromInlineChildren(); 456 else 457 addOverflowFromBlockChildren(); 458 LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore(); 459 m_overflow = savedOverflow.release(); 460 461 if (!hasSpecifiedPageLogicalHeight && shouldRelayoutForPagination(pageLogicalHeight, layoutOverflowLogicalBottom)) { 462 setEverHadLayout(true); 463 return false; 464 } 465 466 setColumnCountAndHeight(ceilf(layoutOverflowLogicalBottom.toFloat() / pageLogicalHeight.toFloat()), pageLogicalHeight.toFloat()); 467 } 468 469 if (shouldBreakAtLineToAvoidWidow()) { 470 setEverHadLayout(true); 471 return false; 472 } 473 474 // Calculate our new height. 475 LayoutUnit oldHeight = logicalHeight(); 476 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); 477 478 updateLogicalHeight(); 479 LayoutUnit newHeight = logicalHeight(); 480 if (oldHeight > newHeight && !childrenInline()) { 481 // One of our children's floats may have become an overhanging float for us. 482 for (RenderObject* child = lastChild(); child; child = child->previousSibling()) { 483 if (child->isRenderBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) { 484 RenderBlockFlow* block = toRenderBlockFlow(child); 485 if (block->lowestFloatLogicalBottom() + block->logicalTop() <= newHeight) 486 break; 487 addOverhangingFloats(block, false); 488 } 489 } 490 } 491 492 bool heightChanged = (previousHeight != newHeight); 493 if (heightChanged) 494 relayoutChildren = true; 495 496 layoutPositionedObjects(relayoutChildren || isDocumentElement(), oldLeft != logicalLeft() ? ForcedLayoutAfterContainingBlockMoved : DefaultLayout); 497 498 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 499 computeOverflow(oldClientAfterEdge); 500 501 m_descendantsWithFloatsMarkedForLayout = false; 502 return true; 503 } 504 505 void RenderBlockFlow::determineLogicalLeftPositionForChild(RenderBox* child) 506 { 507 LayoutUnit startPosition = borderStart() + paddingStart(); 508 LayoutUnit initialStartPosition = startPosition; 509 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 510 startPosition -= verticalScrollbarWidth(); 511 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); 512 513 LayoutUnit childMarginStart = marginStartForChild(child); 514 LayoutUnit newPosition = startPosition + childMarginStart; 515 516 LayoutUnit positionToAvoidFloats; 517 if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock()) 518 positionToAvoidFloats = startOffsetForLine(logicalTopForChild(child), false, logicalHeightForChild(child)); 519 520 // If the child has an offset from the content edge to avoid floats then use that, otherwise let any negative 521 // margin pull it back over the content edge or any positive margin push it out. 522 // If the child is being centred then the margin calculated to do that has factored in any offset required to 523 // avoid floats, so use it if necessary. 524 if (style()->textAlign() == WEBKIT_CENTER || child->style()->marginStartUsing(style()).isAuto()) 525 newPosition = std::max(newPosition, positionToAvoidFloats + childMarginStart); 526 else if (positionToAvoidFloats > initialStartPosition) 527 newPosition = std::max(newPosition, positionToAvoidFloats); 528 529 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child)); 530 } 531 532 void RenderBlockFlow::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft) 533 { 534 if (isHorizontalWritingMode()) { 535 child->setX(logicalLeft); 536 } else { 537 child->setY(logicalLeft); 538 } 539 } 540 541 void RenderBlockFlow::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop) 542 { 543 if (isHorizontalWritingMode()) { 544 child->setY(logicalTop); 545 } else { 546 child->setX(logicalTop); 547 } 548 } 549 550 void RenderBlockFlow::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom) 551 { 552 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); 553 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); 554 555 // The child is a normal flow object. Compute the margins we will use for collapsing now. 556 child->computeAndSetBlockDirectionMargins(this); 557 558 // Try to guess our correct logical top position. In most cases this guess will 559 // be correct. Only if we're wrong (when we compute the real logical top position) 560 // will we have to potentially relayout. 561 LayoutUnit estimateWithoutPagination; 562 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination); 563 564 // Cache our old rect so that we can dirty the proper paint invalidation rects if the child moves. 565 LayoutRect oldRect = child->frameRect(); 566 LayoutUnit oldLogicalTop = logicalTopForChild(child); 567 568 // Go ahead and position the child as though it didn't collapse with the top. 569 setLogicalTopForChild(child, logicalTopEstimate); 570 571 RenderBlockFlow* childRenderBlockFlow = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0; 572 bool markDescendantsWithFloats = false; 573 if (logicalTopEstimate != oldLogicalTop && childRenderBlockFlow && !childRenderBlockFlow->avoidsFloats() && childRenderBlockFlow->containsFloats()) { 574 markDescendantsWithFloats = true; 575 } else if (UNLIKELY(logicalTopEstimate.mightBeSaturated())) { 576 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for 577 // very large elements. If it does the comparison with oldLogicalTop might yield a 578 // false negative as adding and removing margins, borders etc from a saturated number 579 // might yield incorrect results. If this is the case always mark for layout. 580 markDescendantsWithFloats = true; 581 } else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 582 // If an element might be affected by the presence of floats, then always mark it for 583 // layout. 584 LayoutUnit fb = std::max(previousFloatLogicalBottom, lowestFloatLogicalBottom()); 585 if (fb > logicalTopEstimate) 586 markDescendantsWithFloats = true; 587 } 588 589 if (childRenderBlockFlow) { 590 if (markDescendantsWithFloats) 591 childRenderBlockFlow->markAllDescendantsWithFloatsForLayout(); 592 if (!child->isWritingModeRoot()) 593 previousFloatLogicalBottom = std::max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlockFlow->lowestFloatLogicalBottom()); 594 } 595 596 SubtreeLayoutScope layoutScope(*child); 597 if (!child->needsLayout()) 598 child->markForPaginationRelayoutIfNeeded(layoutScope); 599 600 bool childHadLayout = child->everHadLayout(); 601 bool childNeededLayout = child->needsLayout(); 602 if (childNeededLayout) 603 child->layout(); 604 605 // Cache if we are at the top of the block right now. 606 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); 607 bool childIsSelfCollapsing = child->isSelfCollapsingBlock(); 608 609 // Now determine the correct ypos based off examination of collapsing margin 610 // values. 611 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo, childIsSelfCollapsing); 612 613 // Now check for clear. 614 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear, childIsSelfCollapsing); 615 616 bool paginated = view()->layoutState()->isPaginated(); 617 if (paginated) { 618 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, 619 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear); 620 } 621 622 setLogicalTopForChild(child, logicalTopAfterClear); 623 624 // Now we have a final top position. See if it really does end up being different from our estimate. 625 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens 626 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins. 627 if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlockFlow && childRenderBlockFlow->shouldBreakAtLineToAvoidWidow())) { 628 SubtreeLayoutScope layoutScope(*child); 629 if (child->shrinkToAvoidFloats()) { 630 // The child's width depends on the line width. 631 // When the child shifts to clear an item, its width can 632 // change (because it has more available line width). 633 // So go ahead and mark the item as dirty. 634 layoutScope.setChildNeedsLayout(child); 635 } 636 637 if (childRenderBlockFlow && !childRenderBlockFlow->avoidsFloats() && childRenderBlockFlow->containsFloats()) 638 childRenderBlockFlow->markAllDescendantsWithFloatsForLayout(); 639 640 if (!child->needsLayout()) 641 child->markForPaginationRelayoutIfNeeded(layoutScope); 642 643 // Our guess was wrong. Make the child lay itself out again. 644 child->layoutIfNeeded(); 645 } 646 647 // If we previously encountered a self-collapsing sibling of this child that had clearance then 648 // we set this bit to ensure we would not collapse the child's margins, and those of any subsequent 649 // self-collapsing siblings, with our parent. If this child is not self-collapsing then it can 650 // collapse its margins with the parent so reset the bit. 651 if (!marginInfo.canCollapseMarginAfterWithLastChild() && !childIsSelfCollapsing) 652 marginInfo.setCanCollapseMarginAfterWithLastChild(true); 653 654 // We are no longer at the top of the block if we encounter a non-empty child. 655 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 656 if (marginInfo.atBeforeSideOfBlock() && !childIsSelfCollapsing) 657 marginInfo.setAtBeforeSideOfBlock(false); 658 659 // Now place the child in the correct left position 660 determineLogicalLeftPositionForChild(child); 661 662 LayoutSize childOffset = child->location() - oldRect.location(); 663 664 // Update our height now that the child has been placed in the correct position. 665 setLogicalHeight(logicalHeight() + logicalHeightForChild(child)); 666 if (mustSeparateMarginAfterForChild(child)) { 667 setLogicalHeight(logicalHeight() + marginAfterForChild(child)); 668 marginInfo.clearMargin(); 669 } 670 // If the child has overhanging floats that intrude into following siblings (or possibly out 671 // of this block), then the parent gets notified of the floats now. 672 if (childRenderBlockFlow) 673 addOverhangingFloats(childRenderBlockFlow, !childNeededLayout); 674 675 // If the child moved, we have to invalidate it's paint as well as any floating/positioned 676 // descendants. An exception is if we need a layout. In this case, we know we're going to 677 // invalidate our paint (and the child) anyway. 678 bool didNotDoFullLayoutAndMoved = childHadLayout && !selfNeedsLayout() && (childOffset.width() || childOffset.height()); 679 bool didNotLayoutAndNeedsPaintInvalidation = !childHadLayout && child->checkForPaintInvalidation(); 680 681 if (didNotDoFullLayoutAndMoved || didNotLayoutAndNeedsPaintInvalidation) 682 child->invalidatePaintForOverhangingFloats(true); 683 684 if (paginated) { 685 // Check for an after page/column break. 686 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo); 687 if (newHeight != height()) 688 setLogicalHeight(newHeight); 689 } 690 } 691 692 LayoutUnit RenderBlockFlow::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock) 693 { 694 RenderBlockFlow* childBlockFlow = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0; 695 696 if (estimateWithoutPagination != logicalTopAfterClear) { 697 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new 698 // position. 699 setLogicalHeight(logicalTopAfterClear); 700 setLogicalTopForChild(child, logicalTopAfterClear); 701 702 if (child->shrinkToAvoidFloats()) { 703 // The child's width depends on the line width. 704 // When the child shifts to clear an item, its width can 705 // change (because it has more available line width). 706 // So go ahead and mark the item as dirty. 707 child->setChildNeedsLayout(MarkOnlyThis); 708 } 709 710 SubtreeLayoutScope layoutScope(*child); 711 712 if (childBlockFlow) { 713 if (!childBlockFlow->avoidsFloats() && childBlockFlow->containsFloats()) 714 childBlockFlow->markAllDescendantsWithFloatsForLayout(); 715 if (!child->needsLayout()) 716 child->markForPaginationRelayoutIfNeeded(layoutScope); 717 } 718 719 // Our guess was wrong. Make the child lay itself out again. 720 child->layoutIfNeeded(); 721 } 722 723 LayoutUnit oldTop = logicalTopAfterClear; 724 725 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 726 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear); 727 728 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 729 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result; 730 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result); 731 732 LayoutUnit paginationStrut = 0; 733 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; 734 LayoutUnit childLogicalHeight = child->logicalHeight(); 735 if (unsplittableAdjustmentDelta) { 736 setPageBreak(result, childLogicalHeight - unsplittableAdjustmentDelta); 737 paginationStrut = unsplittableAdjustmentDelta; 738 } else if (childBlockFlow && childBlockFlow->paginationStrut()) { 739 paginationStrut = childBlockFlow->paginationStrut(); 740 } 741 742 if (paginationStrut) { 743 // We are willing to propagate out to our parent block as long as we were at the top of the block prior 744 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination. 745 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) { 746 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't 747 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too 748 // and pushes to the next page anyway, so not too concerned about it. 749 setPaginationStrut(result + paginationStrut); 750 if (childBlockFlow) 751 childBlockFlow->setPaginationStrut(0); 752 } else { 753 result += paginationStrut; 754 } 755 } 756 757 if (!unsplittableAdjustmentDelta) { 758 if (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(result)) { 759 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary); 760 LayoutUnit spaceShortage = childLogicalHeight - remainingLogicalHeight; 761 if (spaceShortage > 0) { 762 // If the child crosses a column boundary, report a break, in case nothing inside it 763 // has already done so. The column balancer needs to know how much it has to stretch 764 // the columns to make more content fit. If no breaks are reported (but do occur), 765 // the balancer will have no clue. Only measure the space after the last column 766 // boundary, in case it crosses more than one. 767 LayoutUnit spaceShortageInLastColumn = intMod(spaceShortage, pageLogicalHeight); 768 setPageBreak(result, spaceShortageInLastColumn ? spaceShortageInLastColumn : spaceShortage); 769 } else if (remainingLogicalHeight == pageLogicalHeight && offsetFromLogicalTopOfFirstPage() + child->logicalTop()) { 770 // We're at the very top of a page or column, and it's not the first one. This child 771 // may turn out to be the smallest piece of content that causes a page break, so we 772 // need to report it. 773 setPageBreak(result, childLogicalHeight); 774 } 775 } 776 } 777 778 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. 779 setLogicalHeight(logicalHeight() + (result - oldTop)); 780 781 // Return the final adjusted logical top. 782 return result; 783 } 784 785 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom) 786 { 787 // We may require a certain minimum number of lines per page in order to satisfy 788 // orphans and widows, and that may affect the minimum page height. 789 unsigned lineCount = std::max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows()); 790 if (lineCount > 1) { 791 RootInlineBox* line = lastLine; 792 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++) 793 line = line->prevRootBox(); 794 795 // FIXME: Paginating using line overflow isn't all fine. See FIXME in 796 // adjustLinePositionForPagination() for more details. 797 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom()); 798 lineTop = std::min(line->lineTopWithLeading(), overflow.y()); 799 } 800 return lineBottom - lineTop; 801 } 802 803 void RenderBlockFlow::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread) 804 { 805 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we 806 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since 807 // the line on the top of the next page will appear too far down relative to the same kind of line at the top 808 // of the first column. 809 // 810 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow 811 // simply spills out above the top of the column. This effect would match what happens at the top of the first column. 812 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing 813 // for overflow to occur), and then cache visible overflow for each column rect. 814 // 815 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude 816 // content that paints in a previous column (and content that paints in the following column). 817 // 818 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will 819 // at least make positive leading work in typical cases. 820 // 821 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats). 822 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the 823 // line and all following lines. 824 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom()); 825 LayoutUnit logicalOffset = std::min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y()); 826 LayoutUnit logicalBottom = std::max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()); 827 LayoutUnit lineHeight = logicalBottom - logicalOffset; 828 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom)); 829 logicalOffset += delta; 830 lineBox->setPaginationStrut(0); 831 lineBox->setIsFirstAfterPageBreak(false); 832 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); 833 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight(); 834 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are 835 // still going to add a strut, so that the visible overflow fits on a single page. 836 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)) { 837 // 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. 838 // 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. 839 return; 840 } 841 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); 842 843 int lineIndex = lineCount(lineBox); 844 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) { 845 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) { 846 clearShouldBreakAtLineToAvoidWidow(); 847 setDidBreakAtLineToAvoidWidow(); 848 } 849 if (lineHeight > pageLogicalHeight) { 850 // Split the top margin in order to avoid splitting the visible part of the line. 851 remainingLogicalHeight -= std::min(lineHeight - pageLogicalHeight, std::max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading())); 852 } 853 LayoutUnit totalLogicalHeight = lineHeight + std::max<LayoutUnit>(0, logicalOffset); 854 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight); 855 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight); 856 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineIndex)) 857 && !isOutOfFlowPositioned() && !isTableCell()) { 858 setPaginationStrut(remainingLogicalHeight + std::max<LayoutUnit>(0, logicalOffset)); 859 } else { 860 delta += remainingLogicalHeight; 861 lineBox->setPaginationStrut(remainingLogicalHeight); 862 lineBox->setIsFirstAfterPageBreak(true); 863 } 864 } else if (remainingLogicalHeight == pageLogicalHeight) { 865 // We're at the very top of a page or column. 866 if (lineBox != firstRootBox()) 867 lineBox->setIsFirstAfterPageBreak(true); 868 if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage()) 869 setPageBreak(logicalOffset, lineHeight); 870 } 871 } 872 873 LayoutUnit RenderBlockFlow::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins) 874 { 875 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns() || flowThreadContainingBlock(); 876 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); 877 bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID) 878 || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID); 879 if (!isUnsplittable) 880 return logicalOffset; 881 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit()); 882 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); 883 updateMinimumPageHeight(logicalOffset, childLogicalHeight); 884 if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight) 885 return logicalOffset; 886 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); 887 if (remainingLogicalHeight < childLogicalHeight) 888 return logicalOffset + remainingLogicalHeight; 889 return logicalOffset; 890 } 891 892 void RenderBlockFlow::rebuildFloatsFromIntruding() 893 { 894 if (m_floatingObjects) 895 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode()); 896 897 HashSet<RenderBox*> oldIntrudingFloatSet; 898 if (!childrenInline() && m_floatingObjects) { 899 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 900 FloatingObjectSetIterator end = floatingObjectSet.end(); 901 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 902 FloatingObject* floatingObject = it->get(); 903 if (!floatingObject->isDescendant()) 904 oldIntrudingFloatSet.add(floatingObject->renderer()); 905 } 906 } 907 908 // Inline blocks are covered by the isReplaced() check in the avoidFloats method. 909 if (avoidsFloats() || isDocumentElement() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) { 910 if (m_floatingObjects) { 911 m_floatingObjects->clear(); 912 } 913 if (!oldIntrudingFloatSet.isEmpty()) 914 markAllDescendantsWithFloatsForLayout(); 915 return; 916 } 917 918 RendererToFloatInfoMap floatMap; 919 920 if (m_floatingObjects) { 921 if (childrenInline()) 922 m_floatingObjects->moveAllToFloatInfoMap(floatMap); 923 else 924 m_floatingObjects->clear(); 925 } 926 927 // We should not process floats if the parent node is not a RenderBlockFlow. Otherwise, we will add 928 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent. 929 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG. 930 if (!parent() || !parent()->isRenderBlockFlow()) 931 return; 932 933 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that 934 // may have shifted to avoid floats, and any objects whose floats cannot interact with objects 935 // outside it (i.e. objects that create a new block formatting context). 936 RenderBlockFlow* parentBlockFlow = toRenderBlockFlow(parent()); 937 bool parentHasFloats = false; 938 RenderObject* prev = previousSibling(); 939 while (prev && (!prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats() || toRenderBlock(prev)->createsBlockFormattingContext())) { 940 if (prev->isFloating()) 941 parentHasFloats = true; 942 prev = prev->previousSibling(); 943 } 944 945 // First add in floats from the parent. Self-collapsing blocks let their parent track any floats that intrude into 946 // them (as opposed to floats they contain themselves) so check for those here too. 947 LayoutUnit logicalTopOffset = logicalTop(); 948 bool parentHasIntrudingFloats = !parentHasFloats && (!prev || toRenderBlockFlow(prev)->isSelfCollapsingBlock()) && parentBlockFlow->lowestFloatLogicalBottom() > logicalTopOffset; 949 if (parentHasFloats || parentHasIntrudingFloats) 950 addIntrudingFloats(parentBlockFlow, parentBlockFlow->logicalLeftOffsetForContent(), logicalTopOffset); 951 952 // Add overhanging floats from the previous RenderBlockFlow, but only if it has a float that intrudes into our space. 953 if (prev) { 954 RenderBlockFlow* blockFlow = toRenderBlockFlow(prev); 955 logicalTopOffset -= blockFlow->logicalTop(); 956 if (blockFlow->lowestFloatLogicalBottom() > logicalTopOffset) 957 addIntrudingFloats(blockFlow, 0, logicalTopOffset); 958 } 959 960 if (childrenInline()) { 961 LayoutUnit changeLogicalTop = LayoutUnit::max(); 962 LayoutUnit changeLogicalBottom = LayoutUnit::min(); 963 if (m_floatingObjects) { 964 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 965 FloatingObjectSetIterator end = floatingObjectSet.end(); 966 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 967 FloatingObject* floatingObject = it->get(); 968 FloatingObject* oldFloatingObject = floatMap.get(floatingObject->renderer()); 969 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject); 970 if (oldFloatingObject) { 971 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject); 972 if (logicalWidthForFloat(floatingObject) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(floatingObject) != logicalLeftForFloat(oldFloatingObject)) { 973 changeLogicalTop = 0; 974 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom)); 975 } else { 976 if (logicalBottom != oldLogicalBottom) { 977 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalBottom, oldLogicalBottom)); 978 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalBottom, oldLogicalBottom)); 979 } 980 LayoutUnit logicalTop = logicalTopForFloat(floatingObject); 981 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject); 982 if (logicalTop != oldLogicalTop) { 983 changeLogicalTop = std::min(changeLogicalTop, std::min(logicalTop, oldLogicalTop)); 984 changeLogicalBottom = std::max(changeLogicalBottom, std::max(logicalTop, oldLogicalTop)); 985 } 986 } 987 988 if (oldFloatingObject->originatingLine() && !selfNeedsLayout()) { 989 ASSERT(oldFloatingObject->originatingLine()->renderer() == this); 990 oldFloatingObject->originatingLine()->markDirty(); 991 } 992 993 floatMap.remove(floatingObject->renderer()); 994 } else { 995 changeLogicalTop = 0; 996 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottom); 997 } 998 } 999 } 1000 1001 RendererToFloatInfoMap::iterator end = floatMap.end(); 1002 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { 1003 OwnPtr<FloatingObject>& floatingObject = it->value; 1004 if (!floatingObject->isDescendant()) { 1005 changeLogicalTop = 0; 1006 changeLogicalBottom = std::max(changeLogicalBottom, logicalBottomForFloat(floatingObject.get())); 1007 } 1008 } 1009 1010 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); 1011 } else if (!oldIntrudingFloatSet.isEmpty()) { 1012 // If there are previously intruding floats that no longer intrude, then children with floats 1013 // should also get layout because they might need their floating object lists cleared. 1014 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size()) { 1015 markAllDescendantsWithFloatsForLayout(); 1016 } else { 1017 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1018 FloatingObjectSetIterator end = floatingObjectSet.end(); 1019 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it) 1020 oldIntrudingFloatSet.remove((*it)->renderer()); 1021 if (!oldIntrudingFloatSet.isEmpty()) 1022 markAllDescendantsWithFloatsForLayout(); 1023 } 1024 } 1025 } 1026 1027 void RenderBlockFlow::layoutBlockChildren(bool relayoutChildren, SubtreeLayoutScope& layoutScope, LayoutUnit beforeEdge, LayoutUnit afterEdge) 1028 { 1029 dirtyForLayoutFromPercentageHeightDescendants(layoutScope); 1030 1031 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 1032 MarginInfo marginInfo(this, beforeEdge, afterEdge); 1033 1034 // Fieldsets need to find their legend and position it inside the border of the object. 1035 // The legend then gets skipped during normal layout. The same is true for ruby text. 1036 // It doesn't get included in the normal layout process but is instead skipped. 1037 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren, layoutScope); 1038 1039 LayoutUnit previousFloatLogicalBottom = 0; 1040 1041 RenderBox* next = firstChildBox(); 1042 RenderBox* lastNormalFlowChild = 0; 1043 1044 while (next) { 1045 RenderBox* child = next; 1046 next = child->nextSiblingBox(); 1047 1048 // FIXME: this should only be set from clearNeedsLayout crbug.com/361250 1049 child->setLayoutDidGetCalled(true); 1050 1051 if (childToExclude == child) 1052 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs). 1053 1054 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); 1055 1056 if (child->isOutOfFlowPositioned()) { 1057 child->containingBlock()->insertPositionedObject(child); 1058 adjustPositionedBlock(child, marginInfo); 1059 continue; 1060 } 1061 if (child->isFloating()) { 1062 insertFloatingObject(child); 1063 adjustFloatingBlock(marginInfo); 1064 continue; 1065 } 1066 1067 // Lay out the child. 1068 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom); 1069 lastNormalFlowChild = child; 1070 } 1071 1072 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 1073 // determining the correct collapsed bottom margin information. 1074 handleAfterSideOfBlock(lastNormalFlowChild, beforeEdge, afterEdge, marginInfo); 1075 } 1076 1077 // Our MarginInfo state used when laying out block children. 1078 MarginInfo::MarginInfo(RenderBlockFlow* blockFlow, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding) 1079 : m_canCollapseMarginAfterWithLastChild(true) 1080 , m_atBeforeSideOfBlock(true) 1081 , m_atAfterSideOfBlock(false) 1082 , m_hasMarginBeforeQuirk(false) 1083 , m_hasMarginAfterQuirk(false) 1084 , m_determinedMarginBeforeQuirk(false) 1085 , m_discardMargin(false) 1086 { 1087 RenderStyle* blockStyle = blockFlow->style(); 1088 ASSERT(blockFlow->isRenderView() || blockFlow->parent()); 1089 m_canCollapseWithChildren = !blockFlow->createsBlockFormattingContext() && !blockFlow->isRenderFlowThread() && !blockFlow->isRenderView(); 1090 1091 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE; 1092 1093 // If any height other than auto is specified in CSS, then we don't collapse our bottom 1094 // margins with our children's margins. To do otherwise would be to risk odd visual 1095 // effects when the children overflow out of the parent block and yet still collapse 1096 // with it. We also don't collapse if we have any bottom border/padding. 1097 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && !afterBorderPadding 1098 && (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE; 1099 1100 m_quirkContainer = blockFlow->isTableCell() || blockFlow->isBody(); 1101 1102 m_discardMargin = m_canCollapseMarginBeforeWithChildren && blockFlow->mustDiscardMarginBefore(); 1103 1104 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mustDiscardMarginBefore()) ? blockFlow->maxPositiveMarginBefore() : LayoutUnit(); 1105 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !blockFlow->mustDiscardMarginBefore()) ? blockFlow->maxNegativeMarginBefore() : LayoutUnit(); 1106 } 1107 1108 RenderBlockFlow::MarginValues RenderBlockFlow::marginValuesForChild(RenderBox* child) const 1109 { 1110 LayoutUnit childBeforePositive = 0; 1111 LayoutUnit childBeforeNegative = 0; 1112 LayoutUnit childAfterPositive = 0; 1113 LayoutUnit childAfterNegative = 0; 1114 1115 LayoutUnit beforeMargin = 0; 1116 LayoutUnit afterMargin = 0; 1117 1118 RenderBlockFlow* childRenderBlockFlow = child->isRenderBlockFlow() ? toRenderBlockFlow(child) : 0; 1119 1120 // If the child has the same directionality as we do, then we can just return its 1121 // margins in the same direction. 1122 if (!child->isWritingModeRoot()) { 1123 if (childRenderBlockFlow) { 1124 childBeforePositive = childRenderBlockFlow->maxPositiveMarginBefore(); 1125 childBeforeNegative = childRenderBlockFlow->maxNegativeMarginBefore(); 1126 childAfterPositive = childRenderBlockFlow->maxPositiveMarginAfter(); 1127 childAfterNegative = childRenderBlockFlow->maxNegativeMarginAfter(); 1128 } else { 1129 beforeMargin = child->marginBefore(); 1130 afterMargin = child->marginAfter(); 1131 } 1132 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) { 1133 // The child has a different directionality. If the child is parallel, then it's just 1134 // flipped relative to us. We can use the margins for the opposite edges. 1135 if (childRenderBlockFlow) { 1136 childBeforePositive = childRenderBlockFlow->maxPositiveMarginAfter(); 1137 childBeforeNegative = childRenderBlockFlow->maxNegativeMarginAfter(); 1138 childAfterPositive = childRenderBlockFlow->maxPositiveMarginBefore(); 1139 childAfterNegative = childRenderBlockFlow->maxNegativeMarginBefore(); 1140 } else { 1141 beforeMargin = child->marginAfter(); 1142 afterMargin = child->marginBefore(); 1143 } 1144 } else { 1145 // The child is perpendicular to us, which means its margins don't collapse but are on the 1146 // "logical left/right" sides of the child box. We can just return the raw margin in this case. 1147 beforeMargin = marginBeforeForChild(child); 1148 afterMargin = marginAfterForChild(child); 1149 } 1150 1151 // Resolve uncollapsing margins into their positive/negative buckets. 1152 if (beforeMargin) { 1153 if (beforeMargin > 0) 1154 childBeforePositive = beforeMargin; 1155 else 1156 childBeforeNegative = -beforeMargin; 1157 } 1158 if (afterMargin) { 1159 if (afterMargin > 0) 1160 childAfterPositive = afterMargin; 1161 else 1162 childAfterNegative = -afterMargin; 1163 } 1164 1165 return RenderBlockFlow::MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative); 1166 } 1167 1168 LayoutUnit RenderBlockFlow::collapseMargins(RenderBox* child, MarginInfo& marginInfo, bool childIsSelfCollapsing) 1169 { 1170 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child); 1171 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child); 1172 1173 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block. 1174 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing); 1175 1176 // Get the four margin values for the child and cache them. 1177 const RenderBlockFlow::MarginValues childMargins = marginValuesForChild(child); 1178 1179 // Get our max pos and neg top margins. 1180 LayoutUnit posTop = childMargins.positiveMarginBefore(); 1181 LayoutUnit negTop = childMargins.negativeMarginBefore(); 1182 1183 // For self-collapsing blocks, collapse our bottom margins into our 1184 // top to get new posTop and negTop values. 1185 if (childIsSelfCollapsing) { 1186 posTop = std::max(posTop, childMargins.positiveMarginAfter()); 1187 negTop = std::max(negTop, childMargins.negativeMarginAfter()); 1188 } 1189 1190 // See if the top margin is quirky. We only care if this child has 1191 // margins that will collapse with us. 1192 bool topQuirk = hasMarginBeforeQuirk(child); 1193 1194 if (marginInfo.canCollapseWithMarginBefore()) { 1195 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) { 1196 // This child is collapsing with the top of the 1197 // block. If it has larger margin values, then we need to update 1198 // our own maximal values. 1199 if (!document().inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk) 1200 setMaxMarginBeforeValues(std::max(posTop, maxPositiveMarginBefore()), std::max(negTop, maxNegativeMarginBefore())); 1201 1202 // The minute any of the margins involved isn't a quirk, don't 1203 // collapse it away, even if the margin is smaller (www.webreference.com 1204 // has an example of this, a <dt> with 0.8em author-specified inside 1205 // a <dl> inside a <td>. 1206 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) { 1207 setHasMarginBeforeQuirk(false); 1208 marginInfo.setDeterminedMarginBeforeQuirk(true); 1209 } 1210 1211 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore()) { 1212 // We have no top margin and our top child has a quirky margin. 1213 // We will pick up this quirky margin and pass it through. 1214 // This deals with the <td><div><p> case. 1215 // Don't do this for a block that split two inlines though. You do 1216 // still apply margins in this case. 1217 setHasMarginBeforeQuirk(true); 1218 } 1219 } else { 1220 // The before margin of the container will also discard all the margins it is collapsing with. 1221 setMustDiscardMarginBefore(); 1222 } 1223 } 1224 1225 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard. 1226 if (childDiscardMarginBefore) { 1227 marginInfo.setDiscardMargin(true); 1228 marginInfo.clearMargin(); 1229 } 1230 1231 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop)) 1232 marginInfo.setHasMarginBeforeQuirk(topQuirk); 1233 1234 LayoutUnit beforeCollapseLogicalTop = logicalHeight(); 1235 LayoutUnit logicalTop = beforeCollapseLogicalTop; 1236 1237 LayoutUnit clearanceForSelfCollapsingBlock; 1238 RenderObject* prev = child->previousSibling(); 1239 RenderBlockFlow* previousBlockFlow = prev && prev->isRenderBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned() ? toRenderBlockFlow(prev) : 0; 1240 // If the child's previous sibling is a self-collapsing block that cleared a float then its top border edge has been set at the bottom border edge 1241 // of the float. Since we want to collapse the child's top margin with the self-collapsing block's top and bottom margins we need to adjust our parent's height to match the 1242 // margin top of the self-collapsing block. If the resulting collapsed margin leaves the child still intruding into the float then we will want to clear it. 1243 if (!marginInfo.canCollapseWithMarginBefore() && previousBlockFlow && previousBlockFlow->isSelfCollapsingBlock()) { 1244 clearanceForSelfCollapsingBlock = previousBlockFlow->marginOffsetForSelfCollapsingBlock(); 1245 setLogicalHeight(logicalHeight() - clearanceForSelfCollapsingBlock); 1246 } 1247 1248 if (childIsSelfCollapsing) { 1249 // 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. 1250 // Also, the child's top position equals the logical height of the container. 1251 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) { 1252 // This child has no height. We need to compute our 1253 // position before we collapse the child's margins together, 1254 // so that we can get an accurate position for the zero-height block. 1255 LayoutUnit collapsedBeforePos = std::max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore()); 1256 LayoutUnit collapsedBeforeNeg = std::max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore()); 1257 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg); 1258 1259 // Now collapse the child's margins together, which means examining our 1260 // bottom margin values as well. 1261 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter()); 1262 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter()); 1263 1264 if (!marginInfo.canCollapseWithMarginBefore()) { 1265 // We need to make sure that the position of the self-collapsing block 1266 // is correct, since it could have overflowing content 1267 // that needs to be positioned correctly (e.g., a block that 1268 // had a specified height of 0 but that actually had subcontent). 1269 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg; 1270 } 1271 } 1272 } else { 1273 if (mustSeparateMarginBeforeForChild(child)) { 1274 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin())); 1275 // If we are at the before side of the block and we collapse, ignore the computed margin 1276 // and just add the child margin to the container height. This will correctly position 1277 // the child inside the container. 1278 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0); 1279 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child)); 1280 logicalTop = logicalHeight(); 1281 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock() 1282 || (!marginInfo.canCollapseMarginBeforeWithChildren() 1283 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) { 1284 // We're collapsing with a previous sibling's margins and not 1285 // with the top of the block. 1286 setLogicalHeight(logicalHeight() + std::max(marginInfo.positiveMargin(), posTop) - std::max(marginInfo.negativeMargin(), negTop)); 1287 logicalTop = logicalHeight(); 1288 } 1289 1290 marginInfo.setDiscardMargin(childDiscardMarginAfter); 1291 1292 if (!marginInfo.discardMargin()) { 1293 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); 1294 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); 1295 } else { 1296 marginInfo.clearMargin(); 1297 } 1298 1299 if (marginInfo.margin()) 1300 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child)); 1301 } 1302 1303 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins 1304 // collapsed into the page edge. 1305 LayoutState* layoutState = view()->layoutState(); 1306 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop) { 1307 LayoutUnit oldLogicalTop = logicalTop; 1308 logicalTop = std::min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); 1309 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); 1310 } 1311 1312 if (previousBlockFlow) { 1313 // If |child| is a self-collapsing block it may have collapsed into a previous sibling and although it hasn't reduced the height of the parent yet 1314 // any floats from the parent will now overhang. 1315 LayoutUnit oldLogicalHeight = logicalHeight(); 1316 setLogicalHeight(logicalTop); 1317 if (!previousBlockFlow->avoidsFloats() && (previousBlockFlow->logicalTop() + previousBlockFlow->lowestFloatLogicalBottom()) > logicalTop) 1318 addOverhangingFloats(previousBlockFlow, false); 1319 setLogicalHeight(oldLogicalHeight); 1320 1321 // If |child|'s previous sibling is a self-collapsing block that cleared a float and margin collapsing resulted in |child| moving up 1322 // into the margin area of the self-collapsing block then the float it clears is now intruding into |child|. Layout again so that we can look for 1323 // floats in the parent that overhang |child|'s new logical top. 1324 bool logicalTopIntrudesIntoFloat = clearanceForSelfCollapsingBlock > 0 && logicalTop < beforeCollapseLogicalTop; 1325 if (logicalTopIntrudesIntoFloat && containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop) 1326 child->setNeedsLayoutAndFullPaintInvalidation(); 1327 } 1328 1329 return logicalTop; 1330 } 1331 1332 void RenderBlockFlow::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 1333 { 1334 bool isHorizontal = isHorizontalWritingMode(); 1335 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal); 1336 1337 LayoutUnit logicalTop = logicalHeight(); 1338 updateStaticInlinePositionForChild(child, logicalTop); 1339 1340 if (!marginInfo.canCollapseWithMarginBefore()) { 1341 // Positioned blocks don't collapse margins, so add the margin provided by 1342 // the container now. The child's own margin is added later when calculating its logical top. 1343 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin(); 1344 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin(); 1345 logicalTop += collapsedBeforePos - collapsedBeforeNeg; 1346 } 1347 1348 RenderLayer* childLayer = child->layer(); 1349 if (childLayer->staticBlockPosition() != logicalTop) { 1350 childLayer->setStaticBlockPosition(logicalTop); 1351 if (hasStaticBlockPosition) 1352 child->setChildNeedsLayout(MarkOnlyThis); 1353 } 1354 } 1355 1356 LayoutUnit RenderBlockFlow::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos, bool childIsSelfCollapsing) 1357 { 1358 LayoutUnit heightIncrease = getClearDelta(child, yPos); 1359 if (!heightIncrease) 1360 return yPos; 1361 1362 if (childIsSelfCollapsing) { 1363 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child); 1364 1365 // For self-collapsing blocks that clear, they can still collapse their 1366 // margins with following siblings. Reset the current margins to represent 1367 // the self-collapsing block's margins only. 1368 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values. 1369 RenderBlockFlow::MarginValues childMargins = marginValuesForChild(child); 1370 if (!childDiscardMargin) { 1371 marginInfo.setPositiveMargin(std::max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); 1372 marginInfo.setNegativeMargin(std::max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); 1373 } else { 1374 marginInfo.clearMargin(); 1375 } 1376 marginInfo.setDiscardMargin(childDiscardMargin); 1377 1378 // CSS2.1 states: 1379 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with 1380 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block." 1381 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Set a bit to ensure 1382 // this happens; it will get reset if we encounter an in-flow sibling that is not self-collapsing. 1383 marginInfo.setCanCollapseMarginAfterWithLastChild(false); 1384 1385 // For now set the border-top of |child| flush with the bottom border-edge of the float so it can layout any floating or positioned children of 1386 // its own at the correct vertical position. If subsequent siblings attempt to collapse with |child|'s margins in |collapseMargins| we will 1387 // adjust the height of the parent to |child|'s margin top (which if it is positive sits up 'inside' the float it's clearing) so that all three 1388 // margins can collapse at the correct vertical position. 1389 // Per CSS2.1 we need to ensure that any negative margin-top clears |child| beyond the bottom border-edge of the float so that the top border edge of the child 1390 // (i.e. its clearance) is at a position that satisfies the equation: "the amount of clearance is set so that clearance + margin-top = [height of float], 1391 // i.e., clearance = [height of float] - margin-top". 1392 setLogicalHeight(child->logicalTop() + childMargins.negativeMarginBefore()); 1393 } else { 1394 // Increase our height by the amount we had to clear. 1395 setLogicalHeight(logicalHeight() + heightIncrease); 1396 } 1397 1398 if (marginInfo.canCollapseWithMarginBefore()) { 1399 // We can no longer collapse with the top of the block since a clear 1400 // occurred. The empty blocks collapse into the cleared block. 1401 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin); 1402 marginInfo.setAtBeforeSideOfBlock(false); 1403 1404 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value. 1405 setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD); 1406 } 1407 1408 return yPos + heightIncrease; 1409 } 1410 1411 void RenderBlockFlow::setCollapsedBottomMargin(const MarginInfo& marginInfo) 1412 { 1413 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) { 1414 // 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. 1415 // Don't update the max margin values because we won't need them anyway. 1416 if (marginInfo.discardMargin()) { 1417 setMustDiscardMarginAfter(); 1418 return; 1419 } 1420 1421 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 1422 // with our children. 1423 setMaxMarginAfterValues(std::max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), std::max(maxNegativeMarginAfter(), marginInfo.negativeMargin())); 1424 1425 if (!marginInfo.hasMarginAfterQuirk()) 1426 setHasMarginAfterQuirk(false); 1427 1428 if (marginInfo.hasMarginAfterQuirk() && !marginAfter()) { 1429 // We have no bottom margin and our last child has a quirky margin. 1430 // We will pick up this quirky margin and pass it through. 1431 // This deals with the <td><div><p> case. 1432 setHasMarginAfterQuirk(true); 1433 } 1434 } 1435 } 1436 1437 void RenderBlockFlow::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const 1438 { 1439 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky. 1440 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing. 1441 // FIXME: Use writing mode independent accessor for marginBeforeCollapse. 1442 if ((document().inQuirksMode() && hasMarginBeforeQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE) 1443 return; 1444 1445 // The margins are discarded by a child that specified -webkit-margin-collapse: discard. 1446 // FIXME: Use writing mode independent accessor for marginBeforeCollapse. 1447 if (child->style()->marginBeforeCollapse() == MDISCARD) { 1448 positiveMarginBefore = 0; 1449 negativeMarginBefore = 0; 1450 discardMarginBefore = true; 1451 return; 1452 } 1453 1454 LayoutUnit beforeChildMargin = marginBeforeForChild(child); 1455 positiveMarginBefore = std::max(positiveMarginBefore, beforeChildMargin); 1456 negativeMarginBefore = std::max(negativeMarginBefore, -beforeChildMargin); 1457 1458 if (!child->isRenderBlockFlow()) 1459 return; 1460 1461 RenderBlockFlow* childBlockFlow = toRenderBlockFlow(child); 1462 if (childBlockFlow->childrenInline() || childBlockFlow->isWritingModeRoot()) 1463 return; 1464 1465 MarginInfo childMarginInfo(childBlockFlow, childBlockFlow->borderBefore() + childBlockFlow->paddingBefore(), childBlockFlow->borderAfter() + childBlockFlow->paddingAfter()); 1466 if (!childMarginInfo.canCollapseMarginBeforeWithChildren()) 1467 return; 1468 1469 RenderBox* grandchildBox = childBlockFlow->firstChildBox(); 1470 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) { 1471 if (!grandchildBox->isFloatingOrOutOfFlowPositioned()) 1472 break; 1473 } 1474 1475 // Give up if there is clearance on the box, since it probably won't collapse into us. 1476 if (!grandchildBox || grandchildBox->style()->clear() != CNONE) 1477 return; 1478 1479 // Make sure to update the block margins now for the grandchild box so that we're looking at current values. 1480 if (grandchildBox->needsLayout()) { 1481 grandchildBox->computeAndSetBlockDirectionMargins(this); 1482 if (grandchildBox->isRenderBlock()) { 1483 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox); 1484 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk()); 1485 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk()); 1486 } 1487 } 1488 1489 // Collapse the margin of the grandchild box with our own to produce an estimate. 1490 childBlockFlow->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore); 1491 } 1492 1493 LayoutUnit RenderBlockFlow::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination) 1494 { 1495 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 1496 // relayout if there are intruding floats. 1497 LayoutUnit logicalTopEstimate = logicalHeight(); 1498 if (!marginInfo.canCollapseWithMarginBefore()) { 1499 LayoutUnit positiveMarginBefore = 0; 1500 LayoutUnit negativeMarginBefore = 0; 1501 bool discardMarginBefore = false; 1502 if (child->selfNeedsLayout()) { 1503 // Try to do a basic estimation of how the collapse is going to go. 1504 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore); 1505 } else { 1506 // Use the cached collapsed margin values from a previous layout. Most of the time they 1507 // will be right. 1508 RenderBlockFlow::MarginValues marginValues = marginValuesForChild(child); 1509 positiveMarginBefore = std::max(positiveMarginBefore, marginValues.positiveMarginBefore()); 1510 negativeMarginBefore = std::max(negativeMarginBefore, marginValues.negativeMarginBefore()); 1511 discardMarginBefore = mustDiscardMarginBeforeForChild(child); 1512 } 1513 1514 // Collapse the result with our current margins. 1515 if (!discardMarginBefore) 1516 logicalTopEstimate += std::max(marginInfo.positiveMargin(), positiveMarginBefore) - std::max(marginInfo.negativeMargin(), negativeMarginBefore); 1517 } 1518 1519 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current 1520 // page. 1521 LayoutState* layoutState = view()->layoutState(); 1522 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()) 1523 logicalTopEstimate = std::min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); 1524 1525 logicalTopEstimate += getClearDelta(child, logicalTopEstimate); 1526 1527 estimateWithoutPagination = logicalTopEstimate; 1528 1529 if (layoutState->isPaginated()) { 1530 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 1531 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate); 1532 1533 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 1534 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate); 1535 1536 if (!child->selfNeedsLayout() && child->isRenderBlockFlow()) 1537 logicalTopEstimate += toRenderBlockFlow(child)->paginationStrut(); 1538 } 1539 1540 return logicalTopEstimate; 1541 } 1542 1543 LayoutUnit RenderBlockFlow::marginOffsetForSelfCollapsingBlock() 1544 { 1545 ASSERT(isSelfCollapsingBlock()); 1546 RenderBlockFlow* parentBlock = toRenderBlockFlow(parent()); 1547 if (parentBlock && style()->clear() && parentBlock->getClearDelta(this, logicalHeight())) 1548 return marginValuesForChild(this).positiveMarginBefore(); 1549 return LayoutUnit(); 1550 } 1551 1552 void RenderBlockFlow::adjustFloatingBlock(const MarginInfo& marginInfo) 1553 { 1554 // The float should be positioned taking into account the bottom margin 1555 // of the previous flow. We add that margin into the height, get the 1556 // float positioned properly, and then subtract the margin out of the 1557 // height again. In the case of self-collapsing blocks, we always just 1558 // use the top margins, since the self-collapsing block collapsed its 1559 // own bottom margin into its top margin. 1560 // 1561 // Note also that the previous flow may collapse its margin into the top of 1562 // our block. If this is the case, then we do not add the margin in to our 1563 // height when computing the position of the float. This condition can be tested 1564 // for by simply calling canCollapseWithMarginBefore. See 1565 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 1566 // an example of this scenario. 1567 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin(); 1568 setLogicalHeight(logicalHeight() + marginOffset); 1569 positionNewFloats(); 1570 setLogicalHeight(logicalHeight() - marginOffset); 1571 } 1572 1573 void RenderBlockFlow::handleAfterSideOfBlock(RenderBox* lastChild, LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo) 1574 { 1575 marginInfo.setAtAfterSideOfBlock(true); 1576 1577 // If our last child was a self-collapsing block with clearance then our logical height is flush with the 1578 // bottom edge of the float that the child clears. The correct vertical position for the margin-collapsing we want 1579 // to perform now is at the child's margin-top - so adjust our height to that position. 1580 if (lastChild && lastChild->isRenderBlockFlow() && lastChild->isSelfCollapsingBlock()) 1581 setLogicalHeight(logicalHeight() - toRenderBlockFlow(lastChild)->marginOffsetForSelfCollapsingBlock()); 1582 1583 if (marginInfo.canCollapseMarginAfterWithChildren() && !marginInfo.canCollapseMarginAfterWithLastChild()) 1584 marginInfo.setCanCollapseMarginAfterWithChildren(false); 1585 1586 // If we can't collapse with children then go ahead and add in the bottom margin. 1587 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() 1588 && (!document().inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk()))) 1589 setLogicalHeight(logicalHeight() + marginInfo.margin()); 1590 1591 // Now add in our bottom border/padding. 1592 setLogicalHeight(logicalHeight() + afterSide); 1593 1594 // Negative margins can cause our height to shrink below our minimal height (border/padding). 1595 // If this happens, ensure that the computed height is increased to the minimal height. 1596 setLogicalHeight(std::max(logicalHeight(), beforeSide + afterSide)); 1597 1598 // Update our bottom collapsed margin info. 1599 setCollapsedBottomMargin(marginInfo); 1600 } 1601 1602 void RenderBlockFlow::setMustDiscardMarginBefore(bool value) 1603 { 1604 if (style()->marginBeforeCollapse() == MDISCARD) { 1605 ASSERT(value); 1606 return; 1607 } 1608 1609 if (!m_rareData && !value) 1610 return; 1611 1612 if (!m_rareData) 1613 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 1614 1615 m_rareData->m_discardMarginBefore = value; 1616 } 1617 1618 void RenderBlockFlow::setMustDiscardMarginAfter(bool value) 1619 { 1620 if (style()->marginAfterCollapse() == MDISCARD) { 1621 ASSERT(value); 1622 return; 1623 } 1624 1625 if (!m_rareData && !value) 1626 return; 1627 1628 if (!m_rareData) 1629 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 1630 1631 m_rareData->m_discardMarginAfter = value; 1632 } 1633 1634 bool RenderBlockFlow::mustDiscardMarginBefore() const 1635 { 1636 return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore); 1637 } 1638 1639 bool RenderBlockFlow::mustDiscardMarginAfter() const 1640 { 1641 return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter); 1642 } 1643 1644 bool RenderBlockFlow::mustDiscardMarginBeforeForChild(const RenderBox* child) const 1645 { 1646 ASSERT(!child->selfNeedsLayout()); 1647 if (!child->isWritingModeRoot()) 1648 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD); 1649 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 1650 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD); 1651 1652 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end. 1653 // In case the boxes are perpendicular we assume the property is not specified. 1654 return false; 1655 } 1656 1657 bool RenderBlockFlow::mustDiscardMarginAfterForChild(const RenderBox* child) const 1658 { 1659 ASSERT(!child->selfNeedsLayout()); 1660 if (!child->isWritingModeRoot()) 1661 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD); 1662 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 1663 return child->isRenderBlockFlow() ? toRenderBlockFlow(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD); 1664 1665 // FIXME: See |mustDiscardMarginBeforeForChild| above. 1666 return false; 1667 } 1668 1669 void RenderBlockFlow::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg) 1670 { 1671 if (!m_rareData) { 1672 if (pos == RenderBlockFlowRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockFlowRareData::negativeMarginBeforeDefault(this)) 1673 return; 1674 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 1675 } 1676 m_rareData->m_margins.setPositiveMarginBefore(pos); 1677 m_rareData->m_margins.setNegativeMarginBefore(neg); 1678 } 1679 1680 void RenderBlockFlow::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg) 1681 { 1682 if (!m_rareData) { 1683 if (pos == RenderBlockFlowRareData::positiveMarginAfterDefault(this) && neg == RenderBlockFlowRareData::negativeMarginAfterDefault(this)) 1684 return; 1685 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 1686 } 1687 m_rareData->m_margins.setPositiveMarginAfter(pos); 1688 m_rareData->m_margins.setNegativeMarginAfter(neg); 1689 } 1690 1691 bool RenderBlockFlow::mustSeparateMarginBeforeForChild(const RenderBox* child) const 1692 { 1693 ASSERT(!child->selfNeedsLayout()); 1694 const RenderStyle* childStyle = child->style(); 1695 if (!child->isWritingModeRoot()) 1696 return childStyle->marginBeforeCollapse() == MSEPARATE; 1697 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 1698 return childStyle->marginAfterCollapse() == MSEPARATE; 1699 1700 // FIXME: See |mustDiscardMarginBeforeForChild| above. 1701 return false; 1702 } 1703 1704 bool RenderBlockFlow::mustSeparateMarginAfterForChild(const RenderBox* child) const 1705 { 1706 ASSERT(!child->selfNeedsLayout()); 1707 const RenderStyle* childStyle = child->style(); 1708 if (!child->isWritingModeRoot()) 1709 return childStyle->marginAfterCollapse() == MSEPARATE; 1710 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 1711 return childStyle->marginBeforeCollapse() == MSEPARATE; 1712 1713 // FIXME: See |mustDiscardMarginBeforeForChild| above. 1714 return false; 1715 } 1716 1717 LayoutUnit RenderBlockFlow::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset) 1718 { 1719 // FIXME: Add page break checking here when we support printing. 1720 RenderFlowThread* flowThread = flowThreadContainingBlock(); 1721 bool isInsideMulticolFlowThread = flowThread; 1722 bool checkColumnBreaks = isInsideMulticolFlowThread || view()->layoutState()->isPaginatingColumns(); 1723 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this. 1724 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) 1725 || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS); 1726 if (checkBeforeAlways && inNormalFlow(child)) { 1727 if (checkColumnBreaks) { 1728 if (isInsideMulticolFlowThread) { 1729 LayoutUnit offsetBreakAdjustment = 0; 1730 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment)) 1731 return logicalOffset + offsetBreakAdjustment; 1732 } else { 1733 view()->layoutState()->addForcedColumnBreak(*child, logicalOffset); 1734 } 1735 } 1736 return nextPageLogicalTop(logicalOffset, IncludePageBoundary); 1737 } 1738 return logicalOffset; 1739 } 1740 1741 LayoutUnit RenderBlockFlow::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo) 1742 { 1743 // FIXME: Add page break checking here when we support printing. 1744 RenderFlowThread* flowThread = flowThreadContainingBlock(); 1745 bool isInsideMulticolFlowThread = flowThread; 1746 bool checkColumnBreaks = isInsideMulticolFlowThread || view()->layoutState()->isPaginatingColumns(); 1747 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->pageLogicalHeight(); // FIXME: Once columns can print we have to check this. 1748 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) 1749 || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS); 1750 if (checkAfterAlways && inNormalFlow(child)) { 1751 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin(); 1752 1753 // So our margin doesn't participate in the next collapsing steps. 1754 marginInfo.clearMargin(); 1755 1756 if (checkColumnBreaks) { 1757 if (isInsideMulticolFlowThread) { 1758 LayoutUnit offsetBreakAdjustment = 0; 1759 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment)) 1760 return logicalOffset + marginOffset + offsetBreakAdjustment; 1761 } else { 1762 view()->layoutState()->addForcedColumnBreak(*child, logicalOffset); 1763 } 1764 } 1765 return nextPageLogicalTop(logicalOffset, IncludePageBoundary); 1766 } 1767 return logicalOffset; 1768 } 1769 1770 void RenderBlockFlow::addOverflowFromFloats() 1771 { 1772 if (!m_floatingObjects) 1773 return; 1774 1775 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1776 FloatingObjectSetIterator end = floatingObjectSet.end(); 1777 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1778 FloatingObject* floatingObject = it->get(); 1779 if (floatingObject->isDescendant()) 1780 addOverflowFromChild(floatingObject->renderer(), IntSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject))); 1781 } 1782 } 1783 1784 void RenderBlockFlow::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats) 1785 { 1786 RenderBlock::computeOverflow(oldClientAfterEdge, recomputeFloats); 1787 if (!hasColumns() && (recomputeFloats || createsBlockFormattingContext() || hasSelfPaintingLayer())) 1788 addOverflowFromFloats(); 1789 } 1790 1791 RootInlineBox* RenderBlockFlow::createAndAppendRootInlineBox() 1792 { 1793 RootInlineBox* rootBox = createRootInlineBox(); 1794 m_lineBoxes.appendLineBox(rootBox); 1795 1796 return rootBox; 1797 } 1798 1799 void RenderBlockFlow::deleteLineBoxTree() 1800 { 1801 if (containsFloats()) 1802 m_floatingObjects->clearLineBoxTreePointers(); 1803 1804 m_lineBoxes.deleteLineBoxTree(); 1805 } 1806 1807 void RenderBlockFlow::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) 1808 { 1809 if (!everHadLayout() && !containsFloats()) 1810 return; 1811 1812 if (m_descendantsWithFloatsMarkedForLayout && !floatToRemove) 1813 return; 1814 m_descendantsWithFloatsMarkedForLayout |= !floatToRemove; 1815 1816 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain; 1817 setChildNeedsLayout(markParents); 1818 1819 if (floatToRemove) 1820 removeFloatingObject(floatToRemove); 1821 1822 // Iterate over our children and mark them as needed. 1823 if (!childrenInline()) { 1824 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 1825 if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isRenderBlock()) 1826 continue; 1827 if (!child->isRenderBlockFlow()) { 1828 RenderBlock* childBlock = toRenderBlock(child); 1829 if (childBlock->shrinkToAvoidFloats() && childBlock->everHadLayout()) 1830 childBlock->setChildNeedsLayout(markParents); 1831 continue; 1832 } 1833 RenderBlockFlow* childBlockFlow = toRenderBlockFlow(child); 1834 if ((floatToRemove ? childBlockFlow->containsFloat(floatToRemove) : childBlockFlow->containsFloats()) || childBlockFlow->shrinkToAvoidFloats()) 1835 childBlockFlow->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); 1836 } 1837 } 1838 } 1839 1840 void RenderBlockFlow::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove) 1841 { 1842 if (!m_floatingObjects) 1843 return; 1844 1845 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1846 FloatingObjectSetIterator end = floatingObjectSet.end(); 1847 1848 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) { 1849 if (!next->isRenderBlockFlow() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlockFlow(next)->avoidsFloats()) 1850 continue; 1851 1852 RenderBlockFlow* nextBlock = toRenderBlockFlow(next); 1853 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1854 RenderBox* floatingBox = (*it)->renderer(); 1855 if (floatToRemove && floatingBox != floatToRemove) 1856 continue; 1857 if (nextBlock->containsFloat(floatingBox)) 1858 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox); 1859 } 1860 } 1861 } 1862 1863 LayoutUnit RenderBlockFlow::getClearDelta(RenderBox* child, LayoutUnit logicalTop) 1864 { 1865 // There is no need to compute clearance if we have no floats. 1866 if (!containsFloats()) 1867 return 0; 1868 1869 // At least one float is present. We need to perform the clearance computation. 1870 bool clearSet = child->style()->clear() != CNONE; 1871 LayoutUnit logicalBottom = 0; 1872 switch (child->style()->clear()) { 1873 case CNONE: 1874 break; 1875 case CLEFT: 1876 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 1877 break; 1878 case CRIGHT: 1879 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight); 1880 break; 1881 case CBOTH: 1882 logicalBottom = lowestFloatLogicalBottom(); 1883 break; 1884 } 1885 1886 // 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). 1887 LayoutUnit result = clearSet ? std::max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit(); 1888 if (!result && child->avoidsFloats()) { 1889 LayoutUnit newLogicalTop = logicalTop; 1890 while (true) { 1891 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child)); 1892 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent()) 1893 return newLogicalTop - logicalTop; 1894 1895 LayoutRect borderBox = child->borderBoxRect(); 1896 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); 1897 1898 // FIXME: None of this is right for perpendicular writing-mode children. 1899 LayoutUnit childOldLogicalWidth = child->logicalWidth(); 1900 LayoutUnit childOldMarginLeft = child->marginLeft(); 1901 LayoutUnit childOldMarginRight = child->marginRight(); 1902 LayoutUnit childOldLogicalTop = child->logicalTop(); 1903 1904 child->setLogicalTop(newLogicalTop); 1905 child->updateLogicalWidth(); 1906 borderBox = child->borderBoxRect(); 1907 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); 1908 1909 child->setLogicalTop(childOldLogicalTop); 1910 child->setLogicalWidth(childOldLogicalWidth); 1911 child->setMarginLeft(childOldMarginLeft); 1912 child->setMarginRight(childOldMarginRight); 1913 1914 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) { 1915 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then 1916 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats 1917 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins). 1918 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset) 1919 child->setChildNeedsLayout(MarkOnlyThis); 1920 return newLogicalTop - logicalTop; 1921 } 1922 1923 newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop); 1924 ASSERT(newLogicalTop >= logicalTop); 1925 if (newLogicalTop < logicalTop) 1926 break; 1927 } 1928 ASSERT_NOT_REACHED(); 1929 } 1930 return result; 1931 } 1932 1933 void RenderBlockFlow::createFloatingObjects() 1934 { 1935 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode())); 1936 } 1937 1938 void RenderBlockFlow::styleWillChange(StyleDifference diff, const RenderStyle& newStyle) 1939 { 1940 RenderStyle* oldStyle = style(); 1941 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false; 1942 if (oldStyle && parent() && diff.needsFullLayout() && oldStyle->position() != newStyle.position() 1943 && containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition()) 1944 markAllDescendantsWithFloatsForLayout(); 1945 1946 RenderBlock::styleWillChange(diff, newStyle); 1947 } 1948 1949 void RenderBlockFlow::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 1950 { 1951 RenderBlock::styleDidChange(diff, oldStyle); 1952 1953 // After our style changed, if we lose our ability to propagate floats into next sibling 1954 // blocks, then we need to find the top most parent containing that overhanging float and 1955 // then mark its descendants with floats for layout and clear all floats from its next 1956 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875. 1957 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats(); 1958 if (diff.needsFullLayout() && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) { 1959 RenderBlockFlow* parentBlockFlow = this; 1960 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1961 FloatingObjectSetIterator end = floatingObjectSet.end(); 1962 1963 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) { 1964 if (curr->isRenderBlockFlow()) { 1965 RenderBlockFlow* currBlock = toRenderBlockFlow(curr); 1966 1967 if (currBlock->hasOverhangingFloats()) { 1968 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1969 RenderBox* renderer = (*it)->renderer(); 1970 if (currBlock->hasOverhangingFloat(renderer)) { 1971 parentBlockFlow = currBlock; 1972 break; 1973 } 1974 } 1975 } 1976 } 1977 } 1978 1979 parentBlockFlow->markAllDescendantsWithFloatsForLayout(); 1980 parentBlockFlow->markSiblingsWithFloatsForLayout(); 1981 } 1982 1983 if (diff.needsFullLayout() || !oldStyle) 1984 createOrDestroyMultiColumnFlowThreadIfNeeded(oldStyle); 1985 } 1986 1987 void RenderBlockFlow::updateStaticInlinePositionForChild(RenderBox* child, LayoutUnit logicalTop) 1988 { 1989 if (child->style()->isOriginalDisplayInlineType()) 1990 setStaticInlinePositionForChild(child, startAlignedOffsetForLine(logicalTop, false)); 1991 else 1992 setStaticInlinePositionForChild(child, startOffsetForContent()); 1993 } 1994 1995 void RenderBlockFlow::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit inlinePosition) 1996 { 1997 child->layer()->setStaticInlinePosition(inlinePosition); 1998 } 1999 2000 void RenderBlockFlow::addChild(RenderObject* newChild, RenderObject* beforeChild) 2001 { 2002 if (RenderMultiColumnFlowThread* flowThread = multiColumnFlowThread()) { 2003 flowThread->addChild(newChild, beforeChild); 2004 return; 2005 } 2006 RenderBlock::addChild(newChild, beforeChild); 2007 } 2008 2009 void RenderBlockFlow::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert) 2010 { 2011 RenderBlockFlow* toBlockFlow = toRenderBlockFlow(toBlock); 2012 moveAllChildrenTo(toBlockFlow, fullRemoveInsert); 2013 2014 // When a portion of the render tree is being detached, anonymous blocks 2015 // will be combined as their children are deleted. In this process, the 2016 // anonymous block later in the tree is merged into the one preceeding it. 2017 // It can happen that the later block (this) contains floats that the 2018 // previous block (toBlockFlow) did not contain, and thus are not in the 2019 // floating objects list for toBlockFlow. This can result in toBlockFlow containing 2020 // floats that are not in it's floating objects list, but are in the 2021 // floating objects lists of siblings and parents. This can cause problems 2022 // when the float itself is deleted, since the deletion code assumes that 2023 // if a float is not in it's containing block's floating objects list, it 2024 // isn't in any floating objects list. In order to preserve this condition 2025 // (removing it has serious performance implications), we need to copy the 2026 // floating objects from the old block (this) to the new block (toBlockFlow). 2027 // The float's metrics will likely all be wrong, but since toBlockFlow is 2028 // already marked for layout, this will get fixed before anything gets 2029 // displayed. 2030 // See bug https://code.google.com/p/chromium/issues/detail?id=230907 2031 if (m_floatingObjects) { 2032 if (!toBlockFlow->m_floatingObjects) 2033 toBlockFlow->createFloatingObjects(); 2034 2035 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set(); 2036 FloatingObjectSetIterator end = fromFloatingObjectSet.end(); 2037 2038 for (FloatingObjectSetIterator it = fromFloatingObjectSet.begin(); it != end; ++it) { 2039 FloatingObject* floatingObject = it->get(); 2040 2041 // Don't insert the object again if it's already in the list 2042 if (toBlockFlow->containsFloat(floatingObject->renderer())) 2043 continue; 2044 2045 toBlockFlow->m_floatingObjects->add(floatingObject->unsafeClone()); 2046 } 2047 } 2048 2049 } 2050 2051 void RenderBlockFlow::invalidatePaintForOverhangingFloats(bool paintAllDescendants) 2052 { 2053 // Invalidate paint of any overhanging floats (if we know we're the one to paint them). 2054 // Otherwise, bail out. 2055 if (!hasOverhangingFloats()) 2056 return; 2057 2058 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2059 FloatingObjectSetIterator end = floatingObjectSet.end(); 2060 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2061 FloatingObject* floatingObject = it->get(); 2062 // Only issue paint invaldiations for the object if it is overhanging, is not in its own layer, and 2063 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 2064 // condition is replaced with being a descendant of us. 2065 if (logicalBottomForFloat(floatingObject) > logicalHeight() 2066 && !floatingObject->renderer()->hasSelfPaintingLayer() 2067 && (floatingObject->shouldPaint() || (paintAllDescendants && floatingObject->renderer()->isDescendantOf(this)))) { 2068 2069 RenderBox* floatingRenderer = floatingObject->renderer(); 2070 floatingRenderer->setShouldDoFullPaintInvalidation(true); 2071 floatingRenderer->invalidatePaintForOverhangingFloats(false); 2072 } 2073 } 2074 } 2075 2076 void RenderBlockFlow::invalidatePaintForOverflow() 2077 { 2078 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines 2079 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. 2080 LayoutUnit paintInvalidationLogicalLeft = logicalLeftVisualOverflow(); 2081 LayoutUnit paintInvalidationLogicalRight = logicalRightVisualOverflow(); 2082 if (hasOverflowClip()) { 2083 // 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. 2084 // 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. 2085 // layoutInlineChildren should be patched to compute the entire paint invalidation rect. 2086 paintInvalidationLogicalLeft = std::min(paintInvalidationLogicalLeft, logicalLeftLayoutOverflow()); 2087 paintInvalidationLogicalRight = std::max(paintInvalidationLogicalRight, logicalRightLayoutOverflow()); 2088 } 2089 2090 LayoutRect paintInvalidationRect; 2091 if (isHorizontalWritingMode()) 2092 paintInvalidationRect = LayoutRect(paintInvalidationLogicalLeft, m_paintInvalidationLogicalTop, paintInvalidationLogicalRight - paintInvalidationLogicalLeft, m_paintInvalidationLogicalBottom - m_paintInvalidationLogicalTop); 2093 else 2094 paintInvalidationRect = LayoutRect(m_paintInvalidationLogicalTop, paintInvalidationLogicalLeft, m_paintInvalidationLogicalBottom - m_paintInvalidationLogicalTop, paintInvalidationLogicalRight - paintInvalidationLogicalLeft); 2095 2096 // The paint invalidation rect may be split across columns, in which case adjustRectForColumns() will return the union. 2097 adjustRectForColumns(paintInvalidationRect); 2098 2099 if (hasOverflowClip()) { 2100 // Adjust the paint invalidation rect for scroll offset 2101 paintInvalidationRect.move(-scrolledContentOffset()); 2102 2103 // Don't allow this rect to spill out of our overflow box. 2104 paintInvalidationRect.intersect(LayoutRect(LayoutPoint(), size())); 2105 } 2106 2107 // Make sure the rect is still non-empty after intersecting for overflow above 2108 if (!paintInvalidationRect.isEmpty()) { 2109 // Hits in media/event-attributes.html 2110 DisableCompositingQueryAsserts disabler; 2111 2112 invalidatePaintRectangle(paintInvalidationRect); // We need to do a partial paint invalidation of our content. 2113 if (hasReflection()) 2114 invalidatePaintRectangle(reflectedRect(paintInvalidationRect)); 2115 } 2116 2117 m_paintInvalidationLogicalTop = 0; 2118 m_paintInvalidationLogicalBottom = 0; 2119 } 2120 2121 void RenderBlockFlow::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase) 2122 { 2123 BlockFlowPainter(*this).paintFloats(paintInfo, paintOffset, preservePhase); 2124 } 2125 2126 void RenderBlockFlow::clipOutFloatingObjects(const RenderBlock* rootBlock, const PaintInfo* paintInfo, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock) const 2127 { 2128 if (m_floatingObjects) { 2129 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2130 FloatingObjectSetIterator end = floatingObjectSet.end(); 2131 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2132 FloatingObject* floatingObject = it->get(); 2133 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(floatingObject), 2134 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(floatingObject), 2135 floatingObject->renderer()->width(), floatingObject->renderer()->height()); 2136 rootBlock->flipForWritingMode(floatBox); 2137 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); 2138 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox)); 2139 } 2140 } 2141 } 2142 2143 void RenderBlockFlow::clearFloats(EClear clear) 2144 { 2145 positionNewFloats(); 2146 // set y position 2147 LayoutUnit newY = 0; 2148 switch (clear) { 2149 case CLEFT: 2150 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 2151 break; 2152 case CRIGHT: 2153 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight); 2154 break; 2155 case CBOTH: 2156 newY = lowestFloatLogicalBottom(); 2157 default: 2158 break; 2159 } 2160 if (height() < newY) 2161 setLogicalHeight(newY); 2162 } 2163 2164 bool RenderBlockFlow::containsFloat(RenderBox* renderer) const 2165 { 2166 return m_floatingObjects && m_floatingObjects->set().contains<FloatingObjectHashTranslator>(renderer); 2167 } 2168 2169 void RenderBlockFlow::removeFloatingObjects() 2170 { 2171 if (!m_floatingObjects) 2172 return; 2173 2174 markSiblingsWithFloatsForLayout(); 2175 2176 m_floatingObjects->clear(); 2177 } 2178 2179 LayoutPoint RenderBlockFlow::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const 2180 { 2181 if (!style()->isFlippedBlocksWritingMode()) 2182 return point; 2183 2184 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since 2185 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped 2186 // case. 2187 if (isHorizontalWritingMode()) 2188 return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child)); 2189 return LayoutPoint(point.x() + width() - child->renderer()->width() - 2 * xPositionForFloatIncludingMargin(child), point.y()); 2190 } 2191 2192 LayoutUnit RenderBlockFlow::logicalLeftOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const 2193 { 2194 LayoutUnit offset = fixedOffset; 2195 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) 2196 offset = m_floatingObjects->logicalLeftOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining); 2197 return adjustLogicalLeftOffsetForLine(offset, applyTextIndent); 2198 } 2199 2200 LayoutUnit RenderBlockFlow::logicalRightOffsetForPositioningFloat(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining) const 2201 { 2202 LayoutUnit offset = fixedOffset; 2203 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) 2204 offset = m_floatingObjects->logicalRightOffsetForPositioningFloat(fixedOffset, logicalTop, heightRemaining); 2205 return adjustLogicalRightOffsetForLine(offset, applyTextIndent); 2206 } 2207 2208 LayoutUnit RenderBlockFlow::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const 2209 { 2210 LayoutUnit left = offsetFromFloats; 2211 2212 if (applyTextIndent && style()->isLeftToRightDirection()) 2213 left += textIndentOffset(); 2214 2215 return left; 2216 } 2217 2218 LayoutUnit RenderBlockFlow::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const 2219 { 2220 LayoutUnit right = offsetFromFloats; 2221 2222 if (applyTextIndent && !style()->isLeftToRightDirection()) 2223 right -= textIndentOffset(); 2224 2225 return right; 2226 } 2227 2228 LayoutPoint RenderBlockFlow::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const 2229 { 2230 RenderBox* childBox = floatingObject->renderer(); 2231 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. 2232 LayoutUnit logicalRightOffset; // Constant part of right offset. 2233 logicalRightOffset = logicalRightOffsetForContent(); 2234 2235 LayoutUnit floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for. 2236 2237 LayoutUnit floatLogicalLeft; 2238 2239 bool insideFlowThread = flowThreadContainingBlock(); 2240 2241 if (childBox->style()->floating() == LeftFloat) { 2242 LayoutUnit heightRemainingLeft = 1; 2243 LayoutUnit heightRemainingRight = 1; 2244 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); 2245 while (logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { 2246 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight); 2247 floatLogicalLeft = logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); 2248 if (insideFlowThread) { 2249 // Have to re-evaluate all of our offsets, since they may have changed. 2250 logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. 2251 logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. 2252 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); 2253 } 2254 } 2255 floatLogicalLeft = std::max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft); 2256 } else { 2257 LayoutUnit heightRemainingLeft = 1; 2258 LayoutUnit heightRemainingRight = 1; 2259 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); 2260 while (floatLogicalLeft - logicalLeftOffsetForPositioningFloat(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) { 2261 logicalTopOffset += std::min(heightRemainingLeft, heightRemainingRight); 2262 floatLogicalLeft = logicalRightOffsetForPositioningFloat(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); 2263 if (insideFlowThread) { 2264 // Have to re-evaluate all of our offsets, since they may have changed. 2265 logicalRightOffset = logicalRightOffsetForContent(); // Constant part of right offset. 2266 logicalLeftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. 2267 floatLogicalWidth = std::min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); 2268 } 2269 } 2270 // Use the original width of the float here, since the local variable 2271 // |floatLogicalWidth| was capped to the available line width. See 2272 // fast/block/float/clamped-right-float.html. 2273 floatLogicalLeft -= logicalWidthForFloat(floatingObject); 2274 } 2275 2276 return LayoutPoint(floatLogicalLeft, logicalTopOffset); 2277 } 2278 2279 FloatingObject* RenderBlockFlow::insertFloatingObject(RenderBox* floatBox) 2280 { 2281 ASSERT(floatBox->isFloating()); 2282 2283 // Create the list of special objects if we don't aleady have one 2284 if (!m_floatingObjects) { 2285 createFloatingObjects(); 2286 } else { 2287 // Don't insert the object again if it's already in the list 2288 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2289 FloatingObjectSetIterator it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox); 2290 if (it != floatingObjectSet.end()) 2291 return it->get(); 2292 } 2293 2294 // Create the special object entry & append it to the list 2295 2296 OwnPtr<FloatingObject> newObj = FloatingObject::create(floatBox); 2297 2298 // Our location is irrelevant if we're unsplittable or no pagination is in effect. 2299 // Just go ahead and lay out the float. 2300 bool isChildRenderBlock = floatBox->isRenderBlock(); 2301 if (isChildRenderBlock && !floatBox->needsLayout() && view()->layoutState()->pageLogicalHeightChanged()) 2302 floatBox->setChildNeedsLayout(MarkOnlyThis); 2303 2304 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); 2305 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) { // We are unsplittable if we're a block flow root. 2306 floatBox->layoutIfNeeded(); 2307 } else { 2308 floatBox->updateLogicalWidth(); 2309 floatBox->computeAndSetBlockDirectionMargins(this); 2310 } 2311 2312 setLogicalWidthForFloat(newObj.get(), logicalWidthForChild(floatBox) + marginStartForChild(floatBox) + marginEndForChild(floatBox)); 2313 2314 return m_floatingObjects->add(newObj.release()); 2315 } 2316 2317 void RenderBlockFlow::removeFloatingObject(RenderBox* floatBox) 2318 { 2319 if (m_floatingObjects) { 2320 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2321 FloatingObjectSetIterator it = floatingObjectSet.find<FloatingObjectHashTranslator>(floatBox); 2322 if (it != floatingObjectSet.end()) { 2323 FloatingObject* floatingObject = it->get(); 2324 if (childrenInline()) { 2325 LayoutUnit logicalTop = logicalTopForFloat(floatingObject); 2326 LayoutUnit logicalBottom = logicalBottomForFloat(floatingObject); 2327 2328 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995. 2329 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max()) { 2330 logicalBottom = LayoutUnit::max(); 2331 } else { 2332 // Special-case zero- and less-than-zero-height floats: those don't touch 2333 // the line that they're on, but it still needs to be dirtied. This is 2334 // accomplished by pretending they have a height of 1. 2335 logicalBottom = std::max(logicalBottom, logicalTop + 1); 2336 } 2337 if (floatingObject->originatingLine()) { 2338 if (!selfNeedsLayout()) { 2339 ASSERT(floatingObject->originatingLine()->renderer() == this); 2340 floatingObject->originatingLine()->markDirty(); 2341 } 2342 #if ENABLE(ASSERT) 2343 floatingObject->setOriginatingLine(0); 2344 #endif 2345 } 2346 markLinesDirtyInBlockRange(0, logicalBottom); 2347 } 2348 m_floatingObjects->remove(floatingObject); 2349 } 2350 } 2351 } 2352 2353 void RenderBlockFlow::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset) 2354 { 2355 if (!containsFloats()) 2356 return; 2357 2358 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2359 FloatingObject* curr = floatingObjectSet.last().get(); 2360 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { 2361 m_floatingObjects->remove(curr); 2362 if (floatingObjectSet.isEmpty()) 2363 break; 2364 curr = floatingObjectSet.last().get(); 2365 } 2366 } 2367 2368 bool RenderBlockFlow::positionNewFloats() 2369 { 2370 if (!m_floatingObjects) 2371 return false; 2372 2373 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2374 if (floatingObjectSet.isEmpty()) 2375 return false; 2376 2377 // If all floats have already been positioned, then we have no work to do. 2378 if (floatingObjectSet.last()->isPlaced()) 2379 return false; 2380 2381 // Move backwards through our floating object list until we find a float that has 2382 // already been positioned. Then we'll be able to move forward, positioning all of 2383 // the new floats that need it. 2384 FloatingObjectSetIterator it = floatingObjectSet.end(); 2385 --it; // Go to last item. 2386 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 2387 FloatingObject* lastPlacedFloatingObject = 0; 2388 while (it != begin) { 2389 --it; 2390 if ((*it)->isPlaced()) { 2391 lastPlacedFloatingObject = it->get(); 2392 ++it; 2393 break; 2394 } 2395 } 2396 2397 LayoutUnit logicalTop = logicalHeight(); 2398 2399 // The float cannot start above the top position of the last positioned float. 2400 if (lastPlacedFloatingObject) 2401 logicalTop = std::max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop); 2402 2403 FloatingObjectSetIterator end = floatingObjectSet.end(); 2404 // Now walk through the set of unpositioned floats and place them. 2405 for (; it != end; ++it) { 2406 FloatingObject* floatingObject = it->get(); 2407 // The containing block is responsible for positioning floats, so if we have floats in our 2408 // list that come from somewhere else, do not attempt to position them. 2409 if (floatingObject->renderer()->containingBlock() != this) 2410 continue; 2411 2412 RenderBox* childBox = floatingObject->renderer(); 2413 2414 // FIXME Investigate if this can be removed. crbug.com/370006 2415 childBox->setMayNeedPaintInvalidation(true); 2416 2417 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); 2418 if (childBox->style()->clear() & CLEFT) 2419 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop); 2420 if (childBox->style()->clear() & CRIGHT) 2421 logicalTop = std::max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop); 2422 2423 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop); 2424 2425 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x()); 2426 2427 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin); 2428 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); 2429 2430 SubtreeLayoutScope layoutScope(*childBox); 2431 LayoutState* layoutState = view()->layoutState(); 2432 bool isPaginated = layoutState->isPaginated(); 2433 if (isPaginated && !childBox->needsLayout()) 2434 childBox->markForPaginationRelayoutIfNeeded(layoutScope); 2435 2436 childBox->layoutIfNeeded(); 2437 2438 if (isPaginated) { 2439 // If we are unsplittable and don't fit, then we need to move down. 2440 // We include our margins as part of the unsplittable area. 2441 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true); 2442 2443 // See if we have a pagination strut that is making us move down further. 2444 // Note that an unsplittable child can't also have a pagination strut, so this is 2445 // exclusive with the case above. 2446 RenderBlockFlow* childBlockFlow = childBox->isRenderBlockFlow() ? toRenderBlockFlow(childBox) : 0; 2447 if (childBlockFlow && childBlockFlow->paginationStrut()) { 2448 newLogicalTop += childBlockFlow->paginationStrut(); 2449 childBlockFlow->setPaginationStrut(0); 2450 } 2451 2452 if (newLogicalTop != floatLogicalLocation.y()) { 2453 floatingObject->setPaginationStrut(newLogicalTop - floatLogicalLocation.y()); 2454 2455 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop); 2456 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x()); 2457 2458 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin); 2459 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); 2460 2461 if (childBox->isRenderBlock()) 2462 childBox->setChildNeedsLayout(MarkOnlyThis); 2463 childBox->layoutIfNeeded(); 2464 } 2465 } 2466 2467 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y()); 2468 2469 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox)); 2470 2471 m_floatingObjects->addPlacedObject(floatingObject); 2472 2473 if (ShapeOutsideInfo* shapeOutside = childBox->shapeOutsideInfo()) 2474 shapeOutside->setReferenceBoxLogicalSize(logicalSizeForChild(childBox)); 2475 } 2476 return true; 2477 } 2478 2479 bool RenderBlockFlow::hasOverhangingFloat(RenderBox* renderer) 2480 { 2481 if (!m_floatingObjects || hasColumns() || !parent()) 2482 return false; 2483 2484 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2485 FloatingObjectSetIterator it = floatingObjectSet.find<FloatingObjectHashTranslator>(renderer); 2486 if (it == floatingObjectSet.end()) 2487 return false; 2488 2489 return logicalBottomForFloat(it->get()) > logicalHeight(); 2490 } 2491 2492 void RenderBlockFlow::addIntrudingFloats(RenderBlockFlow* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset) 2493 { 2494 ASSERT(!avoidsFloats()); 2495 2496 // If we create our own block formatting context then our contents don't interact with floats outside it, even those from our parent. 2497 if (createsBlockFormattingContext()) 2498 return; 2499 2500 // If the parent or previous sibling doesn't have any floats to add, don't bother. 2501 if (!prev->m_floatingObjects) 2502 return; 2503 2504 logicalLeftOffset += marginLogicalLeft(); 2505 2506 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set(); 2507 FloatingObjectSetIterator prevEnd = prevSet.end(); 2508 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) { 2509 FloatingObject* floatingObject = prevIt->get(); 2510 if (logicalBottomForFloat(floatingObject) > logicalTopOffset) { 2511 if (!m_floatingObjects || !m_floatingObjects->set().contains(floatingObject)) { 2512 // We create the floating object list lazily. 2513 if (!m_floatingObjects) 2514 createFloatingObjects(); 2515 2516 // Applying the child's margin makes no sense in the case where the child was passed in. 2517 // since this margin was added already through the modification of the |logicalLeftOffset| variable 2518 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken 2519 // into account. Only apply this code if prev is the parent, since otherwise the left margin 2520 // will get applied twice. 2521 LayoutSize offset = isHorizontalWritingMode() 2522 ? LayoutSize(logicalLeftOffset - (prev != parent() ? prev->marginLeft() : LayoutUnit()), logicalTopOffset) 2523 : LayoutSize(logicalTopOffset, logicalLeftOffset - (prev != parent() ? prev->marginTop() : LayoutUnit())); 2524 2525 m_floatingObjects->add(floatingObject->copyToNewContainer(offset)); 2526 } 2527 } 2528 } 2529 } 2530 2531 void RenderBlockFlow::addOverhangingFloats(RenderBlockFlow* child, bool makeChildPaintOtherFloats) 2532 { 2533 // Prevent floats from being added to the canvas by the root element, e.g., <html>. 2534 if (!child->containsFloats() || child->isRenderRegion() || child->createsBlockFormattingContext()) 2535 return; 2536 2537 LayoutUnit childLogicalTop = child->logicalTop(); 2538 LayoutUnit childLogicalLeft = child->logicalLeft(); 2539 2540 // Floats that will remain the child's responsibility to paint should factor into its 2541 // overflow. 2542 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); 2543 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { 2544 FloatingObject* floatingObject = childIt->get(); 2545 LayoutUnit logicalBottomForFloat = std::min(this->logicalBottomForFloat(floatingObject), LayoutUnit::max() - childLogicalTop); 2546 LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat; 2547 2548 if (logicalBottom > logicalHeight()) { 2549 // If the object is not in the list, we add it now. 2550 if (!containsFloat(floatingObject->renderer())) { 2551 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft); 2552 bool shouldPaint = false; 2553 2554 // The nearest enclosing layer always paints the float (so that zindex and stacking 2555 // behaves properly). We always want to propagate the desire to paint the float as 2556 // far out as we can, to the outermost block that overlaps the float, stopping only 2557 // if we hit a self-painting layer boundary. 2558 if (floatingObject->renderer()->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) { 2559 floatingObject->setShouldPaint(false); 2560 shouldPaint = true; 2561 } 2562 // We create the floating object list lazily. 2563 if (!m_floatingObjects) 2564 createFloatingObjects(); 2565 2566 m_floatingObjects->add(floatingObject->copyToNewContainer(offset, shouldPaint, true)); 2567 } 2568 } else { 2569 if (makeChildPaintOtherFloats && !floatingObject->shouldPaint() && !floatingObject->renderer()->hasSelfPaintingLayer() 2570 && floatingObject->renderer()->isDescendantOf(child) && floatingObject->renderer()->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) { 2571 // The float is not overhanging from this block, so if it is a descendant of the child, the child should 2572 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing 2573 // layer. 2574 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats 2575 // it should paint. 2576 floatingObject->setShouldPaint(true); 2577 } 2578 2579 // 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 2580 // child now. 2581 if (floatingObject->isDescendant()) 2582 child->addOverflowFromChild(floatingObject->renderer(), LayoutSize(xPositionForFloatIncludingMargin(floatingObject), yPositionForFloatIncludingMargin(floatingObject))); 2583 } 2584 } 2585 } 2586 2587 LayoutUnit RenderBlockFlow::lowestFloatLogicalBottom(FloatingObject::Type floatType) const 2588 { 2589 if (!m_floatingObjects) 2590 return 0; 2591 2592 return m_floatingObjects->lowestFloatLogicalBottom(floatType); 2593 } 2594 2595 LayoutUnit RenderBlockFlow::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const 2596 { 2597 if (!m_floatingObjects) 2598 return logicalHeight; 2599 2600 LayoutUnit logicalBottom; 2601 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2602 FloatingObjectSetIterator end = floatingObjectSet.end(); 2603 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2604 FloatingObject* floatingObject = it->get(); 2605 LayoutUnit floatLogicalBottom = logicalBottomForFloat(floatingObject); 2606 ShapeOutsideInfo* shapeOutside = floatingObject->renderer()->shapeOutsideInfo(); 2607 if (shapeOutside && (offsetMode == ShapeOutsideFloatShapeOffset)) { 2608 LayoutUnit shapeLogicalBottom = logicalTopForFloat(floatingObject) + marginBeforeForChild(floatingObject->renderer()) + shapeOutside->shapeLogicalBottom(); 2609 // Use the shapeLogicalBottom unless it extends outside of the margin box, in which case it is clipped. 2610 if (shapeLogicalBottom < floatLogicalBottom) 2611 floatLogicalBottom = shapeLogicalBottom; 2612 } 2613 if (floatLogicalBottom > logicalHeight) 2614 logicalBottom = logicalBottom ? std::min(floatLogicalBottom, logicalBottom) : floatLogicalBottom; 2615 } 2616 2617 return logicalBottom; 2618 } 2619 2620 bool RenderBlockFlow::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) 2621 { 2622 if (!m_floatingObjects) 2623 return false; 2624 2625 LayoutPoint adjustedLocation = accumulatedOffset; 2626 if (isRenderView()) { 2627 adjustedLocation += toLayoutSize(toRenderView(this)->frameView()->scrollPosition()); 2628 } 2629 2630 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2631 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 2632 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { 2633 --it; 2634 FloatingObject* floatingObject = it->get(); 2635 if (floatingObject->shouldPaint() && !floatingObject->renderer()->hasSelfPaintingLayer()) { 2636 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->x(); 2637 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->y(); 2638 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset)); 2639 if (floatingObject->renderer()->hitTest(request, result, locationInContainer, childPoint)) { 2640 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint)); 2641 return true; 2642 } 2643 } 2644 } 2645 2646 return false; 2647 } 2648 2649 void RenderBlockFlow::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const 2650 { 2651 if (style()->visibility() != VISIBLE) 2652 return; 2653 2654 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting 2655 // for either overflow or translations via relative positioning. 2656 if (childrenInline()) { 2657 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { 2658 if (box->firstChild()) 2659 left = std::min(left, x + static_cast<LayoutUnit>(box->firstChild()->x())); 2660 if (box->lastChild()) 2661 right = std::max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight()))); 2662 } 2663 } else { 2664 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { 2665 if (!obj->isFloatingOrOutOfFlowPositioned()) { 2666 if (obj->isRenderBlockFlow() && !obj->hasOverflowClip()) { 2667 toRenderBlockFlow(obj)->adjustForBorderFit(x + obj->x(), left, right); 2668 } else if (obj->style()->visibility() == VISIBLE) { 2669 // We are a replaced element or some kind of non-block-flow object. 2670 left = std::min(left, x + obj->x()); 2671 right = std::max(right, x + obj->x() + obj->width()); 2672 } 2673 } 2674 } 2675 } 2676 2677 if (m_floatingObjects) { 2678 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2679 FloatingObjectSetIterator end = floatingObjectSet.end(); 2680 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2681 FloatingObject* floatingObject = it->get(); 2682 // Only examine the object if our m_shouldPaint flag is set. 2683 if (floatingObject->shouldPaint()) { 2684 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->renderer()->x(); 2685 LayoutUnit floatRight = floatLeft + floatingObject->renderer()->width(); 2686 left = std::min(left, floatLeft); 2687 right = std::max(right, floatRight); 2688 } 2689 } 2690 } 2691 } 2692 2693 void RenderBlockFlow::fitBorderToLinesIfNeeded() 2694 { 2695 if (style()->borderFit() == BorderFitBorder || hasOverrideWidth()) 2696 return; 2697 2698 // Walk any normal flow lines to snugly fit. 2699 LayoutUnit left = LayoutUnit::max(); 2700 LayoutUnit right = LayoutUnit::min(); 2701 LayoutUnit oldWidth = contentWidth(); 2702 adjustForBorderFit(0, left, right); 2703 2704 // Clamp to our existing edges. We can never grow. We only shrink. 2705 LayoutUnit leftEdge = borderLeft() + paddingLeft(); 2706 LayoutUnit rightEdge = leftEdge + oldWidth; 2707 left = std::min(rightEdge, std::max(leftEdge, left)); 2708 right = std::max(left, std::min(rightEdge, right)); 2709 2710 LayoutUnit newContentWidth = right - left; 2711 if (newContentWidth == oldWidth) 2712 return; 2713 2714 setOverrideLogicalContentWidth(newContentWidth); 2715 layoutBlock(false); 2716 clearOverrideLogicalContentWidth(); 2717 } 2718 2719 LayoutUnit RenderBlockFlow::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const 2720 { 2721 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) 2722 return m_floatingObjects->logicalLeftOffset(fixedOffset, logicalTop, logicalHeight); 2723 2724 return fixedOffset; 2725 } 2726 2727 LayoutUnit RenderBlockFlow::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit logicalHeight) const 2728 { 2729 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) 2730 return m_floatingObjects->logicalRightOffset(fixedOffset, logicalTop, logicalHeight); 2731 2732 return fixedOffset; 2733 } 2734 2735 GapRects RenderBlockFlow::inlineSelectionGaps(const RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 2736 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo) const 2737 { 2738 GapRects result; 2739 2740 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 2741 2742 if (!firstLineBox()) { 2743 if (containsStart) { 2744 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this 2745 // case. 2746 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalHeight(); 2747 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight()); 2748 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight()); 2749 } 2750 return result; 2751 } 2752 2753 RootInlineBox* lastSelectedLine = 0; 2754 RootInlineBox* curr; 2755 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 2756 2757 // Now paint the gaps for the lines. 2758 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 2759 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock(); 2760 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock(); 2761 2762 if (!containsStart && !lastSelectedLine && selectionState() != SelectionStart && selectionState() != SelectionBoth) { 2763 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, 2764 lastLogicalLeft, lastLogicalRight, selTop, paintInfo)); 2765 } 2766 2767 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight); 2768 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize()); 2769 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect); 2770 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y()) 2771 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x())) 2772 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo)); 2773 2774 lastSelectedLine = curr; 2775 } 2776 2777 if (containsStart && !lastSelectedLine) { 2778 // VisibleSelection must start just after our last line. 2779 lastSelectedLine = lastRootBox(); 2780 } 2781 2782 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 2783 // Go ahead and update our lastY to be the bottom of the last selected line. 2784 lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + lastSelectedLine->selectionBottom(); 2785 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2786 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2787 } 2788 return result; 2789 } 2790 2791 void RenderBlockFlow::setPaginationStrut(LayoutUnit strut) 2792 { 2793 if (!m_rareData) { 2794 if (!strut) 2795 return; 2796 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 2797 } 2798 m_rareData->m_paginationStrut = strut; 2799 } 2800 2801 bool RenderBlockFlow::avoidsFloats() const 2802 { 2803 // Floats can't intrude into our box if we have a non-auto column count or width. 2804 // Note: we need to use RenderBox::avoidsFloats here since RenderBlock::avoidsFloats is always true. 2805 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); 2806 } 2807 2808 LayoutUnit RenderBlockFlow::logicalLeftSelectionOffset(const RenderBlock* rootBlock, LayoutUnit position) const 2809 { 2810 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false); 2811 if (logicalLeft == logicalLeftOffsetForContent()) 2812 return RenderBlock::logicalLeftSelectionOffset(rootBlock, position); 2813 2814 const RenderBlock* cb = this; 2815 while (cb != rootBlock) { 2816 logicalLeft += cb->logicalLeft(); 2817 cb = cb->containingBlock(); 2818 } 2819 return logicalLeft; 2820 } 2821 2822 LayoutUnit RenderBlockFlow::logicalRightSelectionOffset(const RenderBlock* rootBlock, LayoutUnit position) const 2823 { 2824 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false); 2825 if (logicalRight == logicalRightOffsetForContent()) 2826 return RenderBlock::logicalRightSelectionOffset(rootBlock, position); 2827 2828 const RenderBlock* cb = this; 2829 while (cb != rootBlock) { 2830 logicalRight += cb->logicalLeft(); 2831 cb = cb->containingBlock(); 2832 } 2833 return logicalRight; 2834 } 2835 2836 RootInlineBox* RenderBlockFlow::createRootInlineBox() 2837 { 2838 return new RootInlineBox(*this); 2839 } 2840 2841 bool RenderBlockFlow::isPagedOverflow(const RenderStyle* style) 2842 { 2843 return style->isOverflowPaged() && node() != document().viewportDefiningElement(); 2844 } 2845 2846 RenderBlockFlow::FlowThreadType RenderBlockFlow::flowThreadType(const RenderStyle* style) 2847 { 2848 if (isPagedOverflow(style)) 2849 return PagedFlowThread; 2850 if (style->specifiesColumns()) 2851 return MultiColumnFlowThread; 2852 return NoFlowThread; 2853 } 2854 2855 RenderMultiColumnFlowThread* RenderBlockFlow::createMultiColumnFlowThread(FlowThreadType type) 2856 { 2857 switch (type) { 2858 case MultiColumnFlowThread: 2859 return RenderMultiColumnFlowThread::createAnonymous(document(), style()); 2860 case PagedFlowThread: 2861 // Paged overflow is currently done using the multicol implementation. 2862 return RenderPagedFlowThread::createAnonymous(document(), style()); 2863 default: 2864 ASSERT_NOT_REACHED(); 2865 return nullptr; 2866 } 2867 } 2868 2869 void RenderBlockFlow::createOrDestroyMultiColumnFlowThreadIfNeeded(const RenderStyle* oldStyle) 2870 { 2871 if (!document().regionBasedColumnsEnabled()) 2872 return; 2873 2874 // Paged overflow trumps multicol in this implementation. Ideally, it should be possible to have 2875 // both paged overflow and multicol on the same element, but then we need two flow 2876 // threads. Anyway, this is nothing to worry about until we can actually nest multicol properly 2877 // inside other fragmentation contexts. 2878 FlowThreadType type = flowThreadType(style()); 2879 2880 if (multiColumnFlowThread()) { 2881 ASSERT(oldStyle); 2882 if (type != flowThreadType(oldStyle)) { 2883 // If we're no longer to be multicol/paged, destroy the flow thread. Also destroy it 2884 // when switching between multicol and paged, since that affects the column set 2885 // structure (multicol containers may have spanners, paged containers may not). 2886 multiColumnFlowThread()->evacuateAndDestroy(); 2887 ASSERT(!multiColumnFlowThread()); 2888 } 2889 } 2890 2891 if (type == NoFlowThread || multiColumnFlowThread()) 2892 return; 2893 2894 RenderMultiColumnFlowThread* flowThread = createMultiColumnFlowThread(type); 2895 addChild(flowThread); 2896 flowThread->populate(); 2897 RenderBlockFlowRareData& rareData = ensureRareData(); 2898 ASSERT(!rareData.m_multiColumnFlowThread); 2899 rareData.m_multiColumnFlowThread = flowThread; 2900 } 2901 2902 RenderBlockFlow::RenderBlockFlowRareData& RenderBlockFlow::ensureRareData() 2903 { 2904 if (m_rareData) 2905 return *m_rareData; 2906 2907 m_rareData = adoptPtrWillBeNoop(new RenderBlockFlowRareData(this)); 2908 return *m_rareData; 2909 } 2910 2911 void RenderBlockFlow::positionDialog() 2912 { 2913 HTMLDialogElement* dialog = toHTMLDialogElement(node()); 2914 if (dialog->centeringMode() == HTMLDialogElement::NotCentered) 2915 return; 2916 2917 bool canCenterDialog = (style()->position() == AbsolutePosition || style()->position() == FixedPosition) 2918 && style()->hasAutoTopAndBottom(); 2919 2920 if (dialog->centeringMode() == HTMLDialogElement::Centered) { 2921 if (canCenterDialog) 2922 setY(dialog->centeredPosition()); 2923 return; 2924 } 2925 2926 ASSERT(dialog->centeringMode() == HTMLDialogElement::NeedsCentering); 2927 if (!canCenterDialog) { 2928 dialog->setNotCentered(); 2929 return; 2930 } 2931 2932 FrameView* frameView = document().view(); 2933 LayoutUnit top = (style()->position() == FixedPosition) ? 0 : frameView->scrollOffset().height(); 2934 int visibleHeight = frameView->visibleContentRect(IncludeScrollbars).height(); 2935 if (height() < visibleHeight) 2936 top += (visibleHeight - height()) / 2; 2937 setY(top); 2938 dialog->setCentered(top); 2939 } 2940 2941 } // namespace blink 2942