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