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