1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2007 David Smith (catfish.man (at) gmail.com) 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved. 6 * Copyright (C) Research In Motion Limited 2010. All rights reserved. 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Library General Public License for more details. 17 * 18 * You should have received a copy of the GNU Library General Public License 19 * along with this library; see the file COPYING.LIB. If not, write to 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 21 * Boston, MA 02110-1301, USA. 22 */ 23 24 #include "config.h" 25 #include "core/rendering/RenderBlock.h" 26 27 #include "HTMLNames.h" 28 #include "core/accessibility/AXObjectCache.h" 29 #include "core/dom/Document.h" 30 #include "core/dom/Element.h" 31 #include "core/dom/OverflowEvent.h" 32 #include "core/dom/shadow/ShadowRoot.h" 33 #include "core/editing/Editor.h" 34 #include "core/editing/FrameSelection.h" 35 #include "core/page/Frame.h" 36 #include "core/page/FrameView.h" 37 #include "core/page/Page.h" 38 #include "core/page/Settings.h" 39 #include "core/platform/PODFreeListArena.h" 40 #include "core/platform/graphics/FloatQuad.h" 41 #include "core/platform/graphics/GraphicsContextStateSaver.h" 42 #include "core/platform/graphics/transforms/TransformState.h" 43 #include "core/rendering/ColumnInfo.h" 44 #include "core/rendering/HitTestLocation.h" 45 #include "core/rendering/HitTestResult.h" 46 #include "core/rendering/InlineIterator.h" 47 #include "core/rendering/InlineTextBox.h" 48 #include "core/rendering/LayoutRepainter.h" 49 #include "core/rendering/PaintInfo.h" 50 #include "core/rendering/RenderCombineText.h" 51 #include "core/rendering/RenderDeprecatedFlexibleBox.h" 52 #include "core/rendering/RenderFlexibleBox.h" 53 #include "core/rendering/RenderInline.h" 54 #include "core/rendering/RenderLayer.h" 55 #include "core/rendering/RenderMarquee.h" 56 #include "core/rendering/RenderNamedFlowThread.h" 57 #include "core/rendering/RenderRegion.h" 58 #include "core/rendering/RenderTableCell.h" 59 #include "core/rendering/RenderTextFragment.h" 60 #include "core/rendering/RenderTheme.h" 61 #include "core/rendering/RenderView.h" 62 #include "core/rendering/shapes/ShapeInsideInfo.h" 63 #include "core/rendering/shapes/ShapeOutsideInfo.h" 64 #include "core/rendering/svg/SVGTextRunRenderingContext.h" 65 #include "wtf/StdLibExtras.h" 66 #include "wtf/TemporaryChange.h" 67 68 using namespace std; 69 using namespace WTF; 70 using namespace Unicode; 71 72 namespace WebCore { 73 74 using namespace HTMLNames; 75 76 struct SameSizeAsRenderBlock : public RenderBox { 77 void* pointers[2]; 78 RenderObjectChildList children; 79 RenderLineBoxList lineBoxes; 80 uint32_t bitfields; 81 }; 82 83 COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small); 84 85 struct SameSizeAsFloatingObject { 86 void* pointers[2]; 87 LayoutRect rect; 88 int paginationStrut; 89 uint32_t bitfields : 8; 90 }; 91 92 COMPILE_ASSERT(sizeof(RenderBlock::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small); 93 94 struct SameSizeAsMarginInfo { 95 uint32_t bitfields : 16; 96 LayoutUnit margins[2]; 97 }; 98 99 typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap; 100 static ColumnInfoMap* gColumnInfoMap = 0; 101 102 static TrackedDescendantsMap* gPositionedDescendantsMap = 0; 103 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0; 104 105 static TrackedContainerMap* gPositionedContainerMap = 0; 106 static TrackedContainerMap* gPercentHeightContainerMap = 0; 107 108 typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap; 109 110 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet; 111 static int gDelayUpdateScrollInfo = 0; 112 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; 113 114 static bool gColumnFlowSplitEnabled = true; 115 116 bool RenderBlock::s_canPropagateFloatIntoSibling = false; 117 118 // This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code 119 // only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes. 120 class OverflowEventDispatcher { 121 WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher); 122 public: 123 OverflowEventDispatcher(const RenderBlock* block) 124 : m_block(block) 125 , m_hadHorizontalLayoutOverflow(false) 126 , m_hadVerticalLayoutOverflow(false) 127 { 128 m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER); 129 if (m_shouldDispatchEvent) { 130 m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow(); 131 m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow(); 132 } 133 } 134 135 ~OverflowEventDispatcher() 136 { 137 if (!m_shouldDispatchEvent) 138 return; 139 140 bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow(); 141 bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow(); 142 143 bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow; 144 bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow; 145 if (horizontalLayoutOverflowChanged || verticalLayoutOverflowChanged) { 146 if (FrameView* frameView = m_block->document()->view()) 147 frameView->scheduleEvent(OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow), m_block->node()); 148 } 149 } 150 151 private: 152 const RenderBlock* m_block; 153 bool m_shouldDispatchEvent; 154 bool m_hadHorizontalLayoutOverflow; 155 bool m_hadVerticalLayoutOverflow; 156 }; 157 158 // Our MarginInfo state used when laying out block children. 159 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding) 160 : m_atBeforeSideOfBlock(true) 161 , m_atAfterSideOfBlock(false) 162 , m_hasMarginBeforeQuirk(false) 163 , m_hasMarginAfterQuirk(false) 164 , m_determinedMarginBeforeQuirk(false) 165 , m_discardMargin(false) 166 { 167 RenderStyle* blockStyle = block->style(); 168 ASSERT(block->isRenderView() || block->parent()); 169 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned() 170 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable() 171 && !block->isRenderFlowThread() && !block->isWritingModeRoot() && !block->parent()->isFlexibleBox() 172 && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth() && !blockStyle->columnSpan(); 173 174 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE; 175 176 // If any height other than auto is specified in CSS, then we don't collapse our bottom 177 // margins with our children's margins. To do otherwise would be to risk odd visual 178 // effects when the children overflow out of the parent block and yet still collapse 179 // with it. We also don't collapse if we have any bottom border/padding. 180 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) && 181 (blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE; 182 183 m_quirkContainer = block->isTableCell() || block->isBody(); 184 185 m_discardMargin = m_canCollapseMarginBeforeWithChildren && block->mustDiscardMarginBefore(); 186 187 m_positiveMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxPositiveMarginBefore() : LayoutUnit(); 188 m_negativeMargin = (m_canCollapseMarginBeforeWithChildren && !block->mustDiscardMarginBefore()) ? block->maxNegativeMarginBefore() : LayoutUnit(); 189 } 190 191 // ------------------------------------------------------------------------------------------------------- 192 193 RenderBlock::RenderBlock(ContainerNode* node) 194 : RenderBox(node) 195 , m_lineHeight(-1) 196 , m_hasMarginBeforeQuirk(false) 197 , m_hasMarginAfterQuirk(false) 198 , m_beingDestroyed(false) 199 , m_hasMarkupTruncation(false) 200 , m_hasBorderOrPaddingLogicalWidthChanged(false) 201 { 202 setChildrenInline(true); 203 COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small); 204 COMPILE_ASSERT(sizeof(RenderBlock::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small); 205 } 206 207 static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap) 208 { 209 if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) { 210 TrackedRendererListHashSet::iterator end = descendantSet->end(); 211 for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { 212 TrackedContainerMap::iterator it = containerMap->find(*descendant); 213 ASSERT(it != containerMap->end()); 214 if (it == containerMap->end()) 215 continue; 216 HashSet<RenderBlock*>* containerSet = it->value.get(); 217 ASSERT(containerSet->contains(block)); 218 containerSet->remove(block); 219 if (containerSet->isEmpty()) 220 containerMap->remove(it); 221 } 222 } 223 } 224 225 RenderBlock::~RenderBlock() 226 { 227 if (m_floatingObjects) 228 deleteAllValues(m_floatingObjects->set()); 229 230 if (hasColumns()) 231 gColumnInfoMap->take(this); 232 233 if (gPercentHeightDescendantsMap) 234 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap); 235 if (gPositionedDescendantsMap) 236 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap); 237 } 238 239 RenderBlock* RenderBlock::createAnonymous(Document* document) 240 { 241 RenderBlock* renderer = new RenderBlock(0); 242 renderer->setDocumentForAnonymous(document); 243 return renderer; 244 } 245 246 void RenderBlock::willBeDestroyed() 247 { 248 // Mark as being destroyed to avoid trouble with merges in removeChild(). 249 m_beingDestroyed = true; 250 251 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will 252 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. 253 children()->destroyLeftoverChildren(); 254 255 // Destroy our continuation before anything other than anonymous children. 256 // The reason we don't destroy it before anonymous children is that they may 257 // have continuations of their own that are anonymous children of our continuation. 258 RenderBoxModelObject* continuation = this->continuation(); 259 if (continuation) { 260 continuation->destroy(); 261 setContinuation(0); 262 } 263 264 if (!documentBeingDestroyed()) { 265 if (firstLineBox()) { 266 // We can't wait for RenderBox::destroy to clear the selection, 267 // because by then we will have nuked the line boxes. 268 // FIXME: The FrameSelection should be responsible for this when it 269 // is notified of DOM mutations. 270 if (isSelectionBorder()) 271 view()->clearSelection(); 272 273 // If we are an anonymous block, then our line boxes might have children 274 // that will outlast this block. In the non-anonymous block case those 275 // children will be destroyed by the time we return from this function. 276 if (isAnonymousBlock()) { 277 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) { 278 while (InlineBox* childBox = box->firstChild()) 279 childBox->remove(); 280 } 281 } 282 } else if (parent()) 283 parent()->dirtyLinesFromChangedChild(this); 284 } 285 286 m_lineBoxes.deleteLineBoxes(); 287 288 if (lineGridBox()) 289 lineGridBox()->destroy(); 290 291 if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0)) 292 gDelayedUpdateScrollInfoSet->remove(this); 293 294 RenderBox::willBeDestroyed(); 295 } 296 297 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 298 { 299 RenderStyle* oldStyle = style(); 300 s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false; 301 302 setReplaced(newStyle->isDisplayInlineType()); 303 304 if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) { 305 if (newStyle->position() == StaticPosition) 306 // Clear our positioned objects list. Our absolutely positioned descendants will be 307 // inserted into our containing block's positioned objects list during layout. 308 removePositionedObjects(0, NewContainingBlock); 309 else if (oldStyle->position() == StaticPosition) { 310 // Remove our absolutely positioned descendants from their current containing block. 311 // They will be inserted into our positioned objects list during layout. 312 RenderObject* cb = parent(); 313 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { 314 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { 315 cb = cb->containingBlock(); 316 break; 317 } 318 cb = cb->parent(); 319 } 320 321 if (cb->isRenderBlock()) 322 toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock); 323 } 324 325 if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition()) 326 markAllDescendantsWithFloatsForLayout(); 327 } 328 329 RenderBox::styleWillChange(diff, newStyle); 330 } 331 332 static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle) 333 { 334 if (newStyle->isHorizontalWritingMode()) 335 return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth() 336 || oldStyle->borderRightWidth() != newStyle->borderRightWidth() 337 || oldStyle->paddingLeft() != newStyle->paddingLeft() 338 || oldStyle->paddingRight() != newStyle->paddingRight(); 339 340 return oldStyle->borderTopWidth() != newStyle->borderTopWidth() 341 || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth() 342 || oldStyle->paddingTop() != newStyle->paddingTop() 343 || oldStyle->paddingBottom() != newStyle->paddingBottom(); 344 } 345 346 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 347 { 348 RenderBox::styleDidChange(diff, oldStyle); 349 350 RenderStyle* newStyle = style(); 351 352 updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : 0); 353 354 if (!isAnonymousBlock()) { 355 // Ensure that all of our continuation blocks pick up the new style. 356 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) { 357 RenderBoxModelObject* nextCont = currCont->continuation(); 358 currCont->setContinuation(0); 359 currCont->setStyle(newStyle); 360 currCont->setContinuation(nextCont); 361 } 362 } 363 364 propagateStyleToAnonymousChildren(true); 365 m_lineHeight = -1; 366 367 // After our style changed, if we lose our ability to propagate floats into next sibling 368 // blocks, then we need to find the top most parent containing that overhanging float and 369 // then mark its descendants with floats for layout and clear all floats from its next 370 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875. 371 bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats(); 372 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) { 373 RenderBlock* parentBlock = this; 374 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 375 FloatingObjectSetIterator end = floatingObjectSet.end(); 376 377 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) { 378 if (curr->isRenderBlock()) { 379 RenderBlock* currBlock = toRenderBlock(curr); 380 381 if (currBlock->hasOverhangingFloats()) { 382 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 383 RenderBox* renderer = (*it)->renderer(); 384 if (currBlock->hasOverhangingFloat(renderer)) { 385 parentBlock = currBlock; 386 break; 387 } 388 } 389 } 390 } 391 } 392 393 parentBlock->markAllDescendantsWithFloatsForLayout(); 394 parentBlock->markSiblingsWithFloatsForLayout(); 395 } 396 397 // It's possible for our border/padding to change, but for the overall logical width of the block to 398 // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true. 399 m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle); 400 } 401 402 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild) 403 { 404 if (beforeChild && beforeChild->parent() == this) 405 return this; 406 407 RenderBlock* curr = toRenderBlock(continuation()); 408 RenderBlock* nextToLast = this; 409 RenderBlock* last = this; 410 while (curr) { 411 if (beforeChild && beforeChild->parent() == curr) { 412 if (curr->firstChild() == beforeChild) 413 return last; 414 return curr; 415 } 416 417 nextToLast = last; 418 last = curr; 419 curr = toRenderBlock(curr->continuation()); 420 } 421 422 if (!beforeChild && !last->firstChild()) 423 return nextToLast; 424 return last; 425 } 426 427 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild) 428 { 429 RenderBlock* flow = continuationBefore(beforeChild); 430 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock()); 431 RenderBoxModelObject* beforeChildParent = 0; 432 if (beforeChild) 433 beforeChildParent = toRenderBoxModelObject(beforeChild->parent()); 434 else { 435 RenderBoxModelObject* cont = flow->continuation(); 436 if (cont) 437 beforeChildParent = cont; 438 else 439 beforeChildParent = flow; 440 } 441 442 if (newChild->isFloatingOrOutOfFlowPositioned()) { 443 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 444 return; 445 } 446 447 // A continuation always consists of two potential candidates: a block or an anonymous 448 // column span box holding column span children. 449 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan(); 450 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan(); 451 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan(); 452 453 if (flow == beforeChildParent) { 454 flow->addChildIgnoringContinuation(newChild, beforeChild); 455 return; 456 } 457 458 // The goal here is to match up if we can, so that we can coalesce and create the 459 // minimal # of continuations needed for the inline. 460 if (childIsNormal == bcpIsNormal) { 461 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 462 return; 463 } 464 if (flowIsNormal == childIsNormal) { 465 flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append. 466 return; 467 } 468 beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild); 469 } 470 471 472 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild) 473 { 474 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block. 475 476 // The goal is to locate a suitable box in which to place our child. 477 RenderBlock* beforeChildParent = 0; 478 if (beforeChild) { 479 RenderObject* curr = beforeChild; 480 while (curr && curr->parent() != this) 481 curr = curr->parent(); 482 beforeChildParent = toRenderBlock(curr); 483 ASSERT(beforeChildParent); 484 ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock()); 485 } else 486 beforeChildParent = toRenderBlock(lastChild()); 487 488 // If the new child is floating or positioned it can just go in that block. 489 if (newChild->isFloatingOrOutOfFlowPositioned()) { 490 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); 491 return; 492 } 493 494 // See if the child can be placed in the box. 495 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline(); 496 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock(); 497 498 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) { 499 beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); 500 return; 501 } 502 503 if (!beforeChild) { 504 // Create a new block of the correct type. 505 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock(); 506 children()->appendChildNode(this, newBox); 507 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0); 508 return; 509 } 510 511 RenderObject* immediateChild = beforeChild; 512 bool isPreviousBlockViable = true; 513 while (immediateChild->parent() != this) { 514 if (isPreviousBlockViable) 515 isPreviousBlockViable = !immediateChild->previousSibling(); 516 immediateChild = immediateChild->parent(); 517 } 518 if (isPreviousBlockViable && immediateChild->previousSibling()) { 519 toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append. 520 return; 521 } 522 523 // Split our anonymous blocks. 524 RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild); 525 526 527 // Create a new anonymous box of the appropriate type. 528 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock(); 529 children()->insertChildNode(this, newBox, newBeforeChild); 530 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0); 531 return; 532 } 533 534 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock) 535 { 536 RenderBlock* firstChildIgnoringAnonymousWrappers = 0; 537 for (RenderObject* curr = this; curr; curr = curr->parent()) { 538 if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip() 539 || curr->isInlineBlockOrInlineTable()) 540 return 0; 541 542 // FIXME: Tables, RenderButtons, and RenderListItems all do special management 543 // of their children that breaks when the flow is split through them. Disabling 544 // multi-column for them to avoid this problem. 545 if (curr->isTable() || curr->isRenderButton() || curr->isListItem()) 546 return 0; 547 548 RenderBlock* currBlock = toRenderBlock(curr); 549 if (!currBlock->createsAnonymousWrapper()) 550 firstChildIgnoringAnonymousWrappers = currBlock; 551 552 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock())) 553 return firstChildIgnoringAnonymousWrappers; 554 555 if (currBlock->isAnonymousColumnSpanBlock()) 556 return 0; 557 } 558 return 0; 559 } 560 561 RenderBlock* RenderBlock::clone() const 562 { 563 RenderBlock* cloneBlock; 564 if (isAnonymousBlock()) { 565 cloneBlock = createAnonymousBlock(); 566 cloneBlock->setChildrenInline(childrenInline()); 567 } 568 else { 569 RenderObject* cloneRenderer = toElement(node())->createRenderer(style()); 570 cloneBlock = toRenderBlock(cloneRenderer); 571 cloneBlock->setStyle(style()); 572 573 // This takes care of setting the right value of childrenInline in case 574 // generated content is added to cloneBlock and 'this' does not have 575 // generated content added yet. 576 cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline()); 577 } 578 cloneBlock->setFlowThreadState(flowThreadState()); 579 return cloneBlock; 580 } 581 582 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock, 583 RenderBlock* middleBlock, 584 RenderObject* beforeChild, RenderBoxModelObject* oldCont) 585 { 586 // Create a clone of this inline. 587 RenderBlock* cloneBlock = clone(); 588 if (!isAnonymousBlock()) 589 cloneBlock->setContinuation(oldCont); 590 591 if (!beforeChild && isAfterContent(lastChild())) 592 beforeChild = lastChild(); 593 594 // If we are moving inline children from |this| to cloneBlock, then we need 595 // to clear our line box tree. 596 if (beforeChild && childrenInline()) 597 deleteLineBoxTree(); 598 599 // Now take all of the children from beforeChild to the end and remove 600 // them from |this| and place them in the clone. 601 moveChildrenTo(cloneBlock, beforeChild, 0, true); 602 603 // Hook |clone| up as the continuation of the middle block. 604 if (!cloneBlock->isAnonymousBlock()) 605 middleBlock->setContinuation(cloneBlock); 606 607 // We have been reparented and are now under the fromBlock. We need 608 // to walk up our block parent chain until we hit the containing anonymous columns block. 609 // Once we hit the anonymous columns block we're done. 610 RenderBoxModelObject* curr = toRenderBoxModelObject(parent()); 611 RenderBoxModelObject* currChild = this; 612 RenderObject* currChildNextSibling = currChild->nextSibling(); 613 614 while (curr && curr->isDescendantOf(fromBlock) && curr != fromBlock) { 615 ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock()); 616 617 RenderBlock* blockCurr = toRenderBlock(curr); 618 619 // Create a new clone. 620 RenderBlock* cloneChild = cloneBlock; 621 cloneBlock = blockCurr->clone(); 622 623 // Insert our child clone as the first child. 624 cloneBlock->addChildIgnoringContinuation(cloneChild, 0); 625 626 // Hook the clone up as a continuation of |curr|. Note we do encounter 627 // anonymous blocks possibly as we walk up the block chain. When we split an 628 // anonymous block, there's no need to do any continuation hookup, since we haven't 629 // actually split a real element. 630 if (!blockCurr->isAnonymousBlock()) { 631 oldCont = blockCurr->continuation(); 632 blockCurr->setContinuation(cloneBlock); 633 cloneBlock->setContinuation(oldCont); 634 } 635 636 // Now we need to take all of the children starting from the first child 637 // *after* currChild and append them all to the clone. 638 blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true); 639 640 // Keep walking up the chain. 641 currChild = curr; 642 currChildNextSibling = currChild->nextSibling(); 643 curr = toRenderBoxModelObject(curr->parent()); 644 } 645 646 // Now we are at the columns block level. We need to put the clone into the toBlock. 647 toBlock->children()->appendChildNode(toBlock, cloneBlock); 648 649 // Now take all the children after currChild and remove them from the fromBlock 650 // and put them in the toBlock. 651 fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true); 652 } 653 654 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, 655 RenderObject* newChild, RenderBoxModelObject* oldCont) 656 { 657 RenderBlock* pre = 0; 658 RenderBlock* block = containingColumnsBlock(); 659 660 // Delete our line boxes before we do the inline split into continuations. 661 block->deleteLineBoxTree(); 662 663 bool madeNewBeforeBlock = false; 664 if (block->isAnonymousColumnsBlock()) { 665 // We can reuse this block and make it the preBlock of the next continuation. 666 pre = block; 667 pre->removePositionedObjects(0); 668 pre->removeFloatingObjects(); 669 block = toRenderBlock(block->parent()); 670 } else { 671 // No anonymous block available for use. Make one. 672 pre = block->createAnonymousColumnsBlock(); 673 pre->setChildrenInline(false); 674 madeNewBeforeBlock = true; 675 } 676 677 RenderBlock* post = block->createAnonymousColumnsBlock(); 678 post->setChildrenInline(false); 679 680 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); 681 if (madeNewBeforeBlock) 682 block->children()->insertChildNode(block, pre, boxFirst); 683 block->children()->insertChildNode(block, newBlockBox, boxFirst); 684 block->children()->insertChildNode(block, post, boxFirst); 685 block->setChildrenInline(false); 686 687 if (madeNewBeforeBlock) 688 block->moveChildrenTo(pre, boxFirst, 0, true); 689 690 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont); 691 692 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting 693 // time in makeChildrenNonInline by just setting this explicitly up front. 694 newBlockBox->setChildrenInline(false); 695 696 newBlockBox->addChild(newChild); 697 698 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) 699 // get deleted properly. Because objects moves from the pre block into the post block, we want to 700 // make new line boxes instead of leaving the old line boxes around. 701 pre->setNeedsLayoutAndPrefWidthsRecalc(); 702 block->setNeedsLayoutAndPrefWidthsRecalc(); 703 post->setNeedsLayoutAndPrefWidthsRecalc(); 704 } 705 706 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild) 707 { 708 RenderBlock* pre = 0; 709 RenderBlock* post = 0; 710 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable 711 // so that we don't have to patch all of the rest of the code later on. 712 713 // Delete the block's line boxes before we do the split. 714 block->deleteLineBoxTree(); 715 716 if (beforeChild && beforeChild->parent() != this) 717 beforeChild = splitAnonymousBoxesAroundChild(beforeChild); 718 719 if (beforeChild != firstChild()) { 720 pre = block->createAnonymousColumnsBlock(); 721 pre->setChildrenInline(block->childrenInline()); 722 } 723 724 if (beforeChild) { 725 post = block->createAnonymousColumnsBlock(); 726 post->setChildrenInline(block->childrenInline()); 727 } 728 729 RenderObject* boxFirst = block->firstChild(); 730 if (pre) 731 block->children()->insertChildNode(block, pre, boxFirst); 732 block->children()->insertChildNode(block, newBlockBox, boxFirst); 733 if (post) 734 block->children()->insertChildNode(block, post, boxFirst); 735 block->setChildrenInline(false); 736 737 // The pre/post blocks always have layers, so we know to always do a full insert/remove (so we pass true as the last argument). 738 block->moveChildrenTo(pre, boxFirst, beforeChild, true); 739 block->moveChildrenTo(post, beforeChild, 0, true); 740 741 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting 742 // time in makeChildrenNonInline by just setting this explicitly up front. 743 newBlockBox->setChildrenInline(false); 744 745 newBlockBox->addChild(newChild); 746 747 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) 748 // get deleted properly. Because objects moved from the pre block into the post block, we want to 749 // make new line boxes instead of leaving the old line boxes around. 750 if (pre) 751 pre->setNeedsLayoutAndPrefWidthsRecalc(); 752 block->setNeedsLayoutAndPrefWidthsRecalc(); 753 if (post) 754 post->setNeedsLayoutAndPrefWidthsRecalc(); 755 } 756 757 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild) 758 { 759 // FIXME: This function is the gateway for the addition of column-span support. It will 760 // be added to in three stages: 761 // (1) Immediate children of a multi-column block can span. 762 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span. 763 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we 764 // cross the streams and have to cope with both types of continuations mixed together). 765 // This function currently supports (1) and (2). 766 RenderBlock* columnsBlockAncestor = 0; 767 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent() 768 && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) { 769 columnsBlockAncestor = containingColumnsBlock(false); 770 if (columnsBlockAncestor) { 771 // Make sure that none of the parent ancestors have a continuation. 772 // If yes, we do not want split the block into continuations. 773 RenderObject* curr = this; 774 while (curr && curr != columnsBlockAncestor) { 775 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) { 776 columnsBlockAncestor = 0; 777 break; 778 } 779 curr = curr->parent(); 780 } 781 } 782 } 783 return columnsBlockAncestor; 784 } 785 786 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild) 787 { 788 if (beforeChild && beforeChild->parent() != this) { 789 RenderObject* beforeChildContainer = beforeChild->parent(); 790 while (beforeChildContainer->parent() != this) 791 beforeChildContainer = beforeChildContainer->parent(); 792 ASSERT(beforeChildContainer); 793 794 if (beforeChildContainer->isAnonymous()) { 795 // If the requested beforeChild is not one of our children, then this is because 796 // there is an anonymous container within this object that contains the beforeChild. 797 RenderObject* beforeChildAnonymousContainer = beforeChildContainer; 798 if (beforeChildAnonymousContainer->isAnonymousBlock() 799 // Full screen renderers and full screen placeholders act as anonymous blocks, not tables: 800 || beforeChildAnonymousContainer->isRenderFullScreen() 801 || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder() 802 ) { 803 // Insert the child into the anonymous block box instead of here. 804 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) 805 beforeChild->parent()->addChild(newChild, beforeChild); 806 else 807 addChild(newChild, beforeChild->parent()); 808 return; 809 } 810 811 ASSERT(beforeChildAnonymousContainer->isTable()); 812 if (newChild->isTablePart()) { 813 // Insert into the anonymous table. 814 beforeChildAnonymousContainer->addChild(newChild, beforeChild); 815 return; 816 } 817 818 beforeChild = splitAnonymousBoxesAroundChild(beforeChild); 819 820 ASSERT(beforeChild->parent() == this); 821 if (beforeChild->parent() != this) { 822 // We should never reach here. If we do, we need to use the 823 // safe fallback to use the topmost beforeChild container. 824 beforeChild = beforeChildContainer; 825 } 826 } else { 827 // We will reach here when beforeChild is a run-in element. 828 // If run-in element precedes a block-level element, it becomes the 829 // the first inline child of that block level element. The insertion 830 // point will be before that block-level element. 831 ASSERT(beforeChild->isRunIn()); 832 beforeChild = beforeChildContainer; 833 } 834 } 835 836 // Nothing goes before the intruded run-in. 837 if (beforeChild && beforeChild->isRunIn() && runInIsPlacedIntoSiblingBlock(beforeChild)) 838 beforeChild = beforeChild->nextSibling(); 839 840 // Check for a spanning element in columns. 841 if (gColumnFlowSplitEnabled) { 842 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild); 843 if (columnsBlockAncestor) { 844 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false); 845 // We are placing a column-span element inside a block. 846 RenderBlock* newBox = createAnonymousColumnSpanBlock(); 847 848 if (columnsBlockAncestor != this && !isRenderFlowThread()) { 849 // We are nested inside a multi-column element and are being split by the span. We have to break up 850 // our block into continuations. 851 RenderBoxModelObject* oldContinuation = continuation(); 852 853 // When we split an anonymous block, there's no need to do any continuation hookup, 854 // since we haven't actually split a real element. 855 if (!isAnonymousBlock()) 856 setContinuation(newBox); 857 858 splitFlow(beforeChild, newBox, newChild, oldContinuation); 859 return; 860 } 861 862 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold 863 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into 864 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block. 865 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild); 866 return; 867 } 868 } 869 870 bool madeBoxesNonInline = false; 871 872 // A block has to either have all of its children inline, or all of its children as blocks. 873 // So, if our children are currently inline and a block child has to be inserted, we move all our 874 // inline children into anonymous block boxes. 875 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) { 876 // This is a block with inline content. Wrap the inline content in anonymous blocks. 877 makeChildrenNonInline(beforeChild); 878 madeBoxesNonInline = true; 879 880 if (beforeChild && beforeChild->parent() != this) { 881 beforeChild = beforeChild->parent(); 882 ASSERT(beforeChild->isAnonymousBlock()); 883 ASSERT(beforeChild->parent() == this); 884 } 885 } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) { 886 // If we're inserting an inline child but all of our children are blocks, then we have to make sure 887 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise 888 // a new one is created and inserted into our list of children in the appropriate position. 889 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild(); 890 891 if (afterChild && afterChild->isAnonymousBlock()) { 892 afterChild->addChild(newChild); 893 return; 894 } 895 896 if (newChild->isInline()) { 897 // No suitable existing anonymous box - create a new one. 898 RenderBlock* newBox = createAnonymousBlock(); 899 RenderBox::addChild(newBox, beforeChild); 900 newBox->addChild(newChild); 901 return; 902 } 903 } 904 905 RenderBox::addChild(newChild, beforeChild); 906 907 // Handle placement of run-ins. 908 placeRunInIfNeeded(newChild); 909 910 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) 911 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 912 // this object may be dead here 913 } 914 915 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) 916 { 917 if (continuation() && !isAnonymousBlock()) 918 addChildToContinuation(newChild, beforeChild); 919 else 920 addChildIgnoringContinuation(newChild, beforeChild); 921 } 922 923 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) 924 { 925 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock())) 926 addChildToAnonymousColumnBlocks(newChild, beforeChild); 927 else 928 addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); 929 } 930 931 static void getInlineRun(RenderObject* start, RenderObject* boundary, 932 RenderObject*& inlineRunStart, 933 RenderObject*& inlineRunEnd) 934 { 935 // Beginning at |start| we find the largest contiguous run of inlines that 936 // we can. We denote the run with start and end points, |inlineRunStart| 937 // and |inlineRunEnd|. Note that these two values may be the same if 938 // we encounter only one inline. 939 // 940 // We skip any non-inlines we encounter as long as we haven't found any 941 // inlines yet. 942 // 943 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary| 944 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered 945 // a non-inline. 946 947 // Start by skipping as many non-inlines as we can. 948 RenderObject * curr = start; 949 bool sawInline; 950 do { 951 while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned())) 952 curr = curr->nextSibling(); 953 954 inlineRunStart = inlineRunEnd = curr; 955 956 if (!curr) 957 return; // No more inline children to be found. 958 959 sawInline = curr->isInline(); 960 961 curr = curr->nextSibling(); 962 while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) { 963 inlineRunEnd = curr; 964 if (curr->isInline()) 965 sawInline = true; 966 curr = curr->nextSibling(); 967 } 968 } while (!sawInline); 969 } 970 971 void RenderBlock::deleteLineBoxTree() 972 { 973 if (containsFloats()) { 974 // Clear references to originating lines, since the lines are being deleted 975 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 976 FloatingObjectSetIterator end = floatingObjectSet.end(); 977 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 978 ASSERT(!((*it)->m_originatingLine) || (*it)->m_originatingLine->renderer() == this); 979 (*it)->m_originatingLine = 0; 980 } 981 } 982 m_lineBoxes.deleteLineBoxTree(); 983 984 if (AXObjectCache* cache = document()->existingAXObjectCache()) 985 cache->recomputeIsIgnored(this); 986 } 987 988 RootInlineBox* RenderBlock::createRootInlineBox() 989 { 990 return new RootInlineBox(this); 991 } 992 993 RootInlineBox* RenderBlock::createAndAppendRootInlineBox() 994 { 995 RootInlineBox* rootBox = createRootInlineBox(); 996 m_lineBoxes.appendLineBox(rootBox); 997 998 if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) { 999 if (AXObjectCache* cache = document()->existingAXObjectCache()) 1000 cache->recomputeIsIgnored(this); 1001 } 1002 1003 return rootBox; 1004 } 1005 1006 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) 1007 { 1008 // makeChildrenNonInline takes a block whose children are *all* inline and it 1009 // makes sure that inline children are coalesced under anonymous 1010 // blocks. If |insertionPoint| is defined, then it represents the insertion point for 1011 // the new block child that is causing us to have to wrap all the inlines. This 1012 // means that we cannot coalesce inlines before |insertionPoint| with inlines following 1013 // |insertionPoint|, because the new child is going to be inserted in between the inlines, 1014 // splitting them. 1015 ASSERT(isInlineBlockOrInlineTable() || !isInline()); 1016 ASSERT(!insertionPoint || insertionPoint->parent() == this); 1017 1018 setChildrenInline(false); 1019 1020 RenderObject *child = firstChild(); 1021 if (!child) 1022 return; 1023 1024 deleteLineBoxTree(); 1025 1026 // Since we are going to have block children, we have to move 1027 // back the run-in to its original place. 1028 if (child->isRunIn()) { 1029 moveRunInToOriginalPosition(child); 1030 child = firstChild(); 1031 } 1032 1033 while (child) { 1034 RenderObject *inlineRunStart, *inlineRunEnd; 1035 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); 1036 1037 if (!inlineRunStart) 1038 break; 1039 1040 child = inlineRunEnd->nextSibling(); 1041 1042 RenderBlock* block = createAnonymousBlock(); 1043 children()->insertChildNode(this, block, inlineRunStart); 1044 moveChildrenTo(block, inlineRunStart, child); 1045 } 1046 1047 #ifndef NDEBUG 1048 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) 1049 ASSERT(!c->isInline()); 1050 #endif 1051 1052 repaint(); 1053 } 1054 1055 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) 1056 { 1057 ASSERT(child->isAnonymousBlock()); 1058 ASSERT(!child->childrenInline()); 1059 1060 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock()))) 1061 return; 1062 1063 RenderObject* firstAnChild = child->m_children.firstChild(); 1064 RenderObject* lastAnChild = child->m_children.lastChild(); 1065 if (firstAnChild) { 1066 RenderObject* o = firstAnChild; 1067 while (o) { 1068 o->setParent(this); 1069 o = o->nextSibling(); 1070 } 1071 firstAnChild->setPreviousSibling(child->previousSibling()); 1072 lastAnChild->setNextSibling(child->nextSibling()); 1073 if (child->previousSibling()) 1074 child->previousSibling()->setNextSibling(firstAnChild); 1075 if (child->nextSibling()) 1076 child->nextSibling()->setPreviousSibling(lastAnChild); 1077 1078 if (child == m_children.firstChild()) 1079 m_children.setFirstChild(firstAnChild); 1080 if (child == m_children.lastChild()) 1081 m_children.setLastChild(lastAnChild); 1082 } else { 1083 if (child == m_children.firstChild()) 1084 m_children.setFirstChild(child->nextSibling()); 1085 if (child == m_children.lastChild()) 1086 m_children.setLastChild(child->previousSibling()); 1087 1088 if (child->previousSibling()) 1089 child->previousSibling()->setNextSibling(child->nextSibling()); 1090 if (child->nextSibling()) 1091 child->nextSibling()->setPreviousSibling(child->previousSibling()); 1092 } 1093 1094 child->children()->setFirstChild(0); 1095 child->m_next = 0; 1096 1097 // Remove all the information in the flow thread associated with the leftover anonymous block. 1098 child->removeFromRenderFlowThread(); 1099 1100 child->setParent(0); 1101 child->setPreviousSibling(0); 1102 child->setNextSibling(0); 1103 1104 child->destroy(); 1105 } 1106 1107 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next) 1108 { 1109 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation()) 1110 return false; 1111 1112 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed())) 1113 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed()))) 1114 return false; 1115 1116 // FIXME: This check isn't required when inline run-ins can't be split into continuations. 1117 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn()) 1118 return false; 1119 1120 if ((prev && (prev->isRubyRun() || prev->isRubyBase())) 1121 || (next && (next->isRubyRun() || next->isRubyBase()))) 1122 return false; 1123 1124 if (!prev || !next) 1125 return true; 1126 1127 // Make sure the types of the anonymous blocks match up. 1128 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock() 1129 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock(); 1130 } 1131 1132 void RenderBlock::collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* child) 1133 { 1134 // It's possible that this block's destruction may have been triggered by the 1135 // child's removal. Just bail if the anonymous child block is already being 1136 // destroyed. See crbug.com/282088 1137 if (child->beingDestroyed()) 1138 return; 1139 parent->setNeedsLayoutAndPrefWidthsRecalc(); 1140 parent->setChildrenInline(child->childrenInline()); 1141 RenderObject* nextSibling = child->nextSibling(); 1142 1143 RenderFlowThread* childFlowThread = child->flowThreadContainingBlock(); 1144 CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread); 1145 1146 parent->children()->removeChildNode(parent, child, child->hasLayer()); 1147 child->moveAllChildrenTo(parent, nextSibling, child->hasLayer()); 1148 // Explicitly delete the child's line box tree, or the special anonymous 1149 // block handling in willBeDestroyed will cause problems. 1150 child->deleteLineBoxTree(); 1151 if (childFlowThread && childFlowThread->isRenderNamedFlowThread()) 1152 toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child); 1153 child->destroy(); 1154 } 1155 1156 void RenderBlock::moveAllChildrenIncludingFloatsTo(RenderBlock* toBlock, bool fullRemoveInsert) 1157 { 1158 moveAllChildrenTo(toBlock, fullRemoveInsert); 1159 1160 // When a portion of the render tree is being detached, anonymous blocks 1161 // will be combined as their children are deleted. In this process, the 1162 // anonymous block later in the tree is merged into the one preceeding it. 1163 // It can happen that the later block (this) contains floats that the 1164 // previous block (toBlock) did not contain, and thus are not in the 1165 // floating objects list for toBlock. This can result in toBlock containing 1166 // floats that are not in it's floating objects list, but are in the 1167 // floating objects lists of siblings and parents. This can cause problems 1168 // when the float itself is deleted, since the deletion code assumes that 1169 // if a float is not in it's containing block's floating objects list, it 1170 // isn't in any floating objects list. In order to preserve this condition 1171 // (removing it has serious performance implications), we need to copy the 1172 // floating objects from the old block (this) to the new block (toBlock). 1173 // The float's metrics will likely all be wrong, but since toBlock is 1174 // already marked for layout, this will get fixed before anything gets 1175 // displayed. 1176 // See bug https://code.google.com/p/chromium/issues/detail?id=230907 1177 if (m_floatingObjects) { 1178 if (!toBlock->m_floatingObjects) 1179 toBlock->createFloatingObjects(); 1180 1181 const FloatingObjectSet& fromFloatingObjectSet = m_floatingObjects->set(); 1182 FloatingObjectSetIterator end = fromFloatingObjectSet.end(); 1183 1184 for (FloatingObjectSetIterator it = fromFloatingObjectSet.begin(); it != end; ++it) { 1185 FloatingObject* floatingObject = *it; 1186 1187 // Don't insert the object again if it's already in the list 1188 if (toBlock->containsFloat(floatingObject->renderer())) 1189 continue; 1190 1191 toBlock->m_floatingObjects->add(floatingObject->clone()); 1192 } 1193 } 1194 1195 } 1196 1197 void RenderBlock::removeChild(RenderObject* oldChild) 1198 { 1199 // No need to waste time in merging or removing empty anonymous blocks. 1200 // We can just bail out if our document is getting destroyed. 1201 if (documentBeingDestroyed()) { 1202 RenderBox::removeChild(oldChild); 1203 return; 1204 } 1205 1206 // This protects against column split flows when anonymous blocks are getting merged. 1207 TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false); 1208 1209 // If this child is a block, and if our previous and next siblings are 1210 // both anonymous blocks with inline content, then we can go ahead and 1211 // fold the inline content back together. 1212 RenderObject* prev = oldChild->previousSibling(); 1213 RenderObject* next = oldChild->nextSibling(); 1214 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next); 1215 if (canMergeAnonymousBlocks && prev && next) { 1216 prev->setNeedsLayoutAndPrefWidthsRecalc(); 1217 RenderBlock* nextBlock = toRenderBlock(next); 1218 RenderBlock* prevBlock = toRenderBlock(prev); 1219 1220 if (prev->childrenInline() != next->childrenInline()) { 1221 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock; 1222 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock; 1223 1224 // Place the inline children block inside of the block children block instead of deleting it. 1225 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure 1226 // to clear out inherited column properties by just making a new style, and to also clear the 1227 // column span flag if it is set. 1228 ASSERT(!inlineChildrenBlock->continuation()); 1229 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK); 1230 // Cache this value as it might get changed in setStyle() call. 1231 bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer(); 1232 inlineChildrenBlock->setStyle(newStyle); 1233 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer); 1234 1235 // Now just put the inlineChildrenBlock inside the blockChildrenBlock. 1236 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0, 1237 inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer()); 1238 next->setNeedsLayoutAndPrefWidthsRecalc(); 1239 1240 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child 1241 // of "this". we null out prev or next so that is not used later in the function. 1242 if (inlineChildrenBlock == prevBlock) 1243 prev = 0; 1244 else 1245 next = 0; 1246 } else { 1247 // Take all the children out of the |next| block and put them in 1248 // the |prev| block. 1249 nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer()); 1250 1251 // Delete the now-empty block's lines and nuke it. 1252 nextBlock->deleteLineBoxTree(); 1253 nextBlock->destroy(); 1254 next = 0; 1255 } 1256 } 1257 1258 RenderBox::removeChild(oldChild); 1259 1260 RenderObject* child = prev ? prev : next; 1261 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) { 1262 // The removal has knocked us down to containing only a single anonymous 1263 // box. We can go ahead and pull the content right back up into our 1264 // box. 1265 collapseAnonymousBlockChild(this, toRenderBlock(child)); 1266 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) { 1267 // It's possible that the removal has knocked us down to a single anonymous 1268 // block with pseudo-style element siblings (e.g. first-letter). If these 1269 // are floating, then we need to pull the content up also. 1270 RenderBlock* anonymousBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next); 1271 if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling()) 1272 && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling())) 1273 && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) { 1274 collapseAnonymousBlockChild(this, anonymousBlock); 1275 } 1276 } 1277 1278 if (!firstChild()) { 1279 // If this was our last child be sure to clear out our line boxes. 1280 if (childrenInline()) 1281 deleteLineBoxTree(); 1282 1283 // If we are an empty anonymous block in the continuation chain, 1284 // we need to remove ourself and fix the continuation chain. 1285 if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) { 1286 RenderObject* containingBlockIgnoringAnonymous = containingBlock(); 1287 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock()) 1288 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock(); 1289 for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) { 1290 if (curr->virtualContinuation() != this) 1291 continue; 1292 1293 // Found our previous continuation. We just need to point it to 1294 // |this|'s next continuation. 1295 RenderBoxModelObject* nextContinuation = continuation(); 1296 if (curr->isRenderInline()) 1297 toRenderInline(curr)->setContinuation(nextContinuation); 1298 else if (curr->isRenderBlock()) 1299 toRenderBlock(curr)->setContinuation(nextContinuation); 1300 else 1301 ASSERT_NOT_REACHED(); 1302 1303 break; 1304 } 1305 setContinuation(0); 1306 destroy(); 1307 } 1308 } 1309 } 1310 1311 bool RenderBlock::isSelfCollapsingBlock() const 1312 { 1313 // We are not self-collapsing if we 1314 // (a) have a non-zero height according to layout (an optimization to avoid wasting time) 1315 // (b) are a table, 1316 // (c) have border/padding, 1317 // (d) have a min-height 1318 // (e) have specified that one of our margins can't collapse using a CSS extension 1319 if (logicalHeight() > 0 1320 || isTable() || borderAndPaddingLogicalHeight() 1321 || style()->logicalMinHeight().isPositive() 1322 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE) 1323 return false; 1324 1325 Length logicalHeightLength = style()->logicalHeight(); 1326 bool hasAutoHeight = logicalHeightLength.isAuto(); 1327 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) { 1328 hasAutoHeight = true; 1329 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { 1330 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell()) 1331 hasAutoHeight = false; 1332 } 1333 } 1334 1335 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends 1336 // on whether we have content that is all self-collapsing or not. 1337 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) { 1338 // If the block has inline children, see if we generated any line boxes. If we have any 1339 // line boxes, then we can't be self-collapsing, since we have content. 1340 if (childrenInline()) 1341 return !firstLineBox(); 1342 1343 // Whether or not we collapse is dependent on whether all our normal flow children 1344 // are also self-collapsing. 1345 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1346 if (child->isFloatingOrOutOfFlowPositioned()) 1347 continue; 1348 if (!child->isSelfCollapsingBlock()) 1349 return false; 1350 } 1351 return true; 1352 } 1353 return false; 1354 } 1355 1356 void RenderBlock::startDelayUpdateScrollInfo() 1357 { 1358 if (gDelayUpdateScrollInfo == 0) { 1359 ASSERT(!gDelayedUpdateScrollInfoSet); 1360 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; 1361 } 1362 ASSERT(gDelayedUpdateScrollInfoSet); 1363 ++gDelayUpdateScrollInfo; 1364 } 1365 1366 void RenderBlock::finishDelayUpdateScrollInfo() 1367 { 1368 --gDelayUpdateScrollInfo; 1369 ASSERT(gDelayUpdateScrollInfo >= 0); 1370 if (gDelayUpdateScrollInfo == 0) { 1371 ASSERT(gDelayedUpdateScrollInfoSet); 1372 1373 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet)); 1374 gDelayedUpdateScrollInfoSet = 0; 1375 1376 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { 1377 RenderBlock* block = *it; 1378 if (block->hasOverflowClip()) { 1379 block->layer()->updateScrollInfoAfterLayout(); 1380 } 1381 } 1382 } 1383 } 1384 1385 void RenderBlock::updateScrollInfoAfterLayout() 1386 { 1387 if (hasOverflowClip()) { 1388 if (style()->isFlippedBlocksWritingMode()) { 1389 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937 1390 // Workaround for now. We cannot delay the scroll info for overflow 1391 // for items with opposite writing directions, as the contents needs 1392 // to overflow in that direction 1393 layer()->updateScrollInfoAfterLayout(); 1394 return; 1395 } 1396 1397 if (gDelayUpdateScrollInfo) 1398 gDelayedUpdateScrollInfoSet->add(this); 1399 else 1400 layer()->updateScrollInfoAfterLayout(); 1401 } 1402 } 1403 1404 void RenderBlock::layout() 1405 { 1406 StackStats::LayoutCheckPoint layoutCheckPoint; 1407 OverflowEventDispatcher dispatcher(this); 1408 1409 // Update our first letter info now. 1410 updateFirstLetter(); 1411 1412 // Table cells call layoutBlock directly, so don't add any logic here. Put code into 1413 // layoutBlock(). 1414 layoutBlock(false); 1415 1416 // It's safe to check for control clip here, since controls can never be table cells. 1417 // If we have a lightweight clip, there can never be any overflow from children. 1418 if (hasControlClip() && m_overflow) 1419 clearLayoutOverflow(); 1420 1421 invalidateBackgroundObscurationStatus(); 1422 } 1423 1424 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside) 1425 { 1426 // FIXME: A future optimization would do a deep comparison for equality. 1427 if (shapeInside == oldShapeInside) 1428 return; 1429 1430 if (shapeInside) { 1431 ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo(); 1432 shapeInsideInfo->dirtyShapeSize(); 1433 } else { 1434 setShapeInsideInfo(nullptr); 1435 markShapeInsideDescendantsForLayout(); 1436 } 1437 } 1438 1439 static inline bool shapeInfoRequiresRelayout(const RenderBlock* block) 1440 { 1441 ShapeInsideInfo* info = block->shapeInsideInfo(); 1442 if (info) 1443 info->setNeedsLayout(info->shapeSizeDirty()); 1444 else 1445 info = block->layoutShapeInsideInfo(); 1446 return info && info->needsLayout(); 1447 } 1448 1449 bool RenderBlock::updateRegionsAndShapesLogicalSize(RenderFlowThread* flowThread) 1450 { 1451 if (!flowThread && !shapeInsideInfo()) 1452 return shapeInfoRequiresRelayout(this); 1453 1454 LayoutUnit oldHeight = logicalHeight(); 1455 LayoutUnit oldTop = logicalTop(); 1456 1457 // Compute the maximum logical height content may cause this block to expand to 1458 // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight 1459 setLogicalHeight(LayoutUnit::max() / 2); 1460 updateLogicalHeight(); 1461 1462 computeShapeSize(); 1463 1464 // Set our start and end regions. No regions above or below us will be considered by our children. They are 1465 // effectively clamped to our region range. 1466 computeRegionRangeForBlock(flowThread); 1467 1468 setLogicalHeight(oldHeight); 1469 setLogicalTop(oldTop); 1470 1471 return shapeInfoRequiresRelayout(this); 1472 } 1473 1474 void RenderBlock::computeShapeSize() 1475 { 1476 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo(); 1477 if (shapeInsideInfo) { 1478 bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false); 1479 shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit()); 1480 } 1481 } 1482 1483 void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged) 1484 { 1485 // A previous sibling has changed dimension, so we need to relayout the shape with the content 1486 ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo(); 1487 if (heightChanged && shapeInsideInfo) 1488 shapeInsideInfo->dirtyShapeSize(); 1489 1490 computeRegionRangeForBlock(flowThread); 1491 } 1492 1493 void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread) 1494 { 1495 if (flowThread) 1496 flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage()); 1497 } 1498 1499 bool RenderBlock::updateLogicalWidthAndColumnWidth() 1500 { 1501 LayoutUnit oldWidth = logicalWidth(); 1502 LayoutUnit oldColumnWidth = desiredColumnWidth(); 1503 1504 updateLogicalWidth(); 1505 calcColumnWidth(); 1506 1507 bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged; 1508 m_hasBorderOrPaddingLogicalWidthChanged = false; 1509 1510 return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged; 1511 } 1512 1513 void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight) 1514 { 1515 ColumnInfo* colInfo = columnInfo(); 1516 if (hasColumns()) { 1517 if (!pageLogicalHeight) { 1518 // We need to go ahead and set our explicit page height if one exists, so that we can 1519 // avoid doing two layout passes. 1520 updateLogicalHeight(); 1521 LayoutUnit columnHeight = contentLogicalHeight(); 1522 if (columnHeight > 0) { 1523 pageLogicalHeight = columnHeight; 1524 hasSpecifiedPageLogicalHeight = true; 1525 } 1526 setLogicalHeight(0); 1527 } 1528 if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) { 1529 colInfo->setColumnHeight(pageLogicalHeight); 1530 pageLogicalHeightChanged = true; 1531 } 1532 1533 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight) 1534 colInfo->clearForcedBreaks(); 1535 1536 colInfo->setPaginationUnit(paginationUnit()); 1537 } else if (isRenderFlowThread()) { 1538 pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height. 1539 pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged(); 1540 } 1541 } 1542 1543 void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight) 1544 { 1545 ASSERT(needsLayout()); 1546 1547 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can 1548 return; // cause us to come in here. Just bail. 1549 1550 if (!relayoutChildren && simplifiedLayout()) 1551 return; 1552 1553 LayoutRepainter repainter(*this, checkForRepaintDuringLayout()); 1554 1555 if (updateLogicalWidthAndColumnWidth()) 1556 relayoutChildren = true; 1557 1558 clearFloats(); 1559 1560 LayoutUnit previousHeight = logicalHeight(); 1561 // FIXME: should this start out as borderAndPaddingLogicalHeight() + scrollbarLogicalHeight(), 1562 // for consistency with other render classes? 1563 setLogicalHeight(0); 1564 1565 bool pageLogicalHeightChanged = false; 1566 bool hasSpecifiedPageLogicalHeight = false; 1567 checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight); 1568 1569 RenderView* renderView = view(); 1570 RenderStyle* styleToUse = style(); 1571 LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo()); 1572 1573 // Regions changing widths can force us to relayout our children. 1574 RenderFlowThread* flowThread = flowThreadContainingBlock(); 1575 if (logicalWidthChangedInRegions(flowThread)) 1576 relayoutChildren = true; 1577 if (updateRegionsAndShapesLogicalSize(flowThread)) 1578 relayoutChildren = true; 1579 1580 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 1581 // our current maximal positive and negative margins. These values are used when we 1582 // are collapsed with adjacent blocks, so for example, if you have block A and B 1583 // collapsing together, then you'd take the maximal positive margin from both A and B 1584 // and subtract it from the maximal negative margin from both A and B to get the 1585 // true collapsed margin. This algorithm is recursive, so when we finish layout() 1586 // our block knows its current maximal positive/negative values. 1587 // 1588 // Start out by setting our margin values to our current margins. Table cells have 1589 // no margins, so we don't fill in the values for table cells. 1590 bool isCell = isTableCell(); 1591 if (!isCell) { 1592 initMaxMarginValues(); 1593 1594 setHasMarginBeforeQuirk(styleToUse->hasMarginBeforeQuirk()); 1595 setHasMarginAfterQuirk(styleToUse->hasMarginAfterQuirk()); 1596 setPaginationStrut(0); 1597 } 1598 1599 LayoutUnit repaintLogicalTop = 0; 1600 LayoutUnit repaintLogicalBottom = 0; 1601 LayoutUnit maxFloatLogicalBottom = 0; 1602 if (!firstChild() && !isAnonymousBlock()) 1603 setChildrenInline(true); 1604 if (childrenInline()) 1605 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom); 1606 else 1607 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom); 1608 1609 // Expand our intrinsic height to encompass floats. 1610 LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 1611 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats()) 1612 setLogicalHeight(lowestFloatLogicalBottom() + toAdd); 1613 1614 if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher)) 1615 return; 1616 1617 // Calculate our new height. 1618 LayoutUnit oldHeight = logicalHeight(); 1619 LayoutUnit oldClientAfterEdge = clientLogicalBottom(); 1620 1621 // Before updating the final size of the flow thread make sure a forced break is applied after the content. 1622 // This ensures the size information is correctly computed for the last auto-height region receiving content. 1623 if (isRenderFlowThread()) 1624 toRenderFlowThread(this)->applyBreakAfterContent(oldClientAfterEdge); 1625 1626 updateLogicalHeight(); 1627 LayoutUnit newHeight = logicalHeight(); 1628 if (oldHeight != newHeight) { 1629 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) { 1630 // One of our children's floats may have become an overhanging float for us. We need to look for it. 1631 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 1632 if (child->isBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) { 1633 RenderBlock* block = toRenderBlock(child); 1634 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight) 1635 addOverhangingFloats(block, false); 1636 } 1637 } 1638 } 1639 } 1640 1641 bool heightChanged = (previousHeight != newHeight); 1642 if (heightChanged) 1643 relayoutChildren = true; 1644 1645 layoutPositionedObjects(relayoutChildren || isRoot()); 1646 1647 updateRegionsAndShapesAfterChildLayout(flowThread, heightChanged); 1648 1649 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 1650 computeOverflow(oldClientAfterEdge); 1651 1652 statePusher.pop(); 1653 1654 fitBorderToLinesIfNeeded(); 1655 1656 if (renderView->layoutState()->m_pageLogicalHeight) 1657 setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop())); 1658 1659 updateLayerTransform(); 1660 1661 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 1662 // we overflow or not. 1663 updateScrollInfoAfterLayout(); 1664 1665 // FIXME: This repaint logic should be moved into a separate helper function! 1666 // Repaint with our new bounds if they are different from our old bounds. 1667 bool didFullRepaint = repainter.repaintAfterLayout(); 1668 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { 1669 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines 1670 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. 1671 LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow(); 1672 LayoutUnit repaintLogicalRight = logicalRightVisualOverflow(); 1673 if (hasOverflowClip()) { 1674 // 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. 1675 // 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. 1676 // layoutInlineChildren should be patched to compute the entire repaint rect. 1677 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow()); 1678 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow()); 1679 } 1680 1681 LayoutRect repaintRect; 1682 if (isHorizontalWritingMode()) 1683 repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop); 1684 else 1685 repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft); 1686 1687 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union. 1688 adjustRectForColumns(repaintRect); 1689 1690 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); 1691 1692 if (hasOverflowClip()) { 1693 // Adjust repaint rect for scroll offset 1694 repaintRect.move(-scrolledContentOffset()); 1695 1696 // Don't allow this rect to spill out of our overflow box. 1697 repaintRect.intersect(LayoutRect(LayoutPoint(), size())); 1698 } 1699 1700 // Make sure the rect is still non-empty after intersecting for overflow above 1701 if (!repaintRect.isEmpty()) { 1702 repaintRectangle(repaintRect); // We need to do a partial repaint of our content. 1703 if (hasReflection()) 1704 repaintRectangle(reflectedRect(repaintRect)); 1705 } 1706 } 1707 1708 clearNeedsLayout(); 1709 } 1710 1711 void RenderBlock::addOverflowFromChildren() 1712 { 1713 if (!hasColumns()) { 1714 if (childrenInline()) 1715 addOverflowFromInlineChildren(); 1716 else 1717 addOverflowFromBlockChildren(); 1718 } else { 1719 ColumnInfo* colInfo = columnInfo(); 1720 if (columnCount(colInfo)) { 1721 LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); 1722 addLayoutOverflow(lastRect); 1723 addContentsVisualOverflow(lastRect); 1724 } 1725 } 1726 } 1727 1728 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats) 1729 { 1730 m_overflow.clear(); 1731 1732 // Add overflow from children. 1733 addOverflowFromChildren(); 1734 1735 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer())) 1736 addOverflowFromFloats(); 1737 1738 // Add in the overflow from positioned objects. 1739 addOverflowFromPositionedObjects(); 1740 1741 if (hasOverflowClip()) { 1742 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins 1743 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always 1744 // be considered reachable. 1745 LayoutRect clientRect(noOverflowRect()); 1746 LayoutRect rectToApply; 1747 if (isHorizontalWritingMode()) 1748 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y())); 1749 else 1750 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1); 1751 addLayoutOverflow(rectToApply); 1752 if (hasRenderOverflow()) 1753 m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge); 1754 } 1755 1756 // Allow our overflow to catch cases where the caret in an empty editable element with negative text indent needs to get painted. 1757 LayoutUnit textIndent = textIndentOffset(); 1758 if (textIndent < 0) { 1759 LayoutRect clientRect(noOverflowRect()); 1760 LayoutRect rectToApply = LayoutRect(clientRect.x() + textIndent, clientRect.y(), clientRect.width() - textIndent, clientRect.height()); 1761 addContentsVisualOverflow(rectToApply); 1762 } 1763 1764 // Add visual overflow from box-shadow and border-image-outset. 1765 addVisualEffectOverflow(); 1766 1767 // Add visual overflow from theme. 1768 addVisualOverflowFromTheme(); 1769 1770 if (isRenderNamedFlowThread()) 1771 toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge); 1772 } 1773 1774 void RenderBlock::addOverflowFromBlockChildren() 1775 { 1776 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1777 if (!child->isFloatingOrOutOfFlowPositioned()) 1778 addOverflowFromChild(child); 1779 } 1780 } 1781 1782 void RenderBlock::addOverflowFromFloats() 1783 { 1784 if (!m_floatingObjects) 1785 return; 1786 1787 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1788 FloatingObjectSetIterator end = floatingObjectSet.end(); 1789 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1790 FloatingObject* r = *it; 1791 if (r->isDescendant()) 1792 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); 1793 } 1794 } 1795 1796 void RenderBlock::addOverflowFromPositionedObjects() 1797 { 1798 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); 1799 if (!positionedDescendants) 1800 return; 1801 1802 RenderBox* positionedObject; 1803 TrackedRendererListHashSet::iterator end = positionedDescendants->end(); 1804 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { 1805 positionedObject = *it; 1806 1807 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content. 1808 if (positionedObject->style()->position() != FixedPosition) { 1809 LayoutUnit x = positionedObject->x(); 1810 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 1811 x -= verticalScrollbarWidth(); 1812 addOverflowFromChild(positionedObject, LayoutSize(x, positionedObject->y())); 1813 } 1814 } 1815 } 1816 1817 void RenderBlock::addVisualOverflowFromTheme() 1818 { 1819 if (!style()->hasAppearance()) 1820 return; 1821 1822 IntRect inflatedRect = pixelSnappedBorderBoxRect(); 1823 theme()->adjustRepaintRect(this, inflatedRect); 1824 addVisualOverflow(inflatedRect); 1825 } 1826 1827 bool RenderBlock::expandsToEncloseOverhangingFloats() const 1828 { 1829 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated()) 1830 || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot(); 1831 } 1832 1833 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 1834 { 1835 bool isHorizontal = isHorizontalWritingMode(); 1836 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal); 1837 1838 LayoutUnit logicalTop = logicalHeight(); 1839 updateStaticInlinePositionForChild(child, logicalTop); 1840 1841 if (!marginInfo.canCollapseWithMarginBefore()) { 1842 // Positioned blocks don't collapse margins, so add the margin provided by 1843 // the container now. The child's own margin is added later when calculating its logical top. 1844 LayoutUnit collapsedBeforePos = marginInfo.positiveMargin(); 1845 LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin(); 1846 logicalTop += collapsedBeforePos - collapsedBeforeNeg; 1847 } 1848 1849 RenderLayer* childLayer = child->layer(); 1850 if (childLayer->staticBlockPosition() != logicalTop) { 1851 childLayer->setStaticBlockPosition(logicalTop); 1852 if (hasStaticBlockPosition) 1853 child->setChildNeedsLayout(MarkOnlyThis); 1854 } 1855 } 1856 1857 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) 1858 { 1859 // The float should be positioned taking into account the bottom margin 1860 // of the previous flow. We add that margin into the height, get the 1861 // float positioned properly, and then subtract the margin out of the 1862 // height again. In the case of self-collapsing blocks, we always just 1863 // use the top margins, since the self-collapsing block collapsed its 1864 // own bottom margin into its top margin. 1865 // 1866 // Note also that the previous flow may collapse its margin into the top of 1867 // our block. If this is the case, then we do not add the margin in to our 1868 // height when computing the position of the float. This condition can be tested 1869 // for by simply calling canCollapseWithMarginBefore. See 1870 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 1871 // an example of this scenario. 1872 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin(); 1873 setLogicalHeight(logicalHeight() + marginOffset); 1874 positionNewFloats(); 1875 setLogicalHeight(logicalHeight() - marginOffset); 1876 } 1877 1878 static void destroyRunIn(RenderBoxModelObject* runIn) 1879 { 1880 ASSERT(runIn->isRunIn()); 1881 ASSERT(!runIn->firstChild()); 1882 1883 // Delete our line box tree. This is needed as our children got moved 1884 // and our line box tree is no longer valid. 1885 if (runIn->isRenderBlock()) 1886 toRenderBlock(runIn)->deleteLineBoxTree(); 1887 else if (runIn->isRenderInline()) 1888 toRenderInline(runIn)->deleteLineBoxTree(); 1889 else 1890 ASSERT_NOT_REACHED(); 1891 1892 runIn->destroy(); 1893 } 1894 1895 void RenderBlock::placeRunInIfNeeded(RenderObject* newChild) 1896 { 1897 if (newChild->isRunIn()) 1898 moveRunInUnderSiblingBlockIfNeeded(newChild); 1899 else if (RenderObject* prevSibling = newChild->previousSibling()) { 1900 if (prevSibling->isRunIn()) 1901 moveRunInUnderSiblingBlockIfNeeded(prevSibling); 1902 } 1903 } 1904 1905 RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn) 1906 { 1907 ASSERT(runIn->isRunIn()); 1908 ASSERT(runIn->node()); 1909 1910 RenderBoxModelObject* newRunIn = 0; 1911 if (!runIn->isRenderBlock()) 1912 newRunIn = new RenderBlock(runIn->node()); 1913 else 1914 newRunIn = new RenderInline(toElement(runIn->node())); 1915 1916 runIn->node()->setRenderer(newRunIn); 1917 newRunIn->setStyle(runIn->style()); 1918 1919 runIn->moveAllChildrenTo(newRunIn, true); 1920 1921 return newRunIn; 1922 } 1923 1924 void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn) 1925 { 1926 ASSERT(runIn->isRunIn()); 1927 1928 // See if we have inline children. If the children aren't inline, 1929 // then just treat the run-in as a normal block. 1930 if (!runIn->childrenInline()) 1931 return; 1932 1933 // FIXME: We don't handle non-block elements with run-in for now. 1934 if (!runIn->isRenderBlock()) 1935 return; 1936 1937 // FIXME: We don't support run-ins with or as part of a continuation 1938 // as it makes the back-and-forth placing complex. 1939 if (runIn->isElementContinuation() || runIn->virtualContinuation()) 1940 return; 1941 1942 // Check if this node is allowed to run-in. E.g. <select> expects its renderer to 1943 // be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in. 1944 if (!runIn->canBeReplacedWithInlineRunIn()) 1945 return; 1946 1947 RenderObject* curr = runIn->nextSibling(); 1948 if (!curr || !curr->isRenderBlock() || !curr->childrenInline()) 1949 return; 1950 1951 // Per CSS3, "A run-in cannot run in to a block that already starts with a 1952 // run-in or that itself is a run-in". 1953 if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn())) 1954 return; 1955 1956 if (curr->isAnonymous() || curr->isFloatingOrOutOfFlowPositioned()) 1957 return; 1958 1959 // FIXME: We don't support run-ins with or as part of a continuation 1960 // as it makes the back-and-forth placing complex. 1961 if (curr->isElementContinuation() || curr->virtualContinuation()) 1962 return; 1963 1964 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); 1965 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); 1966 destroyRunIn(oldRunIn); 1967 1968 // Now insert the new child under |curr| block. Use addChild instead of insertChildNode 1969 // since it handles correct placement of the children, especially where we cannot insert 1970 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. 1971 curr->addChild(newRunIn, curr->firstChild()); 1972 1973 // Make sure that |this| get a layout since its run-in child moved. 1974 curr->setNeedsLayoutAndPrefWidthsRecalc(); 1975 } 1976 1977 bool RenderBlock::runInIsPlacedIntoSiblingBlock(RenderObject* runIn) 1978 { 1979 ASSERT(runIn->isRunIn()); 1980 1981 // If we don't have a parent, we can't be moved into our sibling block. 1982 if (!parent()) 1983 return false; 1984 1985 // An intruded run-in needs to be an inline. 1986 if (!runIn->isRenderInline()) 1987 return false; 1988 1989 return true; 1990 } 1991 1992 void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn) 1993 { 1994 ASSERT(runIn->isRunIn()); 1995 1996 if (!runInIsPlacedIntoSiblingBlock(runIn)) 1997 return; 1998 1999 // FIXME: Run-in that are now placed in sibling block can break up into continuation 2000 // chains when new children are added to it. We cannot easily send them back to their 2001 // original place since that requires writing integration logic with RenderInline::addChild 2002 // and all other places that might cause continuations to be created (without blowing away 2003 // |this|). Disabling this feature for now to prevent crashes. 2004 if (runIn->isElementContinuation() || runIn->virtualContinuation()) 2005 return; 2006 2007 RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn); 2008 RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn); 2009 destroyRunIn(oldRunIn); 2010 2011 // Add the run-in block as our previous sibling. 2012 parent()->addChild(newRunIn, this); 2013 2014 // Make sure that the parent holding the new run-in gets layout. 2015 parent()->setNeedsLayoutAndPrefWidthsRecalc(); 2016 } 2017 2018 LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) 2019 { 2020 bool childDiscardMarginBefore = mustDiscardMarginBeforeForChild(child); 2021 bool childDiscardMarginAfter = mustDiscardMarginAfterForChild(child); 2022 bool childIsSelfCollapsing = child->isSelfCollapsingBlock(); 2023 2024 // The child discards the before margin when the the after margin has discard in the case of a self collapsing block. 2025 childDiscardMarginBefore = childDiscardMarginBefore || (childDiscardMarginAfter && childIsSelfCollapsing); 2026 2027 // Get the four margin values for the child and cache them. 2028 const MarginValues childMargins = marginValuesForChild(child); 2029 2030 // Get our max pos and neg top margins. 2031 LayoutUnit posTop = childMargins.positiveMarginBefore(); 2032 LayoutUnit negTop = childMargins.negativeMarginBefore(); 2033 2034 // For self-collapsing blocks, collapse our bottom margins into our 2035 // top to get new posTop and negTop values. 2036 if (childIsSelfCollapsing) { 2037 posTop = max(posTop, childMargins.positiveMarginAfter()); 2038 negTop = max(negTop, childMargins.negativeMarginAfter()); 2039 } 2040 2041 // See if the top margin is quirky. We only care if this child has 2042 // margins that will collapse with us. 2043 bool topQuirk = hasMarginBeforeQuirk(child); 2044 2045 if (marginInfo.canCollapseWithMarginBefore()) { 2046 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) { 2047 // This child is collapsing with the top of the 2048 // block. If it has larger margin values, then we need to update 2049 // our own maximal values. 2050 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk) 2051 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore())); 2052 2053 // The minute any of the margins involved isn't a quirk, don't 2054 // collapse it away, even if the margin is smaller (www.webreference.com 2055 // has an example of this, a <dt> with 0.8em author-specified inside 2056 // a <dl> inside a <td>. 2057 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) { 2058 setHasMarginBeforeQuirk(false); 2059 marginInfo.setDeterminedMarginBeforeQuirk(true); 2060 } 2061 2062 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore()) 2063 // We have no top margin and our top child has a quirky margin. 2064 // We will pick up this quirky margin and pass it through. 2065 // This deals with the <td><div><p> case. 2066 // Don't do this for a block that split two inlines though. You do 2067 // still apply margins in this case. 2068 setHasMarginBeforeQuirk(true); 2069 } else 2070 // The before margin of the container will also discard all the margins it is collapsing with. 2071 setMustDiscardMarginBefore(); 2072 } 2073 2074 // Once we find a child with discardMarginBefore all the margins collapsing with us must also discard. 2075 if (childDiscardMarginBefore) { 2076 marginInfo.setDiscardMargin(true); 2077 marginInfo.clearMargin(); 2078 } 2079 2080 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop)) 2081 marginInfo.setHasMarginBeforeQuirk(topQuirk); 2082 2083 LayoutUnit beforeCollapseLogicalTop = logicalHeight(); 2084 LayoutUnit logicalTop = beforeCollapseLogicalTop; 2085 if (childIsSelfCollapsing) { 2086 // 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. 2087 // Also, the child's top position equals the logical height of the container. 2088 if (!childDiscardMarginBefore && !marginInfo.discardMargin()) { 2089 // This child has no height. We need to compute our 2090 // position before we collapse the child's margins together, 2091 // so that we can get an accurate position for the zero-height block. 2092 LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore()); 2093 LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore()); 2094 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg); 2095 2096 // Now collapse the child's margins together, which means examining our 2097 // bottom margin values as well. 2098 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter()); 2099 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter()); 2100 2101 if (!marginInfo.canCollapseWithMarginBefore()) 2102 // We need to make sure that the position of the self-collapsing block 2103 // is correct, since it could have overflowing content 2104 // that needs to be positioned correctly (e.g., a block that 2105 // had a specified height of 0 but that actually had subcontent). 2106 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg; 2107 } 2108 } else { 2109 if (mustSeparateMarginBeforeForChild(child)) { 2110 ASSERT(!marginInfo.discardMargin() || (marginInfo.discardMargin() && !marginInfo.margin())); 2111 // If we are at the before side of the block and we collapse, ignore the computed margin 2112 // and just add the child margin to the container height. This will correctly position 2113 // the child inside the container. 2114 LayoutUnit separateMargin = !marginInfo.canCollapseWithMarginBefore() ? marginInfo.margin() : LayoutUnit(0); 2115 setLogicalHeight(logicalHeight() + separateMargin + marginBeforeForChild(child)); 2116 logicalTop = logicalHeight(); 2117 } else if (!marginInfo.discardMargin() && (!marginInfo.atBeforeSideOfBlock() 2118 || (!marginInfo.canCollapseMarginBeforeWithChildren() 2119 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginBeforeQuirk())))) { 2120 // We're collapsing with a previous sibling's margins and not 2121 // with the top of the block. 2122 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop)); 2123 logicalTop = logicalHeight(); 2124 } 2125 2126 marginInfo.setDiscardMargin(childDiscardMarginAfter); 2127 2128 if (!marginInfo.discardMargin()) { 2129 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); 2130 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); 2131 } else 2132 marginInfo.clearMargin(); 2133 2134 if (marginInfo.margin()) 2135 marginInfo.setHasMarginAfterQuirk(hasMarginAfterQuirk(child)); 2136 } 2137 2138 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins 2139 // collapsed into the page edge. 2140 LayoutState* layoutState = view()->layoutState(); 2141 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop 2142 && hasNextPage(beforeCollapseLogicalTop)) { 2143 LayoutUnit oldLogicalTop = logicalTop; 2144 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); 2145 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); 2146 } 2147 2148 // If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now 2149 // overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid 2150 // or clear it anyway, so don't worry about any floating children it may contain. 2151 LayoutUnit oldLogicalHeight = logicalHeight(); 2152 setLogicalHeight(logicalTop); 2153 RenderObject* prev = child->previousSibling(); 2154 if (prev && prev->isBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) { 2155 RenderBlock* block = toRenderBlock(prev); 2156 if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop) 2157 addOverhangingFloats(block, false); 2158 } 2159 setLogicalHeight(oldLogicalHeight); 2160 2161 return logicalTop; 2162 } 2163 2164 LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos) 2165 { 2166 LayoutUnit heightIncrease = getClearDelta(child, yPos); 2167 if (!heightIncrease) 2168 return yPos; 2169 2170 if (child->isSelfCollapsingBlock()) { 2171 bool childDiscardMargin = mustDiscardMarginBeforeForChild(child) || mustDiscardMarginAfterForChild(child); 2172 2173 // For self-collapsing blocks that clear, they can still collapse their 2174 // margins with following siblings. Reset the current margins to represent 2175 // the self-collapsing block's margins only. 2176 // If DISCARD is specified for -webkit-margin-collapse, reset the margin values. 2177 if (!childDiscardMargin) { 2178 MarginValues childMargins = marginValuesForChild(child); 2179 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); 2180 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); 2181 } else 2182 marginInfo.clearMargin(); 2183 marginInfo.setDiscardMargin(childDiscardMargin); 2184 2185 // CSS2.1 states: 2186 // "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with 2187 // the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block." 2188 // So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings 2189 // for a block with height - if none is found then don't allow the margins to collapse with the parent. 2190 bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren(); 2191 for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) { 2192 if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock()) 2193 wouldCollapseMarginsWithParent = false; 2194 } 2195 if (wouldCollapseMarginsWithParent) 2196 marginInfo.setCanCollapseMarginAfterWithChildren(false); 2197 2198 // CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top" 2199 // Move the top of the child box to the bottom of the float ignoring the child's top margin. 2200 LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child); 2201 setLogicalHeight(child->logicalTop() - collapsedMargin); 2202 // A negative collapsed margin-top value cancels itself out as it has already been factored into |yPos| above. 2203 heightIncrease -= max(LayoutUnit(), collapsedMargin); 2204 } else 2205 // Increase our height by the amount we had to clear. 2206 setLogicalHeight(logicalHeight() + heightIncrease); 2207 2208 if (marginInfo.canCollapseWithMarginBefore()) { 2209 // We can no longer collapse with the top of the block since a clear 2210 // occurred. The empty blocks collapse into the cleared block. 2211 // FIXME: This isn't quite correct. Need clarification for what to do 2212 // if the height the cleared block is offset by is smaller than the 2213 // margins involved. 2214 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin); 2215 marginInfo.setAtBeforeSideOfBlock(false); 2216 2217 // In case the child discarded the before margin of the block we need to reset the mustDiscardMarginBefore flag to the initial value. 2218 setMustDiscardMarginBefore(style()->marginBeforeCollapse() == MDISCARD); 2219 } 2220 2221 LayoutUnit logicalTop = yPos + heightIncrease; 2222 // After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it 2223 // won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now. 2224 if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop) 2225 toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop); 2226 2227 return logicalTop; 2228 } 2229 2230 void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore, bool& discardMarginBefore) const 2231 { 2232 // Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky. 2233 // Give up if the child specified -webkit-margin-collapse: separate that prevents collapsing. 2234 // FIXME: Use writing mode independent accessor for marginBeforeCollapse. 2235 if ((document()->inQuirksMode() && hasMarginAfterQuirk(child) && (isTableCell() || isBody())) || child->style()->marginBeforeCollapse() == MSEPARATE) 2236 return; 2237 2238 // The margins are discarded by a child that specified -webkit-margin-collapse: discard. 2239 // FIXME: Use writing mode independent accessor for marginBeforeCollapse. 2240 if (child->style()->marginBeforeCollapse() == MDISCARD) { 2241 positiveMarginBefore = 0; 2242 negativeMarginBefore = 0; 2243 discardMarginBefore = true; 2244 return; 2245 } 2246 2247 LayoutUnit beforeChildMargin = marginBeforeForChild(child); 2248 positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin); 2249 negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin); 2250 2251 if (!child->isRenderBlock()) 2252 return; 2253 2254 RenderBlock* childBlock = toRenderBlock(child); 2255 if (childBlock->childrenInline() || childBlock->isWritingModeRoot()) 2256 return; 2257 2258 MarginInfo childMarginInfo(childBlock, childBlock->borderBefore() + childBlock->paddingBefore(), childBlock->borderAfter() + childBlock->paddingAfter()); 2259 if (!childMarginInfo.canCollapseMarginBeforeWithChildren()) 2260 return; 2261 2262 RenderBox* grandchildBox = childBlock->firstChildBox(); 2263 for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) { 2264 if (!grandchildBox->isFloatingOrOutOfFlowPositioned()) 2265 break; 2266 } 2267 2268 // Give up if there is clearance on the box, since it probably won't collapse into us. 2269 if (!grandchildBox || grandchildBox->style()->clear() != CNONE) 2270 return; 2271 2272 // Make sure to update the block margins now for the grandchild box so that we're looking at current values. 2273 if (grandchildBox->needsLayout()) { 2274 grandchildBox->computeAndSetBlockDirectionMargins(this); 2275 if (grandchildBox->isRenderBlock()) { 2276 RenderBlock* grandchildBlock = toRenderBlock(grandchildBox); 2277 grandchildBlock->setHasMarginBeforeQuirk(grandchildBox->style()->hasMarginBeforeQuirk()); 2278 grandchildBlock->setHasMarginAfterQuirk(grandchildBox->style()->hasMarginAfterQuirk()); 2279 } 2280 } 2281 2282 // Collapse the margin of the grandchild box with our own to produce an estimate. 2283 childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore, discardMarginBefore); 2284 } 2285 2286 LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination) 2287 { 2288 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 2289 // relayout if there are intruding floats. 2290 LayoutUnit logicalTopEstimate = logicalHeight(); 2291 if (!marginInfo.canCollapseWithMarginBefore()) { 2292 LayoutUnit positiveMarginBefore = 0; 2293 LayoutUnit negativeMarginBefore = 0; 2294 bool discardMarginBefore = false; 2295 if (child->selfNeedsLayout()) { 2296 // Try to do a basic estimation of how the collapse is going to go. 2297 marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore, discardMarginBefore); 2298 } else { 2299 // Use the cached collapsed margin values from a previous layout. Most of the time they 2300 // will be right. 2301 MarginValues marginValues = marginValuesForChild(child); 2302 positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore()); 2303 negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore()); 2304 discardMarginBefore = mustDiscardMarginBeforeForChild(child); 2305 } 2306 2307 // Collapse the result with our current margins. 2308 if (!discardMarginBefore) 2309 logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore); 2310 } 2311 2312 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current 2313 // page. 2314 LayoutState* layoutState = view()->layoutState(); 2315 if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight() 2316 && hasNextPage(logicalHeight())) 2317 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); 2318 2319 logicalTopEstimate += getClearDelta(child, logicalTopEstimate); 2320 2321 estimateWithoutPagination = logicalTopEstimate; 2322 2323 if (layoutState->isPaginated()) { 2324 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 2325 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate); 2326 2327 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 2328 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate); 2329 2330 if (!child->selfNeedsLayout() && child->isRenderBlock()) 2331 logicalTopEstimate += toRenderBlock(child)->paginationStrut(); 2332 } 2333 2334 return logicalTopEstimate; 2335 } 2336 2337 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, 2338 RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) 2339 { 2340 LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage); 2341 2342 // Add in our start margin. 2343 LayoutUnit oldPosition = startPosition + childMarginStart; 2344 LayoutUnit newPosition = oldPosition; 2345 2346 LayoutUnit blockOffset = logicalTopForChild(child); 2347 if (region) 2348 blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage)); 2349 2350 LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage, logicalHeightForChild(child)); 2351 2352 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) { 2353 if (childMarginStart < 0) 2354 startOff += childMarginStart; 2355 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit. 2356 } else if (startOff != startPosition) 2357 newPosition = startOff + childMarginStart; 2358 2359 return newPosition - oldPosition; 2360 } 2361 2362 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta) 2363 { 2364 LayoutUnit startPosition = borderStart() + paddingStart(); 2365 if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft()) 2366 startPosition -= verticalScrollbarWidth(); 2367 LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); 2368 2369 // Add in our start margin. 2370 LayoutUnit childMarginStart = marginStartForChild(child); 2371 LayoutUnit newPosition = startPosition + childMarginStart; 2372 2373 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need 2374 // to shift over as necessary to dodge any floats that might get in the way. 2375 if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock()) 2376 newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child)); 2377 2378 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta); 2379 } 2380 2381 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) 2382 { 2383 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) { 2384 // 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. 2385 // Don't update the max margin values because we won't need them anyway. 2386 if (marginInfo.discardMargin()) { 2387 setMustDiscardMarginAfter(); 2388 return; 2389 } 2390 2391 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 2392 // with our children. 2393 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin())); 2394 2395 if (!marginInfo.hasMarginAfterQuirk()) 2396 setHasMarginAfterQuirk(false); 2397 2398 if (marginInfo.hasMarginAfterQuirk() && !marginAfter()) 2399 // We have no bottom margin and our last child has a quirky margin. 2400 // We will pick up this quirky margin and pass it through. 2401 // This deals with the <td><div><p> case. 2402 setHasMarginAfterQuirk(true); 2403 } 2404 } 2405 2406 void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo) 2407 { 2408 marginInfo.setAtAfterSideOfBlock(true); 2409 2410 // If we can't collapse with children then go ahead and add in the bottom margin. 2411 if (!marginInfo.discardMargin() && (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() 2412 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.hasMarginAfterQuirk()))) 2413 setLogicalHeight(logicalHeight() + marginInfo.margin()); 2414 2415 // Now add in our bottom border/padding. 2416 setLogicalHeight(logicalHeight() + afterSide); 2417 2418 // Negative margins can cause our height to shrink below our minimal height (border/padding). 2419 // If this happens, ensure that the computed height is increased to the minimal height. 2420 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide)); 2421 2422 // Update our bottom collapsed margin info. 2423 setCollapsedBottomMargin(marginInfo); 2424 } 2425 2426 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta) 2427 { 2428 if (isHorizontalWritingMode()) { 2429 if (applyDelta == ApplyLayoutDelta) 2430 view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0)); 2431 child->setX(logicalLeft); 2432 } else { 2433 if (applyDelta == ApplyLayoutDelta) 2434 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft)); 2435 child->setY(logicalLeft); 2436 } 2437 } 2438 2439 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta) 2440 { 2441 if (isHorizontalWritingMode()) { 2442 if (applyDelta == ApplyLayoutDelta) 2443 view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop)); 2444 child->setY(logicalTop); 2445 } else { 2446 if (applyDelta == ApplyLayoutDelta) 2447 view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0)); 2448 child->setX(logicalTop); 2449 } 2450 } 2451 2452 void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child) 2453 { 2454 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into 2455 // an auto value. Add a method to determine this, so that we can avoid the relayout. 2456 if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView())) 2457 child->setChildNeedsLayout(MarkOnlyThis); 2458 2459 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. 2460 if (relayoutChildren && child->needsPreferredWidthsRecalculation()) 2461 child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis); 2462 } 2463 2464 void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom) 2465 { 2466 if (gPercentHeightDescendantsMap) { 2467 if (TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this)) { 2468 TrackedRendererListHashSet::iterator end = descendants->end(); 2469 for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) { 2470 RenderBox* box = *it; 2471 while (box != this) { 2472 if (box->normalChildNeedsLayout()) 2473 break; 2474 box->setChildNeedsLayout(MarkOnlyThis); 2475 box = box->containingBlock(); 2476 ASSERT(box); 2477 if (!box) 2478 break; 2479 } 2480 } 2481 } 2482 } 2483 2484 LayoutUnit beforeEdge = borderBefore() + paddingBefore(); 2485 LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 2486 2487 setLogicalHeight(beforeEdge); 2488 2489 // Lay out our hypothetical grid line as though it occurs at the top of the block. 2490 if (view()->layoutState()->lineGrid() == this) 2491 layoutLineGridBox(); 2492 2493 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 2494 MarginInfo marginInfo(this, beforeEdge, afterEdge); 2495 2496 // Fieldsets need to find their legend and position it inside the border of the object. 2497 // The legend then gets skipped during normal layout. The same is true for ruby text. 2498 // It doesn't get included in the normal layout process but is instead skipped. 2499 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren); 2500 2501 LayoutUnit previousFloatLogicalBottom = 0; 2502 maxFloatLogicalBottom = 0; 2503 2504 RenderBox* next = firstChildBox(); 2505 2506 while (next) { 2507 RenderBox* child = next; 2508 next = child->nextSiblingBox(); 2509 2510 if (childToExclude == child) 2511 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs). 2512 2513 updateBlockChildDirtyBitsBeforeLayout(relayoutChildren, child); 2514 2515 if (child->isOutOfFlowPositioned()) { 2516 child->containingBlock()->insertPositionedObject(child); 2517 adjustPositionedBlock(child, marginInfo); 2518 continue; 2519 } 2520 if (child->isFloating()) { 2521 insertFloatingObject(child); 2522 adjustFloatingBlock(marginInfo); 2523 continue; 2524 } 2525 2526 // Lay out the child. 2527 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom); 2528 } 2529 2530 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 2531 // determining the correct collapsed bottom margin information. 2532 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo); 2533 } 2534 2535 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom) 2536 { 2537 LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore(); 2538 LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore(); 2539 2540 // The child is a normal flow object. Compute the margins we will use for collapsing now. 2541 child->computeAndSetBlockDirectionMargins(this); 2542 2543 // Try to guess our correct logical top position. In most cases this guess will 2544 // be correct. Only if we're wrong (when we compute the real logical top position) 2545 // will we have to potentially relayout. 2546 LayoutUnit estimateWithoutPagination; 2547 LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination); 2548 2549 // Cache our old rect so that we can dirty the proper repaint rects if the child moves. 2550 LayoutRect oldRect = child->frameRect(); 2551 LayoutUnit oldLogicalTop = logicalTopForChild(child); 2552 2553 #if !ASSERT_DISABLED 2554 LayoutSize oldLayoutDelta = view()->layoutDelta(); 2555 #endif 2556 // Go ahead and position the child as though it didn't collapse with the top. 2557 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta); 2558 2559 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; 2560 bool markDescendantsWithFloats = false; 2561 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats()) 2562 markDescendantsWithFloats = true; 2563 else if (UNLIKELY(logicalTopEstimate.mightBeSaturated())) 2564 // logicalTopEstimate, returned by estimateLogicalTopPosition, might be saturated for 2565 // very large elements. If it does the comparison with oldLogicalTop might yield a 2566 // false negative as adding and removing margins, borders etc from a saturated number 2567 // might yield incorrect results. If this is the case always mark for layout. 2568 markDescendantsWithFloats = true; 2569 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 2570 // If an element might be affected by the presence of floats, then always mark it for 2571 // layout. 2572 LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom()); 2573 if (fb > logicalTopEstimate) 2574 markDescendantsWithFloats = true; 2575 } 2576 2577 if (childRenderBlock) { 2578 if (markDescendantsWithFloats) 2579 childRenderBlock->markAllDescendantsWithFloatsForLayout(); 2580 if (!child->isWritingModeRoot()) 2581 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom()); 2582 } 2583 2584 if (!child->needsLayout()) 2585 child->markForPaginationRelayoutIfNeeded(); 2586 2587 bool childHadLayout = child->everHadLayout(); 2588 bool childNeededLayout = child->needsLayout(); 2589 if (childNeededLayout) 2590 child->layout(); 2591 2592 // Cache if we are at the top of the block right now. 2593 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); 2594 2595 // Now determine the correct ypos based off examination of collapsing margin 2596 // values. 2597 LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo); 2598 2599 // Now check for clear. 2600 LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear); 2601 2602 bool paginated = view()->layoutState()->isPaginated(); 2603 if (paginated) 2604 logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child, 2605 atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear); 2606 2607 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta); 2608 2609 // Now we have a final top position. See if it really does end up being different from our estimate. 2610 // clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens 2611 // when collapseMargins dynamically adds overhanging floats because of a child with negative margins. 2612 if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout() || (paginated && childRenderBlock && childRenderBlock->shouldBreakAtLineToAvoidWidow())) { 2613 if (child->shrinkToAvoidFloats()) { 2614 // The child's width depends on the line width. 2615 // When the child shifts to clear an item, its width can 2616 // change (because it has more available line width). 2617 // So go ahead and mark the item as dirty. 2618 child->setChildNeedsLayout(MarkOnlyThis); 2619 } 2620 2621 if (childRenderBlock) { 2622 if (!child->avoidsFloats() && childRenderBlock->containsFloats()) 2623 childRenderBlock->markAllDescendantsWithFloatsForLayout(); 2624 if (!child->needsLayout()) 2625 child->markForPaginationRelayoutIfNeeded(); 2626 } 2627 2628 // Our guess was wrong. Make the child lay itself out again. 2629 child->layoutIfNeeded(); 2630 } 2631 2632 // We are no longer at the top of the block if we encounter a non-empty child. 2633 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 2634 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock()) 2635 marginInfo.setAtBeforeSideOfBlock(false); 2636 2637 // Now place the child in the correct left position 2638 determineLogicalLeftPositionForChild(child, ApplyLayoutDelta); 2639 2640 // Update our height now that the child has been placed in the correct position. 2641 setLogicalHeight(logicalHeight() + logicalHeightForChild(child)); 2642 if (mustSeparateMarginAfterForChild(child)) { 2643 setLogicalHeight(logicalHeight() + marginAfterForChild(child)); 2644 marginInfo.clearMargin(); 2645 } 2646 // If the child has overhanging floats that intrude into following siblings (or possibly out 2647 // of this block), then the parent gets notified of the floats now. 2648 if (childRenderBlock && childRenderBlock->containsFloats()) 2649 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout)); 2650 2651 LayoutSize childOffset = child->location() - oldRect.location(); 2652 if (childOffset.width() || childOffset.height()) { 2653 view()->addLayoutDelta(childOffset); 2654 2655 // If the child moved, we have to repaint it as well as any floating/positioned 2656 // descendants. An exception is if we need a layout. In this case, we know we're going to 2657 // repaint ourselves (and the child) anyway. 2658 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) 2659 child->repaintDuringLayoutIfMoved(oldRect); 2660 } 2661 2662 if (!childHadLayout && child->checkForRepaintDuringLayout()) { 2663 child->repaint(); 2664 child->repaintOverhangingFloats(true); 2665 } 2666 2667 if (paginated) { 2668 // Check for an after page/column break. 2669 LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo); 2670 if (newHeight != height()) 2671 setLogicalHeight(newHeight); 2672 } 2673 2674 ASSERT(view()->layoutDeltaMatches(oldLayoutDelta)); 2675 } 2676 2677 void RenderBlock::simplifiedNormalFlowLayout() 2678 { 2679 if (childrenInline()) { 2680 ListHashSet<RootInlineBox*> lineBoxes; 2681 for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) { 2682 RenderObject* o = walker.current(); 2683 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) { 2684 o->layoutIfNeeded(); 2685 if (toRenderBox(o)->inlineBoxWrapper()) { 2686 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root(); 2687 lineBoxes.add(box); 2688 } 2689 } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) { 2690 o->clearNeedsLayout(); 2691 } 2692 } 2693 2694 // FIXME: Glyph overflow will get lost in this case, but not really a big deal. 2695 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 2696 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) { 2697 RootInlineBox* box = *it; 2698 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap); 2699 } 2700 } else { 2701 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) { 2702 if (!box->isOutOfFlowPositioned()) 2703 box->layoutIfNeeded(); 2704 } 2705 } 2706 } 2707 2708 bool RenderBlock::simplifiedLayout() 2709 { 2710 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout()) 2711 return false; 2712 2713 LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); 2714 2715 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly()) 2716 return false; 2717 2718 // Lay out positioned descendants or objects that just need to recompute overflow. 2719 if (needsSimplifiedNormalFlowLayout()) 2720 simplifiedNormalFlowLayout(); 2721 2722 // Lay out our positioned objects if our positioned child bit is set. 2723 // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position 2724 // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the 2725 // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them 2726 // are statically positioned and thus need to move with their absolute ancestors. 2727 bool canContainFixedPosObjects = canContainFixedPositionObjects(); 2728 if (posChildNeedsLayout() || canContainFixedPosObjects) 2729 layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects); 2730 2731 // Recompute our overflow information. 2732 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only 2733 // updating our overflow if we either used to have overflow or if the new temporary object has overflow. 2734 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and 2735 // lowestPosition on every relayout so it's not a regression. 2736 // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during 2737 // simplifiedLayout, we cache the value in m_overflow. 2738 LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom(); 2739 computeOverflow(oldClientAfterEdge, true); 2740 2741 statePusher.pop(); 2742 2743 updateLayerTransform(); 2744 2745 updateScrollInfoAfterLayout(); 2746 2747 clearNeedsLayout(); 2748 return true; 2749 } 2750 2751 void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child) 2752 { 2753 if (child->style()->position() != FixedPosition) 2754 return; 2755 2756 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode()); 2757 bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode()); 2758 if (!hasStaticBlockPosition && !hasStaticInlinePosition) 2759 return; 2760 2761 RenderObject* o = child->parent(); 2762 while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition) 2763 o = o->parent(); 2764 if (o->style()->position() != AbsolutePosition) 2765 return; 2766 2767 RenderBox* box = toRenderBox(child); 2768 if (hasStaticInlinePosition) { 2769 LayoutUnit oldLeft = box->logicalLeft(); 2770 box->updateLogicalWidth(); 2771 if (box->logicalLeft() != oldLeft) 2772 child->setChildNeedsLayout(MarkOnlyThis); 2773 } else if (hasStaticBlockPosition) { 2774 LayoutUnit oldTop = box->logicalTop(); 2775 box->updateLogicalHeight(); 2776 if (box->logicalTop() != oldTop) 2777 child->setChildNeedsLayout(MarkOnlyThis); 2778 } 2779 } 2780 2781 void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly) 2782 { 2783 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); 2784 if (!positionedDescendants) 2785 return; 2786 2787 if (hasColumns()) 2788 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns. 2789 2790 RenderBox* r; 2791 TrackedRendererListHashSet::iterator end = positionedDescendants->end(); 2792 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { 2793 r = *it; 2794 2795 // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So 2796 // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e. 2797 // it has static position. 2798 markFixedPositionObjectForLayoutIfNeeded(r); 2799 if (fixedPositionObjectsOnly) { 2800 r->layoutIfNeeded(); 2801 continue; 2802 } 2803 2804 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the 2805 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned 2806 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is 2807 // positioned explicitly) this should not incur a performance penalty. 2808 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this)) 2809 r->setChildNeedsLayout(MarkOnlyThis); 2810 2811 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths. 2812 if (relayoutChildren && r->needsPreferredWidthsRecalculation()) 2813 r->setPreferredLogicalWidthsDirty(true, MarkOnlyThis); 2814 2815 if (!r->needsLayout()) 2816 r->markForPaginationRelayoutIfNeeded(); 2817 2818 // We don't have to do a full layout. We just have to update our position. Try that first. If we have shrink-to-fit width 2819 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. 2820 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly()) 2821 r->clearNeedsLayout(); 2822 2823 // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now. 2824 // If it's wrong we'll lay out again. 2825 LayoutUnit oldLogicalTop = 0; 2826 bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); 2827 if (needsBlockDirectionLocationSetBeforeLayout) { 2828 if (isHorizontalWritingMode() == r->isHorizontalWritingMode()) 2829 r->updateLogicalHeight(); 2830 else 2831 r->updateLogicalWidth(); 2832 oldLogicalTop = logicalTopForChild(r); 2833 } 2834 2835 r->layoutIfNeeded(); 2836 2837 // Lay out again if our estimate was wrong. 2838 if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) 2839 r->forceChildLayout(); 2840 } 2841 2842 if (hasColumns()) 2843 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work. 2844 } 2845 2846 void RenderBlock::markPositionedObjectsForLayout() 2847 { 2848 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); 2849 if (positionedDescendants) { 2850 RenderBox* r; 2851 TrackedRendererListHashSet::iterator end = positionedDescendants->end(); 2852 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { 2853 r = *it; 2854 r->setChildNeedsLayout(); 2855 } 2856 } 2857 } 2858 2859 void RenderBlock::markForPaginationRelayoutIfNeeded() 2860 { 2861 ASSERT(!needsLayout()); 2862 if (needsLayout()) 2863 return; 2864 2865 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()) || shouldBreakAtLineToAvoidWidow()) 2866 setChildNeedsLayout(MarkOnlyThis); 2867 } 2868 2869 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) 2870 { 2871 // Repaint any overhanging floats (if we know we're the one to paint them). 2872 // Otherwise, bail out. 2873 if (!hasOverhangingFloats()) 2874 return; 2875 2876 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating 2877 // in this block. Better yet would be to push extra state for the containers of other floats. 2878 LayoutStateDisabler layoutStateDisabler(view()); 2879 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2880 FloatingObjectSetIterator end = floatingObjectSet.end(); 2881 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2882 FloatingObject* r = *it; 2883 // Only repaint the object if it is overhanging, is not in its own layer, and 2884 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 2885 // condition is replaced with being a descendant of us. 2886 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) { 2887 r->m_renderer->repaint(); 2888 r->m_renderer->repaintOverhangingFloats(false); 2889 } 2890 } 2891 } 2892 2893 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 2894 { 2895 ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this); 2896 2897 LayoutPoint adjustedPaintOffset = paintOffset + location(); 2898 2899 PaintPhase phase = paintInfo.phase; 2900 2901 // Check if we need to do anything at all. 2902 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 2903 // paints the root's background. 2904 if (!isRoot()) { 2905 LayoutRect overflowBox = overflowRectForPaintRejection(); 2906 flipForWritingMode(overflowBox); 2907 overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); 2908 overflowBox.moveBy(adjustedPaintOffset); 2909 if (!overflowBox.intersects(paintInfo.rect)) 2910 return; 2911 } 2912 2913 // There are some cases where not all clipped visual overflow is accounted for. 2914 // FIXME: reduce the number of such cases. 2915 ContentsClipBehavior contentsClipBehavior = ForceContentsClip; 2916 if (hasOverflowClip() && !hasControlClip() && !(shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret()) 2917 contentsClipBehavior = SkipContentsClipIfPossible; 2918 2919 bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior); 2920 paintObject(paintInfo, adjustedPaintOffset); 2921 if (pushedClip) 2922 popContentsClip(paintInfo, phase, adjustedPaintOffset); 2923 2924 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with 2925 // z-index. We paint after we painted the background/border, so that the scrollbars will 2926 // sit above the background/border. 2927 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly()) 2928 layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect); 2929 } 2930 2931 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 2932 { 2933 if (paintInfo.context->paintingDisabled()) 2934 return; 2935 2936 const Color& ruleColor = resolveColor(CSSPropertyWebkitColumnRuleColor); 2937 bool ruleTransparent = style()->columnRuleIsTransparent(); 2938 EBorderStyle ruleStyle = style()->columnRuleStyle(); 2939 LayoutUnit ruleThickness = style()->columnRuleWidth(); 2940 LayoutUnit colGap = columnGap(); 2941 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent; 2942 if (!renderRule) 2943 return; 2944 2945 ColumnInfo* colInfo = columnInfo(); 2946 unsigned colCount = columnCount(colInfo); 2947 2948 bool antialias = shouldAntialiasLines(paintInfo.context); 2949 2950 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { 2951 bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed(); 2952 LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth(); 2953 LayoutUnit ruleAdd = logicalLeftOffsetForContent(); 2954 LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth(); 2955 LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth(); 2956 BoxSide boxSide = isHorizontalWritingMode() 2957 ? leftToRight ? BSLeft : BSRight 2958 : leftToRight ? BSTop : BSBottom; 2959 2960 for (unsigned i = 0; i < colCount; i++) { 2961 // Move to the next position. 2962 if (leftToRight) { 2963 ruleLogicalLeft += inlineDirectionSize + colGap / 2; 2964 currLogicalLeftOffset += inlineDirectionSize + colGap; 2965 } else { 2966 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2); 2967 currLogicalLeftOffset -= (inlineDirectionSize + colGap); 2968 } 2969 2970 // Now paint the column rule. 2971 if (i < colCount - 1) { 2972 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft(); 2973 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth(); 2974 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd; 2975 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness; 2976 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom); 2977 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias); 2978 } 2979 2980 ruleLogicalLeft = currLogicalLeftOffset; 2981 } 2982 } else { 2983 bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed(); 2984 LayoutUnit ruleLeft = isHorizontalWritingMode() 2985 ? borderLeft() + paddingLeft() 2986 : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter()); 2987 LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness; 2988 LayoutUnit ruleTop = isHorizontalWritingMode() 2989 ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter()) 2990 : borderStart() + paddingStart(); 2991 LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight(); 2992 LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight); 2993 2994 if (!topToBottom) { 2995 if (isHorizontalWritingMode()) 2996 ruleRect.setY(height() - ruleRect.maxY()); 2997 else 2998 ruleRect.setX(width() - ruleRect.maxX()); 2999 } 3000 3001 ruleRect.moveBy(paintOffset); 3002 3003 BoxSide boxSide = isHorizontalWritingMode() 3004 ? topToBottom ? BSTop : BSBottom 3005 : topToBottom ? BSLeft : BSRight; 3006 3007 LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap)); 3008 if (!isHorizontalWritingMode()) 3009 step = step.transposedSize(); 3010 3011 for (unsigned i = 1; i < colCount; i++) { 3012 ruleRect.move(step); 3013 IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect); 3014 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias); 3015 } 3016 } 3017 } 3018 3019 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats) 3020 { 3021 // We need to do multiple passes, breaking up our child painting into strips. 3022 GraphicsContext* context = paintInfo.context; 3023 ColumnInfo* colInfo = columnInfo(); 3024 unsigned colCount = columnCount(colInfo); 3025 if (!colCount) 3026 return; 3027 LayoutUnit currLogicalTopOffset = 0; 3028 LayoutUnit colGap = columnGap(); 3029 for (unsigned i = 0; i < colCount; i++) { 3030 // For each rect, we clip to the rect, and then we adjust our coords. 3031 LayoutRect colRect = columnRectAt(colInfo, i); 3032 flipForWritingMode(colRect); 3033 LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent(); 3034 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset); 3035 if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) { 3036 if (isHorizontalWritingMode()) 3037 offset.expand(0, colRect.y() - borderTop() - paddingTop()); 3038 else 3039 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0); 3040 } 3041 colRect.moveBy(paintOffset); 3042 PaintInfo info(paintInfo); 3043 info.rect.intersect(pixelSnappedIntRect(colRect)); 3044 3045 if (!info.rect.isEmpty()) { 3046 GraphicsContextStateSaver stateSaver(*context); 3047 LayoutRect clipRect(colRect); 3048 3049 if (i < colCount - 1) { 3050 if (isHorizontalWritingMode()) 3051 clipRect.expand(colGap / 2, 0); 3052 else 3053 clipRect.expand(0, colGap / 2); 3054 } 3055 // Each strip pushes a clip, since column boxes are specified as being 3056 // like overflow:hidden. 3057 // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element 3058 // are clipped according to the 'overflow' property. 3059 context->clip(pixelSnappedIntRect(clipRect)); 3060 3061 // Adjust our x and y when painting. 3062 LayoutPoint adjustedPaintOffset = paintOffset + offset; 3063 if (paintingFloats) 3064 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); 3065 else 3066 paintContents(info, adjustedPaintOffset); 3067 } 3068 3069 LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width()); 3070 if (style()->isFlippedBlocksWritingMode()) 3071 currLogicalTopOffset += blockDelta; 3072 else 3073 currLogicalTopOffset -= blockDelta; 3074 } 3075 } 3076 3077 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 3078 { 3079 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. 3080 // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document 3081 // will do a full repaint. 3082 if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) 3083 return; 3084 3085 if (childrenInline()) 3086 m_lineBoxes.paint(this, paintInfo, paintOffset); 3087 else { 3088 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 3089 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 3090 3091 // We don't paint our own background, but we do let the kids paint their backgrounds. 3092 PaintInfo paintInfoForChild(paintInfo); 3093 paintInfoForChild.phase = newPhase; 3094 paintInfoForChild.updatePaintingRootForChildren(this); 3095 paintChildren(paintInfoForChild, paintOffset); 3096 } 3097 } 3098 3099 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 3100 { 3101 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) 3102 paintChild(child, paintInfo, paintOffset); 3103 } 3104 3105 void RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset) 3106 { 3107 LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset); 3108 if (!child->hasSelfPaintingLayer() && !child->isFloating()) 3109 child->paint(paintInfo, childPoint); 3110 } 3111 3112 bool RenderBlock::hasCaret(CaretType type) const 3113 { 3114 // Paint the caret if the FrameSelection says so or if caret browsing is enabled 3115 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled(); 3116 RenderObject* caretPainter; 3117 bool isContentEditable; 3118 if (type == CursorCaret) { 3119 caretPainter = frame()->selection()->caretRenderer(); 3120 isContentEditable = frame()->selection()->rendererIsEditable(); 3121 } else { 3122 caretPainter = frame()->page()->dragCaretController().caretRenderer(); 3123 isContentEditable = frame()->page()->dragCaretController().isContentEditable(); 3124 } 3125 return caretPainter == this && (isContentEditable || caretBrowsing); 3126 } 3127 3128 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type) 3129 { 3130 if (!hasCaret(type)) 3131 return; 3132 3133 if (type == CursorCaret) 3134 frame()->selection()->paintCaret(paintInfo.context, paintOffset, paintInfo.rect); 3135 else 3136 frame()->page()->dragCaretController().paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect); 3137 } 3138 3139 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 3140 { 3141 PaintPhase paintPhase = paintInfo.phase; 3142 3143 // 1. paint background, borders etc 3144 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { 3145 if (hasBoxDecorations()) 3146 paintBoxDecorations(paintInfo, paintOffset); 3147 if (hasColumns() && !paintInfo.paintRootBackgroundOnly()) 3148 paintColumnRules(paintInfo, paintOffset); 3149 } 3150 3151 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { 3152 paintMask(paintInfo, paintOffset); 3153 return; 3154 } 3155 3156 // We're done. We don't bother painting any children. 3157 if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly()) 3158 return; 3159 3160 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div). 3161 LayoutPoint scrolledOffset = paintOffset; 3162 if (hasOverflowClip()) 3163 scrolledOffset.move(-scrolledContentOffset()); 3164 3165 // 2. paint contents 3166 if (paintPhase != PaintPhaseSelfOutline) { 3167 if (hasColumns()) 3168 paintColumnContents(paintInfo, scrolledOffset); 3169 else 3170 paintContents(paintInfo, scrolledOffset); 3171 } 3172 3173 // 3. paint selection 3174 // FIXME: Make this work with multi column layouts. For now don't fill gaps. 3175 bool isPrinting = document()->printing(); 3176 if (!isPrinting && !hasColumns()) 3177 paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks. 3178 3179 // 4. paint floats. 3180 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { 3181 if (hasColumns()) 3182 paintColumnContents(paintInfo, scrolledOffset, true); 3183 else 3184 paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); 3185 } 3186 3187 // 5. paint outline. 3188 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) 3189 paintOutline(paintInfo, LayoutRect(paintOffset, size())); 3190 3191 // 6. paint continuation outlines. 3192 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { 3193 RenderInline* inlineCont = inlineElementContinuation(); 3194 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) { 3195 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer()); 3196 RenderBlock* cb = containingBlock(); 3197 3198 bool inlineEnclosedInSelfPaintingLayer = false; 3199 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) { 3200 if (box->hasSelfPaintingLayer()) { 3201 inlineEnclosedInSelfPaintingLayer = true; 3202 break; 3203 } 3204 } 3205 3206 // Do not add continuations for outline painting by our containing block if we are a relative positioned 3207 // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being 3208 // in the same layer. 3209 if (!inlineEnclosedInSelfPaintingLayer && !hasLayer()) 3210 cb->addContinuationWithOutline(inlineRenderer); 3211 else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer())) 3212 inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location()); 3213 } 3214 paintContinuationOutlines(paintInfo, paintOffset); 3215 } 3216 3217 // 7. paint caret. 3218 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, 3219 // then paint the caret. 3220 if (paintPhase == PaintPhaseForeground) { 3221 paintCaret(paintInfo, paintOffset, CursorCaret); 3222 paintCaret(paintInfo, paintOffset, DragCaret); 3223 } 3224 } 3225 3226 LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const 3227 { 3228 if (!style()->isFlippedBlocksWritingMode()) 3229 return point; 3230 3231 // This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since 3232 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped 3233 // case. 3234 if (isHorizontalWritingMode()) 3235 return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child)); 3236 return LayoutPoint(point.x() + width() - child->renderer()->width() - 2 * xPositionForFloatIncludingMargin(child), point.y()); 3237 } 3238 3239 void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase) 3240 { 3241 if (!m_floatingObjects) 3242 return; 3243 3244 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3245 FloatingObjectSetIterator end = floatingObjectSet.end(); 3246 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3247 FloatingObject* r = *it; 3248 // Only paint the object if our m_shouldPaint flag is set. 3249 if (r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()) { 3250 PaintInfo currentPaintInfo(paintInfo); 3251 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 3252 LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y())); 3253 r->m_renderer->paint(currentPaintInfo, childPoint); 3254 if (!preservePhase) { 3255 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 3256 r->m_renderer->paint(currentPaintInfo, childPoint); 3257 currentPaintInfo.phase = PaintPhaseFloat; 3258 r->m_renderer->paint(currentPaintInfo, childPoint); 3259 currentPaintInfo.phase = PaintPhaseForeground; 3260 r->m_renderer->paint(currentPaintInfo, childPoint); 3261 currentPaintInfo.phase = PaintPhaseOutline; 3262 r->m_renderer->paint(currentPaintInfo, childPoint); 3263 } 3264 } 3265 } 3266 } 3267 3268 RenderInline* RenderBlock::inlineElementContinuation() const 3269 { 3270 RenderBoxModelObject* continuation = this->continuation(); 3271 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0; 3272 } 3273 3274 RenderBlock* RenderBlock::blockElementContinuation() const 3275 { 3276 RenderBoxModelObject* currentContinuation = continuation(); 3277 if (!currentContinuation || currentContinuation->isInline()) 3278 return 0; 3279 RenderBlock* nextContinuation = toRenderBlock(currentContinuation); 3280 if (nextContinuation->isAnonymousBlock()) 3281 return nextContinuation->blockElementContinuation(); 3282 return nextContinuation; 3283 } 3284 3285 static ContinuationOutlineTableMap* continuationOutlineTable() 3286 { 3287 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); 3288 return &table; 3289 } 3290 3291 void RenderBlock::addContinuationWithOutline(RenderInline* flow) 3292 { 3293 // We can't make this work if the inline is in a layer. We'll just rely on the broken 3294 // way of painting. 3295 ASSERT(!flow->layer() && !flow->isInlineElementContinuation()); 3296 3297 ContinuationOutlineTableMap* table = continuationOutlineTable(); 3298 ListHashSet<RenderInline*>* continuations = table->get(this); 3299 if (!continuations) { 3300 continuations = new ListHashSet<RenderInline*>; 3301 table->set(this, adoptPtr(continuations)); 3302 } 3303 3304 continuations->add(flow); 3305 } 3306 3307 bool RenderBlock::paintsContinuationOutline(RenderInline* flow) 3308 { 3309 ContinuationOutlineTableMap* table = continuationOutlineTable(); 3310 if (table->isEmpty()) 3311 return false; 3312 3313 ListHashSet<RenderInline*>* continuations = table->get(this); 3314 if (!continuations) 3315 return false; 3316 3317 return continuations->contains(flow); 3318 } 3319 3320 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset) 3321 { 3322 ContinuationOutlineTableMap* table = continuationOutlineTable(); 3323 if (table->isEmpty()) 3324 return; 3325 3326 OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this); 3327 if (!continuations) 3328 return; 3329 3330 LayoutPoint accumulatedPaintOffset = paintOffset; 3331 // Paint each continuation outline. 3332 ListHashSet<RenderInline*>::iterator end = continuations->end(); 3333 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { 3334 // Need to add in the coordinates of the intervening blocks. 3335 RenderInline* flow = *it; 3336 RenderBlock* block = flow->containingBlock(); 3337 for ( ; block && block != this; block = block->containingBlock()) 3338 accumulatedPaintOffset.moveBy(block->location()); 3339 ASSERT(block); 3340 flow->paintOutline(info, accumulatedPaintOffset); 3341 } 3342 } 3343 3344 bool RenderBlock::shouldPaintSelectionGaps() const 3345 { 3346 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); 3347 } 3348 3349 bool RenderBlock::isSelectionRoot() const 3350 { 3351 if (isPseudoElement()) 3352 return false; 3353 ASSERT(node() || isAnonymous()); 3354 3355 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. 3356 if (isTable()) 3357 return false; 3358 3359 if (isBody() || isRoot() || hasOverflowClip() 3360 || isPositioned() || isFloating() 3361 || isTableCell() || isInlineBlockOrInlineTable() 3362 || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot() 3363 || isRenderFlowThread()) 3364 return true; 3365 3366 if (view() && view()->selectionStart()) { 3367 Node* startElement = view()->selectionStart()->node(); 3368 if (startElement && startElement->rootEditableElement() == node()) 3369 return true; 3370 } 3371 3372 return false; 3373 } 3374 3375 GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer) 3376 { 3377 ASSERT(!needsLayout()); 3378 3379 if (!shouldPaintSelectionGaps()) 3380 return GapRects(); 3381 3382 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); 3383 mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms); 3384 LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint()); 3385 3386 if (hasOverflowClip()) 3387 offsetFromRepaintContainer -= scrolledContentOffset(); 3388 3389 LayoutUnit lastTop = 0; 3390 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop); 3391 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop); 3392 3393 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight); 3394 } 3395 3396 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset) 3397 { 3398 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { 3399 LayoutUnit lastTop = 0; 3400 LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop); 3401 LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop); 3402 GraphicsContextStateSaver stateSaver(*paintInfo.context); 3403 3404 LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo); 3405 if (!gapRectsBounds.isEmpty()) { 3406 if (RenderLayer* layer = enclosingLayer()) { 3407 gapRectsBounds.moveBy(-paintOffset); 3408 if (!hasLayer()) { 3409 LayoutRect localBounds(gapRectsBounds); 3410 flipForWritingMode(localBounds); 3411 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox(); 3412 if (layer->renderer()->hasOverflowClip()) 3413 gapRectsBounds.move(layer->renderBox()->scrolledContentOffset()); 3414 } 3415 layer->addBlockSelectionGapsBounds(gapRectsBounds); 3416 } 3417 } 3418 } 3419 } 3420 3421 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects) 3422 { 3423 if (!positionedObjects) 3424 return; 3425 3426 TrackedRendererListHashSet::const_iterator end = positionedObjects->end(); 3427 for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) { 3428 RenderBox* r = *it; 3429 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height())); 3430 } 3431 } 3432 3433 static LayoutUnit blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock) 3434 { 3435 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width(); 3436 } 3437 3438 static LayoutUnit inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock) 3439 { 3440 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height(); 3441 } 3442 3443 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect) 3444 { 3445 LayoutRect result; 3446 if (isHorizontalWritingMode()) 3447 result = logicalRect; 3448 else 3449 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width()); 3450 flipForWritingMode(result); 3451 result.moveBy(rootBlockPhysicalPosition); 3452 return result; 3453 } 3454 3455 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3456 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo) 3457 { 3458 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. 3459 // Clip out floating and positioned objects when painting selection gaps. 3460 if (paintInfo) { 3461 // Note that we don't clip out overflow for positioned objects. We just stick to the border box. 3462 LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height()); 3463 rootBlock->flipForWritingMode(flippedBlockRect); 3464 flippedBlockRect.moveBy(rootBlockPhysicalPosition); 3465 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects()); 3466 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. 3467 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) 3468 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes. 3469 if (m_floatingObjects) { 3470 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3471 FloatingObjectSetIterator end = floatingObjectSet.end(); 3472 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3473 FloatingObject* r = *it; 3474 LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r), 3475 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r), 3476 r->m_renderer->width(), r->m_renderer->height()); 3477 rootBlock->flipForWritingMode(floatBox); 3478 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); 3479 paintInfo->context->clipOut(pixelSnappedIntRect(floatBox)); 3480 } 3481 } 3482 } 3483 3484 // FIXME: overflow: auto/scroll regions need more math here, since painting in the border box is different from painting in the padding box (one is scrolled, the other is 3485 // fixed). 3486 GapRects result; 3487 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. 3488 return result; 3489 3490 if (hasColumns() || hasTransform() || style()->columnSpan()) { 3491 // FIXME: We should learn how to gap fill multiple columns and transforms eventually. 3492 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight(); 3493 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight()); 3494 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight()); 3495 return result; 3496 } 3497 3498 if (childrenInline()) 3499 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo); 3500 else 3501 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo); 3502 3503 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. 3504 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) 3505 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 3506 logicalHeight(), paintInfo)); 3507 return result; 3508 } 3509 3510 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3511 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo) 3512 { 3513 GapRects result; 3514 3515 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 3516 3517 if (!firstLineBox()) { 3518 if (containsStart) { 3519 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this 3520 // case. 3521 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight(); 3522 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight()); 3523 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight()); 3524 } 3525 return result; 3526 } 3527 3528 RootInlineBox* lastSelectedLine = 0; 3529 RootInlineBox* curr; 3530 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 3531 3532 // Now paint the gaps for the lines. 3533 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 3534 LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock(); 3535 LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock(); 3536 3537 if (!containsStart && !lastSelectedLine && 3538 selectionState() != SelectionStart && selectionState() != SelectionBoth) 3539 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 3540 selTop, paintInfo)); 3541 3542 LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight); 3543 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize()); 3544 LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect); 3545 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y()) 3546 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x())) 3547 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo)); 3548 3549 lastSelectedLine = curr; 3550 } 3551 3552 if (containsStart && !lastSelectedLine) 3553 // VisibleSelection must start just after our last line. 3554 lastSelectedLine = lastRootBox(); 3555 3556 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 3557 // Go ahead and update our lastY to be the bottom of the last selected line. 3558 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom(); 3559 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 3560 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 3561 } 3562 return result; 3563 } 3564 3565 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3566 LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo) 3567 { 3568 GapRects result; 3569 3570 // Go ahead and jump right to the first block child that contains some selected objects. 3571 RenderBox* curr; 3572 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } 3573 3574 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { 3575 SelectionState childState = curr->selectionState(); 3576 if (childState == SelectionBoth || childState == SelectionEnd) 3577 sawSelectionEnd = true; 3578 3579 if (curr->isFloatingOrOutOfFlowPositioned()) 3580 continue; // We must be a normal flow object in order to even be considered. 3581 3582 if (curr->isInFlowPositioned() && curr->hasLayer()) { 3583 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. 3584 // Just disregard it completely. 3585 LayoutSize relOffset = curr->layer()->offsetForInFlowPosition(); 3586 if (relOffset.width() || relOffset.height()) 3587 continue; 3588 } 3589 3590 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this. 3591 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone); 3592 if (fillBlockGaps) { 3593 // We need to fill the vertical gap above this object. 3594 if (childState == SelectionEnd || childState == SelectionInside) 3595 // Fill the gap above the object. 3596 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 3597 curr->logicalTop(), paintInfo)); 3598 3599 // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past* 3600 // our object. We know this if the selection did not end inside our object. 3601 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd)) 3602 childState = SelectionNone; 3603 3604 // Fill side gaps on this object based off its state. 3605 bool leftGap, rightGap; 3606 getSelectionGapInfo(childState, leftGap, rightGap); 3607 3608 if (leftGap) 3609 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo)); 3610 if (rightGap) 3611 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo)); 3612 3613 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as 3614 // they can without bumping into floating or positioned objects. Ideally they will go right up 3615 // to the border of the root selection block. 3616 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom(); 3617 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom()); 3618 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom()); 3619 } else if (childState != SelectionNone) 3620 // We must be a block that has some selected object inside it. Go ahead and recur. 3621 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()), 3622 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo)); 3623 } 3624 return result; 3625 } 3626 3627 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3628 LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo) 3629 { 3630 LayoutUnit logicalTop = lastLogicalTop; 3631 LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop; 3632 if (logicalHeight <= 0) 3633 return LayoutRect(); 3634 3635 // Get the selection offsets for the bottom of the gap 3636 LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom)); 3637 LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom)); 3638 LayoutUnit logicalWidth = logicalRight - logicalLeft; 3639 if (logicalWidth <= 0) 3640 return LayoutRect(); 3641 3642 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight)); 3643 if (paintInfo) 3644 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor()); 3645 return gapRect; 3646 } 3647 3648 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3649 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo) 3650 { 3651 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop; 3652 LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)); 3653 LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight))); 3654 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft; 3655 if (rootBlockLogicalWidth <= 0) 3656 return LayoutRect(); 3657 3658 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); 3659 if (paintInfo) 3660 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor()); 3661 return gapRect; 3662 } 3663 3664 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock, 3665 RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo) 3666 { 3667 LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop; 3668 LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight))); 3669 LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)); 3670 LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft; 3671 if (rootBlockLogicalWidth <= 0) 3672 return LayoutRect(); 3673 3674 LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); 3675 if (paintInfo) 3676 paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor()); 3677 return gapRect; 3678 } 3679 3680 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) 3681 { 3682 bool ltr = style()->isLeftToRightDirection(); 3683 leftGap = (state == RenderObject::SelectionInside) || 3684 (state == RenderObject::SelectionEnd && ltr) || 3685 (state == RenderObject::SelectionStart && !ltr); 3686 rightGap = (state == RenderObject::SelectionInside) || 3687 (state == RenderObject::SelectionStart && ltr) || 3688 (state == RenderObject::SelectionEnd && !ltr); 3689 } 3690 3691 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) 3692 { 3693 LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false); 3694 if (logicalLeft == logicalLeftOffsetForContent()) { 3695 if (rootBlock != this) 3696 // The border can potentially be further extended by our containingBlock(). 3697 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop()); 3698 return logicalLeft; 3699 } else { 3700 RenderBlock* cb = this; 3701 while (cb != rootBlock) { 3702 logicalLeft += cb->logicalLeft(); 3703 cb = cb->containingBlock(); 3704 } 3705 } 3706 return logicalLeft; 3707 } 3708 3709 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position) 3710 { 3711 LayoutUnit logicalRight = logicalRightOffsetForLine(position, false); 3712 if (logicalRight == logicalRightOffsetForContent()) { 3713 if (rootBlock != this) 3714 // The border can potentially be further extended by our containingBlock(). 3715 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop()); 3716 return logicalRight; 3717 } else { 3718 RenderBlock* cb = this; 3719 while (cb != rootBlock) { 3720 logicalRight += cb->logicalLeft(); 3721 cb = cb->containingBlock(); 3722 } 3723 } 3724 return logicalRight; 3725 } 3726 3727 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const 3728 { 3729 if (isSelectionRoot()) 3730 return 0; 3731 3732 const RenderObject* object = this; 3733 RenderObject* sibling; 3734 do { 3735 sibling = object->previousSibling(); 3736 while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot())) 3737 sibling = sibling->previousSibling(); 3738 3739 offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop()); 3740 object = object->parent(); 3741 } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot()); 3742 3743 if (!sibling) 3744 return 0; 3745 3746 RenderBlock* beforeBlock = toRenderBlock(sibling); 3747 3748 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop()); 3749 3750 RenderObject* child = beforeBlock->lastChild(); 3751 while (child && child->isRenderBlock()) { 3752 beforeBlock = toRenderBlock(child); 3753 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop()); 3754 child = beforeBlock->lastChild(); 3755 } 3756 return beforeBlock; 3757 } 3758 3759 void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap) 3760 { 3761 if (!descendantsMap) { 3762 descendantsMap = new TrackedDescendantsMap; 3763 containerMap = new TrackedContainerMap; 3764 } 3765 3766 TrackedRendererListHashSet* descendantSet = descendantsMap->get(this); 3767 if (!descendantSet) { 3768 descendantSet = new TrackedRendererListHashSet; 3769 descendantsMap->set(this, adoptPtr(descendantSet)); 3770 } 3771 bool added = descendantSet->add(descendant).isNewEntry; 3772 if (!added) { 3773 ASSERT(containerMap->get(descendant)); 3774 ASSERT(containerMap->get(descendant)->contains(this)); 3775 return; 3776 } 3777 3778 HashSet<RenderBlock*>* containerSet = containerMap->get(descendant); 3779 if (!containerSet) { 3780 containerSet = new HashSet<RenderBlock*>; 3781 containerMap->set(descendant, adoptPtr(containerSet)); 3782 } 3783 ASSERT(!containerSet->contains(this)); 3784 containerSet->add(this); 3785 } 3786 3787 void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap) 3788 { 3789 if (!descendantsMap) 3790 return; 3791 3792 OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant); 3793 if (!containerSet) 3794 return; 3795 3796 HashSet<RenderBlock*>::iterator end = containerSet->end(); 3797 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) { 3798 RenderBlock* container = *it; 3799 3800 // FIXME: Disabling this assert temporarily until we fix the layout 3801 // bugs associated with positioned objects not properly cleared from 3802 // their ancestor chain before being moved. See webkit bug 93766. 3803 // ASSERT(descendant->isDescendantOf(container)); 3804 3805 TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container); 3806 ASSERT(descendantsMapIterator != descendantsMap->end()); 3807 if (descendantsMapIterator == descendantsMap->end()) 3808 continue; 3809 TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get(); 3810 ASSERT(descendantSet->contains(descendant)); 3811 descendantSet->remove(descendant); 3812 if (descendantSet->isEmpty()) 3813 descendantsMap->remove(descendantsMapIterator); 3814 } 3815 } 3816 3817 TrackedRendererListHashSet* RenderBlock::positionedObjects() const 3818 { 3819 if (gPositionedDescendantsMap) 3820 return gPositionedDescendantsMap->get(this); 3821 return 0; 3822 } 3823 3824 void RenderBlock::insertPositionedObject(RenderBox* o) 3825 { 3826 ASSERT(!isAnonymousBlock()); 3827 3828 if (o->isRenderFlowThread()) 3829 return; 3830 3831 insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap); 3832 } 3833 3834 void RenderBlock::removePositionedObject(RenderBox* o) 3835 { 3836 removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap); 3837 } 3838 3839 void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState) 3840 { 3841 TrackedRendererListHashSet* positionedDescendants = positionedObjects(); 3842 if (!positionedDescendants) 3843 return; 3844 3845 RenderBox* r; 3846 3847 TrackedRendererListHashSet::iterator end = positionedDescendants->end(); 3848 3849 Vector<RenderBox*, 16> deadObjects; 3850 3851 for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) { 3852 r = *it; 3853 if (!o || r->isDescendantOf(o)) { 3854 if (containingBlockState == NewContainingBlock) 3855 r->setChildNeedsLayout(MarkOnlyThis); 3856 3857 // It is parent blocks job to add positioned child to positioned objects list of its containing block 3858 // Parent layout needs to be invalidated to ensure this happens. 3859 RenderObject* p = r->parent(); 3860 while (p && !p->isRenderBlock()) 3861 p = p->parent(); 3862 if (p) 3863 p->setChildNeedsLayout(); 3864 3865 deadObjects.append(r); 3866 } 3867 } 3868 3869 for (unsigned i = 0; i < deadObjects.size(); i++) 3870 removePositionedObject(deadObjects.at(i)); 3871 } 3872 3873 void RenderBlock::removeFloatingObjects() 3874 { 3875 if (!m_floatingObjects) 3876 return; 3877 3878 deleteAllValues(m_floatingObjects->set()); 3879 m_floatingObjects->clear(); 3880 } 3881 3882 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) 3883 { 3884 ASSERT(o->isFloating()); 3885 3886 // Create the list of special objects if we don't aleady have one 3887 if (!m_floatingObjects) 3888 createFloatingObjects(); 3889 else { 3890 // Don't insert the object again if it's already in the list 3891 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3892 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); 3893 if (it != floatingObjectSet.end()) 3894 return *it; 3895 } 3896 3897 // Create the special object entry & append it to the list 3898 3899 FloatingObject* newObj = new FloatingObject(o->style()->floating()); 3900 3901 // Our location is irrelevant if we're unsplittable or no pagination is in effect. 3902 // Just go ahead and lay out the float. 3903 bool isChildRenderBlock = o->isRenderBlock(); 3904 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged()) 3905 o->setChildNeedsLayout(MarkOnlyThis); 3906 3907 bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout(); 3908 if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root. 3909 o->layoutIfNeeded(); 3910 else { 3911 o->updateLogicalWidth(); 3912 o->computeAndSetBlockDirectionMargins(this); 3913 } 3914 3915 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o)); 3916 3917 if (ShapeOutsideInfo* shapeOutside = o->shapeOutsideInfo()) 3918 shapeOutside->setShapeSize(logicalWidthForChild(o), logicalHeightForChild(o)); 3919 3920 newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will. 3921 newObj->setIsDescendant(true); 3922 newObj->m_renderer = o; 3923 3924 m_floatingObjects->add(newObj); 3925 3926 return newObj; 3927 } 3928 3929 void RenderBlock::removeFloatingObject(RenderBox* o) 3930 { 3931 if (m_floatingObjects) { 3932 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3933 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); 3934 if (it != floatingObjectSet.end()) { 3935 FloatingObject* r = *it; 3936 if (childrenInline()) { 3937 LayoutUnit logicalTop = logicalTopForFloat(r); 3938 LayoutUnit logicalBottom = logicalBottomForFloat(r); 3939 3940 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995. 3941 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max()) 3942 logicalBottom = LayoutUnit::max(); 3943 else { 3944 // Special-case zero- and less-than-zero-height floats: those don't touch 3945 // the line that they're on, but it still needs to be dirtied. This is 3946 // accomplished by pretending they have a height of 1. 3947 logicalBottom = max(logicalBottom, logicalTop + 1); 3948 } 3949 if (r->m_originatingLine) { 3950 if (!selfNeedsLayout()) { 3951 ASSERT(r->m_originatingLine->renderer() == this); 3952 r->m_originatingLine->markDirty(); 3953 } 3954 #if !ASSERT_DISABLED 3955 r->m_originatingLine = 0; 3956 #endif 3957 } 3958 markLinesDirtyInBlockRange(0, logicalBottom); 3959 } 3960 m_floatingObjects->remove(r); 3961 ASSERT(!r->m_originatingLine); 3962 delete r; 3963 } 3964 } 3965 } 3966 3967 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset) 3968 { 3969 if (!containsFloats()) 3970 return; 3971 3972 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3973 FloatingObject* curr = floatingObjectSet.last(); 3974 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { 3975 m_floatingObjects->remove(curr); 3976 ASSERT(!curr->m_originatingLine); 3977 delete curr; 3978 if (floatingObjectSet.isEmpty()) 3979 break; 3980 curr = floatingObjectSet.last(); 3981 } 3982 } 3983 3984 LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const 3985 { 3986 RenderBox* childBox = floatingObject->renderer(); 3987 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. 3988 LayoutUnit logicalRightOffset; // Constant part of right offset. 3989 // FIXME Bug 102948: This only works for shape outside directly set on this block. 3990 ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo(); 3991 // FIXME Bug 102846: Take into account the height of the content. The offset should be 3992 // equal to the maximum segment length. 3993 if (shapeInsideInfo && shapeInsideInfo->hasSegments() && shapeInsideInfo->segments().size() == 1) { 3994 // FIXME Bug 102949: Add support for shapes with multipe segments. 3995 3996 // The segment offsets are relative to the content box. 3997 logicalRightOffset = logicalLeftOffset + shapeInsideInfo->segments()[0].logicalRight; 3998 logicalLeftOffset += shapeInsideInfo->segments()[0].logicalLeft; 3999 } else 4000 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); 4001 4002 LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for. 4003 4004 LayoutUnit floatLogicalLeft; 4005 4006 bool insideFlowThread = flowThreadContainingBlock(); 4007 4008 if (childBox->style()->floating() == LeftFloat) { 4009 LayoutUnit heightRemainingLeft = 1; 4010 LayoutUnit heightRemainingRight = 1; 4011 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); 4012 while (logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { 4013 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight); 4014 floatLogicalLeft = logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft); 4015 if (insideFlowThread) { 4016 // Have to re-evaluate all of our offsets, since they may have changed. 4017 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset. 4018 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. 4019 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); 4020 } 4021 } 4022 floatLogicalLeft = max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft); 4023 } else { 4024 LayoutUnit heightRemainingLeft = 1; 4025 LayoutUnit heightRemainingRight = 1; 4026 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); 4027 while (floatLogicalLeft - logicalLeftOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) < floatLogicalWidth) { 4028 logicalTopOffset += min(heightRemainingLeft, heightRemainingRight); 4029 floatLogicalLeft = logicalRightOffsetForLineIgnoringShapeOutside(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight); 4030 if (insideFlowThread) { 4031 // Have to re-evaluate all of our offsets, since they may have changed. 4032 logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset. 4033 logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset. 4034 floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); 4035 } 4036 } 4037 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable 4038 // |floatLogicalWidth| was capped to the available line width. 4039 // See fast/block/float/clamped-right-float.html. 4040 } 4041 4042 return LayoutPoint(floatLogicalLeft, logicalTopOffset); 4043 } 4044 4045 bool RenderBlock::positionNewFloats() 4046 { 4047 if (!m_floatingObjects) 4048 return false; 4049 4050 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4051 if (floatingObjectSet.isEmpty()) 4052 return false; 4053 4054 // If all floats have already been positioned, then we have no work to do. 4055 if (floatingObjectSet.last()->isPlaced()) 4056 return false; 4057 4058 // Move backwards through our floating object list until we find a float that has 4059 // already been positioned. Then we'll be able to move forward, positioning all of 4060 // the new floats that need it. 4061 FloatingObjectSetIterator it = floatingObjectSet.end(); 4062 --it; // Go to last item. 4063 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 4064 FloatingObject* lastPlacedFloatingObject = 0; 4065 while (it != begin) { 4066 --it; 4067 if ((*it)->isPlaced()) { 4068 lastPlacedFloatingObject = *it; 4069 ++it; 4070 break; 4071 } 4072 } 4073 4074 LayoutUnit logicalTop = logicalHeight(); 4075 4076 // The float cannot start above the top position of the last positioned float. 4077 if (lastPlacedFloatingObject) 4078 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop); 4079 4080 FloatingObjectSetIterator end = floatingObjectSet.end(); 4081 // Now walk through the set of unpositioned floats and place them. 4082 for (; it != end; ++it) { 4083 FloatingObject* floatingObject = *it; 4084 // The containing block is responsible for positioning floats, so if we have floats in our 4085 // list that come from somewhere else, do not attempt to position them. 4086 if (floatingObject->renderer()->containingBlock() != this) 4087 continue; 4088 4089 RenderBox* childBox = floatingObject->renderer(); 4090 LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); 4091 4092 LayoutRect oldRect = childBox->frameRect(); 4093 4094 if (childBox->style()->clear() & CLEFT) 4095 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop); 4096 if (childBox->style()->clear() & CRIGHT) 4097 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop); 4098 4099 LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop); 4100 4101 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x()); 4102 4103 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin); 4104 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); 4105 4106 LayoutState* layoutState = view()->layoutState(); 4107 bool isPaginated = layoutState->isPaginated(); 4108 if (isPaginated && !childBox->needsLayout()) 4109 childBox->markForPaginationRelayoutIfNeeded(); 4110 4111 childBox->layoutIfNeeded(); 4112 4113 if (isPaginated) { 4114 // If we are unsplittable and don't fit, then we need to move down. 4115 // We include our margins as part of the unsplittable area. 4116 LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true); 4117 4118 // See if we have a pagination strut that is making us move down further. 4119 // Note that an unsplittable child can't also have a pagination strut, so this is 4120 // exclusive with the case above. 4121 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0; 4122 if (childBlock && childBlock->paginationStrut()) { 4123 newLogicalTop += childBlock->paginationStrut(); 4124 childBlock->setPaginationStrut(0); 4125 } 4126 4127 if (newLogicalTop != floatLogicalLocation.y()) { 4128 floatingObject->m_paginationStrut = newLogicalTop - floatLogicalLocation.y(); 4129 4130 floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop); 4131 setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x()); 4132 4133 setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin); 4134 setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox)); 4135 4136 if (childBlock) 4137 childBlock->setChildNeedsLayout(MarkOnlyThis); 4138 childBox->layoutIfNeeded(); 4139 } 4140 } 4141 4142 setLogicalTopForFloat(floatingObject, floatLogicalLocation.y()); 4143 4144 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox)); 4145 4146 m_floatingObjects->addPlacedObject(floatingObject); 4147 4148 // If the child moved, we have to repaint it. 4149 if (childBox->checkForRepaintDuringLayout()) 4150 childBox->repaintDuringLayoutIfMoved(oldRect); 4151 } 4152 return true; 4153 } 4154 4155 void RenderBlock::newLine(EClear clear) 4156 { 4157 positionNewFloats(); 4158 // set y position 4159 LayoutUnit newY = 0; 4160 switch (clear) 4161 { 4162 case CLEFT: 4163 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 4164 break; 4165 case CRIGHT: 4166 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight); 4167 break; 4168 case CBOTH: 4169 newY = lowestFloatLogicalBottom(); 4170 default: 4171 break; 4172 } 4173 if (height() < newY) 4174 setLogicalHeight(newY); 4175 } 4176 4177 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) 4178 { 4179 insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); 4180 } 4181 4182 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) 4183 { 4184 removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap); 4185 } 4186 4187 TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const 4188 { 4189 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; 4190 } 4191 4192 bool RenderBlock::hasPercentHeightContainerMap() 4193 { 4194 return gPercentHeightContainerMap; 4195 } 4196 4197 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant) 4198 { 4199 // We don't null check gPercentHeightContainerMap since the caller 4200 // already ensures this and we need to call this function on every 4201 // descendant in clearPercentHeightDescendantsFrom(). 4202 ASSERT(gPercentHeightContainerMap); 4203 return gPercentHeightContainerMap->contains(descendant); 4204 } 4205 4206 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant) 4207 { 4208 // We query the map directly, rather than looking at style's 4209 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those 4210 // can change with writing mode/directional changes. 4211 if (!hasPercentHeightContainerMap()) 4212 return; 4213 4214 if (!hasPercentHeightDescendant(descendant)) 4215 return; 4216 4217 removePercentHeightDescendant(descendant); 4218 } 4219 4220 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent) 4221 { 4222 ASSERT(gPercentHeightContainerMap); 4223 for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) { 4224 if (!curr->isBox()) 4225 continue; 4226 4227 RenderBox* box = toRenderBox(curr); 4228 if (!hasPercentHeightDescendant(box)) 4229 continue; 4230 4231 removePercentHeightDescendant(box); 4232 } 4233 } 4234 4235 static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom) 4236 { 4237 if (objectTop >= floatBottom || objectBottom < floatTop) 4238 return false; 4239 4240 // The top of the object overlaps the float 4241 if (objectTop >= floatTop) 4242 return true; 4243 4244 // The object encloses the float 4245 if (objectTop < floatTop && objectBottom > floatBottom) 4246 return true; 4247 4248 // The bottom of the object overlaps the float 4249 if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom) 4250 return true; 4251 4252 return false; 4253 } 4254 4255 template<> 4256 bool RenderBlock::FloatIntervalSearchAdapter<RenderBlock::FloatingObject::FloatLeft>::updateOffsetIfNeeded(const FloatingObject* floatingObject) const 4257 { 4258 if (m_renderer->logicalRightForFloat(floatingObject) > m_offset) { 4259 m_offset = m_renderer->logicalRightForFloat(floatingObject); 4260 return true; 4261 } 4262 return false; 4263 } 4264 4265 template<> 4266 bool RenderBlock::FloatIntervalSearchAdapter<RenderBlock::FloatingObject::FloatRight>::updateOffsetIfNeeded(const FloatingObject* floatingObject) const 4267 { 4268 if (m_renderer->logicalLeftForFloat(floatingObject) < m_offset) { 4269 m_offset = m_renderer->logicalLeftForFloat(floatingObject); 4270 return true; 4271 } 4272 return false; 4273 } 4274 4275 template <RenderBlock::FloatingObject::Type FloatTypeValue> 4276 inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) const 4277 { 4278 const FloatingObject* floatingObject = interval.data(); 4279 if (floatingObject->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lowValue, m_highValue)) 4280 return; 4281 4282 // All the objects returned from the tree should be already placed. 4283 ASSERT(floatingObject->isPlaced()); 4284 ASSERT(rangesIntersect(m_renderer->pixelSnappedLogicalTopForFloat(floatingObject), m_renderer->pixelSnappedLogicalBottomForFloat(floatingObject), m_lowValue, m_highValue)); 4285 4286 bool floatIsNewExtreme = updateOffsetIfNeeded(floatingObject); 4287 if (floatIsNewExtreme && m_heightRemaining) 4288 *m_heightRemaining = m_renderer->logicalBottomForFloat(floatingObject) - m_lowValue; 4289 4290 m_last = floatingObject; 4291 } 4292 4293 LayoutUnit RenderBlock::textIndentOffset() const 4294 { 4295 LayoutUnit cw = 0; 4296 RenderView* renderView = 0; 4297 if (style()->textIndent().isPercent()) 4298 cw = containingBlock()->availableLogicalWidth(); 4299 else if (style()->textIndent().isViewportPercentage()) 4300 renderView = view(); 4301 return minimumValueForLength(style()->textIndent(), cw, renderView); 4302 } 4303 4304 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const 4305 { 4306 LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); 4307 if (!region) 4308 return logicalLeftOffset; 4309 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage); 4310 return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y()); 4311 } 4312 4313 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const 4314 { 4315 LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop(); 4316 logicalRightOffset += availableLogicalWidth(); 4317 if (!region) 4318 return logicalRightOffset; 4319 LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage); 4320 return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY())); 4321 } 4322 4323 LayoutUnit RenderBlock::logicalLeftFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const 4324 { 4325 LayoutUnit left = fixedOffset; 4326 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) { 4327 if (heightRemaining) 4328 *heightRemaining = 1; 4329 4330 FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining); 4331 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter); 4332 4333 const FloatingObject* lastFloat = adapter.lastFloat(); 4334 if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) { 4335 if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) { 4336 shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight); 4337 left += shapeOutside->rightSegmentMarginBoxDelta(); 4338 } 4339 } 4340 } 4341 4342 return left; 4343 } 4344 4345 LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const 4346 { 4347 LayoutUnit left = offsetFromFloats; 4348 4349 if (applyTextIndent && style()->isLeftToRightDirection()) 4350 left += textIndentOffset(); 4351 4352 if (style()->lineAlign() == LineAlignNone) 4353 return left; 4354 4355 // Push in our left offset so that it is aligned with the character grid. 4356 LayoutState* layoutState = view()->layoutState(); 4357 if (!layoutState) 4358 return left; 4359 4360 RenderBlock* lineGrid = layoutState->lineGrid(); 4361 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode()) 4362 return left; 4363 4364 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge? 4365 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth(); 4366 if (!maxCharWidth) 4367 return left; 4368 4369 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height(); 4370 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height(); 4371 4372 // Push in to the nearest character width. 4373 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945). 4374 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942). 4375 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time. 4376 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout. 4377 // (https://bugs.webkit.org/show_bug.cgi?id=79944) 4378 float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth); 4379 left += remainder; 4380 return left; 4381 } 4382 4383 LayoutUnit RenderBlock::logicalRightFloatOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, LayoutUnit* heightRemaining, LayoutUnit logicalHeight, ShapeOutsideFloatOffsetMode offsetMode) const 4384 { 4385 LayoutUnit right = fixedOffset; 4386 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) { 4387 if (heightRemaining) 4388 *heightRemaining = 1; 4389 4390 LayoutUnit rightFloatOffset = fixedOffset; 4391 FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining); 4392 m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter); 4393 4394 const FloatingObject* lastFloat = adapter.lastFloat(); 4395 if (offsetMode == ShapeOutsideFloatShapeOffset && lastFloat) { 4396 if (ShapeOutsideInfo* shapeOutside = lastFloat->renderer()->shapeOutsideInfo()) { 4397 shapeOutside->computeSegmentsForContainingBlockLine(logicalTop, logicalTopForFloat(lastFloat), logicalHeight); 4398 rightFloatOffset += shapeOutside->leftSegmentMarginBoxDelta(); 4399 } 4400 } 4401 4402 right = min(right, rightFloatOffset); 4403 } 4404 return right; 4405 } 4406 4407 LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const 4408 { 4409 LayoutUnit right = offsetFromFloats; 4410 4411 if (applyTextIndent && !style()->isLeftToRightDirection()) 4412 right -= textIndentOffset(); 4413 4414 if (style()->lineAlign() == LineAlignNone) 4415 return right; 4416 4417 // Push in our right offset so that it is aligned with the character grid. 4418 LayoutState* layoutState = view()->layoutState(); 4419 if (!layoutState) 4420 return right; 4421 4422 RenderBlock* lineGrid = layoutState->lineGrid(); 4423 if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode()) 4424 return right; 4425 4426 // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge? 4427 float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth(); 4428 if (!maxCharWidth) 4429 return right; 4430 4431 LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height(); 4432 LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height(); 4433 4434 // Push in to the nearest character width. 4435 // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945). 4436 // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942). 4437 // FIXME: This doesn't work when the inline position of the object isn't set ahead of time. 4438 // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout. 4439 // (https://bugs.webkit.org/show_bug.cgi?id=79944) 4440 float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth); 4441 right -= LayoutUnit::fromFloatCeil(remainder); 4442 return right; 4443 } 4444 4445 LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const 4446 { 4447 if (!m_floatingObjects) 4448 return logicalHeight; 4449 4450 LayoutUnit bottom = LayoutUnit::max(); 4451 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4452 FloatingObjectSetIterator end = floatingObjectSet.end(); 4453 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4454 FloatingObject* r = *it; 4455 LayoutUnit floatBottom = logicalBottomForFloat(r); 4456 if (floatBottom > logicalHeight) 4457 bottom = min(floatBottom, bottom); 4458 } 4459 4460 return bottom == LayoutUnit::max() ? LayoutUnit() : bottom; 4461 } 4462 4463 LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const 4464 { 4465 if (!m_floatingObjects) 4466 return 0; 4467 LayoutUnit lowestFloatBottom = 0; 4468 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4469 FloatingObjectSetIterator end = floatingObjectSet.end(); 4470 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4471 FloatingObject* r = *it; 4472 if (r->isPlaced() && r->type() & floatType) 4473 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r)); 4474 } 4475 return lowestFloatBottom; 4476 } 4477 4478 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest) 4479 { 4480 if (logicalTop >= logicalBottom) 4481 return; 4482 4483 RootInlineBox* lowestDirtyLine = lastRootBox(); 4484 RootInlineBox* afterLowest = lowestDirtyLine; 4485 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) { 4486 afterLowest = lowestDirtyLine; 4487 lowestDirtyLine = lowestDirtyLine->prevRootBox(); 4488 } 4489 4490 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) { 4491 afterLowest->markDirty(); 4492 afterLowest = afterLowest->prevRootBox(); 4493 } 4494 } 4495 4496 void RenderBlock::clearFloats() 4497 { 4498 if (m_floatingObjects) 4499 m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode()); 4500 4501 HashSet<RenderBox*> oldIntrudingFloatSet; 4502 if (!childrenInline() && m_floatingObjects) { 4503 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4504 FloatingObjectSetIterator end = floatingObjectSet.end(); 4505 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4506 FloatingObject* floatingObject = *it; 4507 if (!floatingObject->isDescendant()) 4508 oldIntrudingFloatSet.add(floatingObject->m_renderer); 4509 } 4510 } 4511 4512 // Inline blocks are covered by the isReplaced() check in the avoidFloats method. 4513 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) { 4514 if (m_floatingObjects) { 4515 deleteAllValues(m_floatingObjects->set()); 4516 m_floatingObjects->clear(); 4517 } 4518 if (!oldIntrudingFloatSet.isEmpty()) 4519 markAllDescendantsWithFloatsForLayout(); 4520 return; 4521 } 4522 4523 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap; 4524 RendererToFloatInfoMap floatMap; 4525 4526 if (m_floatingObjects) { 4527 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4528 if (childrenInline()) { 4529 FloatingObjectSetIterator end = floatingObjectSet.end(); 4530 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4531 FloatingObject* f = *it; 4532 floatMap.add(f->m_renderer, f); 4533 } 4534 } else { 4535 deleteAllValues(floatingObjectSet); 4536 } 4537 m_floatingObjects->clear(); 4538 } 4539 4540 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add 4541 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent. 4542 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG. 4543 if (!parent() || !parent()->isRenderBlock()) 4544 return; 4545 4546 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are 4547 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted 4548 // to avoid floats. 4549 RenderBlock* parentBlock = toRenderBlock(parent()); 4550 bool parentHasFloats = false; 4551 RenderObject* prev = previousSibling(); 4552 while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { 4553 if (prev->isFloating()) 4554 parentHasFloats = true; 4555 prev = prev->previousSibling(); 4556 } 4557 4558 // First add in floats from the parent. 4559 LayoutUnit logicalTopOffset = logicalTop(); 4560 if (parentHasFloats) 4561 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset); 4562 4563 LayoutUnit logicalLeftOffset = 0; 4564 if (prev) 4565 logicalTopOffset -= toRenderBox(prev)->logicalTop(); 4566 else { 4567 prev = parentBlock; 4568 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent(); 4569 } 4570 4571 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. 4572 RenderBlock* block = toRenderBlock(prev); 4573 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset) 4574 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset); 4575 4576 if (childrenInline()) { 4577 LayoutUnit changeLogicalTop = LayoutUnit::max(); 4578 LayoutUnit changeLogicalBottom = LayoutUnit::min(); 4579 if (m_floatingObjects) { 4580 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4581 FloatingObjectSetIterator end = floatingObjectSet.end(); 4582 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4583 FloatingObject* f = *it; 4584 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); 4585 LayoutUnit logicalBottom = logicalBottomForFloat(f); 4586 if (oldFloatingObject) { 4587 LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject); 4588 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) { 4589 changeLogicalTop = 0; 4590 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); 4591 } else { 4592 if (logicalBottom != oldLogicalBottom) { 4593 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom)); 4594 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); 4595 } 4596 LayoutUnit logicalTop = logicalTopForFloat(f); 4597 LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject); 4598 if (logicalTop != oldLogicalTop) { 4599 changeLogicalTop = min(changeLogicalTop, min(logicalTop, oldLogicalTop)); 4600 changeLogicalBottom = max(changeLogicalBottom, max(logicalTop, oldLogicalTop)); 4601 } 4602 } 4603 4604 floatMap.remove(f->m_renderer); 4605 if (oldFloatingObject->m_originatingLine && !selfNeedsLayout()) { 4606 ASSERT(oldFloatingObject->m_originatingLine->renderer() == this); 4607 oldFloatingObject->m_originatingLine->markDirty(); 4608 } 4609 delete oldFloatingObject; 4610 } else { 4611 changeLogicalTop = 0; 4612 changeLogicalBottom = max(changeLogicalBottom, logicalBottom); 4613 } 4614 } 4615 } 4616 4617 RendererToFloatInfoMap::iterator end = floatMap.end(); 4618 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { 4619 FloatingObject* floatingObject = (*it).value; 4620 if (!floatingObject->isDescendant()) { 4621 changeLogicalTop = 0; 4622 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject)); 4623 } 4624 } 4625 deleteAllValues(floatMap); 4626 4627 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); 4628 } else if (!oldIntrudingFloatSet.isEmpty()) { 4629 // If there are previously intruding floats that no longer intrude, then children with floats 4630 // should also get layout because they might need their floating object lists cleared. 4631 if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size()) 4632 markAllDescendantsWithFloatsForLayout(); 4633 else { 4634 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4635 FloatingObjectSetIterator end = floatingObjectSet.end(); 4636 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it) 4637 oldIntrudingFloatSet.remove((*it)->m_renderer); 4638 if (!oldIntrudingFloatSet.isEmpty()) 4639 markAllDescendantsWithFloatsForLayout(); 4640 } 4641 } 4642 } 4643 4644 LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildPaintOtherFloats) 4645 { 4646 // Prevent floats from being added to the canvas by the root element, e.g., <html>. 4647 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot()) 4648 return 0; 4649 4650 LayoutUnit childLogicalTop = child->logicalTop(); 4651 LayoutUnit childLogicalLeft = child->logicalLeft(); 4652 LayoutUnit lowestFloatLogicalBottom = 0; 4653 4654 // Floats that will remain the child's responsibility to paint should factor into its 4655 // overflow. 4656 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); 4657 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { 4658 FloatingObject* r = *childIt; 4659 LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), LayoutUnit::max() - childLogicalTop); 4660 LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat; 4661 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); 4662 4663 if (logicalBottom > logicalHeight()) { 4664 // If the object is not in the list, we add it now. 4665 if (!containsFloat(r->m_renderer)) { 4666 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft); 4667 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size())); 4668 floatingObj->m_renderer = r->m_renderer; 4669 4670 // The nearest enclosing layer always paints the float (so that zindex and stacking 4671 // behaves properly). We always want to propagate the desire to paint the float as 4672 // far out as we can, to the outermost block that overlaps the float, stopping only 4673 // if we hit a self-painting layer boundary. 4674 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) 4675 r->setShouldPaint(false); 4676 else 4677 floatingObj->setShouldPaint(false); 4678 4679 floatingObj->setIsDescendant(true); 4680 4681 // We create the floating object list lazily. 4682 if (!m_floatingObjects) 4683 createFloatingObjects(); 4684 m_floatingObjects->add(floatingObj); 4685 } 4686 } else { 4687 if (makeChildPaintOtherFloats && !r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer() 4688 && r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) { 4689 // The float is not overhanging from this block, so if it is a descendant of the child, the child should 4690 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing 4691 // layer. 4692 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats 4693 // it should paint. 4694 r->setShouldPaint(true); 4695 } 4696 4697 // 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 4698 // child now. 4699 if (r->isDescendant()) 4700 child->addOverflowFromChild(r->m_renderer, LayoutSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); 4701 } 4702 } 4703 return lowestFloatLogicalBottom; 4704 } 4705 4706 bool RenderBlock::hasOverhangingFloat(RenderBox* renderer) 4707 { 4708 if (!m_floatingObjects || hasColumns() || !parent()) 4709 return false; 4710 4711 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4712 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer); 4713 if (it == floatingObjectSet.end()) 4714 return false; 4715 4716 return logicalBottomForFloat(*it) > logicalHeight(); 4717 } 4718 4719 void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset) 4720 { 4721 ASSERT(!avoidsFloats()); 4722 4723 // If the parent or previous sibling doesn't have any floats to add, don't bother. 4724 if (!prev->m_floatingObjects) 4725 return; 4726 4727 logicalLeftOffset += marginLogicalLeft(); 4728 4729 const FloatingObjectSet& prevSet = prev->m_floatingObjects->set(); 4730 FloatingObjectSetIterator prevEnd = prevSet.end(); 4731 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) { 4732 FloatingObject* r = *prevIt; 4733 if (logicalBottomForFloat(r) > logicalTopOffset) { 4734 if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) { 4735 LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, logicalTopOffset) : LayoutSize(logicalTopOffset, logicalLeftOffset); 4736 FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size())); 4737 4738 // Applying the child's margin makes no sense in the case where the child was passed in. 4739 // since this margin was added already through the modification of the |logicalLeftOffset| variable 4740 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken 4741 // into account. Only apply this code if prev is the parent, since otherwise the left margin 4742 // will get applied twice. 4743 if (prev != parent()) { 4744 if (isHorizontalWritingMode()) 4745 floatingObj->setX(floatingObj->x() + prev->marginLeft()); 4746 else 4747 floatingObj->setY(floatingObj->y() + prev->marginTop()); 4748 } 4749 4750 floatingObj->setShouldPaint(false); // We are not in the direct inheritance chain for this float. We will never paint it. 4751 floatingObj->m_renderer = r->m_renderer; 4752 4753 // We create the floating object list lazily. 4754 if (!m_floatingObjects) 4755 createFloatingObjects(); 4756 m_floatingObjects->add(floatingObj); 4757 } 4758 } 4759 } 4760 } 4761 4762 bool RenderBlock::avoidsFloats() const 4763 { 4764 // Floats can't intrude into our box if we have a non-auto column count or width. 4765 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); 4766 } 4767 4768 bool RenderBlock::containsFloat(RenderBox* renderer) const 4769 { 4770 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer); 4771 } 4772 4773 void RenderBlock::markShapeInsideDescendantsForLayout() 4774 { 4775 if (!everHadLayout()) 4776 return; 4777 if (childrenInline()) { 4778 setNeedsLayout(); 4779 return; 4780 } 4781 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 4782 if (!child->isRenderBlock()) 4783 continue; 4784 RenderBlock* childBlock = toRenderBlock(child); 4785 childBlock->markShapeInsideDescendantsForLayout(); 4786 } 4787 } 4788 4789 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) 4790 { 4791 if (!everHadLayout() && !containsFloats()) 4792 return; 4793 4794 MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain; 4795 setChildNeedsLayout(markParents); 4796 4797 if (floatToRemove) 4798 removeFloatingObject(floatToRemove); 4799 4800 // Iterate over our children and mark them as needed. 4801 if (!childrenInline()) { 4802 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 4803 if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isRenderBlock()) 4804 continue; 4805 RenderBlock* childBlock = toRenderBlock(child); 4806 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats()) 4807 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); 4808 } 4809 } 4810 } 4811 4812 void RenderBlock::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove) 4813 { 4814 if (!m_floatingObjects) 4815 return; 4816 4817 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4818 FloatingObjectSetIterator end = floatingObjectSet.end(); 4819 4820 for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) { 4821 if (!next->isRenderBlock() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlock(next)->avoidsFloats()) 4822 continue; 4823 4824 RenderBlock* nextBlock = toRenderBlock(next); 4825 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 4826 RenderBox* floatingBox = (*it)->renderer(); 4827 if (floatToRemove && floatingBox != floatToRemove) 4828 continue; 4829 if (nextBlock->containsFloat(floatingBox)) 4830 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox); 4831 } 4832 } 4833 } 4834 4835 LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop) 4836 { 4837 // There is no need to compute clearance if we have no floats. 4838 if (!containsFloats()) 4839 return 0; 4840 4841 // At least one float is present. We need to perform the clearance computation. 4842 bool clearSet = child->style()->clear() != CNONE; 4843 LayoutUnit logicalBottom = 0; 4844 switch (child->style()->clear()) { 4845 case CNONE: 4846 break; 4847 case CLEFT: 4848 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 4849 break; 4850 case CRIGHT: 4851 logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight); 4852 break; 4853 case CBOTH: 4854 logicalBottom = lowestFloatLogicalBottom(); 4855 break; 4856 } 4857 4858 // 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). 4859 LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit(); 4860 if (!result && child->avoidsFloats()) { 4861 LayoutUnit newLogicalTop = logicalTop; 4862 while (true) { 4863 LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child)); 4864 if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop)) 4865 return newLogicalTop - logicalTop; 4866 4867 RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child)); 4868 LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo); 4869 LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); 4870 4871 // FIXME: None of this is right for perpendicular writing-mode children. 4872 LayoutUnit childOldLogicalWidth = child->logicalWidth(); 4873 LayoutUnit childOldMarginLeft = child->marginLeft(); 4874 LayoutUnit childOldMarginRight = child->marginRight(); 4875 LayoutUnit childOldLogicalTop = child->logicalTop(); 4876 4877 child->setLogicalTop(newLogicalTop); 4878 child->updateLogicalWidth(); 4879 region = regionAtBlockOffset(logicalTopForChild(child)); 4880 borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo); 4881 LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height(); 4882 4883 child->setLogicalTop(childOldLogicalTop); 4884 child->setLogicalWidth(childOldLogicalWidth); 4885 child->setMarginLeft(childOldMarginLeft); 4886 child->setMarginRight(childOldMarginRight); 4887 4888 if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) { 4889 // Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then 4890 // we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats 4891 // from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins). 4892 if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset) 4893 child->setChildNeedsLayout(MarkOnlyThis); 4894 return newLogicalTop - logicalTop; 4895 } 4896 4897 newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop); 4898 ASSERT(newLogicalTop >= logicalTop); 4899 if (newLogicalTop < logicalTop) 4900 break; 4901 } 4902 ASSERT_NOT_REACHED(); 4903 } 4904 return result; 4905 } 4906 4907 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset) 4908 { 4909 if (!scrollsOverflow()) 4910 return false; 4911 4912 return layer()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset))); 4913 } 4914 4915 Node* RenderBlock::nodeForHitTest() const 4916 { 4917 // If we are in the margins of block elements that are part of a 4918 // continuation we're actually still inside the enclosing element 4919 // that was split. Use the appropriate inner node. 4920 return isAnonymousBlockContinuation() ? continuation()->node() : node(); 4921 } 4922 4923 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) 4924 { 4925 LayoutPoint adjustedLocation(accumulatedOffset + location()); 4926 LayoutSize localOffset = toLayoutSize(adjustedLocation); 4927 4928 if (!isRenderView()) { 4929 // Check if we need to do anything at all. 4930 LayoutRect overflowBox = visualOverflowRect(); 4931 flipForWritingMode(overflowBox); 4932 overflowBox.moveBy(adjustedLocation); 4933 if (!locationInContainer.intersects(overflowBox)) 4934 return false; 4935 } 4936 4937 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) { 4938 updateHitTestResult(result, locationInContainer.point() - localOffset); 4939 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet. 4940 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer)) 4941 return true; 4942 } 4943 4944 // If we have clipping, then we can't have any spillout. 4945 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); 4946 bool useClip = (hasControlClip() || useOverflowClip); 4947 bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize))); 4948 if (checkChildren) { 4949 // Hit test descendants first. 4950 LayoutSize scrolledOffset(localOffset); 4951 if (hasOverflowClip()) 4952 scrolledOffset -= scrolledContentOffset(); 4953 4954 // Hit test contents if we don't have columns. 4955 if (!hasColumns()) { 4956 if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { 4957 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset)); 4958 return true; 4959 } 4960 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset))) 4961 return true; 4962 } else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) { 4963 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset)); 4964 return true; 4965 } 4966 } 4967 4968 // Check if the point is outside radii. 4969 if (!isRenderView() && style()->hasBorderRadius()) { 4970 LayoutRect borderRect = borderBoxRect(); 4971 borderRect.moveBy(adjustedLocation); 4972 RoundedRect border = style()->getRoundedBorderFor(borderRect, view()); 4973 if (!locationInContainer.intersects(border)) 4974 return false; 4975 } 4976 4977 // Now hit test our background 4978 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { 4979 LayoutRect boundsRect(adjustedLocation, size()); 4980 if (visibleToHitTestRequest(request) && locationInContainer.intersects(boundsRect)) { 4981 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset)); 4982 if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect)) 4983 return true; 4984 } 4985 } 4986 4987 return false; 4988 } 4989 4990 bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset) 4991 { 4992 if (!m_floatingObjects) 4993 return false; 4994 4995 LayoutPoint adjustedLocation = accumulatedOffset; 4996 if (isRenderView()) { 4997 adjustedLocation += toLayoutSize(toRenderView(this)->frameView()->scrollPosition()); 4998 } 4999 5000 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 5001 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 5002 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { 5003 --it; 5004 FloatingObject* floatingObject = *it; 5005 if (floatingObject->shouldPaint() && !floatingObject->m_renderer->hasSelfPaintingLayer()) { 5006 LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); 5007 LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); 5008 LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset)); 5009 if (floatingObject->m_renderer->hitTest(request, result, locationInContainer, childPoint)) { 5010 updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint)); 5011 return true; 5012 } 5013 } 5014 } 5015 5016 return false; 5017 } 5018 5019 class ColumnRectIterator { 5020 WTF_MAKE_NONCOPYABLE(ColumnRectIterator); 5021 public: 5022 ColumnRectIterator(const RenderBlock& block) 5023 : m_block(block) 5024 , m_colInfo(block.columnInfo()) 5025 , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1) 5026 , m_isHorizontal(block.isHorizontalWritingMode()) 5027 , m_logicalLeft(block.logicalLeftOffsetForContent()) 5028 { 5029 int colCount = m_colInfo->columnCount(); 5030 m_colIndex = colCount - 1; 5031 m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction; 5032 update(); 5033 } 5034 5035 void advance() 5036 { 5037 ASSERT(hasMore()); 5038 m_colIndex--; 5039 update(); 5040 } 5041 5042 LayoutRect columnRect() const { return m_colRect; } 5043 bool hasMore() const { return m_colIndex >= 0; } 5044 5045 void adjust(LayoutSize& offset) const 5046 { 5047 LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft; 5048 offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset); 5049 if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) { 5050 if (m_isHorizontal) 5051 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop()); 5052 else 5053 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0); 5054 } 5055 } 5056 5057 private: 5058 void update() 5059 { 5060 if (m_colIndex < 0) 5061 return; 5062 5063 m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex); 5064 m_block.flipForWritingMode(m_colRect); 5065 m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction; 5066 } 5067 5068 const RenderBlock& m_block; 5069 const ColumnInfo* const m_colInfo; 5070 const int m_direction; 5071 const bool m_isHorizontal; 5072 const LayoutUnit m_logicalLeft; 5073 int m_colIndex; 5074 LayoutUnit m_currLogicalTopOffset; 5075 LayoutRect m_colRect; 5076 }; 5077 5078 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) 5079 { 5080 // We need to do multiple passes, breaking up our hit testing into strips. 5081 if (!hasColumns()) 5082 return false; 5083 5084 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { 5085 LayoutRect hitRect = locationInContainer.boundingBox(); 5086 LayoutRect colRect = it.columnRect(); 5087 colRect.moveBy(accumulatedOffset); 5088 if (locationInContainer.intersects(colRect)) { 5089 // The point is inside this column. 5090 // Adjust accumulatedOffset to change where we hit test. 5091 LayoutSize offset; 5092 it.adjust(offset); 5093 LayoutPoint finalLocation = accumulatedOffset + offset; 5094 if (!result.isRectBasedTest() || colRect.contains(hitRect)) 5095 return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation)); 5096 5097 hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction); 5098 } 5099 } 5100 5101 return false; 5102 } 5103 5104 void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const 5105 { 5106 for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) { 5107 LayoutRect colRect = it.columnRect(); 5108 if (colRect.contains(locationInContainer)) { 5109 it.adjust(offset); 5110 return; 5111 } 5112 } 5113 } 5114 5115 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction) 5116 { 5117 if (isRenderRegion()) 5118 return toRenderRegion(this)->hitTestFlowThreadContents(request, result, locationInContainer, accumulatedOffset, hitTestAction); 5119 5120 if (childrenInline() && !isTable()) { 5121 // We have to hit-test our line boxes. 5122 if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction)) 5123 return true; 5124 } else { 5125 // Hit test our children. 5126 HitTestAction childHitTest = hitTestAction; 5127 if (hitTestAction == HitTestChildBlockBackgrounds) 5128 childHitTest = HitTestChildBlockBackground; 5129 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { 5130 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset); 5131 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest)) 5132 return true; 5133 } 5134 } 5135 5136 return false; 5137 } 5138 5139 Position RenderBlock::positionForBox(InlineBox *box, bool start) const 5140 { 5141 if (!box) 5142 return Position(); 5143 5144 if (!box->renderer()->nonPseudoNode()) 5145 return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset()); 5146 5147 if (!box->isInlineTextBox()) 5148 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); 5149 5150 InlineTextBox* textBox = toInlineTextBox(box); 5151 return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len()); 5152 } 5153 5154 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child) 5155 { 5156 ASSERT(!ancestor || ancestor->nonPseudoNode()); 5157 ASSERT(child && child->nonPseudoNode()); 5158 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView()) 5159 || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable(); 5160 } 5161 5162 // FIXME: This function should go on RenderObject as an instance method. Then 5163 // all cases in which positionForPoint recurs could call this instead to 5164 // prevent crossing editable boundaries. This would require many tests. 5165 static PositionWithAffinity positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates) 5166 { 5167 LayoutPoint childLocation = child->location(); 5168 if (child->isInFlowPositioned()) 5169 childLocation += child->offsetForInFlowPosition(); 5170 5171 // FIXME: This is wrong if the child's writing-mode is different from the parent's. 5172 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation)); 5173 5174 // If this is an anonymous renderer, we just recur normally 5175 Node* childNode = child->nonPseudoNode(); 5176 if (!childNode) 5177 return child->positionForPoint(pointInChildCoordinates); 5178 5179 // Otherwise, first make sure that the editability of the parent and child agree. 5180 // If they don't agree, then we return a visible position just before or after the child 5181 RenderObject* ancestor = parent; 5182 while (ancestor && !ancestor->nonPseudoNode()) 5183 ancestor = ancestor->parent(); 5184 5185 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal 5186 if (isEditingBoundary(ancestor, child)) 5187 return child->positionForPoint(pointInChildCoordinates); 5188 5189 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child 5190 LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2; 5191 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y(); 5192 if (logicalLeft < childMiddle) 5193 return ancestor->createPositionWithAffinity(childNode->nodeIndex(), DOWNSTREAM); 5194 return ancestor->createPositionWithAffinity(childNode->nodeIndex() + 1, UPSTREAM); 5195 } 5196 5197 PositionWithAffinity RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents) 5198 { 5199 ASSERT(childrenInline()); 5200 5201 if (!firstRootBox()) 5202 return createPositionWithAffinity(0, DOWNSTREAM); 5203 5204 bool linesAreFlipped = style()->isFlippedLinesWritingMode(); 5205 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); 5206 5207 // look for the closest line box in the root box which is at the passed-in y coordinate 5208 InlineBox* closestBox = 0; 5209 RootInlineBox* firstRootBoxWithChildren = 0; 5210 RootInlineBox* lastRootBoxWithChildren = 0; 5211 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { 5212 if (!root->firstLeafChild()) 5213 continue; 5214 if (!firstRootBoxWithChildren) 5215 firstRootBoxWithChildren = root; 5216 5217 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading() 5218 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading()))) 5219 break; 5220 5221 lastRootBoxWithChildren = root; 5222 5223 // check if this root line box is located at this y coordinate 5224 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) { 5225 if (linesAreFlipped) { 5226 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox(); 5227 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild()) 5228 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox(); 5229 5230 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading() 5231 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading()))) 5232 continue; 5233 } 5234 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); 5235 if (closestBox) 5236 break; 5237 } 5238 } 5239 5240 bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom(); 5241 5242 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) { 5243 // y coordinate is below last root line box, pretend we hit it 5244 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); 5245 } 5246 5247 if (closestBox) { 5248 if (moveCaretToBoundary) { 5249 LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop()); 5250 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop 5251 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) { 5252 InlineBox* box = firstRootBoxWithChildren->firstLeafChild(); 5253 if (box->isLineBreak()) { 5254 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak()) 5255 box = newBox; 5256 } 5257 // y coordinate is above first root line box, so return the start of the first 5258 return PositionWithAffinity(positionForBox(box, true), DOWNSTREAM); 5259 } 5260 } 5261 5262 // pass the box a top position that is inside it 5263 LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine()); 5264 if (!isHorizontalWritingMode()) 5265 point = point.transposedPoint(); 5266 if (closestBox->renderer()->isReplaced()) 5267 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point); 5268 return closestBox->renderer()->positionForPoint(point); 5269 } 5270 5271 if (lastRootBoxWithChildren) { 5272 // We hit this case for Mac behavior when the Y coordinate is below the last box. 5273 ASSERT(moveCaretToBoundary); 5274 InlineBox* logicallyLastBox; 5275 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox)) 5276 return PositionWithAffinity(positionForBox(logicallyLastBox, false), DOWNSTREAM); 5277 } 5278 5279 // Can't reach this. We have a root line box, but it has no kids. 5280 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text 5281 // seems to hit this code path. 5282 return createPositionWithAffinity(0, DOWNSTREAM); 5283 } 5284 5285 static inline bool isChildHitTestCandidate(RenderBox* box) 5286 { 5287 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned(); 5288 } 5289 5290 PositionWithAffinity RenderBlock::positionForPoint(const LayoutPoint& point) 5291 { 5292 if (isTable()) 5293 return RenderBox::positionForPoint(point); 5294 5295 if (isReplaced()) { 5296 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode. 5297 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y(); 5298 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x(); 5299 5300 if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0)) 5301 return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM); 5302 if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth())) 5303 return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM); 5304 } 5305 5306 LayoutPoint pointInContents = point; 5307 offsetForContents(pointInContents); 5308 LayoutPoint pointInLogicalContents(pointInContents); 5309 if (!isHorizontalWritingMode()) 5310 pointInLogicalContents = pointInLogicalContents.transposedPoint(); 5311 5312 if (childrenInline()) 5313 return positionForPointWithInlineChildren(pointInLogicalContents); 5314 5315 RenderBox* lastCandidateBox = lastChildBox(); 5316 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox)) 5317 lastCandidateBox = lastCandidateBox->previousSiblingBox(); 5318 5319 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode(); 5320 if (lastCandidateBox) { 5321 if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox) 5322 || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox))) 5323 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents); 5324 5325 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { 5326 if (!isChildHitTestCandidate(childBox)) 5327 continue; 5328 LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox); 5329 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3). 5330 if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom 5331 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom))) 5332 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); 5333 } 5334 } 5335 5336 // We only get here if there are no hit test candidate children below the click. 5337 return RenderBox::positionForPoint(point); 5338 } 5339 5340 void RenderBlock::offsetForContents(LayoutPoint& offset) const 5341 { 5342 offset = flipForWritingMode(offset); 5343 5344 if (hasOverflowClip()) 5345 offset += scrolledContentOffset(); 5346 5347 if (hasColumns()) 5348 adjustPointToColumnContents(offset); 5349 5350 offset = flipForWritingMode(offset); 5351 } 5352 5353 LayoutUnit RenderBlock::availableLogicalWidth() const 5354 { 5355 // If we have multiple columns, then the available logical width is reduced to our column width. 5356 if (hasColumns()) 5357 return desiredColumnWidth(); 5358 return RenderBox::availableLogicalWidth(); 5359 } 5360 5361 int RenderBlock::columnGap() const 5362 { 5363 if (style()->hasNormalColumnGap()) 5364 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins. 5365 return static_cast<int>(style()->columnGap()); 5366 } 5367 5368 void RenderBlock::calcColumnWidth() 5369 { 5370 if (document()->regionBasedColumnsEnabled()) 5371 return; 5372 5373 // Calculate our column width and column count. 5374 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 5375 unsigned desiredColumnCount = 1; 5376 LayoutUnit desiredColumnWidth = contentLogicalWidth(); 5377 5378 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination. 5379 if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) { 5380 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 5381 return; 5382 } 5383 5384 LayoutUnit availWidth = desiredColumnWidth; 5385 LayoutUnit colGap = columnGap(); 5386 LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth())); 5387 int colCount = max<int>(1, style()->columnCount()); 5388 5389 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { 5390 desiredColumnCount = colCount; 5391 desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount); 5392 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) { 5393 desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap)); 5394 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; 5395 } else { 5396 desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1); 5397 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; 5398 } 5399 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 5400 } 5401 5402 bool RenderBlock::requiresColumns(int desiredColumnCount) const 5403 { 5404 // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating 5405 // in the RenderView instead. 5406 bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody()); 5407 5408 return firstChild() 5409 && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated) 5410 && !firstChild()->isAnonymousColumnsBlock() 5411 && !firstChild()->isAnonymousColumnSpanBlock(); 5412 } 5413 5414 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width) 5415 { 5416 bool destroyColumns = !requiresColumns(count); 5417 if (destroyColumns) { 5418 if (hasColumns()) { 5419 gColumnInfoMap->take(this); 5420 setHasColumns(false); 5421 } 5422 } else { 5423 ColumnInfo* info; 5424 if (hasColumns()) 5425 info = gColumnInfoMap->get(this); 5426 else { 5427 if (!gColumnInfoMap) 5428 gColumnInfoMap = new ColumnInfoMap; 5429 info = new ColumnInfo; 5430 gColumnInfoMap->add(this, adoptPtr(info)); 5431 setHasColumns(true); 5432 } 5433 info->setDesiredColumnCount(count); 5434 info->setDesiredColumnWidth(width); 5435 info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis); 5436 info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression); 5437 } 5438 } 5439 5440 void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style) 5441 { 5442 if (!hasColumns()) 5443 return; 5444 5445 ColumnInfo* info = gColumnInfoMap->get(this); 5446 5447 bool needsLayout = false; 5448 ColumnInfo::Axis oldAxis = info->progressionAxis(); 5449 ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis; 5450 if (oldAxis != newAxis) { 5451 info->setProgressionAxis(newAxis); 5452 needsLayout = true; 5453 } 5454 5455 bool oldProgressionIsReversed = info->progressionIsReversed(); 5456 bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression; 5457 if (oldProgressionIsReversed != newProgressionIsReversed) { 5458 info->setProgressionIsReversed(newProgressionIsReversed); 5459 needsLayout = true; 5460 } 5461 5462 if (needsLayout) 5463 setNeedsLayoutAndPrefWidthsRecalc(); 5464 } 5465 5466 LayoutUnit RenderBlock::desiredColumnWidth() const 5467 { 5468 if (!hasColumns()) 5469 return contentLogicalWidth(); 5470 return gColumnInfoMap->get(this)->desiredColumnWidth(); 5471 } 5472 5473 unsigned RenderBlock::desiredColumnCount() const 5474 { 5475 if (!hasColumns()) 5476 return 1; 5477 return gColumnInfoMap->get(this)->desiredColumnCount(); 5478 } 5479 5480 ColumnInfo* RenderBlock::columnInfo() const 5481 { 5482 if (!hasColumns()) 5483 return 0; 5484 return gColumnInfoMap->get(this); 5485 } 5486 5487 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const 5488 { 5489 ASSERT(hasColumns()); 5490 ASSERT(gColumnInfoMap->get(this) == colInfo); 5491 return colInfo->columnCount(); 5492 } 5493 5494 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const 5495 { 5496 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo); 5497 5498 // Compute the appropriate rect based off our information. 5499 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth(); 5500 LayoutUnit colLogicalHeight = colInfo->columnHeight(); 5501 LayoutUnit colLogicalTop = borderBefore() + paddingBefore(); 5502 LayoutUnit colLogicalLeft = logicalLeftOffsetForContent(); 5503 LayoutUnit colGap = columnGap(); 5504 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { 5505 if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed()) 5506 colLogicalLeft += index * (colLogicalWidth + colGap); 5507 else 5508 colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap); 5509 } else { 5510 if (!colInfo->progressionIsReversed()) 5511 colLogicalTop += index * (colLogicalHeight + colGap); 5512 else 5513 colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap); 5514 } 5515 5516 if (isHorizontalWritingMode()) 5517 return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight); 5518 return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth); 5519 } 5520 5521 bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer& statePusher) 5522 { 5523 if (!hasColumns()) 5524 return false; 5525 5526 OwnPtr<RenderOverflow> savedOverflow = m_overflow.release(); 5527 if (childrenInline()) 5528 addOverflowFromInlineChildren(); 5529 else 5530 addOverflowFromBlockChildren(); 5531 LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore(); 5532 5533 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what 5534 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall. 5535 ColumnInfo* colInfo = columnInfo(); 5536 if (!hasSpecifiedPageLogicalHeight) { 5537 LayoutUnit columnHeight = pageLogicalHeight; 5538 int minColumnCount = colInfo->forcedBreaks() + 1; 5539 int desiredColumnCount = colInfo->desiredColumnCount(); 5540 if (minColumnCount >= desiredColumnCount) { 5541 // The forced page breaks are in control of the balancing. Just set the column height to the 5542 // maximum page break distance. 5543 if (!pageLogicalHeight) { 5544 LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(), 5545 view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset()); 5546 columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); 5547 } 5548 } else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) { 5549 // Now that we know the intrinsic height of the columns, we have to rebalance them. 5550 columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf((float)layoutOverflowLogicalBottom / desiredColumnCount)); 5551 } 5552 5553 if (columnHeight && columnHeight != pageLogicalHeight) { 5554 statePusher.pop(); 5555 setEverHadLayout(true); 5556 layoutBlock(false, columnHeight); 5557 return true; 5558 } 5559 } 5560 5561 if (pageLogicalHeight) 5562 colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight); 5563 5564 if (columnCount(colInfo)) { 5565 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); 5566 m_overflow.clear(); 5567 } else 5568 m_overflow = savedOverflow.release(); 5569 5570 return false; 5571 } 5572 5573 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const 5574 { 5575 // Just bail if we have no columns. 5576 if (!hasColumns()) 5577 return; 5578 5579 ColumnInfo* colInfo = columnInfo(); 5580 if (!columnCount(colInfo)) 5581 return; 5582 5583 // Determine which columns we intersect. 5584 LayoutUnit colGap = columnGap(); 5585 LayoutUnit halfColGap = colGap / 2; 5586 LayoutPoint columnPoint(columnRectAt(colInfo, 0).location()); 5587 LayoutUnit logicalOffset = 0; 5588 for (unsigned i = 0; i < colInfo->columnCount(); i++) { 5589 // Add in half the column gap to the left and right of the rect. 5590 LayoutRect colRect = columnRectAt(colInfo, i); 5591 flipForWritingMode(colRect); 5592 if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) { 5593 LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height()); 5594 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) { 5595 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { 5596 // FIXME: The clamping that follows is not completely right for right-to-left 5597 // content. 5598 // Clamp everything above the column to its top left. 5599 if (point.y() < gapAndColumnRect.y()) 5600 point = gapAndColumnRect.location(); 5601 // Clamp everything below the column to the next column's top left. If there is 5602 // no next column, this still maps to just after this column. 5603 else if (point.y() >= gapAndColumnRect.maxY()) { 5604 point = gapAndColumnRect.location(); 5605 point.move(0, gapAndColumnRect.height()); 5606 } 5607 } else { 5608 if (point.x() < colRect.x()) 5609 point.setX(colRect.x()); 5610 else if (point.x() >= colRect.maxX()) 5611 point.setX(colRect.maxX() - 1); 5612 } 5613 5614 // We're inside the column. Translate the x and y into our column coordinate space. 5615 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 5616 point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset)); 5617 else 5618 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0); 5619 return; 5620 } 5621 5622 // Move to the next position. 5623 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width(); 5624 } else { 5625 LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap); 5626 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) { 5627 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { 5628 // FIXME: The clamping that follows is not completely right for right-to-left 5629 // content. 5630 // Clamp everything above the column to its top left. 5631 if (point.x() < gapAndColumnRect.x()) 5632 point = gapAndColumnRect.location(); 5633 // Clamp everything below the column to the next column's top left. If there is 5634 // no next column, this still maps to just after this column. 5635 else if (point.x() >= gapAndColumnRect.maxX()) { 5636 point = gapAndColumnRect.location(); 5637 point.move(gapAndColumnRect.width(), 0); 5638 } 5639 } else { 5640 if (point.y() < colRect.y()) 5641 point.setY(colRect.y()); 5642 else if (point.y() >= colRect.maxY()) 5643 point.setY(colRect.maxY() - 1); 5644 } 5645 5646 // We're inside the column. Translate the x and y into our column coordinate space. 5647 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 5648 point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y()); 5649 else 5650 point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop()); 5651 return; 5652 } 5653 5654 // Move to the next position. 5655 logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height(); 5656 } 5657 } 5658 } 5659 5660 void RenderBlock::adjustRectForColumns(LayoutRect& r) const 5661 { 5662 // Just bail if we have no columns. 5663 if (!hasColumns()) 5664 return; 5665 5666 ColumnInfo* colInfo = columnInfo(); 5667 5668 // Determine which columns we intersect. 5669 unsigned colCount = columnCount(colInfo); 5670 if (!colCount) 5671 return; 5672 5673 // Begin with a result rect that is empty. 5674 LayoutRect result; 5675 5676 bool isHorizontal = isHorizontalWritingMode(); 5677 LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore(); 5678 LayoutUnit colHeight = colInfo->columnHeight(); 5679 if (!colHeight) 5680 return; 5681 5682 LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding); 5683 LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding); 5684 5685 // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744 5686 unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight; 5687 unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight; 5688 5689 if (startColumn == endColumn) { 5690 // The rect is fully contained within one column. Adjust for our offsets 5691 // and repaint only that portion. 5692 LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(); 5693 LayoutRect colRect = columnRectAt(colInfo, startColumn); 5694 LayoutRect repaintRect = r; 5695 5696 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) { 5697 if (isHorizontal) 5698 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight); 5699 else 5700 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset); 5701 } else { 5702 if (isHorizontal) 5703 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding); 5704 else 5705 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0); 5706 } 5707 repaintRect.intersect(colRect); 5708 result.unite(repaintRect); 5709 } else { 5710 // We span multiple columns. We can just unite the start and end column to get the final 5711 // repaint rect. 5712 result.unite(columnRectAt(colInfo, startColumn)); 5713 result.unite(columnRectAt(colInfo, endColumn)); 5714 } 5715 5716 r = result; 5717 } 5718 5719 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const 5720 { 5721 ASSERT(hasColumns()); 5722 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) 5723 return point; 5724 ColumnInfo* colInfo = columnInfo(); 5725 LayoutUnit columnLogicalHeight = colInfo->columnHeight(); 5726 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 5727 if (isHorizontalWritingMode()) 5728 return LayoutPoint(point.x(), expandedLogicalHeight - point.y()); 5729 return LayoutPoint(expandedLogicalHeight - point.x(), point.y()); 5730 } 5731 5732 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const 5733 { 5734 ASSERT(hasColumns()); 5735 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) 5736 return; 5737 5738 ColumnInfo* colInfo = columnInfo(); 5739 LayoutUnit columnLogicalHeight = colInfo->columnHeight(); 5740 LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 5741 5742 if (isHorizontalWritingMode()) 5743 rect.setY(expandedLogicalHeight - rect.maxY()); 5744 else 5745 rect.setX(expandedLogicalHeight - rect.maxX()); 5746 } 5747 5748 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const 5749 { 5750 if (!hasColumns()) 5751 return; 5752 5753 ColumnInfo* colInfo = columnInfo(); 5754 5755 LayoutUnit logicalLeft = logicalLeftOffsetForContent(); 5756 unsigned colCount = columnCount(colInfo); 5757 LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth(); 5758 LayoutUnit colLogicalHeight = colInfo->columnHeight(); 5759 5760 for (unsigned i = 0; i < colCount; ++i) { 5761 // Compute the edges for a given column in the block progression direction. 5762 LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight); 5763 if (!isHorizontalWritingMode()) 5764 sliceRect = sliceRect.transposedRect(); 5765 5766 LayoutUnit logicalOffset = i * colLogicalHeight; 5767 5768 // Now we're in the same coordinate space as the point. See if it is inside the rectangle. 5769 if (isHorizontalWritingMode()) { 5770 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) { 5771 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 5772 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset); 5773 else 5774 offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore()); 5775 return; 5776 } 5777 } else { 5778 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) { 5779 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) 5780 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft); 5781 else 5782 offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0); 5783 return; 5784 } 5785 } 5786 } 5787 } 5788 5789 void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const 5790 { 5791 if (childrenInline()) { 5792 // FIXME: Remove this const_cast. 5793 const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); 5794 } else 5795 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth); 5796 5797 maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth); 5798 5799 // A horizontal marquee with inline children has no minimum width. 5800 if (childrenInline() && isMarquee() && toRenderMarquee(this)->isHorizontal()) 5801 minLogicalWidth = 0; 5802 5803 if (isTableCell()) { 5804 Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth(); 5805 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0) 5806 maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value())); 5807 } 5808 5809 int scrollbarWidth = instrinsicScrollbarLogicalWidth(); 5810 maxLogicalWidth += scrollbarWidth; 5811 minLogicalWidth += scrollbarWidth; 5812 } 5813 5814 void RenderBlock::computePreferredLogicalWidths() 5815 { 5816 ASSERT(preferredLogicalWidthsDirty()); 5817 5818 updateFirstLetter(); 5819 5820 m_minPreferredLogicalWidth = 0; 5821 m_maxPreferredLogicalWidth = 0; 5822 5823 // FIXME: The isFixed() calls here should probably be checking for isSpecified since you 5824 // should be able to use percentage, calc or viewport relative values for width. 5825 RenderStyle* styleToUse = style(); 5826 if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0 5827 && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue())) 5828 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value()); 5829 else 5830 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 5831 5832 if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) { 5833 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); 5834 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value())); 5835 } 5836 5837 if (styleToUse->logicalMaxWidth().isFixed()) { 5838 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); 5839 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value())); 5840 } 5841 5842 // Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents. 5843 if (isTableCell()) { 5844 m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil(); 5845 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil(); 5846 } 5847 5848 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth(); 5849 m_minPreferredLogicalWidth += borderAndPadding; 5850 m_maxPreferredLogicalWidth += borderAndPadding; 5851 5852 setPreferredLogicalWidthsDirty(false); 5853 } 5854 5855 struct InlineMinMaxIterator { 5856 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to 5857 inline min/max width calculations. Note the following about the way it walks: 5858 (1) Positioned content is skipped (since it does not contribute to min/max width of a block) 5859 (2) We do not drill into the children of floats or replaced elements, since you can't break 5860 in the middle of such an element. 5861 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have 5862 distinct borders/margin/padding that contribute to the min/max width. 5863 */ 5864 RenderObject* parent; 5865 RenderObject* current; 5866 bool endOfInline; 5867 5868 InlineMinMaxIterator(RenderObject* p, bool end = false) 5869 :parent(p), current(p), endOfInline(end) {} 5870 5871 RenderObject* next(); 5872 }; 5873 5874 RenderObject* InlineMinMaxIterator::next() 5875 { 5876 RenderObject* result = 0; 5877 bool oldEndOfInline = endOfInline; 5878 endOfInline = false; 5879 while (current || current == parent) { 5880 if (!oldEndOfInline && 5881 (current == parent || 5882 (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned()))) 5883 result = current->firstChild(); 5884 if (!result) { 5885 // We hit the end of our inline. (It was empty, e.g., <span></span>.) 5886 if (!oldEndOfInline && current->isRenderInline()) { 5887 result = current; 5888 endOfInline = true; 5889 break; 5890 } 5891 5892 while (current && current != parent) { 5893 result = current->nextSibling(); 5894 if (result) break; 5895 current = current->parent(); 5896 if (current && current != parent && current->isRenderInline()) { 5897 result = current; 5898 endOfInline = true; 5899 break; 5900 } 5901 } 5902 } 5903 5904 if (!result) 5905 break; 5906 5907 if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) 5908 break; 5909 5910 current = result; 5911 result = 0; 5912 } 5913 5914 // Update our position. 5915 current = result; 5916 return current; 5917 } 5918 5919 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit) 5920 { 5921 if (cssUnit.type() != Auto) 5922 return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue); 5923 return 0; 5924 } 5925 5926 static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) 5927 { 5928 RenderStyle* childStyle = child->style(); 5929 if (endOfInline) 5930 return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) + 5931 getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) + 5932 child->borderEnd(); 5933 return getBPMWidth(child->marginStart(), childStyle->marginStart()) + 5934 getBPMWidth(child->paddingStart(), childStyle->paddingStart()) + 5935 child->borderStart(); 5936 } 5937 5938 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, 5939 RenderObject* trailingSpaceChild) 5940 { 5941 if (trailingSpaceChild && trailingSpaceChild->isText()) { 5942 // Collapse away the trailing space at the end of a block. 5943 RenderText* t = toRenderText(trailingSpaceChild); 5944 const UChar space = ' '; 5945 const Font& font = t->style()->font(); // FIXME: This ignores first-line. 5946 float spaceWidth = font.width(RenderBlock::constructTextRun(t, font, &space, 1, t->style())); 5947 inlineMax -= spaceWidth + font.wordSpacing(); 5948 if (inlineMin > inlineMax) 5949 inlineMin = inlineMax; 5950 } 5951 } 5952 5953 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result) 5954 { 5955 LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result); 5956 preferredWidth = max(snappedResult, preferredWidth); 5957 } 5958 5959 // When converting between floating point and LayoutUnits we risk losing precision 5960 // with each conversion. When this occurs while accumulating our preferred widths, 5961 // we can wind up with a line width that's larger than our maxPreferredWidth due to 5962 // pure float accumulation. 5963 static inline LayoutUnit adjustFloatForSubPixelLayout(float value) 5964 { 5965 return LayoutUnit::fromFloatCeil(value); 5966 } 5967 5968 5969 void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) 5970 { 5971 float inlineMax = 0; 5972 float inlineMin = 0; 5973 5974 RenderStyle* styleToUse = style(); 5975 RenderBlock* containingBlock = this->containingBlock(); 5976 LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit(); 5977 5978 // If we are at the start of a line, we want to ignore all white-space. 5979 // Also strip spaces if we previously had text that ended in a trailing space. 5980 bool stripFrontSpaces = true; 5981 RenderObject* trailingSpaceChild = 0; 5982 5983 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 5984 // very specific cirucumstances (in order to match common WinIE renderings). 5985 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 5986 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto(); 5987 5988 bool autoWrap, oldAutoWrap; 5989 autoWrap = oldAutoWrap = styleToUse->autoWrap(); 5990 5991 InlineMinMaxIterator childIterator(this); 5992 5993 // Only gets added to the max preffered width once. 5994 bool addedTextIndent = false; 5995 // Signals the text indent was more negative than the min preferred width 5996 bool hasRemainingNegativeTextIndent = false; 5997 5998 LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view()); 5999 RenderObject* prevFloat = 0; 6000 bool isPrevChildInlineFlow = false; 6001 bool shouldBreakLineAfterText = false; 6002 while (RenderObject* child = childIterator.next()) { 6003 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : 6004 child->style()->autoWrap(); 6005 6006 if (!child->isBR()) { 6007 // Step One: determine whether or not we need to go ahead and 6008 // terminate our current line. Each discrete chunk can become 6009 // the new min-width, if it is the widest chunk seen so far, and 6010 // it can also become the max-width. 6011 6012 // Children fall into three categories: 6013 // (1) An inline flow object. These objects always have a min/max of 0, 6014 // and are included in the iteration solely so that their margins can 6015 // be added in. 6016 // 6017 // (2) An inline non-text non-flow object, e.g., an inline replaced element. 6018 // These objects can always be on a line by themselves, so in this situation 6019 // we need to go ahead and break the current line, and then add in our own 6020 // margins and min/max width on its own line, and then terminate the line. 6021 // 6022 // (3) A text object. Text runs can have breakable characters at the start, 6023 // the middle or the end. They may also lose whitespace off the front if 6024 // we're already ignoring whitespace. In order to compute accurate min-width 6025 // information, we need three pieces of information. 6026 // (a) the min-width of the first non-breakable run. Should be 0 if the text string 6027 // starts with whitespace. 6028 // (b) the min-width of the last non-breakable run. Should be 0 if the text string 6029 // ends with whitespace. 6030 // (c) the min/max width of the string (trimmed for whitespace). 6031 // 6032 // If the text string starts with whitespace, then we need to go ahead and 6033 // terminate our current line (unless we're already in a whitespace stripping 6034 // mode. 6035 // 6036 // If the text string has a breakable character in the middle, but didn't start 6037 // with whitespace, then we add the width of the first non-breakable run and 6038 // then end the current line. We then need to use the intermediate min/max width 6039 // values (if any of them are larger than our current min/max). We then look at 6040 // the width of the last non-breakable run and use that to start a new line 6041 // (unless we end in whitespace). 6042 RenderStyle* childStyle = child->style(); 6043 float childMin = 0; 6044 float childMax = 0; 6045 6046 if (!child->isText()) { 6047 // Case (1) and (2). Inline replaced and inline flow elements. 6048 if (child->isRenderInline()) { 6049 // Add in padding/border/margin from the appropriate side of 6050 // the element. 6051 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); 6052 childMin += bpm; 6053 childMax += bpm; 6054 6055 inlineMin += childMin; 6056 inlineMax += childMax; 6057 6058 child->setPreferredLogicalWidthsDirty(false); 6059 } else { 6060 // Inline replaced elts add in their margins to their min/max values. 6061 LayoutUnit margins = 0; 6062 Length startMargin = childStyle->marginStart(); 6063 Length endMargin = childStyle->marginEnd(); 6064 if (startMargin.isFixed()) 6065 margins += adjustFloatForSubPixelLayout(startMargin.value()); 6066 if (endMargin.isFixed()) 6067 margins += adjustFloatForSubPixelLayout(endMargin.value()); 6068 childMin += margins.ceilToFloat(); 6069 childMax += margins.ceilToFloat(); 6070 } 6071 } 6072 6073 if (!child->isRenderInline() && !child->isText()) { 6074 // Case (2). Inline replaced elements and floats. 6075 // Go ahead and terminate the current line as far as 6076 // minwidth is concerned. 6077 childMin += child->minPreferredLogicalWidth().ceilToFloat(); 6078 childMax += child->maxPreferredLogicalWidth().ceilToFloat(); 6079 6080 bool clearPreviousFloat; 6081 if (child->isFloating()) { 6082 clearPreviousFloat = (prevFloat 6083 && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT)) 6084 || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT)))); 6085 prevFloat = child; 6086 } else 6087 clearPreviousFloat = false; 6088 6089 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; 6090 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) { 6091 updatePreferredWidth(minLogicalWidth, inlineMin); 6092 inlineMin = 0; 6093 } 6094 6095 // If we're supposed to clear the previous float, then terminate maxwidth as well. 6096 if (clearPreviousFloat) { 6097 updatePreferredWidth(maxLogicalWidth, inlineMax); 6098 inlineMax = 0; 6099 } 6100 6101 // Add in text-indent. This is added in only once. 6102 if (!addedTextIndent && !child->isFloating()) { 6103 float ceiledTextIndent = textIndent.ceilToFloat(); 6104 childMin += ceiledTextIndent; 6105 childMax += ceiledTextIndent; 6106 6107 if (childMin < 0) 6108 textIndent = adjustFloatForSubPixelLayout(childMin); 6109 else 6110 addedTextIndent = true; 6111 } 6112 6113 // Add our width to the max. 6114 inlineMax += max<float>(0, childMax); 6115 6116 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) { 6117 if (child->isFloating()) 6118 updatePreferredWidth(minLogicalWidth, childMin); 6119 else 6120 inlineMin += childMin; 6121 } else { 6122 // Now check our line. 6123 updatePreferredWidth(minLogicalWidth, childMin); 6124 6125 // Now start a new line. 6126 inlineMin = 0; 6127 } 6128 6129 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) { 6130 updatePreferredWidth(minLogicalWidth, inlineMin); 6131 inlineMin = 0; 6132 } 6133 6134 // We are no longer stripping whitespace at the start of 6135 // a line. 6136 if (!child->isFloating()) { 6137 stripFrontSpaces = false; 6138 trailingSpaceChild = 0; 6139 } 6140 } else if (child->isText()) { 6141 // Case (3). Text. 6142 RenderText* t = toRenderText(child); 6143 6144 if (t->isWordBreak()) { 6145 updatePreferredWidth(minLogicalWidth, inlineMin); 6146 inlineMin = 0; 6147 continue; 6148 } 6149 6150 if (t->style()->hasTextCombine() && t->isCombineText()) 6151 toRenderCombineText(t)->combineText(); 6152 6153 // Determine if we have a breakable character. Pass in 6154 // whether or not we should ignore any spaces at the front 6155 // of the string. If those are going to be stripped out, 6156 // then they shouldn't be considered in the breakable char 6157 // check. 6158 bool hasBreakableChar, hasBreak; 6159 float firstLineMinWidth, lastLineMinWidth; 6160 bool hasBreakableStart, hasBreakableEnd; 6161 float firstLineMaxWidth, lastLineMaxWidth; 6162 t->trimmedPrefWidths(inlineMax, 6163 firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd, 6164 hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth, 6165 childMin, childMax, stripFrontSpaces); 6166 6167 // This text object will not be rendered, but it may still provide a breaking opportunity. 6168 if (!hasBreak && childMax == 0) { 6169 if (autoWrap && (hasBreakableStart || hasBreakableEnd)) { 6170 updatePreferredWidth(minLogicalWidth, inlineMin); 6171 inlineMin = 0; 6172 } 6173 continue; 6174 } 6175 6176 if (stripFrontSpaces) 6177 trailingSpaceChild = child; 6178 else 6179 trailingSpaceChild = 0; 6180 6181 // Add in text-indent. This is added in only once. 6182 float ti = 0; 6183 if (!addedTextIndent || hasRemainingNegativeTextIndent) { 6184 ti = textIndent.ceilToFloat(); 6185 childMin += ti; 6186 firstLineMinWidth += ti; 6187 6188 // It the text indent negative and larger than the child minimum, we re-use the remainder 6189 // in future minimum calculations, but using the negative value again on the maximum 6190 // will lead to under-counting the max pref width. 6191 if (!addedTextIndent) { 6192 childMax += ti; 6193 firstLineMaxWidth += ti; 6194 addedTextIndent = true; 6195 } 6196 6197 if (childMin < 0) { 6198 textIndent = childMin; 6199 hasRemainingNegativeTextIndent = true; 6200 } 6201 } 6202 6203 // If we have no breakable characters at all, 6204 // then this is the easy case. We add ourselves to the current 6205 // min and max and continue. 6206 if (!hasBreakableChar) { 6207 inlineMin += childMin; 6208 } else { 6209 if (hasBreakableStart) { 6210 updatePreferredWidth(minLogicalWidth, inlineMin); 6211 } else { 6212 inlineMin += firstLineMinWidth; 6213 updatePreferredWidth(minLogicalWidth, inlineMin); 6214 childMin -= ti; 6215 } 6216 6217 inlineMin = childMin; 6218 6219 if (hasBreakableEnd) { 6220 updatePreferredWidth(minLogicalWidth, inlineMin); 6221 inlineMin = 0; 6222 shouldBreakLineAfterText = false; 6223 } else { 6224 updatePreferredWidth(minLogicalWidth, inlineMin); 6225 inlineMin = lastLineMinWidth; 6226 shouldBreakLineAfterText = true; 6227 } 6228 } 6229 6230 if (hasBreak) { 6231 inlineMax += firstLineMaxWidth; 6232 updatePreferredWidth(maxLogicalWidth, inlineMax); 6233 updatePreferredWidth(maxLogicalWidth, childMax); 6234 inlineMax = lastLineMaxWidth; 6235 addedTextIndent = true; 6236 } else { 6237 inlineMax += max<float>(0, childMax); 6238 } 6239 } 6240 6241 // Ignore spaces after a list marker. 6242 if (child->isListMarker()) 6243 stripFrontSpaces = true; 6244 } else { 6245 updatePreferredWidth(minLogicalWidth, inlineMin); 6246 updatePreferredWidth(maxLogicalWidth, inlineMax); 6247 inlineMin = inlineMax = 0; 6248 stripFrontSpaces = true; 6249 trailingSpaceChild = 0; 6250 addedTextIndent = true; 6251 } 6252 6253 if (!child->isText() && child->isRenderInline()) 6254 isPrevChildInlineFlow = true; 6255 else 6256 isPrevChildInlineFlow = false; 6257 6258 oldAutoWrap = autoWrap; 6259 } 6260 6261 if (styleToUse->collapseWhiteSpace()) 6262 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); 6263 6264 updatePreferredWidth(minLogicalWidth, inlineMin); 6265 updatePreferredWidth(maxLogicalWidth, inlineMax); 6266 } 6267 6268 void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const 6269 { 6270 RenderStyle* styleToUse = style(); 6271 bool nowrap = styleToUse->whiteSpace() == NOWRAP; 6272 6273 RenderObject* child = firstChild(); 6274 RenderBlock* containingBlock = this->containingBlock(); 6275 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0; 6276 while (child) { 6277 // Positioned children don't affect the min/max width 6278 if (child->isOutOfFlowPositioned()) { 6279 child = child->nextSibling(); 6280 continue; 6281 } 6282 6283 RenderStyle* childStyle = child->style(); 6284 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) { 6285 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth; 6286 if (childStyle->clear() & CLEFT) { 6287 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth); 6288 floatLeftWidth = 0; 6289 } 6290 if (childStyle->clear() & CRIGHT) { 6291 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth); 6292 floatRightWidth = 0; 6293 } 6294 } 6295 6296 // A margin basically has three types: fixed, percentage, and auto (variable). 6297 // Auto and percentage margins simply become 0 when computing min/max width. 6298 // Fixed margins can be added in as is. 6299 Length startMarginLength = childStyle->marginStartUsing(styleToUse); 6300 Length endMarginLength = childStyle->marginEndUsing(styleToUse); 6301 LayoutUnit margin = 0; 6302 LayoutUnit marginStart = 0; 6303 LayoutUnit marginEnd = 0; 6304 if (startMarginLength.isFixed()) 6305 marginStart += startMarginLength.value(); 6306 if (endMarginLength.isFixed()) 6307 marginEnd += endMarginLength.value(); 6308 margin = marginStart + marginEnd; 6309 6310 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth; 6311 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) { 6312 RenderBox* childBox = toRenderBox(child); 6313 LogicalExtentComputedValues computedValues; 6314 childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues); 6315 childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent; 6316 } else { 6317 childMinPreferredLogicalWidth = child->minPreferredLogicalWidth(); 6318 childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth(); 6319 } 6320 6321 LayoutUnit w = childMinPreferredLogicalWidth + margin; 6322 minLogicalWidth = max(w, minLogicalWidth); 6323 6324 // IE ignores tables for calculation of nowrap. Makes some sense. 6325 if (nowrap && !child->isTable()) 6326 maxLogicalWidth = max(w, maxLogicalWidth); 6327 6328 w = childMaxPreferredLogicalWidth + margin; 6329 6330 if (!child->isFloating()) { 6331 if (child->isBox() && toRenderBox(child)->avoidsFloats()) { 6332 // Determine a left and right max value based off whether or not the floats can fit in the 6333 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin 6334 // is smaller than the float width. 6335 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection(); 6336 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd; 6337 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart; 6338 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft; 6339 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight; 6340 w = childMaxPreferredLogicalWidth + maxLeft + maxRight; 6341 w = max(w, floatLeftWidth + floatRightWidth); 6342 } 6343 else 6344 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth); 6345 floatLeftWidth = floatRightWidth = 0; 6346 } 6347 6348 if (child->isFloating()) { 6349 if (childStyle->floating() == LeftFloat) 6350 floatLeftWidth += w; 6351 else 6352 floatRightWidth += w; 6353 } else 6354 maxLogicalWidth = max(w, maxLogicalWidth); 6355 6356 child = child->nextSibling(); 6357 } 6358 6359 // Always make sure these values are non-negative. 6360 minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth); 6361 maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth); 6362 6363 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth); 6364 } 6365 6366 bool RenderBlock::hasLineIfEmpty() const 6367 { 6368 if (!node()) 6369 return false; 6370 6371 if (node()->isRootEditableElement()) 6372 return true; 6373 6374 if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag)) 6375 return true; 6376 6377 return false; 6378 } 6379 6380 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const 6381 { 6382 // Inline blocks are replaced elements. Otherwise, just pass off to 6383 // the base class. If we're being queried as though we're the root line 6384 // box, then the fact that we're an inline-block is irrelevant, and we behave 6385 // just like a block. 6386 if (isReplaced() && linePositionMode == PositionOnContainingLine) 6387 return RenderBox::lineHeight(firstLine, direction, linePositionMode); 6388 6389 if (firstLine && document()->styleSheetCollection()->usesFirstLineRules()) { 6390 RenderStyle* s = style(firstLine); 6391 if (s != style()) 6392 return s->computedLineHeight(view()); 6393 } 6394 6395 if (m_lineHeight == -1) 6396 m_lineHeight = style()->computedLineHeight(view()); 6397 6398 return m_lineHeight; 6399 } 6400 6401 int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const 6402 { 6403 // Inline blocks are replaced elements. Otherwise, just pass off to 6404 // the base class. If we're being queried as though we're the root line 6405 // box, then the fact that we're an inline-block is irrelevant, and we behave 6406 // just like a block. 6407 if (isReplaced() && linePositionMode == PositionOnContainingLine) { 6408 // For "leaf" theme objects, let the theme decide what the baseline position is. 6409 // FIXME: Might be better to have a custom CSS property instead, so that if the theme 6410 // is turned off, checkboxes/radios will still have decent baselines. 6411 // FIXME: Need to patch form controls to deal with vertical lines. 6412 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance())) 6413 return theme()->baselinePosition(this); 6414 6415 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in 6416 // the normal flow. We make an exception for marquees, since their baselines are meaningless 6417 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them. 6418 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled 6419 // vertically (e.g., an overflow:hidden block that has had scrollTop moved). 6420 bool ignoreBaseline = (layer() && (isMarquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset()) 6421 : (layer()->horizontalScrollbar() || layer()->scrollXOffset())))) || (isWritingModeRoot() && !isRubyRun()); 6422 6423 int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction); 6424 6425 if (isDeprecatedFlexibleBox()) { 6426 // Historically, we did this check for all baselines. But we can't 6427 // remove this code from deprecated flexbox, because it effectively 6428 // breaks -webkit-line-clamp, which is used in the wild -- we would 6429 // calculate the baseline as if -webkit-line-clamp wasn't used. 6430 // For simplicity, we use this for all uses of deprecated flexbox. 6431 LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth(); 6432 if (baselinePos > bottomOfContent) 6433 baselinePos = -1; 6434 } 6435 if (baselinePos != -1) 6436 return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos; 6437 6438 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); 6439 } 6440 6441 // If we're not replaced, we'll only get called with PositionOfInteriorLineBoxes. 6442 // Note that inline-block counts as replaced here. 6443 ASSERT(linePositionMode == PositionOfInteriorLineBoxes); 6444 6445 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics(); 6446 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2; 6447 } 6448 6449 int RenderBlock::firstLineBoxBaseline() const 6450 { 6451 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun())) 6452 return -1; 6453 6454 if (childrenInline()) { 6455 if (firstLineBox()) 6456 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType()); 6457 else 6458 return -1; 6459 } 6460 else { 6461 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { 6462 if (!curr->isFloatingOrOutOfFlowPositioned()) { 6463 int result = curr->firstLineBoxBaseline(); 6464 if (result != -1) 6465 return curr->logicalTop() + result; // Translate to our coordinate space. 6466 } 6467 } 6468 } 6469 6470 return -1; 6471 } 6472 6473 int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const 6474 { 6475 if (style()->overflowY() != OVISIBLE) { 6476 // We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us. 6477 return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left(); 6478 } 6479 6480 return lastLineBoxBaseline(direction); 6481 } 6482 6483 int RenderBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const 6484 { 6485 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun())) 6486 return -1; 6487 6488 if (childrenInline()) { 6489 if (!firstLineBox() && hasLineIfEmpty()) { 6490 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); 6491 return fontMetrics.ascent() 6492 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 6493 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); 6494 } 6495 if (lastLineBox()) 6496 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType()); 6497 return -1; 6498 } else { 6499 bool haveNormalFlowChild = false; 6500 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { 6501 if (!curr->isFloatingOrOutOfFlowPositioned()) { 6502 haveNormalFlowChild = true; 6503 int result = curr->inlineBlockBaseline(lineDirection); 6504 if (result != -1) 6505 return curr->logicalTop() + result; // Translate to our coordinate space. 6506 } 6507 } 6508 if (!haveNormalFlowChild && hasLineIfEmpty()) { 6509 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); 6510 return fontMetrics.ascent() 6511 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 6512 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); 6513 } 6514 } 6515 6516 return -1; 6517 } 6518 6519 RenderBlock* RenderBlock::firstLineBlock() const 6520 { 6521 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); 6522 bool hasPseudo = false; 6523 while (true) { 6524 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE); 6525 if (hasPseudo) 6526 break; 6527 RenderObject* parentBlock = firstLineBlock->parent(); 6528 // We include isRenderButton in this check because buttons are 6529 // implemented using flex box but should still support first-line. The 6530 // flex box spec requires that flex box does not support first-line, 6531 // though. 6532 // FIXME: Remove when buttons are implemented with align-items instead 6533 // of flexbox. 6534 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() 6535 || !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow() 6536 || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton())) 6537 break; 6538 ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock()); 6539 firstLineBlock = toRenderBlock(parentBlock); 6540 } 6541 6542 if (!hasPseudo) 6543 return 0; 6544 6545 return firstLineBlock; 6546 } 6547 6548 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer) 6549 { 6550 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); 6551 // Force inline display (except for floating first-letters). 6552 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); 6553 // CSS2 says first-letter can't be positioned. 6554 pseudoStyle->setPosition(StaticPosition); 6555 return pseudoStyle; 6556 } 6557 6558 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter 6559 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe), 6560 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included" 6561 static inline bool isPunctuationForFirstLetter(UChar c) 6562 { 6563 CharCategory charCategory = category(c); 6564 return charCategory == Punctuation_Open 6565 || charCategory == Punctuation_Close 6566 || charCategory == Punctuation_InitialQuote 6567 || charCategory == Punctuation_FinalQuote 6568 || charCategory == Punctuation_Other; 6569 } 6570 6571 static inline bool shouldSkipForFirstLetter(UChar c) 6572 { 6573 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c); 6574 } 6575 6576 static inline RenderObject* findFirstLetterBlock(RenderBlock* start) 6577 { 6578 RenderObject* firstLetterBlock = start; 6579 while (true) { 6580 // We include isRenderButton in these two checks because buttons are 6581 // implemented using flex box but should still support first-letter. 6582 // The flex box spec requires that flex box does not support 6583 // first-letter, though. 6584 // FIXME: Remove when buttons are implemented with align-items instead 6585 // of flexbox. 6586 bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER) 6587 && firstLetterBlock->canHaveGeneratedChildren() 6588 && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton()); 6589 if (canHaveFirstLetterRenderer) 6590 return firstLetterBlock; 6591 6592 RenderObject* parentBlock = firstLetterBlock->parent(); 6593 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock || 6594 !parentBlock->isBlockFlow() || (parentBlock->isFlexibleBox() && !parentBlock->isRenderButton())) 6595 return 0; 6596 firstLetterBlock = parentBlock; 6597 } 6598 6599 return 0; 6600 } 6601 6602 void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild) 6603 { 6604 RenderObject* firstLetter = currentChild->parent(); 6605 RenderObject* firstLetterContainer = firstLetter->parent(); 6606 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); 6607 ASSERT(firstLetter->isFloating() || firstLetter->isInline()); 6608 6609 if (Node::diff(firstLetter->style(), pseudoStyle, document()) == Node::Detach) { 6610 // The first-letter renderer needs to be replaced. Create a new renderer of the right type. 6611 RenderObject* newFirstLetter; 6612 if (pseudoStyle->display() == INLINE) 6613 newFirstLetter = RenderInline::createAnonymous(document()); 6614 else 6615 newFirstLetter = RenderBlock::createAnonymous(document()); 6616 newFirstLetter->setStyle(pseudoStyle); 6617 6618 // Move the first letter into the new renderer. 6619 LayoutStateDisabler layoutStateDisabler(view()); 6620 while (RenderObject* child = firstLetter->firstChild()) { 6621 if (child->isText()) 6622 toRenderText(child)->removeAndDestroyTextBoxes(); 6623 firstLetter->removeChild(child); 6624 newFirstLetter->addChild(child, 0); 6625 } 6626 6627 RenderTextFragment* remainingText = 0; 6628 RenderObject* nextSibling = firstLetter->nextSibling(); 6629 RenderObject* remainingTextObject = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText(); 6630 if (remainingTextObject && remainingTextObject->isText() && toRenderText(remainingTextObject)->isTextFragment()) 6631 remainingText = toRenderTextFragment(remainingTextObject); 6632 if (remainingText) { 6633 ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText); 6634 // Replace the old renderer with the new one. 6635 remainingText->setFirstLetter(newFirstLetter); 6636 toRenderBoxModelObject(newFirstLetter)->setFirstLetterRemainingText(remainingText); 6637 } 6638 // To prevent removal of single anonymous block in RenderBlock::removeChild and causing 6639 // |nextSibling| to go stale, we remove the old first letter using removeChildNode first. 6640 firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter); 6641 firstLetter->destroy(); 6642 firstLetter = newFirstLetter; 6643 firstLetterContainer->addChild(firstLetter, nextSibling); 6644 } else 6645 firstLetter->setStyle(pseudoStyle); 6646 6647 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { 6648 if (genChild->isText()) 6649 genChild->setStyle(pseudoStyle); 6650 } 6651 } 6652 6653 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild) 6654 { 6655 RenderObject* firstLetterContainer = currentChild->parent(); 6656 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); 6657 RenderObject* firstLetter = 0; 6658 if (pseudoStyle->display() == INLINE) 6659 firstLetter = RenderInline::createAnonymous(document()); 6660 else 6661 firstLetter = RenderBlock::createAnonymous(document()); 6662 firstLetter->setStyle(pseudoStyle); 6663 firstLetterContainer->addChild(firstLetter, currentChild); 6664 6665 RenderText* textObj = toRenderText(currentChild); 6666 6667 // The original string is going to be either a generated content string or a DOM node's 6668 // string. We want the original string before it got transformed in case first-letter has 6669 // no text-transform or a different text-transform applied to it. 6670 RefPtr<StringImpl> oldText = textObj->originalText(); 6671 ASSERT(oldText); 6672 6673 if (oldText && oldText->length() > 0) { 6674 unsigned length = 0; 6675 6676 // Account for leading spaces and punctuation. 6677 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length])) 6678 length++; 6679 6680 // Account for first letter. 6681 length++; 6682 6683 // Keep looking for whitespace and allowed punctuation, but avoid 6684 // accumulating just whitespace into the :first-letter. 6685 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) { 6686 UChar c = (*oldText)[scanLength]; 6687 6688 if (!shouldSkipForFirstLetter(c)) 6689 break; 6690 6691 if (isPunctuationForFirstLetter(c)) 6692 length = scanLength + 1; 6693 } 6694 6695 // Construct a text fragment for the text after the first letter. 6696 // This text fragment might be empty. 6697 RenderTextFragment* remainingText = 6698 new RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); 6699 remainingText->setStyle(textObj->style()); 6700 if (remainingText->node()) 6701 remainingText->node()->setRenderer(remainingText); 6702 6703 firstLetterContainer->addChild(remainingText, textObj); 6704 firstLetterContainer->removeChild(textObj); 6705 remainingText->setFirstLetter(firstLetter); 6706 toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText); 6707 6708 // construct text fragment for the first letter 6709 RenderTextFragment* letter = 6710 new RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); 6711 letter->setStyle(pseudoStyle); 6712 firstLetter->addChild(letter); 6713 6714 textObj->destroy(); 6715 } 6716 } 6717 6718 void RenderBlock::updateFirstLetter() 6719 { 6720 if (!document()->styleSheetCollection()->usesFirstLetterRules()) 6721 return; 6722 // Don't recur 6723 if (style()->styleType() == FIRST_LETTER) 6724 return; 6725 6726 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find 6727 // an efficient way to check for that situation though before implementing anything. 6728 RenderObject* firstLetterBlock = findFirstLetterBlock(this); 6729 if (!firstLetterBlock) 6730 return; 6731 6732 // Drill into inlines looking for our first text child. 6733 RenderObject* currChild = firstLetterBlock->firstChild(); 6734 while (currChild) { 6735 if (currChild->isText()) 6736 break; 6737 if (currChild->isListMarker()) 6738 currChild = currChild->nextSibling(); 6739 else if (currChild->isFloatingOrOutOfFlowPositioned()) { 6740 if (currChild->style()->styleType() == FIRST_LETTER) { 6741 currChild = currChild->firstChild(); 6742 break; 6743 } 6744 currChild = currChild->nextSibling(); 6745 } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList()) 6746 break; 6747 else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) { 6748 // We found a lower-level node with first-letter, which supersedes the higher-level style 6749 firstLetterBlock = currChild; 6750 currChild = currChild->firstChild(); 6751 } else 6752 currChild = currChild->firstChild(); 6753 } 6754 6755 if (!currChild) 6756 return; 6757 6758 // If the child already has style, then it has already been created, so we just want 6759 // to update it. 6760 if (currChild->parent()->style()->styleType() == FIRST_LETTER) { 6761 updateFirstLetterStyle(firstLetterBlock, currChild); 6762 return; 6763 } 6764 6765 if (!currChild->isText() || currChild->isBR()) 6766 return; 6767 6768 // Our layout state is not valid for the repaints we are going to trigger by 6769 // adding and removing children of firstLetterContainer. 6770 LayoutStateDisabler layoutStateDisabler(view()); 6771 6772 createFirstLetterRenderer(firstLetterBlock, currChild); 6773 } 6774 6775 // Helper methods for obtaining the last line, computing line counts and heights for line counts 6776 // (crawling into blocks). 6777 static bool shouldCheckLines(RenderObject* obj) 6778 { 6779 return !obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn() 6780 && obj->isBlockFlow() && obj->style()->height().isAuto() 6781 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL); 6782 } 6783 6784 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) 6785 { 6786 if (block->style()->visibility() == VISIBLE) { 6787 if (block->childrenInline()) { 6788 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { 6789 if (++count == l) 6790 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit()); 6791 } 6792 } 6793 else { 6794 RenderBox* normalFlowChildWithoutLines = 0; 6795 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { 6796 if (shouldCheckLines(obj)) { 6797 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); 6798 if (result != -1) 6799 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit()); 6800 } else if (!obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn()) 6801 normalFlowChildWithoutLines = obj; 6802 } 6803 if (normalFlowChildWithoutLines && l == 0) 6804 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); 6805 } 6806 } 6807 6808 return -1; 6809 } 6810 6811 RootInlineBox* RenderBlock::lineAtIndex(int i) const 6812 { 6813 ASSERT(i >= 0); 6814 6815 if (style()->visibility() != VISIBLE) 6816 return 0; 6817 6818 if (childrenInline()) { 6819 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 6820 if (!i--) 6821 return box; 6822 } else { 6823 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 6824 if (!shouldCheckLines(child)) 6825 continue; 6826 if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i)) 6827 return box; 6828 } 6829 } 6830 6831 return 0; 6832 } 6833 6834 int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const 6835 { 6836 int count = 0; 6837 6838 if (style()->visibility() == VISIBLE) { 6839 if (childrenInline()) 6840 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { 6841 count++; 6842 if (box == stopRootInlineBox) { 6843 if (found) 6844 *found = true; 6845 break; 6846 } 6847 } 6848 else 6849 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) 6850 if (shouldCheckLines(obj)) { 6851 bool recursiveFound = false; 6852 count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound); 6853 if (recursiveFound) { 6854 if (found) 6855 *found = true; 6856 break; 6857 } 6858 } 6859 } 6860 return count; 6861 } 6862 6863 int RenderBlock::heightForLineCount(int l) 6864 { 6865 int count = 0; 6866 return getHeightForLineCount(this, l, true, count); 6867 } 6868 6869 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const 6870 { 6871 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting 6872 // for either overflow or translations via relative positioning. 6873 if (style()->visibility() == VISIBLE) { 6874 if (childrenInline()) { 6875 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { 6876 if (box->firstChild()) 6877 left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x())); 6878 if (box->lastChild()) 6879 right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight()))); 6880 } 6881 } 6882 else { 6883 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { 6884 if (!obj->isFloatingOrOutOfFlowPositioned()) { 6885 if (obj->isBlockFlow() && !obj->hasOverflowClip()) 6886 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right); 6887 else if (obj->style()->visibility() == VISIBLE) { 6888 // We are a replaced element or some kind of non-block-flow object. 6889 left = min(left, x + obj->x()); 6890 right = max(right, x + obj->x() + obj->width()); 6891 } 6892 } 6893 } 6894 } 6895 6896 if (m_floatingObjects) { 6897 const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 6898 FloatingObjectSetIterator end = floatingObjectSet.end(); 6899 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 6900 FloatingObject* r = *it; 6901 // Only examine the object if our m_shouldPaint flag is set. 6902 if (r->shouldPaint()) { 6903 LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x(); 6904 LayoutUnit floatRight = floatLeft + r->m_renderer->width(); 6905 left = min(left, floatLeft); 6906 right = max(right, floatRight); 6907 } 6908 } 6909 } 6910 } 6911 } 6912 6913 void RenderBlock::fitBorderToLinesIfNeeded() 6914 { 6915 if (style()->borderFit() == BorderFitBorder || hasOverrideWidth()) 6916 return; 6917 6918 // Walk any normal flow lines to snugly fit. 6919 LayoutUnit left = LayoutUnit::max(); 6920 LayoutUnit right = LayoutUnit::min(); 6921 LayoutUnit oldWidth = contentWidth(); 6922 adjustForBorderFit(0, left, right); 6923 6924 // Clamp to our existing edges. We can never grow. We only shrink. 6925 LayoutUnit leftEdge = borderLeft() + paddingLeft(); 6926 LayoutUnit rightEdge = leftEdge + oldWidth; 6927 left = min(rightEdge, max(leftEdge, left)); 6928 right = max(leftEdge, min(rightEdge, right)); 6929 6930 LayoutUnit newContentWidth = right - left; 6931 if (newContentWidth == oldWidth) 6932 return; 6933 6934 setOverrideLogicalContentWidth(newContentWidth); 6935 layoutBlock(false); 6936 clearOverrideLogicalContentWidth(); 6937 } 6938 6939 void RenderBlock::clearTruncation() 6940 { 6941 if (style()->visibility() == VISIBLE) { 6942 if (childrenInline() && hasMarkupTruncation()) { 6943 setHasMarkupTruncation(false); 6944 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 6945 box->clearTruncation(); 6946 } else { 6947 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) { 6948 if (shouldCheckLines(obj)) 6949 toRenderBlock(obj)->clearTruncation(); 6950 } 6951 } 6952 } 6953 } 6954 6955 void RenderBlock::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg) 6956 { 6957 if (!m_rareData) { 6958 if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this)) 6959 return; 6960 m_rareData = adoptPtr(new RenderBlockRareData(this)); 6961 } 6962 m_rareData->m_margins.setPositiveMarginBefore(pos); 6963 m_rareData->m_margins.setNegativeMarginBefore(neg); 6964 } 6965 6966 void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg) 6967 { 6968 if (!m_rareData) { 6969 if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this)) 6970 return; 6971 m_rareData = adoptPtr(new RenderBlockRareData(this)); 6972 } 6973 m_rareData->m_margins.setPositiveMarginAfter(pos); 6974 m_rareData->m_margins.setNegativeMarginAfter(neg); 6975 } 6976 6977 void RenderBlock::setMustDiscardMarginBefore(bool value) 6978 { 6979 if (style()->marginBeforeCollapse() == MDISCARD) { 6980 ASSERT(value); 6981 return; 6982 } 6983 6984 if (!m_rareData && !value) 6985 return; 6986 6987 if (!m_rareData) 6988 m_rareData = adoptPtr(new RenderBlockRareData(this)); 6989 6990 m_rareData->m_discardMarginBefore = value; 6991 } 6992 6993 void RenderBlock::setMustDiscardMarginAfter(bool value) 6994 { 6995 if (style()->marginAfterCollapse() == MDISCARD) { 6996 ASSERT(value); 6997 return; 6998 } 6999 7000 if (!m_rareData && !value) 7001 return; 7002 7003 if (!m_rareData) 7004 m_rareData = adoptPtr(new RenderBlockRareData(this)); 7005 7006 m_rareData->m_discardMarginAfter = value; 7007 } 7008 7009 bool RenderBlock::mustDiscardMarginBefore() const 7010 { 7011 return style()->marginBeforeCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginBefore); 7012 } 7013 7014 bool RenderBlock::mustDiscardMarginAfter() const 7015 { 7016 return style()->marginAfterCollapse() == MDISCARD || (m_rareData && m_rareData->m_discardMarginAfter); 7017 } 7018 7019 bool RenderBlock::mustDiscardMarginBeforeForChild(const RenderBox* child) const 7020 { 7021 ASSERT(!child->selfNeedsLayout()); 7022 if (!child->isWritingModeRoot()) 7023 return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD); 7024 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7025 return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD); 7026 7027 // FIXME: We return false here because the implementation is not geometrically complete. We have values only for before/after, not start/end. 7028 // In case the boxes are perpendicular we assume the property is not specified. 7029 return false; 7030 } 7031 7032 bool RenderBlock::mustDiscardMarginAfterForChild(const RenderBox* child) const 7033 { 7034 ASSERT(!child->selfNeedsLayout()); 7035 if (!child->isWritingModeRoot()) 7036 return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginAfter() : (child->style()->marginAfterCollapse() == MDISCARD); 7037 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7038 return child->isRenderBlock() ? toRenderBlock(child)->mustDiscardMarginBefore() : (child->style()->marginBeforeCollapse() == MDISCARD); 7039 7040 // FIXME: See |mustDiscardMarginBeforeForChild| above. 7041 return false; 7042 } 7043 7044 bool RenderBlock::mustSeparateMarginBeforeForChild(const RenderBox* child) const 7045 { 7046 ASSERT(!child->selfNeedsLayout()); 7047 const RenderStyle* childStyle = child->style(); 7048 if (!child->isWritingModeRoot()) 7049 return childStyle->marginBeforeCollapse() == MSEPARATE; 7050 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7051 return childStyle->marginAfterCollapse() == MSEPARATE; 7052 7053 // FIXME: See |mustDiscardMarginBeforeForChild| above. 7054 return false; 7055 } 7056 7057 bool RenderBlock::mustSeparateMarginAfterForChild(const RenderBox* child) const 7058 { 7059 ASSERT(!child->selfNeedsLayout()); 7060 const RenderStyle* childStyle = child->style(); 7061 if (!child->isWritingModeRoot()) 7062 return childStyle->marginAfterCollapse() == MSEPARATE; 7063 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7064 return childStyle->marginBeforeCollapse() == MSEPARATE; 7065 7066 // FIXME: See |mustDiscardMarginBeforeForChild| above. 7067 return false; 7068 } 7069 7070 void RenderBlock::setPaginationStrut(LayoutUnit strut) 7071 { 7072 if (!m_rareData) { 7073 if (!strut) 7074 return; 7075 m_rareData = adoptPtr(new RenderBlockRareData(this)); 7076 } 7077 m_rareData->m_paginationStrut = strut; 7078 } 7079 7080 void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset) 7081 { 7082 if (!m_rareData) { 7083 if (!logicalOffset) 7084 return; 7085 m_rareData = adoptPtr(new RenderBlockRareData(this)); 7086 } 7087 m_rareData->m_pageLogicalOffset = logicalOffset; 7088 } 7089 7090 void RenderBlock::setBreakAtLineToAvoidWidow(RootInlineBox* lineToBreak) 7091 { 7092 ASSERT(lineToBreak); 7093 if (!m_rareData) 7094 m_rareData = adoptPtr(new RenderBlockRareData(this)); 7095 m_rareData->m_shouldBreakAtLineToAvoidWidow = true; 7096 m_rareData->m_lineBreakToAvoidWidow = lineToBreak; 7097 } 7098 7099 void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const 7100 { 7101 if (!m_rareData) 7102 return; 7103 m_rareData->m_shouldBreakAtLineToAvoidWidow = false; 7104 m_rareData->m_lineBreakToAvoidWidow = 0; 7105 } 7106 7107 void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const 7108 { 7109 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 7110 // inline boxes above and below us (thus getting merged with them to form a single irregular 7111 // shape). 7112 if (isAnonymousBlockContinuation()) { 7113 // FIXME: This is wrong for block-flows that are horizontal. 7114 // https://bugs.webkit.org/show_bug.cgi?id=46781 7115 rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(), 7116 width(), height() + collapsedMarginBefore() + collapsedMarginAfter())); 7117 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() + 7118 inlineElementContinuation()->containingBlock()->location())); 7119 } else 7120 rects.append(pixelSnappedIntRect(accumulatedOffset, size())); 7121 } 7122 7123 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const 7124 { 7125 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 7126 // inline boxes above and below us (thus getting merged with them to form a single irregular 7127 // shape). 7128 if (isAnonymousBlockContinuation()) { 7129 // FIXME: This is wrong for block-flows that are horizontal. 7130 // https://bugs.webkit.org/show_bug.cgi?id=46781 7131 FloatRect localRect(0, -collapsedMarginBefore(), 7132 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()); 7133 quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed)); 7134 continuation()->absoluteQuads(quads, wasFixed); 7135 } else 7136 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed)); 7137 } 7138 7139 LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const 7140 { 7141 LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); 7142 if (isAnonymousBlockContinuation()) 7143 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal. 7144 return r; 7145 } 7146 7147 RenderObject* RenderBlock::hoverAncestor() const 7148 { 7149 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor(); 7150 } 7151 7152 void RenderBlock::updateDragState(bool dragOn) 7153 { 7154 RenderBox::updateDragState(dragOn); 7155 if (continuation()) 7156 continuation()->updateDragState(dragOn); 7157 } 7158 7159 RenderStyle* RenderBlock::outlineStyleForRepaint() const 7160 { 7161 return isAnonymousBlockContinuation() ? continuation()->style() : style(); 7162 } 7163 7164 void RenderBlock::childBecameNonInline(RenderObject*) 7165 { 7166 makeChildrenNonInline(); 7167 if (isAnonymousBlock() && parent() && parent()->isRenderBlock()) 7168 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 7169 // |this| may be dead here 7170 } 7171 7172 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point) 7173 { 7174 if (result.innerNode()) 7175 return; 7176 7177 if (Node* n = nodeForHitTest()) { 7178 result.setInnerNode(n); 7179 if (!result.innerNonSharedNode()) 7180 result.setInnerNonSharedNode(n); 7181 result.setLocalPoint(point); 7182 } 7183 } 7184 7185 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine) 7186 { 7187 // Do the normal calculation in most cases. 7188 if (firstChild()) 7189 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); 7190 7191 LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset()); 7192 7193 if (extraWidthToEndOfLine) { 7194 if (isRenderBlock()) { 7195 *extraWidthToEndOfLine = width() - caretRect.maxX(); 7196 } else { 7197 // FIXME: This code looks wrong. 7198 // myRight and containerRight are set up, but then clobbered. 7199 // So *extraWidthToEndOfLine will always be 0 here. 7200 7201 LayoutUnit myRight = caretRect.maxX(); 7202 // FIXME: why call localToAbsoluteForContent() twice here, too? 7203 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); 7204 7205 LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent(); 7206 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); 7207 7208 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); 7209 } 7210 } 7211 7212 return caretRect; 7213 } 7214 7215 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer) 7216 { 7217 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 7218 // inline boxes above and below us (thus getting merged with them to form a single irregular 7219 // shape). 7220 if (inlineElementContinuation()) { 7221 // FIXME: This check really isn't accurate. 7222 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox(); 7223 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block. 7224 // FIXME: This is wrong for block-flows that are horizontal. 7225 // https://bugs.webkit.org/show_bug.cgi?id=46781 7226 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox(); 7227 float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit(); 7228 float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit(); 7229 LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin); 7230 if (!rect.isEmpty()) 7231 rects.append(pixelSnappedIntRect(rect)); 7232 } else if (width() && height()) 7233 rects.append(pixelSnappedIntRect(additionalOffset, size())); 7234 7235 if (!hasOverflowClip() && !hasControlClip()) { 7236 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 7237 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top()); 7238 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height()); 7239 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top); 7240 if (!rect.isEmpty()) 7241 rects.append(pixelSnappedIntRect(rect)); 7242 } 7243 7244 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { 7245 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { 7246 RenderBox* box = toRenderBox(curr); 7247 FloatPoint pos; 7248 // FIXME: This doesn't work correctly with transforms. 7249 if (box->layer()) 7250 pos = curr->localToContainerPoint(FloatPoint(), paintContainer); 7251 else 7252 pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y()); 7253 box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer); 7254 } 7255 } 7256 } 7257 7258 if (inlineElementContinuation()) 7259 inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer); 7260 } 7261 7262 void RenderBlock::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const 7263 { 7264 RenderBox::computeSelfHitTestRects(rects, layerOffset); 7265 7266 if (hasHorizontalLayoutOverflow() || hasVerticalLayoutOverflow()) { 7267 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 7268 LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top()); 7269 LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height()); 7270 LayoutRect rect(layerOffset.x() + curr->x(), layerOffset.y() + top, curr->width(), bottom - top); 7271 // It's common for this rect to be entirely contained in our box, so exclude that simple case. 7272 if (!rect.isEmpty() && (rects.isEmpty() || !rects[0].contains(rect))) 7273 rects.append(rect); 7274 } 7275 } 7276 } 7277 7278 RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const 7279 { 7280 if (isAnonymousColumnsBlock()) 7281 return createAnonymousColumnsWithParentRenderer(parent); 7282 if (isAnonymousColumnSpanBlock()) 7283 return createAnonymousColumnSpanWithParentRenderer(parent); 7284 return createAnonymousWithParentRendererAndDisplay(parent, style()->display()); 7285 } 7286 7287 bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const 7288 { 7289 ASSERT(view()->layoutState() && view()->layoutState()->isPaginated()); 7290 7291 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7292 if (!flowThread) 7293 return true; // Printing and multi-column both make new pages to accommodate content. 7294 7295 // See if we're in the last region. 7296 LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset; 7297 RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this); 7298 if (!region) 7299 return false; 7300 if (region->isLastRegion()) 7301 return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment 7302 || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent()); 7303 return true; 7304 } 7305 7306 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const 7307 { 7308 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); 7309 if (!pageLogicalHeight) 7310 return logicalOffset; 7311 7312 // The logicalOffset is in our coordinate space. We can add in our pushed offset. 7313 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset); 7314 if (pageBoundaryRule == ExcludePageBoundary) 7315 return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight); 7316 return logicalOffset + remainingLogicalHeight; 7317 } 7318 7319 static bool inNormalFlow(RenderBox* child) 7320 { 7321 RenderBlock* curr = child->containingBlock(); 7322 RenderView* renderView = child->view(); 7323 while (curr && curr != renderView) { 7324 if (curr->hasColumns() || curr->isRenderFlowThread()) 7325 return true; 7326 if (curr->isFloatingOrOutOfFlowPositioned()) 7327 return false; 7328 curr = curr->containingBlock(); 7329 } 7330 return true; 7331 } 7332 7333 ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const 7334 { 7335 return ColumnInfo::Column; 7336 } 7337 7338 LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset) 7339 { 7340 // FIXME: Add page break checking here when we support printing. 7341 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); 7342 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. 7343 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7344 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); 7345 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS) 7346 || (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS); 7347 if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { 7348 if (checkColumnBreaks) 7349 view()->layoutState()->addForcedColumnBreak(child, logicalOffset); 7350 if (checkRegionBreaks) { 7351 LayoutUnit offsetBreakAdjustment = 0; 7352 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment)) 7353 return logicalOffset + offsetBreakAdjustment; 7354 } 7355 return nextPageLogicalTop(logicalOffset, IncludePageBoundary); 7356 } 7357 return logicalOffset; 7358 } 7359 7360 LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo) 7361 { 7362 // FIXME: Add page break checking here when we support printing. 7363 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); 7364 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. 7365 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7366 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); 7367 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS) 7368 || (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS); 7369 if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) { 7370 LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin(); 7371 7372 // So our margin doesn't participate in the next collapsing steps. 7373 marginInfo.clearMargin(); 7374 7375 if (checkColumnBreaks) 7376 view()->layoutState()->addForcedColumnBreak(child, logicalOffset); 7377 if (checkRegionBreaks) { 7378 LayoutUnit offsetBreakAdjustment = 0; 7379 if (flowThread->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment)) 7380 return logicalOffset + marginOffset + offsetBreakAdjustment; 7381 } 7382 return nextPageLogicalTop(logicalOffset, IncludePageBoundary); 7383 } 7384 return logicalOffset; 7385 } 7386 7387 LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const 7388 { 7389 RenderView* renderView = view(); 7390 LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width(); 7391 LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width(); 7392 7393 LayoutUnit cumulativeOffset = offset + blockLogicalTop; 7394 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7395 if (!flowThread) { 7396 LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight(); 7397 if (!pageLogicalHeight) 7398 return 0; 7399 return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight); 7400 } 7401 return flowThread->pageLogicalTopForOffset(cumulativeOffset); 7402 } 7403 7404 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const 7405 { 7406 RenderView* renderView = view(); 7407 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7408 if (!flowThread) 7409 return renderView->layoutState()->m_pageLogicalHeight; 7410 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage()); 7411 } 7412 7413 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const 7414 { 7415 RenderView* renderView = view(); 7416 offset += offsetFromLogicalTopOfFirstPage(); 7417 7418 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7419 if (!flowThread) { 7420 LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight; 7421 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight); 7422 if (pageBoundaryRule == IncludePageBoundary) { 7423 // If includeBoundaryPoint is true the line exactly on the top edge of a 7424 // column will act as being part of the previous column. 7425 remainingHeight = intMod(remainingHeight, pageLogicalHeight); 7426 } 7427 return remainingHeight; 7428 } 7429 7430 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule); 7431 } 7432 7433 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins) 7434 { 7435 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); 7436 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; 7437 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7438 bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread(); 7439 bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID) 7440 || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID) 7441 || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID); 7442 if (!isUnsplittable) 7443 return logicalOffset; 7444 LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit()); 7445 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); 7446 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight(); 7447 updateMinimumPageHeight(logicalOffset, childLogicalHeight); 7448 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight) 7449 || !hasNextPage(logicalOffset)) 7450 return logicalOffset; 7451 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); 7452 if (remainingLogicalHeight < childLogicalHeight) { 7453 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight)) 7454 return logicalOffset; 7455 return logicalOffset + remainingLogicalHeight; 7456 } 7457 return logicalOffset; 7458 } 7459 7460 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const 7461 { 7462 bool checkRegion = false; 7463 for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight; 7464 pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) { 7465 if (minimumLogicalHeight <= pageLogicalHeight) 7466 return true; 7467 if (!hasNextPage(logicalOffset + adjustment)) 7468 return false; 7469 adjustment += pageLogicalHeight; 7470 checkRegion = true; 7471 } 7472 return !checkRegion; 7473 } 7474 7475 void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage) 7476 { 7477 if (RenderFlowThread* flowThread = flowThreadContainingBlock()) 7478 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage); 7479 } 7480 7481 void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight) 7482 { 7483 if (RenderFlowThread* flowThread = flowThreadContainingBlock()) 7484 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight); 7485 else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo) 7486 colInfo->updateMinimumColumnHeight(minHeight); 7487 } 7488 7489 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom) 7490 { 7491 // We may require a certain minimum number of lines per page in order to satisfy 7492 // orphans and widows, and that may affect the minimum page height. 7493 unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows()); 7494 if (lineCount > 1) { 7495 RootInlineBox* line = lastLine; 7496 for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++) 7497 line = line->prevRootBox(); 7498 7499 // FIXME: Paginating using line overflow isn't all fine. See FIXME in 7500 // adjustLinePositionForPagination() for more details. 7501 LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom()); 7502 lineTop = min(line->lineTopWithLeading(), overflow.y()); 7503 } 7504 return lineBottom - lineTop; 7505 } 7506 7507 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread) 7508 { 7509 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we 7510 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since 7511 // the line on the top of the next page will appear too far down relative to the same kind of line at the top 7512 // of the first column. 7513 // 7514 // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow 7515 // simply spills out above the top of the column. This effect would match what happens at the top of the first column. 7516 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing 7517 // for overflow to occur), and then cache visible overflow for each column rect. 7518 // 7519 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude 7520 // content that paints in a previous column (and content that paints in the following column). 7521 // 7522 // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will 7523 // at least make positive leading work in typical cases. 7524 // 7525 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats). 7526 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the 7527 // line and all following lines. 7528 LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom()); 7529 LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y()); 7530 LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()); 7531 LayoutUnit lineHeight = logicalBottom - logicalOffset; 7532 updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom)); 7533 logicalOffset += delta; 7534 lineBox->setPaginationStrut(0); 7535 lineBox->setIsFirstAfterPageBreak(false); 7536 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset); 7537 bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight(); 7538 // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are 7539 // still going to add a strut, so that the visible overflow fits on a single page. 7540 if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight) 7541 || !hasNextPage(logicalOffset)) 7542 return; 7543 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary); 7544 7545 if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox)) { 7546 if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineBox) 7547 clearShouldBreakAtLineToAvoidWidow(); 7548 // If we have a non-uniform page height, then we have to shift further possibly. 7549 if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight)) 7550 return; 7551 if (lineHeight > pageLogicalHeight) { 7552 // Split the top margin in order to avoid splitting the visible part of the line. 7553 remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading())); 7554 } 7555 LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset); 7556 LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight); 7557 setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight); 7558 if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineCount(lineBox))) 7559 && !isOutOfFlowPositioned() && !isTableCell()) 7560 setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset)); 7561 else { 7562 delta += remainingLogicalHeight; 7563 lineBox->setPaginationStrut(remainingLogicalHeight); 7564 lineBox->setIsFirstAfterPageBreak(true); 7565 } 7566 } else if (remainingLogicalHeight == pageLogicalHeight && lineBox != firstRootBox()) 7567 lineBox->setIsFirstAfterPageBreak(true); 7568 } 7569 7570 LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock) 7571 { 7572 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; 7573 7574 if (estimateWithoutPagination != logicalTopAfterClear) { 7575 // Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new 7576 // position. 7577 setLogicalHeight(logicalTopAfterClear); 7578 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta); 7579 7580 if (child->shrinkToAvoidFloats()) { 7581 // The child's width depends on the line width. 7582 // When the child shifts to clear an item, its width can 7583 // change (because it has more available line width). 7584 // So go ahead and mark the item as dirty. 7585 child->setChildNeedsLayout(MarkOnlyThis); 7586 } 7587 7588 if (childRenderBlock) { 7589 if (!child->avoidsFloats() && childRenderBlock->containsFloats()) 7590 childRenderBlock->markAllDescendantsWithFloatsForLayout(); 7591 if (!child->needsLayout()) 7592 child->markForPaginationRelayoutIfNeeded(); 7593 } 7594 7595 // Our guess was wrong. Make the child lay itself out again. 7596 child->layoutIfNeeded(); 7597 } 7598 7599 LayoutUnit oldTop = logicalTopAfterClear; 7600 7601 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 7602 LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear); 7603 7604 if (pageLogicalHeightForOffset(result)) { 7605 LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(result, ExcludePageBoundary); 7606 LayoutUnit spaceShortage = child->logicalHeight() - remainingLogicalHeight; 7607 if (spaceShortage > 0) { 7608 // If the child crosses a column boundary, report a break, in case nothing inside it has already 7609 // done so. The column balancer needs to know how much it has to stretch the columns to make more 7610 // content fit. If no breaks are reported (but do occur), the balancer will have no clue. FIXME: 7611 // This should be improved, though, because here we just pretend that the child is 7612 // unsplittable. A splittable child, on the other hand, has break opportunities at every position 7613 // where there's no child content, border or padding. In other words, we risk stretching more 7614 // than necessary. 7615 setPageBreak(result, spaceShortage); 7616 } 7617 } 7618 7619 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 7620 LayoutUnit logicalTopBeforeUnsplittableAdjustment = result; 7621 LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result); 7622 7623 LayoutUnit paginationStrut = 0; 7624 LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; 7625 if (unsplittableAdjustmentDelta) 7626 paginationStrut = unsplittableAdjustmentDelta; 7627 else if (childRenderBlock && childRenderBlock->paginationStrut()) 7628 paginationStrut = childRenderBlock->paginationStrut(); 7629 7630 if (paginationStrut) { 7631 // We are willing to propagate out to our parent block as long as we were at the top of the block prior 7632 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination. 7633 if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) { 7634 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't 7635 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too 7636 // and pushes to the next page anyway, so not too concerned about it. 7637 setPaginationStrut(result + paginationStrut); 7638 if (childRenderBlock) 7639 childRenderBlock->setPaginationStrut(0); 7640 } else 7641 result += paginationStrut; 7642 } 7643 7644 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. 7645 setLogicalHeight(logicalHeight() + (result - oldTop)); 7646 7647 // Return the final adjusted logical top. 7648 return result; 7649 } 7650 7651 bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const 7652 { 7653 if (!flowThread) 7654 return false; 7655 7656 RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta); 7657 // Just bail if the region didn't change. 7658 if (rootBox->containingRegion() == currentRegion) 7659 return false; 7660 return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion, offsetFromLogicalTopOfFirstPage()); 7661 } 7662 7663 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const 7664 { 7665 LayoutState* layoutState = view()->layoutState(); 7666 if (layoutState && !layoutState->isPaginated()) 7667 return 0; 7668 if (layoutState) { 7669 // FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off. 7670 // Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using 7671 // widths which can vary in each region. Until we patch that, we can't have this assert. 7672 // ASSERT(layoutState->m_renderer == this); 7673 7674 LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; 7675 return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); 7676 } 7677 // FIXME: Right now, this assert is hit outside layout, from logicalLeftSelectionOffset in selectionGapRectsForRepaint (called from FrameSelection::selectAll). 7678 // ASSERT(inRenderFlowThread()); 7679 7680 // FIXME: This is a slower path that doesn't use layout state and relies on getting your logical top inside the enclosing flow thread. It doesn't 7681 // work with columns or pages currently, but it should once they have been switched over to using flow threads. 7682 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7683 if (!flowThread) 7684 return 0; 7685 7686 const RenderBlock* currentBlock = this; 7687 LayoutRect blockRect(0, 0, width(), height()); 7688 7689 while (currentBlock && !currentBlock->isRenderFlowThread()) { 7690 RenderBlock* containerBlock = currentBlock->containingBlock(); 7691 ASSERT(containerBlock); 7692 if (!containerBlock) 7693 return 0; 7694 LayoutPoint currentBlockLocation = currentBlock->location(); 7695 7696 if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) { 7697 // We have to put the block rect in container coordinates 7698 // and we have to take into account both the container and current block flipping modes 7699 if (containerBlock->style()->isFlippedBlocksWritingMode()) { 7700 if (containerBlock->isHorizontalWritingMode()) 7701 blockRect.setY(currentBlock->height() - blockRect.maxY()); 7702 else 7703 blockRect.setX(currentBlock->width() - blockRect.maxX()); 7704 } 7705 currentBlock->flipForWritingMode(blockRect); 7706 } 7707 blockRect.moveBy(currentBlockLocation); 7708 currentBlock = containerBlock; 7709 }; 7710 return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x(); 7711 } 7712 7713 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const 7714 { 7715 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7716 if (!flowThread || !flowThread->hasValidRegionInfo()) 7717 return 0; 7718 7719 return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true); 7720 } 7721 7722 void RenderBlock::updateStaticInlinePositionForChild(RenderBox* child, LayoutUnit logicalTop) 7723 { 7724 if (child->style()->isOriginalDisplayInlineType()) 7725 setStaticInlinePositionForChild(child, logicalTop, startAlignedOffsetForLine(logicalTop, false)); 7726 else 7727 setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop)); 7728 } 7729 7730 void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition) 7731 { 7732 if (flowThreadContainingBlock()) { 7733 // Shift the inline position to exclude the region offset. 7734 inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset); 7735 } 7736 child->layer()->setStaticInlinePosition(inlinePosition); 7737 } 7738 7739 bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const 7740 { 7741 if (!flowThread || !flowThread->hasValidRegionInfo()) 7742 return false; 7743 7744 return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage()); 7745 } 7746 7747 RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const 7748 { 7749 RenderFlowThread* flowThread = flowThreadContainingBlock(); 7750 7751 ASSERT(isRenderView() || (region && flowThread)); 7752 if (isRenderView()) 7753 return region; 7754 7755 // We need to clamp to the block, since we want any lines or blocks that overflow out of the 7756 // logical top or logical bottom of the block to size as though the border box in the first and 7757 // last regions extended infinitely. Otherwise the lines are going to size according to the regions 7758 // they overflow into, which makes no sense when this block doesn't exist in |region| at all. 7759 RenderRegion* startRegion; 7760 RenderRegion* endRegion; 7761 flowThread->getRegionRangeForBox(this, startRegion, endRegion); 7762 7763 if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent()) 7764 return startRegion; 7765 if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent()) 7766 return endRegion; 7767 7768 return region; 7769 } 7770 7771 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const 7772 { 7773 // If the child has the same directionality as we do, then we can just return its 7774 // collapsed margin. 7775 if (!child->isWritingModeRoot()) 7776 return child->collapsedMarginBefore(); 7777 7778 // The child has a different directionality. If the child is parallel, then it's just 7779 // flipped relative to us. We can use the collapsed margin for the opposite edge. 7780 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7781 return child->collapsedMarginAfter(); 7782 7783 // The child is perpendicular to us, which means its margins don't collapse but are on the 7784 // "logical left/right" sides of the child box. We can just return the raw margin in this case. 7785 return marginBeforeForChild(child); 7786 } 7787 7788 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const 7789 { 7790 // If the child has the same directionality as we do, then we can just return its 7791 // collapsed margin. 7792 if (!child->isWritingModeRoot()) 7793 return child->collapsedMarginAfter(); 7794 7795 // The child has a different directionality. If the child is parallel, then it's just 7796 // flipped relative to us. We can use the collapsed margin for the opposite edge. 7797 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7798 return child->collapsedMarginBefore(); 7799 7800 // The child is perpendicular to us, which means its margins don't collapse but are on the 7801 // "logical left/right" side of the child box. We can just return the raw margin in this case. 7802 return marginAfterForChild(child); 7803 } 7804 7805 bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const 7806 { 7807 // If the child has the same directionality as we do, then we can just return its 7808 // margin quirk. 7809 if (!child->isWritingModeRoot()) 7810 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk(); 7811 7812 // The child has a different directionality. If the child is parallel, then it's just 7813 // flipped relative to us. We can use the opposite edge. 7814 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7815 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk(); 7816 7817 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about 7818 // whether or not authors specified quirky ems, since they're an implementation detail. 7819 return false; 7820 } 7821 7822 bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const 7823 { 7824 // If the child has the same directionality as we do, then we can just return its 7825 // margin quirk. 7826 if (!child->isWritingModeRoot()) 7827 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk(); 7828 7829 // The child has a different directionality. If the child is parallel, then it's just 7830 // flipped relative to us. We can use the opposite edge. 7831 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 7832 return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk(); 7833 7834 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about 7835 // whether or not authors specified quirky ems, since they're an implementation detail. 7836 return false; 7837 } 7838 7839 RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const 7840 { 7841 LayoutUnit childBeforePositive = 0; 7842 LayoutUnit childBeforeNegative = 0; 7843 LayoutUnit childAfterPositive = 0; 7844 LayoutUnit childAfterNegative = 0; 7845 7846 LayoutUnit beforeMargin = 0; 7847 LayoutUnit afterMargin = 0; 7848 7849 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; 7850 7851 // If the child has the same directionality as we do, then we can just return its 7852 // margins in the same direction. 7853 if (!child->isWritingModeRoot()) { 7854 if (childRenderBlock) { 7855 childBeforePositive = childRenderBlock->maxPositiveMarginBefore(); 7856 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore(); 7857 childAfterPositive = childRenderBlock->maxPositiveMarginAfter(); 7858 childAfterNegative = childRenderBlock->maxNegativeMarginAfter(); 7859 } else { 7860 beforeMargin = child->marginBefore(); 7861 afterMargin = child->marginAfter(); 7862 } 7863 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) { 7864 // The child has a different directionality. If the child is parallel, then it's just 7865 // flipped relative to us. We can use the margins for the opposite edges. 7866 if (childRenderBlock) { 7867 childBeforePositive = childRenderBlock->maxPositiveMarginAfter(); 7868 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter(); 7869 childAfterPositive = childRenderBlock->maxPositiveMarginBefore(); 7870 childAfterNegative = childRenderBlock->maxNegativeMarginBefore(); 7871 } else { 7872 beforeMargin = child->marginAfter(); 7873 afterMargin = child->marginBefore(); 7874 } 7875 } else { 7876 // The child is perpendicular to us, which means its margins don't collapse but are on the 7877 // "logical left/right" sides of the child box. We can just return the raw margin in this case. 7878 beforeMargin = marginBeforeForChild(child); 7879 afterMargin = marginAfterForChild(child); 7880 } 7881 7882 // Resolve uncollapsing margins into their positive/negative buckets. 7883 if (beforeMargin) { 7884 if (beforeMargin > 0) 7885 childBeforePositive = beforeMargin; 7886 else 7887 childBeforeNegative = -beforeMargin; 7888 } 7889 if (afterMargin) { 7890 if (afterMargin > 0) 7891 childAfterPositive = afterMargin; 7892 else 7893 childAfterNegative = -afterMargin; 7894 } 7895 7896 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative); 7897 } 7898 7899 const char* RenderBlock::renderName() const 7900 { 7901 if (isBody()) 7902 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass. 7903 7904 if (isFloating()) 7905 return "RenderBlock (floating)"; 7906 if (isOutOfFlowPositioned()) 7907 return "RenderBlock (positioned)"; 7908 if (isAnonymousColumnsBlock()) 7909 return "RenderBlock (anonymous multi-column)"; 7910 if (isAnonymousColumnSpanBlock()) 7911 return "RenderBlock (anonymous multi-column span)"; 7912 if (isAnonymousBlock()) 7913 return "RenderBlock (anonymous)"; 7914 // FIXME: Temporary hack while the new generated content system is being implemented. 7915 if (isPseudoElement()) 7916 return "RenderBlock (generated)"; 7917 if (isAnonymous()) 7918 return "RenderBlock (generated)"; 7919 if (isRelPositioned()) 7920 return "RenderBlock (relative positioned)"; 7921 if (isStickyPositioned()) 7922 return "RenderBlock (sticky positioned)"; 7923 if (isRunIn()) 7924 return "RenderBlock (run-in)"; 7925 return "RenderBlock"; 7926 } 7927 7928 inline RenderBlock::FloatingObjects::FloatingObjects(const RenderBlock* renderer, bool horizontalWritingMode) 7929 : m_placedFloatsTree(UninitializedTree) 7930 , m_leftObjectsCount(0) 7931 , m_rightObjectsCount(0) 7932 , m_horizontalWritingMode(horizontalWritingMode) 7933 , m_renderer(renderer) 7934 { 7935 } 7936 7937 void RenderBlock::createFloatingObjects() 7938 { 7939 m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode())); 7940 } 7941 7942 inline void RenderBlock::FloatingObjects::clear() 7943 { 7944 m_set.clear(); 7945 m_placedFloatsTree.clear(); 7946 m_leftObjectsCount = 0; 7947 m_rightObjectsCount = 0; 7948 } 7949 7950 inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type) 7951 { 7952 if (type == FloatingObject::FloatLeft) 7953 m_leftObjectsCount++; 7954 else 7955 m_rightObjectsCount++; 7956 } 7957 7958 inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type) 7959 { 7960 if (type == FloatingObject::FloatLeft) 7961 m_leftObjectsCount--; 7962 else 7963 m_rightObjectsCount--; 7964 } 7965 7966 inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject) 7967 { 7968 if (m_horizontalWritingMode) 7969 return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject); 7970 return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject); 7971 } 7972 7973 void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject) 7974 { 7975 ASSERT(!floatingObject->isInPlacedTree()); 7976 7977 floatingObject->setIsPlaced(true); 7978 if (m_placedFloatsTree.isInitialized()) 7979 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); 7980 7981 #ifndef NDEBUG 7982 floatingObject->setIsInPlacedTree(true); 7983 #endif 7984 } 7985 7986 void RenderBlock::FloatingObjects::removePlacedObject(FloatingObject* floatingObject) 7987 { 7988 ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree()); 7989 7990 if (m_placedFloatsTree.isInitialized()) { 7991 bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject)); 7992 ASSERT_UNUSED(removed, removed); 7993 } 7994 7995 floatingObject->setIsPlaced(false); 7996 #ifndef NDEBUG 7997 floatingObject->setIsInPlacedTree(false); 7998 #endif 7999 } 8000 8001 inline void RenderBlock::FloatingObjects::add(FloatingObject* floatingObject) 8002 { 8003 increaseObjectsCount(floatingObject->type()); 8004 m_set.add(floatingObject); 8005 if (floatingObject->isPlaced()) 8006 addPlacedObject(floatingObject); 8007 } 8008 8009 inline void RenderBlock::FloatingObjects::remove(FloatingObject* floatingObject) 8010 { 8011 decreaseObjectsCount(floatingObject->type()); 8012 m_set.remove(floatingObject); 8013 ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree()); 8014 if (floatingObject->isPlaced()) 8015 removePlacedObject(floatingObject); 8016 } 8017 8018 void RenderBlock::FloatingObjects::computePlacedFloatsTree() 8019 { 8020 ASSERT(!m_placedFloatsTree.isInitialized()); 8021 if (m_set.isEmpty()) 8022 return; 8023 m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena()); 8024 FloatingObjectSetIterator it = m_set.begin(); 8025 FloatingObjectSetIterator end = m_set.end(); 8026 for (; it != end; ++it) { 8027 FloatingObject* floatingObject = *it; 8028 if (floatingObject->isPlaced()) 8029 m_placedFloatsTree.add(intervalForFloatingObject(floatingObject)); 8030 } 8031 } 8032 8033 template <typename CharacterType> 8034 static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) 8035 { 8036 ASSERT(style); 8037 8038 TextDirection textDirection = LTR; 8039 bool directionalOverride = style->rtlOrdering() == VisualOrder; 8040 8041 TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride); 8042 if (textRunNeedsRenderingContext(font)) 8043 run.setRenderingContext(SVGTextRunRenderingContext::create(context)); 8044 8045 return run; 8046 } 8047 8048 template <typename CharacterType> 8049 static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) 8050 { 8051 ASSERT(style); 8052 8053 TextDirection textDirection = LTR; 8054 bool directionalOverride = style->rtlOrdering() == VisualOrder; 8055 if (flags != DefaultTextRunFlags) { 8056 if (flags & RespectDirection) 8057 textDirection = style->direction(); 8058 if (flags & RespectDirectionOverride) 8059 directionalOverride |= isOverride(style->unicodeBidi()); 8060 } 8061 TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride); 8062 if (textRunNeedsRenderingContext(font)) 8063 run.setRenderingContext(SVGTextRunRenderingContext::create(context)); 8064 8065 return run; 8066 } 8067 8068 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const LChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) 8069 { 8070 return constructTextRunInternal(context, font, characters, length, style, expansion); 8071 } 8072 8073 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion) 8074 { 8075 return constructTextRunInternal(context, font, characters, length, style, expansion); 8076 } 8077 8078 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, RenderStyle* style, TextRun::ExpansionBehavior expansion) 8079 { 8080 if (text->is8Bit()) 8081 return constructTextRunInternal(context, font, text->characters8(), text->textLength(), style, expansion); 8082 return constructTextRunInternal(context, font, text->characters16(), text->textLength(), style, expansion); 8083 } 8084 8085 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, unsigned offset, unsigned length, RenderStyle* style, TextRun::ExpansionBehavior expansion) 8086 { 8087 ASSERT(offset + length <= text->textLength()); 8088 if (text->is8Bit()) 8089 return constructTextRunInternal(context, font, text->characters8() + offset, length, style, expansion); 8090 return constructTextRunInternal(context, font, text->characters16() + offset, length, style, expansion); 8091 } 8092 8093 TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags) 8094 { 8095 unsigned length = string.length(); 8096 if (!length) 8097 return constructTextRunInternal(context, font, static_cast<const LChar*>(0), length, style, expansion, flags); 8098 if (string.is8Bit()) 8099 return constructTextRunInternal(context, font, string.characters8(), length, style, expansion, flags); 8100 return constructTextRunInternal(context, font, string.characters16(), length, style, expansion, flags); 8101 } 8102 8103 RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display) 8104 { 8105 // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ? 8106 EDisplay newDisplay; 8107 RenderBlock* newBox = 0; 8108 if (display == BOX || display == INLINE_BOX) { 8109 // FIXME: Remove this case once we have eliminated all internal users of old flexbox 8110 newBox = RenderDeprecatedFlexibleBox::createAnonymous(parent->document()); 8111 newDisplay = BOX; 8112 } else if (display == FLEX || display == INLINE_FLEX) { 8113 newBox = RenderFlexibleBox::createAnonymous(parent->document()); 8114 newDisplay = FLEX; 8115 } else { 8116 newBox = RenderBlock::createAnonymous(parent->document()); 8117 newDisplay = BLOCK; 8118 } 8119 8120 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay); 8121 newBox->setStyle(newStyle.release()); 8122 return newBox; 8123 } 8124 8125 RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent) 8126 { 8127 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK); 8128 newStyle->inheritColumnPropertiesFrom(parent->style()); 8129 8130 RenderBlock* newBox = RenderBlock::createAnonymous(parent->document()); 8131 newBox->setStyle(newStyle.release()); 8132 return newBox; 8133 } 8134 8135 RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent) 8136 { 8137 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK); 8138 newStyle->setColumnSpan(ColumnSpanAll); 8139 8140 RenderBlock* newBox = RenderBlock::createAnonymous(parent->document()); 8141 newBox->setStyle(newStyle.release()); 8142 return newBox; 8143 } 8144 8145 #ifndef NDEBUG 8146 void RenderBlock::checkPositionedObjectsNeedLayout() 8147 { 8148 if (!gPositionedDescendantsMap) 8149 return; 8150 8151 if (TrackedRendererListHashSet* positionedDescendantSet = positionedObjects()) { 8152 TrackedRendererListHashSet::const_iterator end = positionedDescendantSet->end(); 8153 for (TrackedRendererListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) { 8154 RenderBox* currBox = *it; 8155 ASSERT(!currBox->needsLayout()); 8156 } 8157 } 8158 } 8159 8160 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const 8161 { 8162 showRenderObject(); 8163 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) 8164 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1); 8165 } 8166 8167 // These helpers are only used by the PODIntervalTree for debugging purposes. 8168 String ValueToString<int>::string(const int value) 8169 { 8170 return String::number(value); 8171 } 8172 8173 String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject) 8174 { 8175 return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY()); 8176 } 8177 8178 8179 #endif 8180 8181 } // namespace WebCore 8182