1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2007 David Smith (catfish.man (at) gmail.com) 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 #include "RenderBlock.h" 25 26 #include "Document.h" 27 #include "Element.h" 28 #include "FloatQuad.h" 29 #include "Frame.h" 30 #include "FrameView.h" 31 #include "GraphicsContext.h" 32 #include "HTMLFormElement.h" 33 #include "HTMLNames.h" 34 #include "HitTestResult.h" 35 #include "InlineTextBox.h" 36 #include "RenderFlexibleBox.h" 37 #include "RenderImage.h" 38 #include "RenderInline.h" 39 #include "RenderMarquee.h" 40 #include "RenderReplica.h" 41 #include "RenderTableCell.h" 42 #include "RenderTextFragment.h" 43 #include "RenderTheme.h" 44 #include "RenderView.h" 45 #include "SelectionController.h" 46 #include "Settings.h" 47 #include "TransformState.h" 48 #include <wtf/StdLibExtras.h> 49 50 #ifdef ANDROID_LAYOUT 51 #include "Settings.h" 52 #endif 53 54 using namespace std; 55 using namespace WTF; 56 using namespace Unicode; 57 58 namespace WebCore { 59 60 // Number of pixels to allow as a fudge factor when clicking above or below a line. 61 // clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line. 62 static const int verticalLineClickFudgeFactor = 3; 63 64 using namespace HTMLNames; 65 66 struct ColumnInfo : public Noncopyable { 67 ColumnInfo() 68 : m_desiredColumnWidth(0) 69 , m_desiredColumnCount(1) 70 { } 71 int m_desiredColumnWidth; 72 unsigned m_desiredColumnCount; 73 Vector<IntRect> m_columnRects; 74 }; 75 76 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap; 77 static ColumnInfoMap* gColumnInfoMap = 0; 78 79 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap; 80 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; 81 82 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; 83 static PercentHeightContainerMap* gPercentHeightContainerMap = 0; 84 85 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; 86 87 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet; 88 static int gDelayUpdateScrollInfo = 0; 89 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; 90 91 // Our MarginInfo state used when laying out block children. 92 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) 93 { 94 // Whether or not we can collapse our own margins with our children. We don't do this 95 // if we had any border/padding (obviously), if we're the root or HTML elements, or if 96 // we're positioned, floating, a table cell. 97 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() && 98 !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable(); 99 100 m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE; 101 102 // If any height other than auto is specified in CSS, then we don't collapse our bottom 103 // margins with our children's margins. To do otherwise would be to risk odd visual 104 // effects when the children overflow out of the parent block and yet still collapse 105 // with it. We also don't collapse if we have any bottom border/padding. 106 m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) && 107 (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE; 108 109 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD || 110 block->style()->marginBottomCollapse() == MDISCARD; 111 112 m_atTopOfBlock = true; 113 m_atBottomOfBlock = false; 114 115 m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0; 116 m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0; 117 118 m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false; 119 } 120 121 // ------------------------------------------------------------------------------------------------------- 122 123 RenderBlock::RenderBlock(Node* node) 124 : RenderBox(node) 125 , m_floatingObjects(0) 126 , m_positionedObjects(0) 127 , m_inlineContinuation(0) 128 , m_maxMargin(0) 129 , m_lineHeight(-1) 130 { 131 setChildrenInline(true); 132 } 133 134 RenderBlock::~RenderBlock() 135 { 136 delete m_floatingObjects; 137 delete m_positionedObjects; 138 delete m_maxMargin; 139 140 if (hasColumns()) 141 delete gColumnInfoMap->take(this); 142 143 if (gPercentHeightDescendantsMap) { 144 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) { 145 HashSet<RenderBox*>::iterator end = descendantSet->end(); 146 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { 147 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant); 148 ASSERT(containerSet); 149 if (!containerSet) 150 continue; 151 ASSERT(containerSet->contains(this)); 152 containerSet->remove(this); 153 if (containerSet->isEmpty()) { 154 gPercentHeightContainerMap->remove(*descendant); 155 delete containerSet; 156 } 157 } 158 delete descendantSet; 159 } 160 } 161 } 162 163 void RenderBlock::destroy() 164 { 165 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will 166 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. 167 children()->destroyLeftoverChildren(); 168 169 // Destroy our continuation before anything other than anonymous children. 170 // The reason we don't destroy it before anonymous children is that they may 171 // have continuations of their own that are anonymous children of our continuation. 172 if (m_inlineContinuation) { 173 m_inlineContinuation->destroy(); 174 m_inlineContinuation = 0; 175 } 176 177 if (!documentBeingDestroyed()) { 178 if (firstLineBox()) { 179 // We can't wait for RenderBox::destroy to clear the selection, 180 // because by then we will have nuked the line boxes. 181 // FIXME: The SelectionController should be responsible for this when it 182 // is notified of DOM mutations. 183 if (isSelectionBorder()) 184 view()->clearSelection(); 185 186 // If we are an anonymous block, then our line boxes might have children 187 // that will outlast this block. In the non-anonymous block case those 188 // children will be destroyed by the time we return from this function. 189 if (isAnonymousBlock()) { 190 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) { 191 while (InlineBox* childBox = box->firstChild()) 192 childBox->remove(); 193 } 194 } 195 } else if (isInline() && parent()) 196 parent()->dirtyLinesFromChangedChild(this); 197 } 198 199 m_lineBoxes.deleteLineBoxes(renderArena()); 200 201 RenderBox::destroy(); 202 } 203 204 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 205 { 206 setReplaced(newStyle->isDisplayReplacedType()); 207 208 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) { 209 if (newStyle->position() == StaticPosition) 210 // Clear our positioned objects list. Our absolutely positioned descendants will be 211 // inserted into our containing block's positioned objects list during layout. 212 removePositionedObjects(0); 213 else if (style()->position() == StaticPosition) { 214 // Remove our absolutely positioned descendants from their current containing block. 215 // They will be inserted into our positioned objects list during layout. 216 RenderObject* cb = parent(); 217 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { 218 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { 219 cb = cb->containingBlock(); 220 break; 221 } 222 cb = cb->parent(); 223 } 224 225 if (cb->isRenderBlock()) 226 toRenderBlock(cb)->removePositionedObjects(this); 227 } 228 } 229 230 RenderBox::styleWillChange(diff, newStyle); 231 } 232 233 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 234 { 235 RenderBox::styleDidChange(diff, oldStyle); 236 237 // FIXME: We could save this call when the change only affected non-inherited properties 238 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 239 if (child->isAnonymousBlock()) { 240 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 241 newStyle->inheritFrom(style()); 242 newStyle->setDisplay(BLOCK); 243 child->setStyle(newStyle.release()); 244 } 245 } 246 247 m_lineHeight = -1; 248 249 // Update pseudos for :before and :after now. 250 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { 251 updateBeforeAfterContent(BEFORE); 252 updateBeforeAfterContent(AFTER); 253 } 254 updateFirstLetter(); 255 } 256 257 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId) 258 { 259 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. 260 if (parent() && parent()->createsAnonymousWrapper()) 261 return; 262 return children()->updateBeforeAfterContent(this, pseudoId); 263 } 264 265 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) 266 { 267 // Make sure we don't append things after :after-generated content if we have it. 268 if (!beforeChild && isAfterContent(lastChild())) 269 beforeChild = lastChild(); 270 271 bool madeBoxesNonInline = false; 272 273 // If the requested beforeChild is not one of our children, then this is because 274 // there is an anonymous container within this object that contains the beforeChild. 275 if (beforeChild && beforeChild->parent() != this) { 276 RenderObject* anonymousChild = beforeChild->parent(); 277 ASSERT(anonymousChild); 278 279 while (anonymousChild->parent() != this) 280 anonymousChild = anonymousChild->parent(); 281 282 ASSERT(anonymousChild->isAnonymous()); 283 284 if (anonymousChild->isAnonymousBlock()) { 285 // Insert the child into the anonymous block box instead of here. 286 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) 287 beforeChild->parent()->addChild(newChild, beforeChild); 288 else 289 addChild(newChild, beforeChild->parent()); 290 return; 291 } 292 293 ASSERT(anonymousChild->isTable()); 294 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) 295 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) 296 || newChild->isTableSection() 297 || newChild->isTableRow() 298 || newChild->isTableCell()) { 299 // Insert into the anonymous table. 300 anonymousChild->addChild(newChild, beforeChild); 301 return; 302 } 303 304 // Go on to insert before the anonymous table. 305 beforeChild = anonymousChild; 306 } 307 308 // A block has to either have all of its children inline, or all of its children as blocks. 309 // So, if our children are currently inline and a block child has to be inserted, we move all our 310 // inline children into anonymous block boxes. 311 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { 312 // This is a block with inline content. Wrap the inline content in anonymous blocks. 313 makeChildrenNonInline(beforeChild); 314 madeBoxesNonInline = true; 315 316 if (beforeChild && beforeChild->parent() != this) { 317 beforeChild = beforeChild->parent(); 318 ASSERT(beforeChild->isAnonymousBlock()); 319 ASSERT(beforeChild->parent() == this); 320 } 321 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) { 322 // If we're inserting an inline child but all of our children are blocks, then we have to make sure 323 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise 324 // a new one is created and inserted into our list of children in the appropriate position. 325 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild(); 326 327 if (afterChild && afterChild->isAnonymousBlock()) { 328 afterChild->addChild(newChild); 329 return; 330 } 331 332 if (newChild->isInline()) { 333 // No suitable existing anonymous box - create a new one. 334 RenderBlock* newBox = createAnonymousBlock(); 335 RenderBox::addChild(newBox, beforeChild); 336 newBox->addChild(newChild); 337 return; 338 } 339 } 340 341 RenderBox::addChild(newChild, beforeChild); 342 343 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) 344 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 345 // this object may be dead here 346 } 347 348 static void getInlineRun(RenderObject* start, RenderObject* boundary, 349 RenderObject*& inlineRunStart, 350 RenderObject*& inlineRunEnd) 351 { 352 // Beginning at |start| we find the largest contiguous run of inlines that 353 // we can. We denote the run with start and end points, |inlineRunStart| 354 // and |inlineRunEnd|. Note that these two values may be the same if 355 // we encounter only one inline. 356 // 357 // We skip any non-inlines we encounter as long as we haven't found any 358 // inlines yet. 359 // 360 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary| 361 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered 362 // a non-inline. 363 364 // Start by skipping as many non-inlines as we can. 365 RenderObject * curr = start; 366 bool sawInline; 367 do { 368 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) 369 curr = curr->nextSibling(); 370 371 inlineRunStart = inlineRunEnd = curr; 372 373 if (!curr) 374 return; // No more inline children to be found. 375 376 sawInline = curr->isInline(); 377 378 curr = curr->nextSibling(); 379 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) { 380 inlineRunEnd = curr; 381 if (curr->isInline()) 382 sawInline = true; 383 curr = curr->nextSibling(); 384 } 385 } while (!sawInline); 386 } 387 388 void RenderBlock::deleteLineBoxTree() 389 { 390 m_lineBoxes.deleteLineBoxTree(renderArena()); 391 } 392 393 RootInlineBox* RenderBlock::createRootInlineBox() 394 { 395 return new (renderArena()) RootInlineBox(this); 396 } 397 398 RootInlineBox* RenderBlock::createAndAppendRootInlineBox() 399 { 400 RootInlineBox* rootBox = createRootInlineBox(); 401 m_lineBoxes.appendLineBox(rootBox); 402 return rootBox; 403 } 404 405 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child) 406 { 407 ASSERT(this == child->parent()); 408 toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); 409 } 410 411 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child) 412 { 413 ASSERT(this == child->parent()); 414 ASSERT(!beforeChild || to == beforeChild->parent()); 415 toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); 416 } 417 418 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList) 419 { 420 RenderObject* nextChild = children()->firstChild(); 421 while (nextChild) { 422 RenderObject* child = nextChild; 423 nextChild = child->nextSibling(); 424 toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); 425 } 426 } 427 428 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild) 429 { 430 ASSERT(!beforeChild || to == beforeChild->parent()); 431 if (!beforeChild) { 432 moveAllChildrenTo(to, toChildList); 433 return; 434 } 435 RenderObject* nextChild = children()->firstChild(); 436 while (nextChild) { 437 RenderObject* child = nextChild; 438 nextChild = child->nextSibling(); 439 toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); 440 } 441 } 442 443 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) 444 { 445 // makeChildrenNonInline takes a block whose children are *all* inline and it 446 // makes sure that inline children are coalesced under anonymous 447 // blocks. If |insertionPoint| is defined, then it represents the insertion point for 448 // the new block child that is causing us to have to wrap all the inlines. This 449 // means that we cannot coalesce inlines before |insertionPoint| with inlines following 450 // |insertionPoint|, because the new child is going to be inserted in between the inlines, 451 // splitting them. 452 ASSERT(isInlineBlockOrInlineTable() || !isInline()); 453 ASSERT(!insertionPoint || insertionPoint->parent() == this); 454 455 setChildrenInline(false); 456 457 RenderObject *child = firstChild(); 458 if (!child) 459 return; 460 461 deleteLineBoxTree(); 462 463 while (child) { 464 RenderObject *inlineRunStart, *inlineRunEnd; 465 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); 466 467 if (!inlineRunStart) 468 break; 469 470 child = inlineRunEnd->nextSibling(); 471 472 RenderBlock* block = createAnonymousBlock(); 473 children()->insertChildNode(this, block, inlineRunStart); 474 RenderObject* o = inlineRunStart; 475 while (o != inlineRunEnd) { 476 RenderObject* no = o; 477 o = no->nextSibling(); 478 479 moveChildTo(block, block->children(), no); 480 } 481 moveChildTo(block, block->children(), inlineRunEnd); 482 } 483 484 #ifndef NDEBUG 485 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) 486 ASSERT(!c->isInline()); 487 #endif 488 489 repaint(); 490 } 491 492 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) 493 { 494 ASSERT(child->isAnonymousBlock()); 495 ASSERT(!child->childrenInline()); 496 497 if (child->inlineContinuation()) 498 return; 499 500 RenderObject* firstAnChild = child->m_children.firstChild(); 501 RenderObject* lastAnChild = child->m_children.lastChild(); 502 if (firstAnChild) { 503 RenderObject* o = firstAnChild; 504 while (o) { 505 o->setParent(this); 506 o = o->nextSibling(); 507 } 508 firstAnChild->setPreviousSibling(child->previousSibling()); 509 lastAnChild->setNextSibling(child->nextSibling()); 510 if (child->previousSibling()) 511 child->previousSibling()->setNextSibling(firstAnChild); 512 if (child->nextSibling()) 513 child->nextSibling()->setPreviousSibling(lastAnChild); 514 } else { 515 if (child->previousSibling()) 516 child->previousSibling()->setNextSibling(child->nextSibling()); 517 if (child->nextSibling()) 518 child->nextSibling()->setPreviousSibling(child->previousSibling()); 519 } 520 if (child == m_children.firstChild()) 521 m_children.setFirstChild(firstAnChild); 522 if (child == m_children.lastChild()) 523 m_children.setLastChild(lastAnChild); 524 child->setParent(0); 525 child->setPreviousSibling(0); 526 child->setNextSibling(0); 527 528 child->children()->setFirstChild(0); 529 child->m_next = 0; 530 531 child->destroy(); 532 } 533 534 void RenderBlock::removeChild(RenderObject* oldChild) 535 { 536 // If this child is a block, and if our previous and next siblings are 537 // both anonymous blocks with inline content, then we can go ahead and 538 // fold the inline content back together. 539 RenderObject* prev = oldChild->previousSibling(); 540 RenderObject* next = oldChild->nextSibling(); 541 bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && 542 (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) && 543 (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) && 544 (!next || (next->isAnonymousBlock() && next->childrenInline())); 545 if (canDeleteAnonymousBlocks && prev && next) { 546 // Take all the children out of the |next| block and put them in 547 // the |prev| block. 548 prev->setNeedsLayoutAndPrefWidthsRecalc(); 549 RenderBlock* nextBlock = toRenderBlock(next); 550 RenderBlock* prevBlock = toRenderBlock(prev); 551 nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children()); 552 // Delete the now-empty block's lines and nuke it. 553 nextBlock->deleteLineBoxTree(); 554 nextBlock->destroy(); 555 } 556 557 RenderBox::removeChild(oldChild); 558 559 RenderObject* child = prev ? prev : next; 560 if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { 561 // The removal has knocked us down to containing only a single anonymous 562 // box. We can go ahead and pull the content right back up into our 563 // box. 564 setNeedsLayoutAndPrefWidthsRecalc(); 565 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); 566 setChildrenInline(true); 567 anonBlock->moveAllChildrenTo(this, children()); 568 // Delete the now-empty block's lines and nuke it. 569 anonBlock->deleteLineBoxTree(); 570 anonBlock->destroy(); 571 } 572 573 // If this was our last child be sure to clear out our line boxes. 574 if (childrenInline() && !firstChild()) 575 lineBoxes()->deleteLineBoxes(renderArena()); 576 } 577 578 bool RenderBlock::isSelfCollapsingBlock() const 579 { 580 // We are not self-collapsing if we 581 // (a) have a non-zero height according to layout (an optimization to avoid wasting time) 582 // (b) are a table, 583 // (c) have border/padding, 584 // (d) have a min-height 585 // (e) have specified that one of our margins can't collapse using a CSS extension 586 if (height() > 0 || 587 isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || 588 style()->minHeight().isPositive() || 589 style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) 590 return false; 591 592 bool hasAutoHeight = style()->height().isAuto(); 593 if (style()->height().isPercent() && !style()->htmlHacks()) { 594 hasAutoHeight = true; 595 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { 596 if (cb->style()->height().isFixed() || cb->isTableCell()) 597 hasAutoHeight = false; 598 } 599 } 600 601 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends 602 // on whether we have content that is all self-collapsing or not. 603 if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) { 604 // If the block has inline children, see if we generated any line boxes. If we have any 605 // line boxes, then we can't be self-collapsing, since we have content. 606 if (childrenInline()) 607 return !firstLineBox(); 608 609 // Whether or not we collapse is dependent on whether all our normal flow children 610 // are also self-collapsing. 611 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 612 if (child->isFloatingOrPositioned()) 613 continue; 614 if (!child->isSelfCollapsingBlock()) 615 return false; 616 } 617 return true; 618 } 619 return false; 620 } 621 622 void RenderBlock::startDelayUpdateScrollInfo() 623 { 624 if (gDelayUpdateScrollInfo == 0) { 625 ASSERT(!gDelayedUpdateScrollInfoSet); 626 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; 627 } 628 ASSERT(gDelayedUpdateScrollInfoSet); 629 ++gDelayUpdateScrollInfo; 630 } 631 632 void RenderBlock::finishDelayUpdateScrollInfo() 633 { 634 --gDelayUpdateScrollInfo; 635 ASSERT(gDelayUpdateScrollInfo >= 0); 636 if (gDelayUpdateScrollInfo == 0) { 637 ASSERT(gDelayedUpdateScrollInfoSet); 638 639 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet); 640 gDelayedUpdateScrollInfoSet = 0; 641 642 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { 643 RenderBlock* block = *it; 644 if (block->hasOverflowClip()) { 645 block->layer()->updateScrollInfoAfterLayout(); 646 } 647 } 648 } 649 } 650 651 void RenderBlock::updateScrollInfoAfterLayout() 652 { 653 if (hasOverflowClip()) { 654 if (gDelayUpdateScrollInfo) 655 gDelayedUpdateScrollInfoSet->add(this); 656 else 657 layer()->updateScrollInfoAfterLayout(); 658 } 659 } 660 661 void RenderBlock::layout() 662 { 663 // Update our first letter info now. 664 updateFirstLetter(); 665 666 // Table cells call layoutBlock directly, so don't add any logic here. Put code into 667 // layoutBlock(). 668 layoutBlock(false); 669 670 // It's safe to check for control clip here, since controls can never be table cells. 671 // If we have a lightweight clip, there can never be any overflow from children. 672 if (hasControlClip() && m_overflow) 673 clearLayoutOverflow(); 674 } 675 676 void RenderBlock::layoutBlock(bool relayoutChildren) 677 { 678 ASSERT(needsLayout()); 679 680 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can 681 return; // cause us to come in here. Just bail. 682 683 if (!relayoutChildren && layoutOnlyPositionedObjects()) 684 return; 685 686 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); 687 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 688 689 int oldWidth = width(); 690 int oldColumnWidth = desiredColumnWidth(); 691 692 #ifdef ANDROID_LAYOUT 693 int oldVisibleWidth = m_visibleWidth; 694 #endif 695 696 calcWidth(); 697 calcColumnWidth(); 698 699 m_overflow.clear(); 700 701 if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) 702 relayoutChildren = true; 703 704 #ifdef ANDROID_LAYOUT 705 const Settings* settings = document()->settings(); 706 ASSERT(settings); 707 if (oldVisibleWidth != m_visibleWidth 708 && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) 709 relayoutChildren = true; 710 #endif 711 712 clearFloats(); 713 714 int previousHeight = height(); 715 setHeight(0); 716 717 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 718 // our current maximal positive and negative margins. These values are used when we 719 // are collapsed with adjacent blocks, so for example, if you have block A and B 720 // collapsing together, then you'd take the maximal positive margin from both A and B 721 // and subtract it from the maximal negative margin from both A and B to get the 722 // true collapsed margin. This algorithm is recursive, so when we finish layout() 723 // our block knows its current maximal positive/negative values. 724 // 725 // Start out by setting our margin values to our current margins. Table cells have 726 // no margins, so we don't fill in the values for table cells. 727 bool isCell = isTableCell(); 728 if (!isCell) { 729 initMaxMarginValues(); 730 731 setTopMarginQuirk(style()->marginTop().quirk()); 732 setBottomMarginQuirk(style()->marginBottom().quirk()); 733 734 Node* n = node(); 735 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { 736 // See if this form is malformed (i.e., unclosed). If so, don't give the form 737 // a bottom margin. 738 setMaxBottomMargins(0, 0); 739 } 740 } 741 742 // For overflow:scroll blocks, ensure we have both scrollbars in place always. 743 if (scrollsOverflow()) { 744 if (style()->overflowX() == OSCROLL) 745 layer()->setHasHorizontalScrollbar(true); 746 if (style()->overflowY() == OSCROLL) 747 layer()->setHasVerticalScrollbar(true); 748 } 749 750 int repaintTop = 0; 751 int repaintBottom = 0; 752 int maxFloatBottom = 0; 753 if (childrenInline()) 754 layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); 755 else 756 layoutBlockChildren(relayoutChildren, maxFloatBottom); 757 758 // Expand our intrinsic height to encompass floats. 759 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 760 if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) 761 setHeight(floatBottom() + toAdd); 762 763 // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as 764 // we adjust for clean column breaks. 765 int singleColumnBottom = layoutColumns(); 766 767 // Calculate our new height. 768 int oldHeight = height(); 769 calcHeight(); 770 if (oldHeight != height()) { 771 if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) { 772 // One of our children's floats may have become an overhanging float for us. We need to look for it. 773 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 774 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { 775 RenderBlock* block = toRenderBlock(child); 776 if (block->floatBottom() + block->y() > height()) 777 addOverhangingFloats(block, -block->x(), -block->y(), false); 778 } 779 } 780 } 781 782 // We have to rebalance columns to the new height. 783 layoutColumns(singleColumnBottom); 784 } 785 786 if (previousHeight != height()) 787 relayoutChildren = true; 788 789 // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't 790 // able to be propagated up the render tree yet. Overflow information is however. This check is designed to catch anyone 791 // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor. 792 if (isRoot() || expandsToEncloseOverhangingFloats()) 793 addOverflowFromFloats(); 794 795 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 796 if (!hasColumns()) { 797 if (childrenInline()) 798 addOverflowFromInlineChildren(); 799 else 800 addOverflowFromBlockChildren(); 801 } 802 803 // Add visual overflow from box-shadow and reflections. 804 addShadowOverflow(); 805 806 layoutPositionedObjects(relayoutChildren || isRoot()); 807 808 positionListMarker(); 809 810 statePusher.pop(); 811 812 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 813 // we overflow or not. 814 updateScrollInfoAfterLayout(); 815 816 // Repaint with our new bounds if they are different from our old bounds. 817 bool didFullRepaint = repainter.repaintAfterLayout(); 818 if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { 819 int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow()); 820 int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow()); 821 IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop); 822 823 // FIXME: Deal with multiple column repainting. We have to split the repaint 824 // rect up into multiple rects if it spans columns. 825 826 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); 827 828 if (hasOverflowClip()) { 829 // Adjust repaint rect for scroll offset 830 int x = repaintRect.x(); 831 int y = repaintRect.y(); 832 layer()->subtractScrolledContentOffset(x, y); 833 repaintRect.setX(x); 834 repaintRect.setY(y); 835 836 // Don't allow this rect to spill out of our overflow box. 837 repaintRect.intersect(IntRect(0, 0, width(), height())); 838 } 839 840 // Make sure the rect is still non-empty after intersecting for overflow above 841 if (!repaintRect.isEmpty()) { 842 repaintRectangle(repaintRect); // We need to do a partial repaint of our content. 843 if (hasReflection()) 844 repaintRectangle(reflectedRect(repaintRect)); 845 } 846 } 847 setNeedsLayout(false); 848 } 849 850 void RenderBlock::addOverflowFromBlockChildren() 851 { 852 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 853 if (!child->isFloatingOrPositioned()) 854 addOverflowFromChild(child); 855 } 856 } 857 858 void RenderBlock::addOverflowFromFloats() 859 { 860 IntRect result; 861 if (!m_floatingObjects) 862 return; 863 FloatingObject* r; 864 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 865 for (; (r = it.current()); ++it) { 866 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) 867 addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); 868 } 869 return; 870 } 871 872 bool RenderBlock::expandsToEncloseOverhangingFloats() const 873 { 874 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset(); 875 } 876 877 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 878 { 879 if (child->style()->hasStaticX()) { 880 if (style()->direction() == LTR) 881 child->layer()->setStaticX(borderLeft() + paddingLeft()); 882 else 883 child->layer()->setStaticX(borderRight() + paddingRight()); 884 } 885 886 if (child->style()->hasStaticY()) { 887 int y = height(); 888 if (!marginInfo.canCollapseWithTop()) { 889 child->calcVerticalMargins(); 890 int marginTop = child->marginTop(); 891 int collapsedTopPos = marginInfo.posMargin(); 892 int collapsedTopNeg = marginInfo.negMargin(); 893 if (marginTop > 0) { 894 if (marginTop > collapsedTopPos) 895 collapsedTopPos = marginTop; 896 } else { 897 if (-marginTop > collapsedTopNeg) 898 collapsedTopNeg = -marginTop; 899 } 900 y += (collapsedTopPos - collapsedTopNeg) - marginTop; 901 } 902 RenderLayer* childLayer = child->layer(); 903 if (childLayer->staticY() != y) { 904 child->layer()->setStaticY(y); 905 child->setChildNeedsLayout(true, false); 906 } 907 } 908 } 909 910 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) 911 { 912 // The float should be positioned taking into account the bottom margin 913 // of the previous flow. We add that margin into the height, get the 914 // float positioned properly, and then subtract the margin out of the 915 // height again. In the case of self-collapsing blocks, we always just 916 // use the top margins, since the self-collapsing block collapsed its 917 // own bottom margin into its top margin. 918 // 919 // Note also that the previous flow may collapse its margin into the top of 920 // our block. If this is the case, then we do not add the margin in to our 921 // height when computing the position of the float. This condition can be tested 922 // for by simply calling canCollapseWithTop. See 923 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 924 // an example of this scenario. 925 int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); 926 setHeight(height() + marginOffset); 927 positionNewFloats(); 928 setHeight(height() - marginOffset); 929 } 930 931 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) 932 { 933 // Handle in the given order 934 return handlePositionedChild(child, marginInfo) 935 || handleFloatingChild(child, marginInfo) 936 || handleRunInChild(child); 937 } 938 939 940 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) 941 { 942 if (child->isPositioned()) { 943 child->containingBlock()->insertPositionedObject(child); 944 adjustPositionedBlock(child, marginInfo); 945 return true; 946 } 947 return false; 948 } 949 950 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) 951 { 952 if (child->isFloating()) { 953 insertFloatingObject(child); 954 adjustFloatingBlock(marginInfo); 955 return true; 956 } 957 return false; 958 } 959 960 bool RenderBlock::handleRunInChild(RenderBox* child) 961 { 962 // See if we have a run-in element with inline children. If the 963 // children aren't inline, then just treat the run-in as a normal 964 // block. 965 if (!child->isRunIn() || !child->childrenInline()) 966 return false; 967 // FIXME: We don't handle non-block elements with run-in for now. 968 if (!child->isRenderBlock()) 969 return false; 970 971 // Get the next non-positioned/non-floating RenderBlock. 972 RenderBlock* blockRunIn = toRenderBlock(child); 973 RenderObject* curr = blockRunIn->nextSibling(); 974 while (curr && curr->isFloatingOrPositioned()) 975 curr = curr->nextSibling(); 976 977 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous()) 978 return false; 979 980 RenderBlock* currBlock = toRenderBlock(curr); 981 982 // Remove the old child. 983 children()->removeChildNode(this, blockRunIn); 984 985 // Create an inline. 986 Node* runInNode = blockRunIn->node(); 987 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); 988 inlineRunIn->setStyle(blockRunIn->style()); 989 990 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER; 991 992 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already 993 // been regenerated by the new inline. 994 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { 995 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) { 996 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); 997 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. 998 } 999 } 1000 1001 // Now insert the new child under |currBlock|. 1002 currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); 1003 1004 // If the run-in had an element, we need to set the new renderer. 1005 if (runInNode) 1006 runInNode->setRenderer(inlineRunIn); 1007 1008 // Destroy the block run-in. 1009 blockRunIn->destroy(); 1010 1011 // The block acts like an inline, so just null out its 1012 // position. 1013 1014 return true; 1015 } 1016 1017 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) 1018 { 1019 // Get our max pos and neg top margins. 1020 int posTop = child->maxTopMargin(true); 1021 int negTop = child->maxTopMargin(false); 1022 1023 // For self-collapsing blocks, collapse our bottom margins into our 1024 // top to get new posTop and negTop values. 1025 if (child->isSelfCollapsingBlock()) { 1026 posTop = max(posTop, child->maxBottomMargin(true)); 1027 negTop = max(negTop, child->maxBottomMargin(false)); 1028 } 1029 1030 // See if the top margin is quirky. We only care if this child has 1031 // margins that will collapse with us. 1032 bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD; 1033 1034 if (marginInfo.canCollapseWithTop()) { 1035 // This child is collapsing with the top of the 1036 // block. If it has larger margin values, then we need to update 1037 // our own maximal values. 1038 if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) 1039 setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin())); 1040 1041 // The minute any of the margins involved isn't a quirk, don't 1042 // collapse it away, even if the margin is smaller (www.webreference.com 1043 // has an example of this, a <dt> with 0.8em author-specified inside 1044 // a <dl> inside a <td>. 1045 if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { 1046 setTopMarginQuirk(false); 1047 marginInfo.setDeterminedTopQuirk(true); 1048 } 1049 1050 if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0) 1051 // We have no top margin and our top child has a quirky margin. 1052 // We will pick up this quirky margin and pass it through. 1053 // This deals with the <td><div><p> case. 1054 // Don't do this for a block that split two inlines though. You do 1055 // still apply margins in this case. 1056 setTopMarginQuirk(true); 1057 } 1058 1059 if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) 1060 marginInfo.setTopQuirk(topQuirk); 1061 1062 int ypos = height(); 1063 if (child->isSelfCollapsingBlock()) { 1064 // This child has no height. We need to compute our 1065 // position before we collapse the child's margins together, 1066 // so that we can get an accurate position for the zero-height block. 1067 int collapsedTopPos = max(marginInfo.posMargin(), child->maxTopMargin(true)); 1068 int collapsedTopNeg = max(marginInfo.negMargin(), child->maxTopMargin(false)); 1069 marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); 1070 1071 // Now collapse the child's margins together, which means examining our 1072 // bottom margin values as well. 1073 marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true)); 1074 marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false)); 1075 1076 if (!marginInfo.canCollapseWithTop()) 1077 // We need to make sure that the position of the self-collapsing block 1078 // is correct, since it could have overflowing content 1079 // that needs to be positioned correctly (e.g., a block that 1080 // had a specified height of 0 but that actually had subcontent). 1081 ypos = height() + collapsedTopPos - collapsedTopNeg; 1082 } 1083 else { 1084 if (child->style()->marginTopCollapse() == MSEPARATE) { 1085 setHeight(height() + marginInfo.margin() + child->marginTop()); 1086 ypos = height(); 1087 } 1088 else if (!marginInfo.atTopOfBlock() || 1089 (!marginInfo.canCollapseTopWithChildren() 1090 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { 1091 // We're collapsing with a previous sibling's margins and not 1092 // with the top of the block. 1093 setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); 1094 ypos = height(); 1095 } 1096 1097 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1098 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1099 1100 if (marginInfo.margin()) 1101 marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD); 1102 } 1103 1104 return ypos; 1105 } 1106 1107 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) 1108 { 1109 int heightIncrease = getClearDelta(child, yPos); 1110 if (!heightIncrease) 1111 return yPos; 1112 1113 if (child->isSelfCollapsingBlock()) { 1114 // For self-collapsing blocks that clear, they can still collapse their 1115 // margins with following siblings. Reset the current margins to represent 1116 // the self-collapsing block's margins only. 1117 // CSS2.1 states: 1118 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin. 1119 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the 1120 // self-collapsing block's bottom margin. 1121 bool atBottomOfBlock = true; 1122 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) { 1123 if (!curr->isFloatingOrPositioned()) 1124 atBottomOfBlock = false; 1125 } 1126 if (atBottomOfBlock) { 1127 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1128 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1129 } else { 1130 marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true))); 1131 marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); 1132 } 1133 1134 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom 1135 // of the parent block). 1136 setHeight(child->y() - max(0, marginInfo.margin())); 1137 } else 1138 // Increase our height by the amount we had to clear. 1139 setHeight(height() + heightIncrease); 1140 1141 if (marginInfo.canCollapseWithTop()) { 1142 // We can no longer collapse with the top of the block since a clear 1143 // occurred. The empty blocks collapse into the cleared block. 1144 // FIXME: This isn't quite correct. Need clarification for what to do 1145 // if the height the cleared block is offset by is smaller than the 1146 // margins involved. 1147 setMaxTopMargins(oldTopPosMargin, oldTopNegMargin); 1148 marginInfo.setAtTopOfBlock(false); 1149 } 1150 1151 return yPos + heightIncrease; 1152 } 1153 1154 int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) 1155 { 1156 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 1157 // relayout if there are intruding floats. 1158 int yPosEstimate = height(); 1159 if (!marginInfo.canCollapseWithTop()) { 1160 int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); 1161 yPosEstimate += max(marginInfo.margin(), childMarginTop); 1162 } 1163 yPosEstimate += getClearDelta(child, yPosEstimate); 1164 return yPosEstimate; 1165 } 1166 1167 void RenderBlock::determineHorizontalPosition(RenderBox* child) 1168 { 1169 if (style()->direction() == LTR) { 1170 int xPos = borderLeft() + paddingLeft(); 1171 1172 // Add in our left margin. 1173 int chPos = xPos + child->marginLeft(); 1174 1175 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need 1176 // to shift over as necessary to dodge any floats that might get in the way. 1177 if (child->avoidsFloats()) { 1178 int leftOff = leftOffset(height(), false); 1179 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { 1180 if (child->marginLeft() < 0) 1181 leftOff += child->marginLeft(); 1182 chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit. 1183 } 1184 else if (leftOff != xPos) { 1185 // The object is shifting right. The object might be centered, so we need to 1186 // recalculate our horizontal margins. Note that the containing block content 1187 // width computation will take into account the delta between |leftOff| and |xPos| 1188 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1189 // function. 1190 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1191 chPos = leftOff + child->marginLeft(); 1192 } 1193 } 1194 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1195 child->setLocation(chPos, child->y()); 1196 } else { 1197 int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); 1198 int chPos = xPos - (child->width() + child->marginRight()); 1199 if (child->avoidsFloats()) { 1200 int rightOff = rightOffset(height(), false); 1201 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { 1202 if (child->marginRight() < 0) 1203 rightOff -= child->marginRight(); 1204 chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. 1205 } else if (rightOff != xPos) { 1206 // The object is shifting left. The object might be centered, so we need to 1207 // recalculate our horizontal margins. Note that the containing block content 1208 // width computation will take into account the delta between |rightOff| and |xPos| 1209 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1210 // function. 1211 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1212 chPos = rightOff - child->marginRight() - child->width(); 1213 } 1214 } 1215 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1216 child->setLocation(chPos, child->y()); 1217 } 1218 } 1219 1220 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) 1221 { 1222 if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) { 1223 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 1224 // with our children. 1225 setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin())); 1226 1227 if (!marginInfo.bottomQuirk()) 1228 setBottomMarginQuirk(false); 1229 1230 if (marginInfo.bottomQuirk() && marginBottom() == 0) 1231 // We have no bottom margin and our last child has a quirky margin. 1232 // We will pick up this quirky margin and pass it through. 1233 // This deals with the <td><div><p> case. 1234 setBottomMarginQuirk(true); 1235 } 1236 } 1237 1238 void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo) 1239 { 1240 marginInfo.setAtBottomOfBlock(true); 1241 1242 // If we can't collapse with children then go ahead and add in the bottom margin. 1243 if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() 1244 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) 1245 setHeight(height() + marginInfo.margin()); 1246 1247 // Now add in our bottom border/padding. 1248 setHeight(height() + bottom); 1249 1250 // Negative margins can cause our height to shrink below our minimal height (border/padding). 1251 // If this happens, ensure that the computed height is increased to the minimal height. 1252 setHeight(max(height(), top + bottom)); 1253 1254 // Update our bottom collapsed margin info. 1255 setCollapsedBottomMargin(marginInfo); 1256 } 1257 1258 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom) 1259 { 1260 if (gPercentHeightDescendantsMap) { 1261 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { 1262 HashSet<RenderBox*>::iterator end = descendants->end(); 1263 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) { 1264 RenderBox* box = *it; 1265 while (box != this) { 1266 if (box->normalChildNeedsLayout()) 1267 break; 1268 box->setChildNeedsLayout(true, false); 1269 box = box->containingBlock(); 1270 ASSERT(box); 1271 if (!box) 1272 break; 1273 } 1274 } 1275 } 1276 } 1277 1278 int top = borderTop() + paddingTop(); 1279 int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 1280 1281 setHeight(top); 1282 1283 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 1284 MarginInfo marginInfo(this, top, bottom); 1285 1286 // Fieldsets need to find their legend and position it inside the border of the object. 1287 // The legend then gets skipped during normal layout. 1288 RenderObject* legend = layoutLegend(relayoutChildren); 1289 1290 int previousFloatBottom = 0; 1291 maxFloatBottom = 0; 1292 1293 RenderBox* next = firstChildBox(); 1294 1295 while (next) { 1296 RenderBox* child = next; 1297 next = child->nextSiblingBox(); 1298 1299 if (legend == child) 1300 continue; // Skip the legend, since it has already been positioned up in the fieldset's border. 1301 1302 // Make sure we layout children if they need it. 1303 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into 1304 // an auto value. Add a method to determine this, so that we can avoid the relayout. 1305 if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView())) 1306 child->setChildNeedsLayout(true, false); 1307 1308 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1309 if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent())) 1310 child->setPrefWidthsDirty(true, false); 1311 1312 // Handle the four types of special elements first. These include positioned content, floating content, compacts and 1313 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. 1314 if (handleSpecialChild(child, marginInfo)) 1315 continue; 1316 1317 // Lay out the child. 1318 layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom); 1319 } 1320 1321 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 1322 // determining the correct collapsed bottom margin information. 1323 handleBottomOfBlock(top, bottom, marginInfo); 1324 } 1325 1326 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom) 1327 { 1328 int oldTopPosMargin = maxTopPosMargin(); 1329 int oldTopNegMargin = maxTopNegMargin(); 1330 1331 // The child is a normal flow object. Compute its vertical margins now. 1332 child->calcVerticalMargins(); 1333 1334 // Do not allow a collapse if the margin top collapse style is set to SEPARATE. 1335 if (child->style()->marginTopCollapse() == MSEPARATE) { 1336 marginInfo.setAtTopOfBlock(false); 1337 marginInfo.clearMargin(); 1338 } 1339 1340 // Try to guess our correct y position. In most cases this guess will 1341 // be correct. Only if we're wrong (when we compute the real y position) 1342 // will we have to potentially relayout. 1343 int yPosEstimate = estimateVerticalPosition(child, marginInfo); 1344 1345 // Cache our old rect so that we can dirty the proper repaint rects if the child moves. 1346 IntRect oldRect(child->x(), child->y() , child->width(), child->height()); 1347 #ifndef NDEBUG 1348 IntSize oldLayoutDelta = view()->layoutDelta(); 1349 #endif 1350 // Go ahead and position the child as though it didn't collapse with the top. 1351 view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); 1352 child->setLocation(child->x(), yPosEstimate); 1353 1354 bool markDescendantsWithFloats = false; 1355 if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1356 markDescendantsWithFloats = true; 1357 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 1358 // If an element might be affected by the presence of floats, then always mark it for 1359 // layout. 1360 int fb = max(previousFloatBottom, floatBottom()); 1361 if (fb > yPosEstimate) 1362 markDescendantsWithFloats = true; 1363 } 1364 1365 if (child->isRenderBlock()) { 1366 if (markDescendantsWithFloats) 1367 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1368 1369 previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); 1370 } 1371 1372 bool childHadLayout = child->m_everHadLayout; 1373 bool childNeededLayout = child->needsLayout(); 1374 if (childNeededLayout) 1375 child->layout(); 1376 1377 // Now determine the correct ypos based off examination of collapsing margin 1378 // values. 1379 int yBeforeClear = collapseMargins(child, marginInfo); 1380 1381 // Now check for clear. 1382 int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); 1383 1384 view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); 1385 child->setLocation(child->x(), yAfterClear); 1386 1387 // Now we have a final y position. See if it really does end up being different from our estimate. 1388 if (yAfterClear != yPosEstimate) { 1389 if (child->shrinkToAvoidFloats()) { 1390 // The child's width depends on the line width. 1391 // When the child shifts to clear an item, its width can 1392 // change (because it has more available line width). 1393 // So go ahead and mark the item as dirty. 1394 child->setChildNeedsLayout(true, false); 1395 } 1396 if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1397 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1398 // Our guess was wrong. Make the child lay itself out again. 1399 child->layoutIfNeeded(); 1400 } 1401 1402 // We are no longer at the top of the block if we encounter a non-empty child. 1403 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 1404 if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) 1405 marginInfo.setAtTopOfBlock(false); 1406 1407 // Now place the child in the correct horizontal position 1408 determineHorizontalPosition(child); 1409 1410 // Update our height now that the child has been placed in the correct position. 1411 setHeight(height() + child->height()); 1412 if (child->style()->marginBottomCollapse() == MSEPARATE) { 1413 setHeight(height() + child->marginBottom()); 1414 marginInfo.clearMargin(); 1415 } 1416 // If the child has overhanging floats that intrude into following siblings (or possibly out 1417 // of this block), then the parent gets notified of the floats now. 1418 if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1419 maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); 1420 1421 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); 1422 if (childOffset.width() || childOffset.height()) { 1423 view()->addLayoutDelta(childOffset); 1424 1425 // If the child moved, we have to repaint it as well as any floating/positioned 1426 // descendants. An exception is if we need a layout. In this case, we know we're going to 1427 // repaint ourselves (and the child) anyway. 1428 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) 1429 child->repaintDuringLayoutIfMoved(oldRect); 1430 } 1431 1432 if (!childHadLayout && child->checkForRepaintDuringLayout()) { 1433 child->repaint(); 1434 child->repaintOverhangingFloats(true); 1435 } 1436 1437 ASSERT(oldLayoutDelta == view()->layoutDelta()); 1438 } 1439 1440 bool RenderBlock::layoutOnlyPositionedObjects() 1441 { 1442 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1443 return false; 1444 1445 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 1446 1447 if (needsPositionedMovementLayout()) { 1448 tryLayoutDoingPositionedMovementOnly(); 1449 if (needsLayout()) 1450 return false; 1451 } 1452 1453 // All we have to is lay out our positioned objects. 1454 layoutPositionedObjects(false); 1455 1456 statePusher.pop(); 1457 1458 updateScrollInfoAfterLayout(); 1459 1460 #ifdef ANDROID_FIX 1461 // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks, 1462 // which may make us need to layout again 1463 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1464 return false; 1465 #endif 1466 1467 setNeedsLayout(false); 1468 return true; 1469 } 1470 1471 void RenderBlock::layoutPositionedObjects(bool relayoutChildren) 1472 { 1473 if (m_positionedObjects) { 1474 RenderBox* r; 1475 Iterator end = m_positionedObjects->end(); 1476 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1477 r = *it; 1478 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the 1479 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned 1480 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is 1481 // positioned explicitly) this should not incur a performance penalty. 1482 if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) 1483 r->setChildNeedsLayout(true, false); 1484 1485 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1486 //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) 1487 r->setPrefWidthsDirty(true, false); 1488 1489 // 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 1490 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. 1491 if (r->needsPositionedMovementLayoutOnly()) 1492 r->tryLayoutDoingPositionedMovementOnly(); 1493 r->layoutIfNeeded(); 1494 } 1495 } 1496 } 1497 1498 void RenderBlock::markPositionedObjectsForLayout() 1499 { 1500 if (m_positionedObjects) { 1501 RenderBox* r; 1502 Iterator end = m_positionedObjects->end(); 1503 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1504 r = *it; 1505 r->setChildNeedsLayout(true); 1506 } 1507 } 1508 } 1509 1510 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) 1511 { 1512 // Repaint any overhanging floats (if we know we're the one to paint them). 1513 if (hasOverhangingFloats()) { 1514 // We think that we must be in a bad state if m_floatingObjects is nil at this point, so 1515 // we assert on Debug builds and nil-check Release builds. 1516 ASSERT(m_floatingObjects); 1517 if (!m_floatingObjects) 1518 return; 1519 1520 FloatingObject* r; 1521 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1522 1523 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating 1524 // in this block. Better yet would be to push extra state for the containers of other floats. 1525 view()->disableLayoutState(); 1526 for ( ; (r = it.current()); ++it) { 1527 // Only repaint the object if it is overhanging, is not in its own layer, and 1528 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 1529 // condition is replaced with being a descendant of us. 1530 if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { 1531 r->m_renderer->repaint(); 1532 r->m_renderer->repaintOverhangingFloats(); 1533 } 1534 } 1535 view()->enableLayoutState(); 1536 } 1537 } 1538 1539 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) 1540 { 1541 tx += x(); 1542 ty += y(); 1543 1544 PaintPhase phase = paintInfo.phase; 1545 1546 // Check if we need to do anything at all. 1547 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 1548 // paints the root's background. 1549 if (!isRoot()) { 1550 IntRect overflowBox = visibleOverflowRect(); 1551 overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); 1552 overflowBox.move(tx, ty); 1553 if (!overflowBox.intersects(paintInfo.rect)) 1554 return; 1555 } 1556 1557 bool pushedClip = pushContentsClip(paintInfo, tx, ty); 1558 paintObject(paintInfo, tx, ty); 1559 if (pushedClip) 1560 popContentsClip(paintInfo, phase, tx, ty); 1561 1562 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with 1563 // z-index. We paint after we painted the background/border, so that the scrollbars will 1564 // sit above the background/border. 1565 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo)) 1566 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); 1567 } 1568 1569 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) 1570 { 1571 const Color& ruleColor = style()->columnRuleColor(); 1572 bool ruleTransparent = style()->columnRuleIsTransparent(); 1573 EBorderStyle ruleStyle = style()->columnRuleStyle(); 1574 int ruleWidth = style()->columnRuleWidth(); 1575 int colGap = columnGap(); 1576 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; 1577 if (!renderRule) 1578 return; 1579 1580 // We need to do multiple passes, breaking up our child painting into strips. 1581 int currXOffset = 0; 1582 int ruleAdd = borderLeft() + paddingLeft(); 1583 int ruleX = 0; 1584 Vector<IntRect>* colRects = columnRects(); 1585 unsigned colCount = colRects->size(); 1586 for (unsigned i = 0; i < colCount; i++) { 1587 // For each rect, we clip to the rect, and then we adjust our coords. 1588 IntRect colRect = colRects->at(i); 1589 1590 // Move to the next position. 1591 if (style()->direction() == LTR) { 1592 ruleX += colRect.width() + colGap / 2; 1593 currXOffset += colRect.width() + colGap; 1594 } else { 1595 ruleX -= (colRect.width() + colGap / 2); 1596 currXOffset -= (colRect.width() + colGap); 1597 } 1598 1599 // Now paint the column rule. 1600 if (i < colCount - 1) { 1601 int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; 1602 int ruleEnd = ruleStart + ruleWidth; 1603 int ruleTop = ty + borderTop() + paddingTop(); 1604 int ruleBottom = ruleTop + contentHeight(); 1605 drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, 1606 style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); 1607 } 1608 1609 ruleX = currXOffset; 1610 } 1611 } 1612 1613 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) 1614 { 1615 // We need to do multiple passes, breaking up our child painting into strips. 1616 GraphicsContext* context = paintInfo.context; 1617 int currXOffset = 0; 1618 int currYOffset = 0; 1619 int colGap = columnGap(); 1620 Vector<IntRect>* colRects = columnRects(); 1621 unsigned colCount = colRects->size(); 1622 for (unsigned i = 0; i < colCount; i++) { 1623 // For each rect, we clip to the rect, and then we adjust our coords. 1624 IntRect colRect = colRects->at(i); 1625 colRect.move(tx, ty); 1626 context->save(); 1627 1628 // Each strip pushes a clip, since column boxes are specified as being 1629 // like overflow:hidden. 1630 context->clip(colRect); 1631 1632 // Adjust tx and ty to change where we paint. 1633 PaintInfo info(paintInfo); 1634 info.rect.intersect(colRect); 1635 1636 // Adjust our x and y when painting. 1637 int finalX = tx + currXOffset; 1638 int finalY = ty + currYOffset; 1639 if (paintingFloats) 1640 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); 1641 else 1642 paintContents(info, finalX, finalY); 1643 1644 // Move to the next position. 1645 if (style()->direction() == LTR) 1646 currXOffset += colRect.width() + colGap; 1647 else 1648 currXOffset -= (colRect.width() + colGap); 1649 1650 currYOffset -= colRect.height(); 1651 1652 context->restore(); 1653 } 1654 } 1655 1656 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) 1657 { 1658 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. 1659 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 1660 // will do a full repaint(). 1661 if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) 1662 return; 1663 1664 if (childrenInline()) 1665 m_lineBoxes.paint(this, paintInfo, tx, ty); 1666 else 1667 paintChildren(paintInfo, tx, ty); 1668 } 1669 1670 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) 1671 { 1672 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 1673 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 1674 1675 // We don't paint our own background, but we do let the kids paint their backgrounds. 1676 PaintInfo info(paintInfo); 1677 info.phase = newPhase; 1678 info.paintingRoot = paintingRootForChildren(paintInfo); 1679 bool isPrinting = document()->printing(); 1680 1681 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1682 // Check for page-break-before: always, and if it's set, break and bail. 1683 if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && 1684 inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && 1685 (ty + child->y()) < paintInfo.rect.bottom()) { 1686 view()->setBestTruncatedAt(ty + child->y(), this, true); 1687 return; 1688 } 1689 1690 if (!child->hasSelfPaintingLayer() && !child->isFloating()) 1691 child->paint(info, tx, ty); 1692 1693 // Check for page-break-after: always, and if it's set, break and bail. 1694 if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && 1695 inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && 1696 (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { 1697 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); 1698 return; 1699 } 1700 } 1701 } 1702 1703 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type) 1704 { 1705 SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); 1706 1707 // Paint the caret if the SelectionController says so or if caret browsing is enabled 1708 bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled(); 1709 RenderObject* caretPainter = selection->caretRenderer(); 1710 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { 1711 // Convert the painting offset into the local coordinate system of this renderer, 1712 // to match the localCaretRect computed by the SelectionController 1713 offsetForContents(tx, ty); 1714 1715 if (type == CursorCaret) 1716 document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); 1717 else 1718 document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); 1719 } 1720 } 1721 1722 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) 1723 { 1724 PaintPhase paintPhase = paintInfo.phase; 1725 1726 // 1. paint background, borders etc 1727 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { 1728 if (hasBoxDecorations()) 1729 paintBoxDecorations(paintInfo, tx, ty); 1730 if (hasColumns()) 1731 paintColumnRules(paintInfo, tx, ty); 1732 } 1733 1734 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { 1735 paintMask(paintInfo, tx, ty); 1736 return; 1737 } 1738 1739 // We're done. We don't bother painting any children. 1740 if (paintPhase == PaintPhaseBlockBackground) 1741 return; 1742 1743 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s 1744 int scrolledX = tx; 1745 int scrolledY = ty; 1746 if (hasOverflowClip()) 1747 layer()->subtractScrolledContentOffset(scrolledX, scrolledY); 1748 1749 // 2. paint contents 1750 if (paintPhase != PaintPhaseSelfOutline) { 1751 if (hasColumns()) 1752 paintColumnContents(paintInfo, scrolledX, scrolledY); 1753 else 1754 paintContents(paintInfo, scrolledX, scrolledY); 1755 } 1756 1757 // 3. paint selection 1758 // FIXME: Make this work with multi column layouts. For now don't fill gaps. 1759 bool isPrinting = document()->printing(); 1760 if (!isPrinting && !hasColumns()) 1761 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. 1762 1763 // 4. paint floats. 1764 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { 1765 if (hasColumns()) 1766 paintColumnContents(paintInfo, scrolledX, scrolledY, true); 1767 else 1768 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); 1769 } 1770 1771 // 5. paint outline. 1772 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) 1773 paintOutline(paintInfo.context, tx, ty, width(), height(), style()); 1774 1775 // 6. paint continuation outlines. 1776 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { 1777 if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) { 1778 RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer()); 1779 if (!inlineRenderer->hasSelfPaintingLayer()) 1780 containingBlock()->addContinuationWithOutline(inlineRenderer); 1781 else if (!inlineRenderer->firstLineBox()) 1782 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), 1783 ty - y() + inlineRenderer->containingBlock()->y()); 1784 } 1785 paintContinuationOutlines(paintInfo, tx, ty); 1786 } 1787 1788 // 7. paint caret. 1789 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, 1790 // then paint the caret. 1791 if (paintPhase == PaintPhaseForeground) { 1792 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); 1793 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); 1794 } 1795 } 1796 1797 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase) 1798 { 1799 if (!m_floatingObjects) 1800 return; 1801 1802 FloatingObject* r; 1803 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1804 for (; (r = it.current()); ++it) { 1805 // Only paint the object if our m_shouldPaint flag is set. 1806 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 1807 PaintInfo currentPaintInfo(paintInfo); 1808 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 1809 int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); 1810 int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); 1811 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1812 if (!preservePhase) { 1813 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 1814 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1815 currentPaintInfo.phase = PaintPhaseFloat; 1816 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1817 currentPaintInfo.phase = PaintPhaseForeground; 1818 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1819 currentPaintInfo.phase = PaintPhaseOutline; 1820 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1821 } 1822 } 1823 } 1824 } 1825 1826 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) 1827 { 1828 if (!shouldPaintWithinRoot(paintInfo) || !firstLineBox()) 1829 return; 1830 1831 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { 1832 // We can check the first box and last box and avoid painting if we don't 1833 // intersect. 1834 int yPos = ty + firstLineBox()->y(); 1835 int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y(); 1836 if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) 1837 return; 1838 1839 // See if our boxes intersect with the dirty rect. If so, then we paint 1840 // them. Note that boxes can easily overlap, so we can't make any assumptions 1841 // based off positions of our first line box or our last line box. 1842 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 1843 yPos = ty + curr->y(); 1844 h = curr->height(); 1845 if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) 1846 curr->paintEllipsisBox(paintInfo, tx, ty); 1847 } 1848 } 1849 } 1850 1851 static ContinuationOutlineTableMap* continuationOutlineTable() 1852 { 1853 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); 1854 return &table; 1855 } 1856 1857 void RenderBlock::addContinuationWithOutline(RenderInline* flow) 1858 { 1859 // We can't make this work if the inline is in a layer. We'll just rely on the broken 1860 // way of painting. 1861 ASSERT(!flow->layer() && !flow->isInlineContinuation()); 1862 1863 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1864 ListHashSet<RenderInline*>* continuations = table->get(this); 1865 if (!continuations) { 1866 continuations = new ListHashSet<RenderInline*>; 1867 table->set(this, continuations); 1868 } 1869 1870 continuations->add(flow); 1871 } 1872 1873 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) 1874 { 1875 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1876 if (table->isEmpty()) 1877 return; 1878 1879 ListHashSet<RenderInline*>* continuations = table->get(this); 1880 if (!continuations) 1881 return; 1882 1883 // Paint each continuation outline. 1884 ListHashSet<RenderInline*>::iterator end = continuations->end(); 1885 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { 1886 // Need to add in the coordinates of the intervening blocks. 1887 RenderInline* flow = *it; 1888 RenderBlock* block = flow->containingBlock(); 1889 for ( ; block && block != this; block = block->containingBlock()) { 1890 tx += block->x(); 1891 ty += block->y(); 1892 } 1893 ASSERT(block); 1894 flow->paintOutline(info.context, tx, ty); 1895 } 1896 1897 // Delete 1898 delete continuations; 1899 table->remove(this); 1900 } 1901 1902 void RenderBlock::setSelectionState(SelectionState s) 1903 { 1904 if (selectionState() == s) 1905 return; 1906 1907 if (s == SelectionInside && selectionState() != SelectionNone) 1908 return; 1909 1910 if ((s == SelectionStart && selectionState() == SelectionEnd) || 1911 (s == SelectionEnd && selectionState() == SelectionStart)) 1912 RenderBox::setSelectionState(SelectionBoth); 1913 else 1914 RenderBox::setSelectionState(s); 1915 1916 RenderBlock* cb = containingBlock(); 1917 if (cb && !cb->isRenderView()) 1918 cb->setSelectionState(s); 1919 } 1920 1921 bool RenderBlock::shouldPaintSelectionGaps() const 1922 { 1923 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); 1924 } 1925 1926 bool RenderBlock::isSelectionRoot() const 1927 { 1928 if (!node()) 1929 return false; 1930 1931 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. 1932 if (isTable()) 1933 return false; 1934 1935 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() || 1936 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() || 1937 hasReflection() || hasMask()) 1938 return true; 1939 1940 if (view() && view()->selectionStart()) { 1941 Node* startElement = view()->selectionStart()->node(); 1942 if (startElement && startElement->rootEditableElement() == node()) 1943 return true; 1944 } 1945 1946 return false; 1947 } 1948 1949 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer) 1950 { 1951 ASSERT(!needsLayout()); 1952 1953 if (!shouldPaintSelectionGaps()) 1954 return GapRects(); 1955 1956 // FIXME: this is broken with transforms 1957 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); 1958 mapLocalToContainer(repaintContainer, false, false, transformState); 1959 FloatPoint offsetFromRepaintContainer = transformState.mappedPoint(); 1960 int x = offsetFromRepaintContainer.x(); 1961 int y = offsetFromRepaintContainer.y(); 1962 1963 if (hasOverflowClip()) 1964 layer()->subtractScrolledContentOffset(x, y); 1965 1966 int lastTop = 0; 1967 int lastLeft = leftSelectionOffset(this, lastTop); 1968 int lastRight = rightSelectionOffset(this, lastTop); 1969 1970 return fillSelectionGaps(this, x, y, x, y, lastTop, lastLeft, lastRight); 1971 } 1972 1973 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) 1974 { 1975 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { 1976 int lastTop = 0; 1977 int lastLeft = leftSelectionOffset(this, lastTop); 1978 int lastRight = rightSelectionOffset(this, lastTop); 1979 paintInfo.context->save(); 1980 IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo); 1981 if (!gapRectsBounds.isEmpty()) { 1982 if (RenderLayer* layer = enclosingLayer()) { 1983 gapRectsBounds.move(IntSize(-tx, -ty)); 1984 if (!hasLayer()) { 1985 FloatRect localBounds(gapRectsBounds); 1986 gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox(); 1987 } 1988 layer->addBlockSelectionGapsBounds(gapRectsBounds); 1989 } 1990 } 1991 paintInfo.context->restore(); 1992 } 1993 } 1994 1995 #ifndef BUILDING_ON_TIGER 1996 static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) 1997 { 1998 if (!positionedObjects) 1999 return; 2000 2001 ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); 2002 for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { 2003 RenderBox* r = *it; 2004 paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); 2005 } 2006 } 2007 #endif 2008 2009 GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2010 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2011 { 2012 #ifndef BUILDING_ON_TIGER 2013 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. 2014 // Clip out floating and positioned objects when painting selection gaps. 2015 if (paintInfo) { 2016 // Note that we don't clip out overflow for positioned objects. We just stick to the border box. 2017 clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); 2018 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. 2019 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) 2020 clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); 2021 if (m_floatingObjects) { 2022 for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { 2023 FloatingObject* r = it.current(); 2024 paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(), 2025 ty + r->m_top + r->m_renderer->marginTop(), 2026 r->m_renderer->width(), r->m_renderer->height())); 2027 } 2028 } 2029 } 2030 #endif 2031 2032 // 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 2033 // fixed). 2034 GapRects result; 2035 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. 2036 return result; 2037 2038 if (hasColumns() || hasTransform()) { 2039 // FIXME: We should learn how to gap fill multiple columns and transforms eventually. 2040 lastTop = (ty - blockY) + height(); 2041 lastLeft = leftSelectionOffset(rootBlock, height()); 2042 lastRight = rightSelectionOffset(rootBlock, height()); 2043 return result; 2044 } 2045 2046 if (childrenInline()) 2047 result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2048 else 2049 result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2050 2051 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. 2052 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) 2053 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), 2054 rootBlock, blockX, blockY, paintInfo)); 2055 return result; 2056 } 2057 2058 GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2059 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2060 { 2061 GapRects result; 2062 2063 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 2064 2065 if (!firstLineBox()) { 2066 if (containsStart) { 2067 // Go ahead and update our lastY to be the bottom of the block. <hr>s or empty blocks with height can trip this 2068 // case. 2069 lastTop = (ty - blockY) + height(); 2070 lastLeft = leftSelectionOffset(rootBlock, height()); 2071 lastRight = rightSelectionOffset(rootBlock, height()); 2072 } 2073 return result; 2074 } 2075 2076 RootInlineBox* lastSelectedLine = 0; 2077 RootInlineBox* curr; 2078 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 2079 2080 // Now paint the gaps for the lines. 2081 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 2082 int selTop = curr->selectionTop(); 2083 int selHeight = curr->selectionHeight(); 2084 2085 if (!containsStart && !lastSelectedLine && 2086 selectionState() != SelectionStart && selectionState() != SelectionBoth) 2087 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop, 2088 rootBlock, blockX, blockY, paintInfo)); 2089 2090 if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())) 2091 result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); 2092 2093 lastSelectedLine = curr; 2094 } 2095 2096 if (containsStart && !lastSelectedLine) 2097 // VisibleSelection must start just after our last line. 2098 lastSelectedLine = lastRootBox(); 2099 2100 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 2101 // Go ahead and update our lastY to be the bottom of the last selected line. 2102 lastTop = (ty - blockY) + lastSelectedLine->selectionBottom(); 2103 lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2104 lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2105 } 2106 return result; 2107 } 2108 2109 GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2110 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2111 { 2112 GapRects result; 2113 2114 // Go ahead and jump right to the first block child that contains some selected objects. 2115 RenderBox* curr; 2116 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } 2117 2118 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { 2119 SelectionState childState = curr->selectionState(); 2120 if (childState == SelectionBoth || childState == SelectionEnd) 2121 sawSelectionEnd = true; 2122 2123 if (curr->isFloatingOrPositioned()) 2124 continue; // We must be a normal flow object in order to even be considered. 2125 2126 if (curr->isRelPositioned() && curr->hasLayer()) { 2127 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. 2128 // Just disregard it completely. 2129 IntSize relOffset = curr->layer()->relativePositionOffset(); 2130 if (relOffset.width() || relOffset.height()) 2131 continue; 2132 } 2133 2134 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this. 2135 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone); 2136 if (fillBlockGaps) { 2137 // We need to fill the vertical gap above this object. 2138 if (childState == SelectionEnd || childState == SelectionInside) 2139 // Fill the gap above the object. 2140 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, 2141 ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); 2142 2143 // 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* 2144 // our object. We know this if the selection did not end inside our object. 2145 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd)) 2146 childState = SelectionNone; 2147 2148 // Fill side gaps on this object based off its state. 2149 bool leftGap, rightGap; 2150 getHorizontalSelectionGapInfo(childState, leftGap, rightGap); 2151 2152 if (leftGap) 2153 result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2154 if (rightGap) 2155 result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2156 2157 // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as 2158 // they can without bumping into floating or positioned objects. Ideally they will go right up 2159 // to the border of the root selection block. 2160 lastTop = (ty - blockY) + (curr->y() + curr->height()); 2161 lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); 2162 lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); 2163 } else if (childState != SelectionNone) 2164 // We must be a block that has some selected object inside it. Go ahead and recur. 2165 result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), 2166 lastTop, lastLeft, lastRight, paintInfo)); 2167 } 2168 return result; 2169 } 2170 2171 IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo* paintInfo) 2172 { 2173 if (width <= 0 || height <= 0) 2174 return IntRect(); 2175 IntRect gapRect(xPos, yPos, width, height); 2176 if (paintInfo && selObj->style()->visibility() == VISIBLE) 2177 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2178 return gapRect; 2179 } 2180 2181 IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock, 2182 int blockX, int blockY, const PaintInfo* paintInfo) 2183 { 2184 int top = blockY + lastTop; 2185 int height = bottomY - top; 2186 if (height <= 0) 2187 return IntRect(); 2188 2189 // Get the selection offsets for the bottom of the gap 2190 int left = blockX + max(lastLeft, leftSelectionOffset(rootBlock, bottomY)); 2191 int right = blockX + min(lastRight, rightSelectionOffset(rootBlock, bottomY)); 2192 int width = right - left; 2193 if (width <= 0) 2194 return IntRect(); 2195 2196 IntRect gapRect(left, top, width, height); 2197 if (paintInfo) 2198 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace()); 2199 return gapRect; 2200 } 2201 2202 IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2203 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2204 { 2205 int top = yPos + ty; 2206 int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)); 2207 int right = min(xPos + tx, blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height))); 2208 int width = right - left; 2209 if (width <= 0) 2210 return IntRect(); 2211 2212 IntRect gapRect(left, top, width, height); 2213 if (paintInfo) 2214 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2215 return gapRect; 2216 } 2217 2218 IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2219 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2220 { 2221 int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height))); 2222 int top = yPos + ty; 2223 int right = blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height)); 2224 int width = right - left; 2225 if (width <= 0) 2226 return IntRect(); 2227 2228 IntRect gapRect(left, top, width, height); 2229 if (paintInfo) 2230 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2231 return gapRect; 2232 } 2233 2234 void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) 2235 { 2236 bool ltr = style()->direction() == LTR; 2237 leftGap = (state == RenderObject::SelectionInside) || 2238 (state == RenderObject::SelectionEnd && ltr) || 2239 (state == RenderObject::SelectionStart && !ltr); 2240 rightGap = (state == RenderObject::SelectionInside) || 2241 (state == RenderObject::SelectionStart && ltr) || 2242 (state == RenderObject::SelectionEnd && !ltr); 2243 } 2244 2245 int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) 2246 { 2247 int left = leftOffset(yPos, false); 2248 if (left == borderLeft() + paddingLeft()) { 2249 if (rootBlock != this) 2250 // The border can potentially be further extended by our containingBlock(). 2251 return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); 2252 return left; 2253 } 2254 else { 2255 RenderBlock* cb = this; 2256 while (cb != rootBlock) { 2257 left += cb->x(); 2258 cb = cb->containingBlock(); 2259 } 2260 } 2261 2262 return left; 2263 } 2264 2265 int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) 2266 { 2267 int right = rightOffset(yPos, false); 2268 if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { 2269 if (rootBlock != this) 2270 // The border can potentially be further extended by our containingBlock(). 2271 return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); 2272 return right; 2273 } 2274 else { 2275 RenderBlock* cb = this; 2276 while (cb != rootBlock) { 2277 right += cb->x(); 2278 cb = cb->containingBlock(); 2279 } 2280 } 2281 return right; 2282 } 2283 2284 void RenderBlock::insertPositionedObject(RenderBox* o) 2285 { 2286 // Create the list of special objects if we don't aleady have one 2287 if (!m_positionedObjects) 2288 m_positionedObjects = new ListHashSet<RenderBox*>; 2289 2290 m_positionedObjects->add(o); 2291 } 2292 2293 void RenderBlock::removePositionedObject(RenderBox* o) 2294 { 2295 if (m_positionedObjects) 2296 m_positionedObjects->remove(o); 2297 } 2298 2299 void RenderBlock::removePositionedObjects(RenderBlock* o) 2300 { 2301 if (!m_positionedObjects) 2302 return; 2303 2304 RenderBox* r; 2305 2306 Iterator end = m_positionedObjects->end(); 2307 2308 Vector<RenderBox*, 16> deadObjects; 2309 2310 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2311 r = *it; 2312 if (!o || r->isDescendantOf(o)) { 2313 if (o) 2314 r->setChildNeedsLayout(true, false); 2315 2316 // It is parent blocks job to add positioned child to positioned objects list of its containing block 2317 // Parent layout needs to be invalidated to ensure this happens. 2318 RenderObject* p = r->parent(); 2319 while (p && !p->isRenderBlock()) 2320 p = p->parent(); 2321 if (p) 2322 p->setChildNeedsLayout(true); 2323 2324 deadObjects.append(r); 2325 } 2326 } 2327 2328 for (unsigned i = 0; i < deadObjects.size(); i++) 2329 m_positionedObjects->remove(deadObjects.at(i)); 2330 } 2331 2332 void RenderBlock::insertFloatingObject(RenderBox* o) 2333 { 2334 ASSERT(o->isFloating()); 2335 2336 // Create the list of special objects if we don't aleady have one 2337 if (!m_floatingObjects) { 2338 m_floatingObjects = new DeprecatedPtrList<FloatingObject>; 2339 m_floatingObjects->setAutoDelete(true); 2340 } else { 2341 // Don't insert the object again if it's already in the list 2342 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2343 FloatingObject* f; 2344 while ( (f = it.current()) ) { 2345 if (f->m_renderer == o) return; 2346 ++it; 2347 } 2348 } 2349 2350 // Create the special object entry & append it to the list 2351 2352 o->layoutIfNeeded(); 2353 2354 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight); 2355 2356 newObj->m_top = -1; 2357 newObj->m_bottom = -1; 2358 newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); 2359 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. 2360 newObj->m_isDescendant = true; 2361 newObj->m_renderer = o; 2362 2363 m_floatingObjects->append(newObj); 2364 } 2365 2366 void RenderBlock::removeFloatingObject(RenderBox* o) 2367 { 2368 if (m_floatingObjects) { 2369 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2370 while (it.current()) { 2371 if (it.current()->m_renderer == o) { 2372 if (childrenInline()) 2373 markLinesDirtyInVerticalRange(0, it.current()->m_bottom); 2374 m_floatingObjects->removeRef(it.current()); 2375 } 2376 ++it; 2377 } 2378 } 2379 } 2380 2381 bool RenderBlock::positionNewFloats() 2382 { 2383 if (!m_floatingObjects) 2384 return false; 2385 2386 FloatingObject* f = m_floatingObjects->last(); 2387 2388 // If all floats have already been positioned, then we have no work to do. 2389 if (!f || f->m_top != -1) 2390 return false; 2391 2392 // Move backwards through our floating object list until we find a float that has 2393 // already been positioned. Then we'll be able to move forward, positioning all of 2394 // the new floats that need it. 2395 FloatingObject* lastFloat = m_floatingObjects->getPrev(); 2396 while (lastFloat && lastFloat->m_top == -1) { 2397 f = m_floatingObjects->prev(); 2398 lastFloat = m_floatingObjects->getPrev(); 2399 } 2400 2401 int y = height(); 2402 2403 // The float cannot start above the y position of the last positioned float. 2404 if (lastFloat) 2405 y = max(lastFloat->m_top, y); 2406 2407 // Now walk through the set of unpositioned floats and place them. 2408 while (f) { 2409 // The containing block is responsible for positioning floats, so if we have floats in our 2410 // list that come from somewhere else, do not attempt to position them. 2411 if (f->m_renderer->containingBlock() != this) { 2412 f = m_floatingObjects->next(); 2413 continue; 2414 } 2415 2416 RenderBox* o = f->m_renderer; 2417 int _height = o->height() + o->marginTop() + o->marginBottom(); 2418 2419 int ro = rightOffset(); // Constant part of right offset. 2420 int lo = leftOffset(); // Constat part of left offset. 2421 int fwidth = f->m_width; // The width we look for. 2422 if (ro - lo < fwidth) 2423 fwidth = ro - lo; // Never look for more than what will be available. 2424 2425 IntRect oldRect(o->x(), o->y() , o->width(), o->height()); 2426 2427 if (o->style()->clear() & CLEFT) 2428 y = max(leftBottom(), y); 2429 if (o->style()->clear() & CRIGHT) 2430 y = max(rightBottom(), y); 2431 2432 if (o->style()->floating() == FLEFT) { 2433 int heightRemainingLeft = 1; 2434 int heightRemainingRight = 1; 2435 int fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2436 while (rightRelOffset(y, ro, false, &heightRemainingRight)-fx < fwidth) { 2437 y += min(heightRemainingLeft, heightRemainingRight); 2438 fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2439 } 2440 fx = max(0, fx); 2441 f->m_left = fx; 2442 o->setLocation(fx + o->marginLeft(), y + o->marginTop()); 2443 } else { 2444 int heightRemainingLeft = 1; 2445 int heightRemainingRight = 1; 2446 int fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2447 while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) { 2448 y += min(heightRemainingLeft, heightRemainingRight); 2449 fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2450 } 2451 f->m_left = fx - f->m_width; 2452 o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); 2453 } 2454 2455 f->m_top = y; 2456 f->m_bottom = f->m_top + _height; 2457 2458 // If the child moved, we have to repaint it. 2459 if (o->checkForRepaintDuringLayout()) 2460 o->repaintDuringLayoutIfMoved(oldRect); 2461 2462 f = m_floatingObjects->next(); 2463 } 2464 return true; 2465 } 2466 2467 void RenderBlock::newLine(EClear clear) 2468 { 2469 positionNewFloats(); 2470 // set y position 2471 int newY = 0; 2472 switch (clear) 2473 { 2474 case CLEFT: 2475 newY = leftBottom(); 2476 break; 2477 case CRIGHT: 2478 newY = rightBottom(); 2479 break; 2480 case CBOTH: 2481 newY = floatBottom(); 2482 default: 2483 break; 2484 } 2485 if (height() < newY) 2486 setHeight(newY); 2487 } 2488 2489 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) 2490 { 2491 if (!gPercentHeightDescendantsMap) { 2492 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap; 2493 gPercentHeightContainerMap = new PercentHeightContainerMap; 2494 } 2495 2496 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this); 2497 if (!descendantSet) { 2498 descendantSet = new HashSet<RenderBox*>; 2499 gPercentHeightDescendantsMap->set(this, descendantSet); 2500 } 2501 bool added = descendantSet->add(descendant).second; 2502 if (!added) { 2503 ASSERT(gPercentHeightContainerMap->get(descendant)); 2504 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this)); 2505 return; 2506 } 2507 2508 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant); 2509 if (!containerSet) { 2510 containerSet = new HashSet<RenderBlock*>; 2511 gPercentHeightContainerMap->set(descendant, containerSet); 2512 } 2513 ASSERT(!containerSet->contains(this)); 2514 containerSet->add(this); 2515 } 2516 2517 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) 2518 { 2519 if (!gPercentHeightContainerMap) 2520 return; 2521 2522 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant); 2523 if (!containerSet) 2524 return; 2525 2526 HashSet<RenderBlock*>::iterator end = containerSet->end(); 2527 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) { 2528 RenderBlock* container = *it; 2529 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container); 2530 ASSERT(descendantSet); 2531 if (!descendantSet) 2532 continue; 2533 ASSERT(descendantSet->contains(descendant)); 2534 descendantSet->remove(descendant); 2535 if (descendantSet->isEmpty()) { 2536 gPercentHeightDescendantsMap->remove(container); 2537 delete descendantSet; 2538 } 2539 } 2540 2541 delete containerSet; 2542 } 2543 2544 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const 2545 { 2546 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; 2547 } 2548 2549 int RenderBlock::leftOffset() const 2550 { 2551 return borderLeft() + paddingLeft(); 2552 } 2553 2554 int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2555 { 2556 int left = fixedOffset; 2557 if (m_floatingObjects) { 2558 if ( heightRemaining ) *heightRemaining = 1; 2559 FloatingObject* r; 2560 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2561 for ( ; (r = it.current()); ++it ) 2562 { 2563 if (r->m_top <= y && r->m_bottom > y && 2564 r->type() == FloatingObject::FloatLeft && 2565 r->m_left + r->m_width > left) { 2566 left = r->m_left + r->m_width; 2567 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2568 } 2569 } 2570 } 2571 2572 if (applyTextIndent && style()->direction() == LTR) { 2573 int cw = 0; 2574 if (style()->textIndent().isPercent()) 2575 cw = containingBlock()->availableWidth(); 2576 left += style()->textIndent().calcMinValue(cw); 2577 } 2578 2579 return left; 2580 } 2581 2582 int RenderBlock::rightOffset() const 2583 { 2584 return borderLeft() + paddingLeft() + availableWidth(); 2585 } 2586 2587 int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2588 { 2589 int right = fixedOffset; 2590 2591 if (m_floatingObjects) { 2592 if (heightRemaining) *heightRemaining = 1; 2593 FloatingObject* r; 2594 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2595 for ( ; (r = it.current()); ++it ) 2596 { 2597 if (r->m_top <= y && r->m_bottom > y && 2598 r->type() == FloatingObject::FloatRight && 2599 r->m_left < right) { 2600 right = r->m_left; 2601 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2602 } 2603 } 2604 } 2605 2606 if (applyTextIndent && style()->direction() == RTL) { 2607 int cw = 0; 2608 if (style()->textIndent().isPercent()) 2609 cw = containingBlock()->availableWidth(); 2610 right -= style()->textIndent().calcMinValue(cw); 2611 } 2612 2613 return right; 2614 } 2615 2616 int 2617 RenderBlock::lineWidth(int y, bool firstLine) const 2618 { 2619 int result = rightOffset(y, firstLine) - leftOffset(y, firstLine); 2620 return (result < 0) ? 0 : result; 2621 } 2622 2623 int RenderBlock::nextFloatBottomBelow(int height) const 2624 { 2625 if (!m_floatingObjects) 2626 return 0; 2627 2628 int bottom = INT_MAX; 2629 FloatingObject* r; 2630 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2631 for ( ; (r = it.current()); ++it) { 2632 if (r->m_bottom > height) 2633 bottom = min(r->m_bottom, bottom); 2634 } 2635 2636 return bottom == INT_MAX ? 0 : bottom; 2637 } 2638 2639 int 2640 RenderBlock::floatBottom() const 2641 { 2642 if (!m_floatingObjects) return 0; 2643 int bottom = 0; 2644 FloatingObject* r; 2645 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2646 for ( ; (r = it.current()); ++it ) 2647 if (r->m_bottom>bottom) 2648 bottom = r->m_bottom; 2649 return bottom; 2650 } 2651 2652 IntRect RenderBlock::floatRect() const 2653 { 2654 IntRect result; 2655 if (!m_floatingObjects || hasOverflowClip() || hasColumns()) 2656 return result; 2657 FloatingObject* r; 2658 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2659 for (; (r = it.current()); ++it) { 2660 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 2661 IntRect childRect = r->m_renderer->visibleOverflowRect(); 2662 childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); 2663 result.unite(childRect); 2664 } 2665 } 2666 2667 return result; 2668 } 2669 2670 int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const 2671 { 2672 int bottom = includeSelf && width() > 0 ? height() : 0; 2673 2674 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2675 return bottom; 2676 2677 if (!firstChild() && (!width() || !height())) 2678 return bottom; 2679 2680 if (!hasColumns()) { 2681 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2682 // For now, we have to descend into all the children, since we may have a huge abs div inside 2683 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2684 // the abs div. 2685 // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem. 2686 // For inline children, we miss relative positioned boxes that might be buried inside <span>s. 2687 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2688 if (!c->isFloatingOrPositioned() && c->isBox()) { 2689 RenderBox* childBox = toRenderBox(c); 2690 bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); 2691 } 2692 } 2693 } 2694 2695 if (includeSelf && isRelPositioned()) 2696 bottom += relativePositionOffsetY(); 2697 if (!includeOverflowInterior && hasOverflowClip()) 2698 return bottom; 2699 2700 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0; 2701 2702 if (includeSelf) 2703 bottom = max(bottom, bottomLayoutOverflow() + relativeOffset); 2704 2705 if (m_positionedObjects) { 2706 RenderBox* r; 2707 Iterator end = m_positionedObjects->end(); 2708 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2709 r = *it; 2710 // Fixed positioned objects do not scroll and thus should not constitute 2711 // part of the lowest position. 2712 if (r->style()->position() != FixedPosition) { 2713 // FIXME: Should work for overflow sections too. 2714 // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. 2715 // Therefore we should not allow it to contribute to the lowest position. 2716 if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { 2717 int lp = r->y() + r->lowestPosition(false); 2718 bottom = max(bottom, lp + relativeOffset); 2719 } 2720 } 2721 } 2722 } 2723 2724 if (hasColumns()) { 2725 Vector<IntRect>* colRects = columnRects(); 2726 for (unsigned i = 0; i < colRects->size(); i++) 2727 bottom = max(bottom, colRects->at(i).bottom() + relativeOffset); 2728 return bottom; 2729 } 2730 2731 if (m_floatingObjects) { 2732 FloatingObject* r; 2733 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2734 for ( ; (r = it.current()); ++it ) { 2735 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2736 int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); 2737 bottom = max(bottom, lp + relativeOffset); 2738 } 2739 } 2740 } 2741 2742 if (!includeSelf) { 2743 bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset); 2744 if (childrenInline()) { 2745 if (lastRootBox()) { 2746 int childBottomEdge = lastRootBox()->selectionBottom(); 2747 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2748 } 2749 } else { 2750 // Find the last normal flow child. 2751 RenderBox* currBox = lastChildBox(); 2752 while (currBox && currBox->isFloatingOrPositioned()) 2753 currBox = currBox->previousSiblingBox(); 2754 if (currBox) { 2755 int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom(); 2756 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2757 } 2758 } 2759 } 2760 2761 return bottom; 2762 } 2763 2764 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const 2765 { 2766 int right = includeSelf && height() > 0 ? width() : 0; 2767 2768 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2769 return right; 2770 2771 if (!firstChild() && (!width() || !height())) 2772 return right; 2773 2774 if (!hasColumns()) { 2775 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2776 // For now, we have to descend into all the children, since we may have a huge abs div inside 2777 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2778 // the abs div. 2779 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2780 if (!c->isFloatingOrPositioned() && c->isBox()) { 2781 RenderBox* childBox = toRenderBox(c); 2782 right = max(right, childBox->x() + childBox->rightmostPosition(false)); 2783 } 2784 } 2785 } 2786 2787 if (includeSelf && isRelPositioned()) 2788 right += relativePositionOffsetX(); 2789 2790 if (!includeOverflowInterior && hasOverflowClip()) 2791 return right; 2792 2793 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0; 2794 2795 if (includeSelf) 2796 right = max(right, rightLayoutOverflow() + relativeOffset); 2797 2798 if (m_positionedObjects) { 2799 RenderBox* r; 2800 Iterator end = m_positionedObjects->end(); 2801 for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) { 2802 r = *it; 2803 // Fixed positioned objects do not scroll and thus should not constitute 2804 // part of the rightmost position. 2805 if (r->style()->position() != FixedPosition) { 2806 // FIXME: Should work for overflow sections too. 2807 // If a positioned object lies completely above the root it will be unreachable via scrolling. 2808 // Therefore we should not allow it to contribute to the rightmost position. 2809 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { 2810 int rp = r->x() + r->rightmostPosition(false); 2811 right = max(right, rp + relativeOffset); 2812 } 2813 } 2814 } 2815 } 2816 2817 if (hasColumns()) { 2818 // This only matters for LTR 2819 if (style()->direction() == LTR) 2820 right = max(columnRects()->last().right() + relativeOffset, right); 2821 return right; 2822 } 2823 2824 if (m_floatingObjects) { 2825 FloatingObject* r; 2826 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2827 for ( ; (r = it.current()); ++it ) { 2828 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2829 int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); 2830 right = max(right, rp + relativeOffset); 2831 } 2832 } 2833 } 2834 2835 if (!includeSelf) { 2836 right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset); 2837 if (childrenInline()) { 2838 for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { 2839 int childRightEdge = currBox->x() + currBox->width(); 2840 2841 // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. 2842 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. 2843 if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight()) 2844 childRightEdge += 1; 2845 right = max(right, childRightEdge + paddingRight() + relativeOffset); 2846 } 2847 } else { 2848 // Walk all normal flow children. 2849 for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) { 2850 if (currBox->isFloatingOrPositioned()) 2851 continue; 2852 int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight(); 2853 right = max(right, childRightEdge + paddingRight() + relativeOffset); 2854 } 2855 } 2856 } 2857 2858 return right; 2859 } 2860 2861 int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const 2862 { 2863 int left = includeSelf && height() > 0 ? 0 : width(); 2864 2865 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2866 return left; 2867 2868 if (!firstChild() && (!width() || !height())) 2869 return left; 2870 2871 if (!hasColumns()) { 2872 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2873 // For now, we have to descend into all the children, since we may have a huge abs div inside 2874 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2875 // the abs div. 2876 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2877 if (!c->isFloatingOrPositioned() && c->isBox()) { 2878 RenderBox* childBox = toRenderBox(c); 2879 left = min(left, childBox->x() + childBox->leftmostPosition(false)); 2880 } 2881 } 2882 } 2883 2884 if (includeSelf && isRelPositioned()) 2885 left += relativePositionOffsetX(); 2886 2887 if (!includeOverflowInterior && hasOverflowClip()) 2888 return left; 2889 2890 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0; 2891 2892 if (includeSelf) 2893 left = min(left, leftLayoutOverflow() + relativeOffset); 2894 2895 if (m_positionedObjects) { 2896 RenderBox* r; 2897 Iterator end = m_positionedObjects->end(); 2898 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2899 r = *it; 2900 // Fixed positioned objects do not scroll and thus should not constitute 2901 // part of the leftmost position. 2902 if (r->style()->position() != FixedPosition) { 2903 // FIXME: Should work for overflow sections too. 2904 // If a positioned object lies completely above the root it will be unreachable via scrolling. 2905 // Therefore we should not allow it to contribute to the leftmost position. 2906 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { 2907 int lp = r->x() + r->leftmostPosition(false); 2908 left = min(left, lp + relativeOffset); 2909 } 2910 } 2911 } 2912 } 2913 2914 if (hasColumns()) { 2915 // This only matters for RTL 2916 if (style()->direction() == RTL) 2917 left = min(columnRects()->last().x() + relativeOffset, left); 2918 return left; 2919 } 2920 2921 if (m_floatingObjects) { 2922 FloatingObject* r; 2923 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2924 for ( ; (r = it.current()); ++it ) { 2925 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2926 int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); 2927 left = min(left, lp + relativeOffset); 2928 } 2929 } 2930 } 2931 2932 if (!includeSelf && firstLineBox()) { 2933 for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) 2934 left = min(left, (int)currBox->x() + relativeOffset); 2935 } 2936 2937 return left; 2938 } 2939 2940 int 2941 RenderBlock::leftBottom() 2942 { 2943 if (!m_floatingObjects) return 0; 2944 int bottom = 0; 2945 FloatingObject* r; 2946 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2947 for ( ; (r = it.current()); ++it ) 2948 if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft) 2949 bottom = r->m_bottom; 2950 2951 return bottom; 2952 } 2953 2954 int 2955 RenderBlock::rightBottom() 2956 { 2957 if (!m_floatingObjects) return 0; 2958 int bottom = 0; 2959 FloatingObject* r; 2960 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2961 for ( ; (r = it.current()); ++it ) 2962 if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight) 2963 bottom = r->m_bottom; 2964 2965 return bottom; 2966 } 2967 2968 void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest) 2969 { 2970 if (top >= bottom) 2971 return; 2972 2973 RootInlineBox* lowestDirtyLine = lastRootBox(); 2974 RootInlineBox* afterLowest = lowestDirtyLine; 2975 while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) { 2976 afterLowest = lowestDirtyLine; 2977 lowestDirtyLine = lowestDirtyLine->prevRootBox(); 2978 } 2979 2980 while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) { 2981 afterLowest->markDirty(); 2982 afterLowest = afterLowest->prevRootBox(); 2983 } 2984 } 2985 2986 void RenderBlock::clearFloats() 2987 { 2988 // Inline blocks are covered by the isReplaced() check in the avoidFloats method. 2989 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) { 2990 if (m_floatingObjects) 2991