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 (!prev || (!prev->firstChild() || !prev->firstChild()->isInline() || !prev->firstChild()->isRunIn())) && 545 (!next || (next->isAnonymousBlock() && next->childrenInline())); 546 if (canDeleteAnonymousBlocks && prev && next) { 547 // Take all the children out of the |next| block and put them in 548 // the |prev| block. 549 prev->setNeedsLayoutAndPrefWidthsRecalc(); 550 RenderBlock* nextBlock = toRenderBlock(next); 551 RenderBlock* prevBlock = toRenderBlock(prev); 552 nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children()); 553 // Delete the now-empty block's lines and nuke it. 554 nextBlock->deleteLineBoxTree(); 555 nextBlock->destroy(); 556 } 557 558 RenderBox::removeChild(oldChild); 559 560 RenderObject* child = prev ? prev : next; 561 if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { 562 // The removal has knocked us down to containing only a single anonymous 563 // box. We can go ahead and pull the content right back up into our 564 // box. 565 setNeedsLayoutAndPrefWidthsRecalc(); 566 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); 567 setChildrenInline(true); 568 anonBlock->moveAllChildrenTo(this, children()); 569 // Delete the now-empty block's lines and nuke it. 570 anonBlock->deleteLineBoxTree(); 571 anonBlock->destroy(); 572 } 573 574 // If this was our last child be sure to clear out our line boxes. 575 if (childrenInline() && !firstChild()) 576 lineBoxes()->deleteLineBoxes(renderArena()); 577 } 578 579 bool RenderBlock::isSelfCollapsingBlock() const 580 { 581 // We are not self-collapsing if we 582 // (a) have a non-zero height according to layout (an optimization to avoid wasting time) 583 // (b) are a table, 584 // (c) have border/padding, 585 // (d) have a min-height 586 // (e) have specified that one of our margins can't collapse using a CSS extension 587 if (height() > 0 || 588 isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || 589 style()->minHeight().isPositive() || 590 style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) 591 return false; 592 593 bool hasAutoHeight = style()->height().isAuto(); 594 if (style()->height().isPercent() && !style()->htmlHacks()) { 595 hasAutoHeight = true; 596 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { 597 if (cb->style()->height().isFixed() || cb->isTableCell()) 598 hasAutoHeight = false; 599 } 600 } 601 602 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends 603 // on whether we have content that is all self-collapsing or not. 604 if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) { 605 // If the block has inline children, see if we generated any line boxes. If we have any 606 // line boxes, then we can't be self-collapsing, since we have content. 607 if (childrenInline()) 608 return !firstLineBox(); 609 610 // Whether or not we collapse is dependent on whether all our normal flow children 611 // are also self-collapsing. 612 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 613 if (child->isFloatingOrPositioned()) 614 continue; 615 if (!child->isSelfCollapsingBlock()) 616 return false; 617 } 618 return true; 619 } 620 return false; 621 } 622 623 void RenderBlock::startDelayUpdateScrollInfo() 624 { 625 if (gDelayUpdateScrollInfo == 0) { 626 ASSERT(!gDelayedUpdateScrollInfoSet); 627 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; 628 } 629 ASSERT(gDelayedUpdateScrollInfoSet); 630 ++gDelayUpdateScrollInfo; 631 } 632 633 void RenderBlock::finishDelayUpdateScrollInfo() 634 { 635 --gDelayUpdateScrollInfo; 636 ASSERT(gDelayUpdateScrollInfo >= 0); 637 if (gDelayUpdateScrollInfo == 0) { 638 ASSERT(gDelayedUpdateScrollInfoSet); 639 640 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet); 641 gDelayedUpdateScrollInfoSet = 0; 642 643 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { 644 RenderBlock* block = *it; 645 if (block->hasOverflowClip()) { 646 block->layer()->updateScrollInfoAfterLayout(); 647 } 648 } 649 } 650 } 651 652 void RenderBlock::updateScrollInfoAfterLayout() 653 { 654 if (hasOverflowClip()) { 655 if (gDelayUpdateScrollInfo) 656 gDelayedUpdateScrollInfoSet->add(this); 657 else 658 layer()->updateScrollInfoAfterLayout(); 659 } 660 } 661 662 void RenderBlock::layout() 663 { 664 // Update our first letter info now. 665 updateFirstLetter(); 666 667 // Table cells call layoutBlock directly, so don't add any logic here. Put code into 668 // layoutBlock(). 669 layoutBlock(false); 670 671 // It's safe to check for control clip here, since controls can never be table cells. 672 // If we have a lightweight clip, there can never be any overflow from children. 673 if (hasControlClip() && m_overflow) 674 clearLayoutOverflow(); 675 } 676 677 void RenderBlock::layoutBlock(bool relayoutChildren) 678 { 679 ASSERT(needsLayout()); 680 681 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can 682 return; // cause us to come in here. Just bail. 683 684 if (!relayoutChildren && layoutOnlyPositionedObjects()) 685 return; 686 687 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); 688 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 689 690 int oldWidth = width(); 691 int oldColumnWidth = desiredColumnWidth(); 692 693 #ifdef ANDROID_LAYOUT 694 int oldVisibleWidth = m_visibleWidth; 695 #endif 696 697 calcWidth(); 698 calcColumnWidth(); 699 700 m_overflow.clear(); 701 702 if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) 703 relayoutChildren = true; 704 705 #ifdef ANDROID_LAYOUT 706 const Settings* settings = document()->settings(); 707 ASSERT(settings); 708 if (oldVisibleWidth != m_visibleWidth 709 && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) 710 relayoutChildren = true; 711 #endif 712 713 clearFloats(); 714 715 int previousHeight = height(); 716 setHeight(0); 717 718 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 719 // our current maximal positive and negative margins. These values are used when we 720 // are collapsed with adjacent blocks, so for example, if you have block A and B 721 // collapsing together, then you'd take the maximal positive margin from both A and B 722 // and subtract it from the maximal negative margin from both A and B to get the 723 // true collapsed margin. This algorithm is recursive, so when we finish layout() 724 // our block knows its current maximal positive/negative values. 725 // 726 // Start out by setting our margin values to our current margins. Table cells have 727 // no margins, so we don't fill in the values for table cells. 728 bool isCell = isTableCell(); 729 if (!isCell) { 730 initMaxMarginValues(); 731 732 setTopMarginQuirk(style()->marginTop().quirk()); 733 setBottomMarginQuirk(style()->marginBottom().quirk()); 734 735 Node* n = node(); 736 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { 737 // See if this form is malformed (i.e., unclosed). If so, don't give the form 738 // a bottom margin. 739 setMaxBottomMargins(0, 0); 740 } 741 } 742 743 // For overflow:scroll blocks, ensure we have both scrollbars in place always. 744 if (scrollsOverflow()) { 745 if (style()->overflowX() == OSCROLL) 746 layer()->setHasHorizontalScrollbar(true); 747 if (style()->overflowY() == OSCROLL) 748 layer()->setHasVerticalScrollbar(true); 749 } 750 751 int repaintTop = 0; 752 int repaintBottom = 0; 753 int maxFloatBottom = 0; 754 if (childrenInline()) 755 layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); 756 else 757 layoutBlockChildren(relayoutChildren, maxFloatBottom); 758 759 // Expand our intrinsic height to encompass floats. 760 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 761 if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) 762 setHeight(floatBottom() + toAdd); 763 764 // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as 765 // we adjust for clean column breaks. 766 int singleColumnBottom = layoutColumns(); 767 768 // Calculate our new height. 769 int oldHeight = height(); 770 calcHeight(); 771 if (oldHeight != height()) { 772 if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) { 773 // One of our children's floats may have become an overhanging float for us. We need to look for it. 774 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 775 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { 776 RenderBlock* block = toRenderBlock(child); 777 if (block->floatBottom() + block->y() > height()) 778 addOverhangingFloats(block, -block->x(), -block->y(), false); 779 } 780 } 781 } 782 783 // We have to rebalance columns to the new height. 784 layoutColumns(singleColumnBottom); 785 } 786 787 if (previousHeight != height()) 788 relayoutChildren = true; 789 790 // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't 791 // able to be propagated up the render tree yet. Overflow information is however. This check is designed to catch anyone 792 // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor. 793 if (isRoot() || expandsToEncloseOverhangingFloats()) 794 addOverflowFromFloats(); 795 796 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 797 if (!hasColumns()) { 798 if (childrenInline()) 799 addOverflowFromInlineChildren(); 800 else 801 addOverflowFromBlockChildren(); 802 } 803 804 // Add visual overflow from box-shadow and reflections. 805 addShadowOverflow(); 806 807 layoutPositionedObjects(relayoutChildren || isRoot()); 808 809 positionListMarker(); 810 811 statePusher.pop(); 812 813 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 814 // we overflow or not. 815 updateScrollInfoAfterLayout(); 816 817 // Repaint with our new bounds if they are different from our old bounds. 818 bool didFullRepaint = repainter.repaintAfterLayout(); 819 if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { 820 int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow()); 821 int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow()); 822 IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop); 823 824 // FIXME: Deal with multiple column repainting. We have to split the repaint 825 // rect up into multiple rects if it spans columns. 826 827 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); 828 829 if (hasOverflowClip()) { 830 // Adjust repaint rect for scroll offset 831 int x = repaintRect.x(); 832 int y = repaintRect.y(); 833 layer()->subtractScrolledContentOffset(x, y); 834 repaintRect.setX(x); 835 repaintRect.setY(y); 836 837 // Don't allow this rect to spill out of our overflow box. 838 repaintRect.intersect(IntRect(0, 0, width(), height())); 839 } 840 841 // Make sure the rect is still non-empty after intersecting for overflow above 842 if (!repaintRect.isEmpty()) { 843 repaintRectangle(repaintRect); // We need to do a partial repaint of our content. 844 if (hasReflection()) 845 repaintRectangle(reflectedRect(repaintRect)); 846 } 847 } 848 setNeedsLayout(false); 849 } 850 851 void RenderBlock::addOverflowFromBlockChildren() 852 { 853 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 854 if (!child->isFloatingOrPositioned()) 855 addOverflowFromChild(child); 856 } 857 } 858 859 void RenderBlock::addOverflowFromFloats() 860 { 861 IntRect result; 862 if (!m_floatingObjects) 863 return; 864 FloatingObject* r; 865 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 866 for (; (r = it.current()); ++it) { 867 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) 868 addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); 869 } 870 return; 871 } 872 873 bool RenderBlock::expandsToEncloseOverhangingFloats() const 874 { 875 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset(); 876 } 877 878 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 879 { 880 if (child->style()->hasStaticX()) { 881 if (style()->direction() == LTR) 882 child->layer()->setStaticX(borderLeft() + paddingLeft()); 883 else 884 child->layer()->setStaticX(borderRight() + paddingRight()); 885 } 886 887 if (child->style()->hasStaticY()) { 888 int y = height(); 889 if (!marginInfo.canCollapseWithTop()) { 890 child->calcVerticalMargins(); 891 int marginTop = child->marginTop(); 892 int collapsedTopPos = marginInfo.posMargin(); 893 int collapsedTopNeg = marginInfo.negMargin(); 894 if (marginTop > 0) { 895 if (marginTop > collapsedTopPos) 896 collapsedTopPos = marginTop; 897 } else { 898 if (-marginTop > collapsedTopNeg) 899 collapsedTopNeg = -marginTop; 900 } 901 y += (collapsedTopPos - collapsedTopNeg) - marginTop; 902 } 903 RenderLayer* childLayer = child->layer(); 904 if (childLayer->staticY() != y) { 905 child->layer()->setStaticY(y); 906 child->setChildNeedsLayout(true, false); 907 } 908 } 909 } 910 911 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) 912 { 913 // The float should be positioned taking into account the bottom margin 914 // of the previous flow. We add that margin into the height, get the 915 // float positioned properly, and then subtract the margin out of the 916 // height again. In the case of self-collapsing blocks, we always just 917 // use the top margins, since the self-collapsing block collapsed its 918 // own bottom margin into its top margin. 919 // 920 // Note also that the previous flow may collapse its margin into the top of 921 // our block. If this is the case, then we do not add the margin in to our 922 // height when computing the position of the float. This condition can be tested 923 // for by simply calling canCollapseWithTop. See 924 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 925 // an example of this scenario. 926 int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); 927 setHeight(height() + marginOffset); 928 positionNewFloats(); 929 setHeight(height() - marginOffset); 930 } 931 932 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) 933 { 934 // Handle in the given order 935 return handlePositionedChild(child, marginInfo) 936 || handleFloatingChild(child, marginInfo) 937 || handleRunInChild(child); 938 } 939 940 941 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) 942 { 943 if (child->isPositioned()) { 944 child->containingBlock()->insertPositionedObject(child); 945 adjustPositionedBlock(child, marginInfo); 946 return true; 947 } 948 return false; 949 } 950 951 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) 952 { 953 if (child->isFloating()) { 954 insertFloatingObject(child); 955 adjustFloatingBlock(marginInfo); 956 return true; 957 } 958 return false; 959 } 960 961 bool RenderBlock::handleRunInChild(RenderBox* child) 962 { 963 // See if we have a run-in element with inline children. If the 964 // children aren't inline, then just treat the run-in as a normal 965 // block. 966 if (!child->isRunIn() || !child->childrenInline()) 967 return false; 968 // FIXME: We don't handle non-block elements with run-in for now. 969 if (!child->isRenderBlock()) 970 return false; 971 972 // Get the next non-positioned/non-floating RenderBlock. 973 RenderBlock* blockRunIn = toRenderBlock(child); 974 RenderObject* curr = blockRunIn->nextSibling(); 975 while (curr && curr->isFloatingOrPositioned()) 976 curr = curr->nextSibling(); 977 978 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous()) 979 return false; 980 981 RenderBlock* currBlock = toRenderBlock(curr); 982 983 // Remove the old child. 984 children()->removeChildNode(this, blockRunIn); 985 986 // Create an inline. 987 Node* runInNode = blockRunIn->node(); 988 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); 989 inlineRunIn->setStyle(blockRunIn->style()); 990 991 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER; 992 993 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already 994 // been regenerated by the new inline. 995 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { 996 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) { 997 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); 998 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. 999 } 1000 } 1001 1002 // Now insert the new child under |currBlock|. 1003 currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); 1004 1005 // If the run-in had an element, we need to set the new renderer. 1006 if (runInNode) 1007 runInNode->setRenderer(inlineRunIn); 1008 1009 // Destroy the block run-in, which includes deleting its line box tree. 1010 blockRunIn->deleteLineBoxTree(); 1011 blockRunIn->destroy(); 1012 1013 // The block acts like an inline, so just null out its 1014 // position. 1015 1016 return true; 1017 } 1018 1019 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) 1020 { 1021 // Get our max pos and neg top margins. 1022 int posTop = child->maxTopMargin(true); 1023 int negTop = child->maxTopMargin(false); 1024 1025 // For self-collapsing blocks, collapse our bottom margins into our 1026 // top to get new posTop and negTop values. 1027 if (child->isSelfCollapsingBlock()) { 1028 posTop = max(posTop, child->maxBottomMargin(true)); 1029 negTop = max(negTop, child->maxBottomMargin(false)); 1030 } 1031 1032 // See if the top margin is quirky. We only care if this child has 1033 // margins that will collapse with us. 1034 bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD; 1035 1036 if (marginInfo.canCollapseWithTop()) { 1037 // This child is collapsing with the top of the 1038 // block. If it has larger margin values, then we need to update 1039 // our own maximal values. 1040 if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) 1041 setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin())); 1042 1043 // The minute any of the margins involved isn't a quirk, don't 1044 // collapse it away, even if the margin is smaller (www.webreference.com 1045 // has an example of this, a <dt> with 0.8em author-specified inside 1046 // a <dl> inside a <td>. 1047 if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { 1048 setTopMarginQuirk(false); 1049 marginInfo.setDeterminedTopQuirk(true); 1050 } 1051 1052 if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0) 1053 // We have no top margin and our top child has a quirky margin. 1054 // We will pick up this quirky margin and pass it through. 1055 // This deals with the <td><div><p> case. 1056 // Don't do this for a block that split two inlines though. You do 1057 // still apply margins in this case. 1058 setTopMarginQuirk(true); 1059 } 1060 1061 if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) 1062 marginInfo.setTopQuirk(topQuirk); 1063 1064 int ypos = height(); 1065 if (child->isSelfCollapsingBlock()) { 1066 // This child has no height. We need to compute our 1067 // position before we collapse the child's margins together, 1068 // so that we can get an accurate position for the zero-height block. 1069 int collapsedTopPos = max(marginInfo.posMargin(), child->maxTopMargin(true)); 1070 int collapsedTopNeg = max(marginInfo.negMargin(), child->maxTopMargin(false)); 1071 marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); 1072 1073 // Now collapse the child's margins together, which means examining our 1074 // bottom margin values as well. 1075 marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true)); 1076 marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false)); 1077 1078 if (!marginInfo.canCollapseWithTop()) 1079 // We need to make sure that the position of the self-collapsing block 1080 // is correct, since it could have overflowing content 1081 // that needs to be positioned correctly (e.g., a block that 1082 // had a specified height of 0 but that actually had subcontent). 1083 ypos = height() + collapsedTopPos - collapsedTopNeg; 1084 } 1085 else { 1086 if (child->style()->marginTopCollapse() == MSEPARATE) { 1087 setHeight(height() + marginInfo.margin() + child->marginTop()); 1088 ypos = height(); 1089 } 1090 else if (!marginInfo.atTopOfBlock() || 1091 (!marginInfo.canCollapseTopWithChildren() 1092 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { 1093 // We're collapsing with a previous sibling's margins and not 1094 // with the top of the block. 1095 setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); 1096 ypos = height(); 1097 } 1098 1099 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1100 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1101 1102 if (marginInfo.margin()) 1103 marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD); 1104 } 1105 1106 return ypos; 1107 } 1108 1109 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) 1110 { 1111 int heightIncrease = getClearDelta(child, yPos); 1112 if (!heightIncrease) 1113 return yPos; 1114 1115 if (child->isSelfCollapsingBlock()) { 1116 // For self-collapsing blocks that clear, they can still collapse their 1117 // margins with following siblings. Reset the current margins to represent 1118 // the self-collapsing block's margins only. 1119 // CSS2.1 states: 1120 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin. 1121 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the 1122 // self-collapsing block's bottom margin. 1123 bool atBottomOfBlock = true; 1124 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) { 1125 if (!curr->isFloatingOrPositioned()) 1126 atBottomOfBlock = false; 1127 } 1128 if (atBottomOfBlock) { 1129 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1130 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1131 } else { 1132 marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true))); 1133 marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); 1134 } 1135 1136 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom 1137 // of the parent block). 1138 setHeight(child->y() - max(0, marginInfo.margin())); 1139 } else 1140 // Increase our height by the amount we had to clear. 1141 setHeight(height() + heightIncrease); 1142 1143 if (marginInfo.canCollapseWithTop()) { 1144 // We can no longer collapse with the top of the block since a clear 1145 // occurred. The empty blocks collapse into the cleared block. 1146 // FIXME: This isn't quite correct. Need clarification for what to do 1147 // if the height the cleared block is offset by is smaller than the 1148 // margins involved. 1149 setMaxTopMargins(oldTopPosMargin, oldTopNegMargin); 1150 marginInfo.setAtTopOfBlock(false); 1151 } 1152 1153 return yPos + heightIncrease; 1154 } 1155 1156 int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) 1157 { 1158 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 1159 // relayout if there are intruding floats. 1160 int yPosEstimate = height(); 1161 if (!marginInfo.canCollapseWithTop()) { 1162 int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); 1163 yPosEstimate += max(marginInfo.margin(), childMarginTop); 1164 } 1165 yPosEstimate += getClearDelta(child, yPosEstimate); 1166 return yPosEstimate; 1167 } 1168 1169 void RenderBlock::determineHorizontalPosition(RenderBox* child) 1170 { 1171 if (style()->direction() == LTR) { 1172 int xPos = borderLeft() + paddingLeft(); 1173 1174 // Add in our left margin. 1175 int chPos = xPos + child->marginLeft(); 1176 1177 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need 1178 // to shift over as necessary to dodge any floats that might get in the way. 1179 if (child->avoidsFloats()) { 1180 int leftOff = leftOffset(height(), false); 1181 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { 1182 if (child->marginLeft() < 0) 1183 leftOff += child->marginLeft(); 1184 chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit. 1185 } 1186 else if (leftOff != xPos) { 1187 // The object is shifting right. The object might be centered, so we need to 1188 // recalculate our horizontal margins. Note that the containing block content 1189 // width computation will take into account the delta between |leftOff| and |xPos| 1190 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1191 // function. 1192 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1193 chPos = leftOff + child->marginLeft(); 1194 } 1195 } 1196 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1197 child->setLocation(chPos, child->y()); 1198 } else { 1199 int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); 1200 int chPos = xPos - (child->width() + child->marginRight()); 1201 if (child->avoidsFloats()) { 1202 int rightOff = rightOffset(height(), false); 1203 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { 1204 if (child->marginRight() < 0) 1205 rightOff -= child->marginRight(); 1206 chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. 1207 } else if (rightOff != xPos) { 1208 // The object is shifting left. The object might be centered, so we need to 1209 // recalculate our horizontal margins. Note that the containing block content 1210 // width computation will take into account the delta between |rightOff| and |xPos| 1211 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1212 // function. 1213 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1214 chPos = rightOff - child->marginRight() - child->width(); 1215 } 1216 } 1217 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1218 child->setLocation(chPos, child->y()); 1219 } 1220 } 1221 1222 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) 1223 { 1224 if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) { 1225 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 1226 // with our children. 1227 setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin())); 1228 1229 if (!marginInfo.bottomQuirk()) 1230 setBottomMarginQuirk(false); 1231 1232 if (marginInfo.bottomQuirk() && marginBottom() == 0) 1233 // We have no bottom margin and our last child has a quirky margin. 1234 // We will pick up this quirky margin and pass it through. 1235 // This deals with the <td><div><p> case. 1236 setBottomMarginQuirk(true); 1237 } 1238 } 1239 1240 void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo) 1241 { 1242 marginInfo.setAtBottomOfBlock(true); 1243 1244 // If we can't collapse with children then go ahead and add in the bottom margin. 1245 if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() 1246 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) 1247 setHeight(height() + marginInfo.margin()); 1248 1249 // Now add in our bottom border/padding. 1250 setHeight(height() + bottom); 1251 1252 // Negative margins can cause our height to shrink below our minimal height (border/padding). 1253 // If this happens, ensure that the computed height is increased to the minimal height. 1254 setHeight(max(height(), top + bottom)); 1255 1256 // Update our bottom collapsed margin info. 1257 setCollapsedBottomMargin(marginInfo); 1258 } 1259 1260 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom) 1261 { 1262 if (gPercentHeightDescendantsMap) { 1263 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { 1264 HashSet<RenderBox*>::iterator end = descendants->end(); 1265 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) { 1266 RenderBox* box = *it; 1267 while (box != this) { 1268 if (box->normalChildNeedsLayout()) 1269 break; 1270 box->setChildNeedsLayout(true, false); 1271 box = box->containingBlock(); 1272 ASSERT(box); 1273 if (!box) 1274 break; 1275 } 1276 } 1277 } 1278 } 1279 1280 int top = borderTop() + paddingTop(); 1281 int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 1282 1283 setHeight(top); 1284 1285 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 1286 MarginInfo marginInfo(this, top, bottom); 1287 1288 // Fieldsets need to find their legend and position it inside the border of the object. 1289 // The legend then gets skipped during normal layout. 1290 RenderObject* legend = layoutLegend(relayoutChildren); 1291 1292 int previousFloatBottom = 0; 1293 maxFloatBottom = 0; 1294 1295 RenderBox* next = firstChildBox(); 1296 1297 while (next) { 1298 RenderBox* child = next; 1299 next = child->nextSiblingBox(); 1300 1301 if (legend == child) 1302 continue; // Skip the legend, since it has already been positioned up in the fieldset's border. 1303 1304 // Make sure we layout children if they need it. 1305 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into 1306 // an auto value. Add a method to determine this, so that we can avoid the relayout. 1307 if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView())) 1308 child->setChildNeedsLayout(true, false); 1309 1310 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1311 if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent())) 1312 child->setPrefWidthsDirty(true, false); 1313 1314 // Handle the four types of special elements first. These include positioned content, floating content, compacts and 1315 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. 1316 if (handleSpecialChild(child, marginInfo)) 1317 continue; 1318 1319 // Lay out the child. 1320 layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom); 1321 } 1322 1323 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 1324 // determining the correct collapsed bottom margin information. 1325 handleBottomOfBlock(top, bottom, marginInfo); 1326 } 1327 1328 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom) 1329 { 1330 int oldTopPosMargin = maxTopPosMargin(); 1331 int oldTopNegMargin = maxTopNegMargin(); 1332 1333 // The child is a normal flow object. Compute its vertical margins now. 1334 child->calcVerticalMargins(); 1335 1336 // Do not allow a collapse if the margin top collapse style is set to SEPARATE. 1337 if (child->style()->marginTopCollapse() == MSEPARATE) { 1338 marginInfo.setAtTopOfBlock(false); 1339 marginInfo.clearMargin(); 1340 } 1341 1342 // Try to guess our correct y position. In most cases this guess will 1343 // be correct. Only if we're wrong (when we compute the real y position) 1344 // will we have to potentially relayout. 1345 int yPosEstimate = estimateVerticalPosition(child, marginInfo); 1346 1347 // Cache our old rect so that we can dirty the proper repaint rects if the child moves. 1348 IntRect oldRect(child->x(), child->y() , child->width(), child->height()); 1349 #ifndef NDEBUG 1350 IntSize oldLayoutDelta = view()->layoutDelta(); 1351 #endif 1352 // Go ahead and position the child as though it didn't collapse with the top. 1353 view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); 1354 child->setLocation(child->x(), yPosEstimate); 1355 1356 bool markDescendantsWithFloats = false; 1357 if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1358 markDescendantsWithFloats = true; 1359 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 1360 // If an element might be affected by the presence of floats, then always mark it for 1361 // layout. 1362 int fb = max(previousFloatBottom, floatBottom()); 1363 if (fb > yPosEstimate) 1364 markDescendantsWithFloats = true; 1365 } 1366 1367 if (child->isRenderBlock()) { 1368 if (markDescendantsWithFloats) 1369 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1370 1371 previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); 1372 } 1373 1374 bool childHadLayout = child->m_everHadLayout; 1375 bool childNeededLayout = child->needsLayout(); 1376 if (childNeededLayout) 1377 child->layout(); 1378 1379 // Now determine the correct ypos based off examination of collapsing margin 1380 // values. 1381 int yBeforeClear = collapseMargins(child, marginInfo); 1382 1383 // Now check for clear. 1384 int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); 1385 1386 view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); 1387 child->setLocation(child->x(), yAfterClear); 1388 1389 // Now we have a final y position. See if it really does end up being different from our estimate. 1390 if (yAfterClear != yPosEstimate) { 1391 if (child->shrinkToAvoidFloats()) { 1392 // The child's width depends on the line width. 1393 // When the child shifts to clear an item, its width can 1394 // change (because it has more available line width). 1395 // So go ahead and mark the item as dirty. 1396 child->setChildNeedsLayout(true, false); 1397 } 1398 if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1399 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1400 // Our guess was wrong. Make the child lay itself out again. 1401 child->layoutIfNeeded(); 1402 } 1403 1404 // We are no longer at the top of the block if we encounter a non-empty child. 1405 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 1406 if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) 1407 marginInfo.setAtTopOfBlock(false); 1408 1409 // Now place the child in the correct horizontal position 1410 determineHorizontalPosition(child); 1411 1412 // Update our height now that the child has been placed in the correct position. 1413 setHeight(height() + child->height()); 1414 if (child->style()->marginBottomCollapse() == MSEPARATE) { 1415 setHeight(height() + child->marginBottom()); 1416 marginInfo.clearMargin(); 1417 } 1418 // If the child has overhanging floats that intrude into following siblings (or possibly out 1419 // of this block), then the parent gets notified of the floats now. 1420 if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1421 maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); 1422 1423 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); 1424 if (childOffset.width() || childOffset.height()) { 1425 view()->addLayoutDelta(childOffset); 1426 1427 // If the child moved, we have to repaint it as well as any floating/positioned 1428 // descendants. An exception is if we need a layout. In this case, we know we're going to 1429 // repaint ourselves (and the child) anyway. 1430 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) 1431 child->repaintDuringLayoutIfMoved(oldRect); 1432 } 1433 1434 if (!childHadLayout && child->checkForRepaintDuringLayout()) { 1435 child->repaint(); 1436 child->repaintOverhangingFloats(true); 1437 } 1438 1439 ASSERT(oldLayoutDelta == view()->layoutDelta()); 1440 } 1441 1442 bool RenderBlock::layoutOnlyPositionedObjects() 1443 { 1444 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1445 return false; 1446 1447 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 1448 1449 if (needsPositionedMovementLayout()) { 1450 tryLayoutDoingPositionedMovementOnly(); 1451 if (needsLayout()) 1452 return false; 1453 } 1454 1455 // All we have to is lay out our positioned objects. 1456 layoutPositionedObjects(false); 1457 1458 statePusher.pop(); 1459 1460 updateScrollInfoAfterLayout(); 1461 1462 #ifdef ANDROID_FIX 1463 // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks, 1464 // which may make us need to layout again 1465 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1466 return false; 1467 #endif 1468 1469 setNeedsLayout(false); 1470 return true; 1471 } 1472 1473 void RenderBlock::layoutPositionedObjects(bool relayoutChildren) 1474 { 1475 if (m_positionedObjects) { 1476 RenderBox* r; 1477 Iterator end = m_positionedObjects->end(); 1478 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1479 r = *it; 1480 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the 1481 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned 1482 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is 1483 // positioned explicitly) this should not incur a performance penalty. 1484 if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) 1485 r->setChildNeedsLayout(true, false); 1486 1487 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1488 //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) 1489 r->setPrefWidthsDirty(true, false); 1490 1491 // 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 1492 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. 1493 if (r->needsPositionedMovementLayoutOnly()) 1494 r->tryLayoutDoingPositionedMovementOnly(); 1495 r->layoutIfNeeded(); 1496 } 1497 } 1498 } 1499 1500 void RenderBlock::markPositionedObjectsForLayout() 1501 { 1502 if (m_positionedObjects) { 1503 RenderBox* r; 1504 Iterator end = m_positionedObjects->end(); 1505 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1506 r = *it; 1507 r->setChildNeedsLayout(true); 1508 } 1509 } 1510 } 1511 1512 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) 1513 { 1514 // Repaint any overhanging floats (if we know we're the one to paint them). 1515 if (hasOverhangingFloats()) { 1516 // We think that we must be in a bad state if m_floatingObjects is nil at this point, so 1517 // we assert on Debug builds and nil-check Release builds. 1518 ASSERT(m_floatingObjects); 1519 if (!m_floatingObjects) 1520 return; 1521 1522 FloatingObject* r; 1523 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1524 1525 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating 1526 // in this block. Better yet would be to push extra state for the containers of other floats. 1527 view()->disableLayoutState(); 1528 for ( ; (r = it.current()); ++it) { 1529 // Only repaint the object if it is overhanging, is not in its own layer, and 1530 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 1531 // condition is replaced with being a descendant of us. 1532 if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { 1533 r->m_renderer->repaint(); 1534 r->m_renderer->repaintOverhangingFloats(); 1535 } 1536 } 1537 view()->enableLayoutState(); 1538 } 1539 } 1540 1541 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) 1542 { 1543 tx += x(); 1544 ty += y(); 1545 1546 PaintPhase phase = paintInfo.phase; 1547 1548 // Check if we need to do anything at all. 1549 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 1550 // paints the root's background. 1551 if (!isRoot()) { 1552 IntRect overflowBox = visibleOverflowRect(); 1553 overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); 1554 overflowBox.move(tx, ty); 1555 if (!overflowBox.intersects(paintInfo.rect)) 1556 return; 1557 } 1558 1559 bool pushedClip = pushContentsClip(paintInfo, tx, ty); 1560 paintObject(paintInfo, tx, ty); 1561 if (pushedClip) 1562 popContentsClip(paintInfo, phase, tx, ty); 1563 1564 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with 1565 // z-index. We paint after we painted the background/border, so that the scrollbars will 1566 // sit above the background/border. 1567 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo)) 1568 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); 1569 } 1570 1571 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) 1572 { 1573 const Color& ruleColor = style()->columnRuleColor(); 1574 bool ruleTransparent = style()->columnRuleIsTransparent(); 1575 EBorderStyle ruleStyle = style()->columnRuleStyle(); 1576 int ruleWidth = style()->columnRuleWidth(); 1577 int colGap = columnGap(); 1578 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; 1579 if (!renderRule) 1580 return; 1581 1582 // We need to do multiple passes, breaking up our child painting into strips. 1583 int currXOffset = 0; 1584 int ruleAdd = borderLeft() + paddingLeft(); 1585 int ruleX = 0; 1586 Vector<IntRect>* colRects = columnRects(); 1587 unsigned colCount = colRects->size(); 1588 for (unsigned i = 0; i < colCount; i++) { 1589 // For each rect, we clip to the rect, and then we adjust our coords. 1590 IntRect colRect = colRects->at(i); 1591 1592 // Move to the next position. 1593 if (style()->direction() == LTR) { 1594 ruleX += colRect.width() + colGap / 2; 1595 currXOffset += colRect.width() + colGap; 1596 } else { 1597 ruleX -= (colRect.width() + colGap / 2); 1598 currXOffset -= (colRect.width() + colGap); 1599 } 1600 1601 // Now paint the column rule. 1602 if (i < colCount - 1) { 1603 int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; 1604 int ruleEnd = ruleStart + ruleWidth; 1605 int ruleTop = ty + borderTop() + paddingTop(); 1606 int ruleBottom = ruleTop + contentHeight(); 1607 drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, 1608 style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); 1609 } 1610 1611 ruleX = currXOffset; 1612 } 1613 } 1614 1615 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) 1616 { 1617 // We need to do multiple passes, breaking up our child painting into strips. 1618 GraphicsContext* context = paintInfo.context; 1619 int currXOffset = 0; 1620 int currYOffset = 0; 1621 int colGap = columnGap(); 1622 Vector<IntRect>* colRects = columnRects(); 1623 unsigned colCount = colRects->size(); 1624 for (unsigned i = 0; i < colCount; i++) { 1625 // For each rect, we clip to the rect, and then we adjust our coords. 1626 IntRect colRect = colRects->at(i); 1627 colRect.move(tx, ty); 1628 context->save(); 1629 1630 // Each strip pushes a clip, since column boxes are specified as being 1631 // like overflow:hidden. 1632 context->clip(colRect); 1633 1634 // Adjust tx and ty to change where we paint. 1635 PaintInfo info(paintInfo); 1636 info.rect.intersect(colRect); 1637 1638 // Adjust our x and y when painting. 1639 int finalX = tx + currXOffset; 1640 int finalY = ty + currYOffset; 1641 if (paintingFloats) 1642 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); 1643 else 1644 paintContents(info, finalX, finalY); 1645 1646 // Move to the next position. 1647 if (style()->direction() == LTR) 1648 currXOffset += colRect.width() + colGap; 1649 else 1650 currXOffset -= (colRect.width() + colGap); 1651 1652 currYOffset -= colRect.height(); 1653 1654 context->restore(); 1655 } 1656 } 1657 1658 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) 1659 { 1660 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. 1661 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 1662 // will do a full repaint(). 1663 if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) 1664 return; 1665 1666 if (childrenInline()) 1667 m_lineBoxes.paint(this, paintInfo, tx, ty); 1668 else 1669 paintChildren(paintInfo, tx, ty); 1670 } 1671 1672 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) 1673 { 1674 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 1675 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 1676 1677 // We don't paint our own background, but we do let the kids paint their backgrounds. 1678 PaintInfo info(paintInfo); 1679 info.phase = newPhase; 1680 info.paintingRoot = paintingRootForChildren(paintInfo); 1681 bool isPrinting = document()->printing(); 1682 1683 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1684 // Check for page-break-before: always, and if it's set, break and bail. 1685 if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && 1686 inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && 1687 (ty + child->y()) < paintInfo.rect.bottom()) { 1688 view()->setBestTruncatedAt(ty + child->y(), this, true); 1689 return; 1690 } 1691 1692 if (!child->hasSelfPaintingLayer() && !child->isFloating()) 1693 child->paint(info, tx, ty); 1694 1695 // Check for page-break-after: always, and if it's set, break and bail. 1696 if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && 1697 inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && 1698 (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { 1699 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); 1700 return; 1701 } 1702 } 1703 } 1704 1705 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type) 1706 { 1707 SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); 1708 1709 // Paint the caret if the SelectionController says so or if caret browsing is enabled 1710 bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled(); 1711 RenderObject* caretPainter = selection->caretRenderer(); 1712 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { 1713 // Convert the painting offset into the local coordinate system of this renderer, 1714 // to match the localCaretRect computed by the SelectionController 1715 offsetForContents(tx, ty); 1716 1717 if (type == CursorCaret) 1718 document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); 1719 else 1720 document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); 1721 } 1722 } 1723 1724 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) 1725 { 1726 PaintPhase paintPhase = paintInfo.phase; 1727 1728 // 1. paint background, borders etc 1729 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { 1730 if (hasBoxDecorations()) 1731 paintBoxDecorations(paintInfo, tx, ty); 1732 if (hasColumns()) 1733 paintColumnRules(paintInfo, tx, ty); 1734 } 1735 1736 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { 1737 paintMask(paintInfo, tx, ty); 1738 return; 1739 } 1740 1741 // We're done. We don't bother painting any children. 1742 if (paintPhase == PaintPhaseBlockBackground) 1743 return; 1744 1745 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s 1746 int scrolledX = tx; 1747 int scrolledY = ty; 1748 if (hasOverflowClip()) 1749 layer()->subtractScrolledContentOffset(scrolledX, scrolledY); 1750 1751 // 2. paint contents 1752 if (paintPhase != PaintPhaseSelfOutline) { 1753 if (hasColumns()) 1754 paintColumnContents(paintInfo, scrolledX, scrolledY); 1755 else 1756 paintContents(paintInfo, scrolledX, scrolledY); 1757 } 1758 1759 // 3. paint selection 1760 // FIXME: Make this work with multi column layouts. For now don't fill gaps. 1761 bool isPrinting = document()->printing(); 1762 if (!isPrinting && !hasColumns()) 1763 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. 1764 1765 // 4. paint floats. 1766 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { 1767 if (hasColumns()) 1768 paintColumnContents(paintInfo, scrolledX, scrolledY, true); 1769 else 1770 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); 1771 } 1772 1773 // 5. paint outline. 1774 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) 1775 paintOutline(paintInfo.context, tx, ty, width(), height(), style()); 1776 1777 // 6. paint continuation outlines. 1778 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { 1779 if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) { 1780 RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer()); 1781 RenderBlock* cb = containingBlock(); 1782 1783 bool inlineEnclosedInSelfPaintingLayer = false; 1784 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) { 1785 if (box->hasSelfPaintingLayer()) { 1786 inlineEnclosedInSelfPaintingLayer = true; 1787 break; 1788 } 1789 } 1790 1791 if (!inlineEnclosedInSelfPaintingLayer) 1792 cb->addContinuationWithOutline(inlineRenderer); 1793 else if (!inlineRenderer->firstLineBox()) 1794 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), 1795 ty - y() + inlineRenderer->containingBlock()->y()); 1796 } 1797 paintContinuationOutlines(paintInfo, tx, ty); 1798 } 1799 1800 // 7. paint caret. 1801 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, 1802 // then paint the caret. 1803 if (paintPhase == PaintPhaseForeground) { 1804 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); 1805 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); 1806 } 1807 } 1808 1809 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase) 1810 { 1811 if (!m_floatingObjects) 1812 return; 1813 1814 FloatingObject* r; 1815 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1816 for (; (r = it.current()); ++it) { 1817 // Only paint the object if our m_shouldPaint flag is set. 1818 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 1819 PaintInfo currentPaintInfo(paintInfo); 1820 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 1821 int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); 1822 int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); 1823 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1824 if (!preservePhase) { 1825 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 1826 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1827 currentPaintInfo.phase = PaintPhaseFloat; 1828 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1829 currentPaintInfo.phase = PaintPhaseForeground; 1830 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1831 currentPaintInfo.phase = PaintPhaseOutline; 1832 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1833 } 1834 } 1835 } 1836 } 1837 1838 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) 1839 { 1840 if (!shouldPaintWithinRoot(paintInfo) || !firstLineBox()) 1841 return; 1842 1843 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { 1844 // We can check the first box and last box and avoid painting if we don't 1845 // intersect. 1846 int yPos = ty + firstLineBox()->y(); 1847 int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y(); 1848 if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) 1849 return; 1850 1851 // See if our boxes intersect with the dirty rect. If so, then we paint 1852 // them. Note that boxes can easily overlap, so we can't make any assumptions 1853 // based off positions of our first line box or our last line box. 1854 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 1855 yPos = ty + curr->y(); 1856 h = curr->height(); 1857 if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) 1858 curr->paintEllipsisBox(paintInfo, tx, ty); 1859 } 1860 } 1861 } 1862 1863 static ContinuationOutlineTableMap* continuationOutlineTable() 1864 { 1865 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); 1866 return &table; 1867 } 1868 1869 void RenderBlock::addContinuationWithOutline(RenderInline* flow) 1870 { 1871 // We can't make this work if the inline is in a layer. We'll just rely on the broken 1872 // way of painting. 1873 ASSERT(!flow->layer() && !flow->isInlineContinuation()); 1874 1875 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1876 ListHashSet<RenderInline*>* continuations = table->get(this); 1877 if (!continuations) { 1878 continuations = new ListHashSet<RenderInline*>; 1879 table->set(this, continuations); 1880 } 1881 1882 continuations->add(flow); 1883 } 1884 1885 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) 1886 { 1887 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1888 if (table->isEmpty()) 1889 return; 1890 1891 ListHashSet<RenderInline*>* continuations = table->get(this); 1892 if (!continuations) 1893 return; 1894 1895 // Paint each continuation outline. 1896 ListHashSet<RenderInline*>::iterator end = continuations->end(); 1897 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { 1898 // Need to add in the coordinates of the intervening blocks. 1899 RenderInline* flow = *it; 1900 RenderBlock* block = flow->containingBlock(); 1901 for ( ; block && block != this; block = block->containingBlock()) { 1902 tx += block->x(); 1903 ty += block->y(); 1904 } 1905 ASSERT(block); 1906 flow->paintOutline(info.context, tx, ty); 1907 } 1908 1909 // Delete 1910 delete continuations; 1911 table->remove(this); 1912 } 1913 1914 void RenderBlock::setSelectionState(SelectionState s) 1915 { 1916 if (selectionState() == s) 1917 return; 1918 1919 if (s == SelectionInside && selectionState() != SelectionNone) 1920 return; 1921 1922 if ((s == SelectionStart && selectionState() == SelectionEnd) || 1923 (s == SelectionEnd && selectionState() == SelectionStart)) 1924 RenderBox::setSelectionState(SelectionBoth); 1925 else 1926 RenderBox::setSelectionState(s); 1927 1928 RenderBlock* cb = containingBlock(); 1929 if (cb && !cb->isRenderView()) 1930 cb->setSelectionState(s); 1931 } 1932 1933 bool RenderBlock::shouldPaintSelectionGaps() const 1934 { 1935 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); 1936 } 1937 1938 bool RenderBlock::isSelectionRoot() const 1939 { 1940 if (!node()) 1941 return false; 1942 1943 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. 1944 if (isTable()) 1945 return false; 1946 1947 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() || 1948 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() || 1949 hasReflection() || hasMask()) 1950 return true; 1951 1952 if (view() && view()->selectionStart()) { 1953 Node* startElement = view()->selectionStart()->node(); 1954 if (startElement && startElement->rootEditableElement() == node()) 1955 return true; 1956 } 1957 1958 return false; 1959 } 1960 1961 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer) 1962 { 1963 ASSERT(!needsLayout()); 1964 1965 if (!shouldPaintSelectionGaps()) 1966 return GapRects(); 1967 1968 // FIXME: this is broken with transforms 1969 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); 1970 mapLocalToContainer(repaintContainer, false, false, transformState); 1971 FloatPoint offsetFromRepaintContainer = transformState.mappedPoint(); 1972 int x = offsetFromRepaintContainer.x(); 1973 int y = offsetFromRepaintContainer.y(); 1974 1975 if (hasOverflowClip()) 1976 layer()->subtractScrolledContentOffset(x, y); 1977 1978 int lastTop = 0; 1979 int lastLeft = leftSelectionOffset(this, lastTop); 1980 int lastRight = rightSelectionOffset(this, lastTop); 1981 1982 return fillSelectionGaps(this, x, y, x, y, lastTop, lastLeft, lastRight); 1983 } 1984 1985 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) 1986 { 1987 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { 1988 int lastTop = 0; 1989 int lastLeft = leftSelectionOffset(this, lastTop); 1990 int lastRight = rightSelectionOffset(this, lastTop); 1991 paintInfo.context->save(); 1992 IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo); 1993 if (!gapRectsBounds.isEmpty()) { 1994 if (RenderLayer* layer = enclosingLayer()) { 1995 gapRectsBounds.move(IntSize(-tx, -ty)); 1996 if (!hasLayer()) { 1997 FloatRect localBounds(gapRectsBounds); 1998 gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox(); 1999 } 2000 layer->addBlockSelectionGapsBounds(gapRectsBounds); 2001 } 2002 } 2003 paintInfo.context->restore(); 2004 } 2005 } 2006 2007 #ifndef BUILDING_ON_TIGER 2008 static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) 2009 { 2010 if (!positionedObjects) 2011 return; 2012 2013 ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); 2014 for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { 2015 RenderBox* r = *it; 2016 paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); 2017 } 2018 } 2019 #endif 2020 2021 GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2022 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2023 { 2024 #ifndef BUILDING_ON_TIGER 2025 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. 2026 // Clip out floating and positioned objects when painting selection gaps. 2027 if (paintInfo) { 2028 // Note that we don't clip out overflow for positioned objects. We just stick to the border box. 2029 clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); 2030 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. 2031 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) 2032 clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); 2033 if (m_floatingObjects) { 2034 for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { 2035 FloatingObject* r = it.current(); 2036 paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(), 2037 ty + r->m_top + r->m_renderer->marginTop(), 2038 r->m_renderer->width(), r->m_renderer->height())); 2039 } 2040 } 2041 } 2042 #endif 2043 2044 // 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 2045 // fixed). 2046 GapRects result; 2047 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. 2048 return result; 2049 2050 if (hasColumns() || hasTransform()) { 2051 // FIXME: We should learn how to gap fill multiple columns and transforms eventually. 2052 lastTop = (ty - blockY) + height(); 2053 lastLeft = leftSelectionOffset(rootBlock, height()); 2054 lastRight = rightSelectionOffset(rootBlock, height()); 2055 return result; 2056 } 2057 2058 if (childrenInline()) 2059 result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2060 else 2061 result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2062 2063 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. 2064 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) 2065 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), 2066 rootBlock, blockX, blockY, paintInfo)); 2067 return result; 2068 } 2069 2070 GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2071 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2072 { 2073 GapRects result; 2074 2075 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 2076 2077 if (!firstLineBox()) { 2078 if (containsStart) { 2079 // Go ahead and update our lastY to be the bottom of the block. <hr>s or empty blocks with height can trip this 2080 // case. 2081 lastTop = (ty - blockY) + height(); 2082 lastLeft = leftSelectionOffset(rootBlock, height()); 2083 lastRight = rightSelectionOffset(rootBlock, height()); 2084 } 2085 return result; 2086 } 2087 2088 RootInlineBox* lastSelectedLine = 0; 2089 RootInlineBox* curr; 2090 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 2091 2092 // Now paint the gaps for the lines. 2093 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 2094 int selTop = curr->selectionTop(); 2095 int selHeight = curr->selectionHeight(); 2096 2097 if (!containsStart && !lastSelectedLine && 2098 selectionState() != SelectionStart && selectionState() != SelectionBoth) 2099 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop, 2100 rootBlock, blockX, blockY, paintInfo)); 2101 2102 if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())) 2103 result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); 2104 2105 lastSelectedLine = curr; 2106 } 2107 2108 if (containsStart && !lastSelectedLine) 2109 // VisibleSelection must start just after our last line. 2110 lastSelectedLine = lastRootBox(); 2111 2112 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 2113 // Go ahead and update our lastY to be the bottom of the last selected line. 2114 lastTop = (ty - blockY) + lastSelectedLine->selectionBottom(); 2115 lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2116 lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2117 } 2118 return result; 2119 } 2120 2121 GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2122 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2123 { 2124 GapRects result; 2125 2126 // Go ahead and jump right to the first block child that contains some selected objects. 2127 RenderBox* curr; 2128 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } 2129 2130 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { 2131 SelectionState childState = curr->selectionState(); 2132 if (childState == SelectionBoth || childState == SelectionEnd) 2133 sawSelectionEnd = true; 2134 2135 if (curr->isFloatingOrPositioned()) 2136 continue; // We must be a normal flow object in order to even be considered. 2137 2138 if (curr->isRelPositioned() && curr->hasLayer()) { 2139 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. 2140 // Just disregard it completely. 2141 IntSize relOffset = curr->layer()->relativePositionOffset(); 2142 if (relOffset.width() || relOffset.height()) 2143 continue; 2144 } 2145 2146 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this. 2147 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone); 2148 if (fillBlockGaps) { 2149 // We need to fill the vertical gap above this object. 2150 if (childState == SelectionEnd || childState == SelectionInside) 2151 // Fill the gap above the object. 2152 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, 2153 ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); 2154 2155 // 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* 2156 // our object. We know this if the selection did not end inside our object. 2157 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd)) 2158 childState = SelectionNone; 2159 2160 // Fill side gaps on this object based off its state. 2161 bool leftGap, rightGap; 2162 getHorizontalSelectionGapInfo(childState, leftGap, rightGap); 2163 2164 if (leftGap) 2165 result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2166 if (rightGap) 2167 result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2168 2169 // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as 2170 // they can without bumping into floating or positioned objects. Ideally they will go right up 2171 // to the border of the root selection block. 2172 lastTop = (ty - blockY) + (curr->y() + curr->height()); 2173 lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); 2174 lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); 2175 } else if (childState != SelectionNone) 2176 // We must be a block that has some selected object inside it. Go ahead and recur. 2177 result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), 2178 lastTop, lastLeft, lastRight, paintInfo)); 2179 } 2180 return result; 2181 } 2182 2183 IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo* paintInfo) 2184 { 2185 if (width <= 0 || height <= 0) 2186 return IntRect(); 2187 IntRect gapRect(xPos, yPos, width, height); 2188 if (paintInfo && selObj->style()->visibility() == VISIBLE) 2189 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2190 return gapRect; 2191 } 2192 2193 IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock, 2194 int blockX, int blockY, const PaintInfo* paintInfo) 2195 { 2196 int top = blockY + lastTop; 2197 int height = bottomY - top; 2198 if (height <= 0) 2199 return IntRect(); 2200 2201 // Get the selection offsets for the bottom of the gap 2202 int left = blockX + max(lastLeft, leftSelectionOffset(rootBlock, bottomY)); 2203 int right = blockX + min(lastRight, rightSelectionOffset(rootBlock, bottomY)); 2204 int width = right - left; 2205 if (width <= 0) 2206 return IntRect(); 2207 2208 IntRect gapRect(left, top, width, height); 2209 if (paintInfo) 2210 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace()); 2211 return gapRect; 2212 } 2213 2214 IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2215 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2216 { 2217 int top = yPos + ty; 2218 int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)); 2219 int right = min(xPos + tx, blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height))); 2220 int width = right - left; 2221 if (width <= 0) 2222 return IntRect(); 2223 2224 IntRect gapRect(left, top, width, height); 2225 if (paintInfo) 2226 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2227 return gapRect; 2228 } 2229 2230 IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2231 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2232 { 2233 int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height))); 2234 int top = yPos + ty; 2235 int right = blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height)); 2236 int width = right - left; 2237 if (width <= 0) 2238 return IntRect(); 2239 2240 IntRect gapRect(left, top, width, height); 2241 if (paintInfo) 2242 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2243 return gapRect; 2244 } 2245 2246 void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) 2247 { 2248 bool ltr = style()->direction() == LTR; 2249 leftGap = (state == RenderObject::SelectionInside) || 2250 (state == RenderObject::SelectionEnd && ltr) || 2251 (state == RenderObject::SelectionStart && !ltr); 2252 rightGap = (state == RenderObject::SelectionInside) || 2253 (state == RenderObject::SelectionStart && ltr) || 2254 (state == RenderObject::SelectionEnd && !ltr); 2255 } 2256 2257 int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) 2258 { 2259 int left = leftOffset(yPos, false); 2260 if (left == borderLeft() + paddingLeft()) { 2261 if (rootBlock != this) 2262 // The border can potentially be further extended by our containingBlock(). 2263 return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); 2264 return left; 2265 } 2266 else { 2267 RenderBlock* cb = this; 2268 while (cb != rootBlock) { 2269 left += cb->x(); 2270 cb = cb->containingBlock(); 2271 } 2272 } 2273 2274 return left; 2275 } 2276 2277 int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) 2278 { 2279 int right = rightOffset(yPos, false); 2280 if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { 2281 if (rootBlock != this) 2282 // The border can potentially be further extended by our containingBlock(). 2283 return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); 2284 return right; 2285 } 2286 else { 2287 RenderBlock* cb = this; 2288 while (cb != rootBlock) { 2289 right += cb->x(); 2290 cb = cb->containingBlock(); 2291 } 2292 } 2293 return right; 2294 } 2295 2296 void RenderBlock::insertPositionedObject(RenderBox* o) 2297 { 2298 // Create the list of special objects if we don't aleady have one 2299 if (!m_positionedObjects) 2300 m_positionedObjects = new ListHashSet<RenderBox*>; 2301 2302 m_positionedObjects->add(o); 2303 } 2304 2305 void RenderBlock::removePositionedObject(RenderBox* o) 2306 { 2307 if (m_positionedObjects) 2308 m_positionedObjects->remove(o); 2309 } 2310 2311 void RenderBlock::removePositionedObjects(RenderBlock* o) 2312 { 2313 if (!m_positionedObjects) 2314 return; 2315 2316 RenderBox* r; 2317 2318 Iterator end = m_positionedObjects->end(); 2319 2320 Vector<RenderBox*, 16> deadObjects; 2321 2322 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2323 r = *it; 2324 if (!o || r->isDescendantOf(o)) { 2325 if (o) 2326 r->setChildNeedsLayout(true, false); 2327 2328 // It is parent blocks job to add positioned child to positioned objects list of its containing block 2329 // Parent layout needs to be invalidated to ensure this happens. 2330 RenderObject* p = r->parent(); 2331 while (p && !p->isRenderBlock()) 2332 p = p->parent(); 2333 if (p) 2334 p->setChildNeedsLayout(true); 2335 2336 deadObjects.append(r); 2337 } 2338 } 2339 2340 for (unsigned i = 0; i < deadObjects.size(); i++) 2341 m_positionedObjects->remove(deadObjects.at(i)); 2342 } 2343 2344 void RenderBlock::insertFloatingObject(RenderBox* o) 2345 { 2346 ASSERT(o->isFloating()); 2347 2348 // Create the list of special objects if we don't aleady have one 2349 if (!m_floatingObjects) { 2350 m_floatingObjects = new DeprecatedPtrList<FloatingObject>; 2351 m_floatingObjects->setAutoDelete(true); 2352 } else { 2353 // Don't insert the object again if it's already in the list 2354 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2355 FloatingObject* f; 2356 while ( (f = it.current()) ) { 2357 if (f->m_renderer == o) return; 2358 ++it; 2359 } 2360 } 2361 2362 // Create the special object entry & append it to the list 2363 2364 o->layoutIfNeeded(); 2365 2366 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight); 2367 2368 newObj->m_top = -1; 2369 newObj->m_bottom = -1; 2370 newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); 2371 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. 2372 newObj->m_isDescendant = true; 2373 newObj->m_renderer = o; 2374 2375 m_floatingObjects->append(newObj); 2376 } 2377 2378 void RenderBlock::removeFloatingObject(RenderBox* o) 2379 { 2380 if (m_floatingObjects) { 2381 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2382 while (it.current()) { 2383 if (it.current()->m_renderer == o) { 2384 if (childrenInline()) 2385 markLinesDirtyInVerticalRange(0, it.current()->m_bottom); 2386 m_floatingObjects->removeRef(it.current()); 2387 } 2388 ++it; 2389 } 2390 } 2391 } 2392 2393 bool RenderBlock::positionNewFloats() 2394 { 2395 if (!m_floatingObjects) 2396 return false; 2397 2398 FloatingObject* f = m_floatingObjects->last(); 2399 2400 // If all floats have already been positioned, then we have no work to do. 2401 if (!f || f->m_top != -1) 2402 return false; 2403 2404 // Move backwards through our floating object list until we find a float that has 2405 // already been positioned. Then we'll be able to move forward, positioning all of 2406 // the new floats that need it. 2407 FloatingObject* lastFloat = m_floatingObjects->getPrev(); 2408 while (lastFloat && lastFloat->m_top == -1) { 2409 f = m_floatingObjects->prev(); 2410 lastFloat = m_floatingObjects->getPrev(); 2411 } 2412 2413 int y = height(); 2414 2415 // The float cannot start above the y position of the last positioned float. 2416 if (lastFloat) 2417 y = max(lastFloat->m_top, y); 2418 2419 // Now walk through the set of unpositioned floats and place them. 2420 while (f) { 2421 // The containing block is responsible for positioning floats, so if we have floats in our 2422 // list that come from somewhere else, do not attempt to position them. 2423 if (f->m_renderer->containingBlock() != this) { 2424 f = m_floatingObjects->next(); 2425 continue; 2426 } 2427 2428 RenderBox* o = f->m_renderer; 2429 int _height = o->height() + o->marginTop() + o->marginBottom(); 2430 2431 int ro = rightOffset(); // Constant part of right offset. 2432 int lo = leftOffset(); // Constat part of left offset. 2433 int fwidth = f->m_width; // The width we look for. 2434 if (ro - lo < fwidth) 2435 fwidth = ro - lo; // Never look for more than what will be available. 2436 2437 IntRect oldRect(o->x(), o->y() , o->width(), o->height()); 2438 2439 if (o->style()->clear() & CLEFT) 2440 y = max(leftBottom(), y); 2441 if (o->style()->clear() & CRIGHT) 2442 y = max(rightBottom(), y); 2443 2444 if (o->style()->floating() == FLEFT) { 2445 int heightRemainingLeft = 1; 2446 int heightRemainingRight = 1; 2447 int fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2448 while (rightRelOffset(y, ro, false, &heightRemainingRight)-fx < fwidth) { 2449 y += min(heightRemainingLeft, heightRemainingRight); 2450 fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2451 } 2452 fx = max(0, fx); 2453 f->m_left = fx; 2454 o->setLocation(fx + o->marginLeft(), y + o->marginTop()); 2455 } else { 2456 int heightRemainingLeft = 1; 2457 int heightRemainingRight = 1; 2458 int fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2459 while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) { 2460 y += min(heightRemainingLeft, heightRemainingRight); 2461 fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2462 } 2463 f->m_left = fx - f->m_width; 2464 o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); 2465 } 2466 2467 f->m_top = y; 2468 f->m_bottom = f->m_top + _height; 2469 2470 // If the child moved, we have to repaint it. 2471 if (o->checkForRepaintDuringLayout()) 2472 o->repaintDuringLayoutIfMoved(oldRect); 2473 2474 f = m_floatingObjects->next(); 2475 } 2476 return true; 2477 } 2478 2479 void RenderBlock::newLine(EClear clear) 2480 { 2481 positionNewFloats(); 2482 // set y position 2483 int newY = 0; 2484 switch (clear) 2485 { 2486 case CLEFT: 2487 newY = leftBottom(); 2488 break; 2489 case CRIGHT: 2490 newY = rightBottom(); 2491 break; 2492 case CBOTH: 2493 newY = floatBottom(); 2494 default: 2495 break; 2496 } 2497 if (height() < newY) 2498 setHeight(newY); 2499 } 2500 2501 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) 2502 { 2503 if (!gPercentHeightDescendantsMap) { 2504 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap; 2505 gPercentHeightContainerMap = new PercentHeightContainerMap; 2506 } 2507 2508 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this); 2509 if (!descendantSet) { 2510 descendantSet = new HashSet<RenderBox*>; 2511 gPercentHeightDescendantsMap->set(this, descendantSet); 2512 } 2513 bool added = descendantSet->add(descendant).second; 2514 if (!added) { 2515 ASSERT(gPercentHeightContainerMap->get(descendant)); 2516 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this)); 2517 return; 2518 } 2519 2520 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant); 2521 if (!containerSet) { 2522 containerSet = new HashSet<RenderBlock*>; 2523 gPercentHeightContainerMap->set(descendant, containerSet); 2524 } 2525 ASSERT(!containerSet->contains(this)); 2526 containerSet->add(this); 2527 } 2528 2529 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) 2530 { 2531 if (!gPercentHeightContainerMap) 2532 return; 2533 2534 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant); 2535 if (!containerSet) 2536 return; 2537 2538 HashSet<RenderBlock*>::iterator end = containerSet->end(); 2539 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) { 2540 RenderBlock* container = *it; 2541 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container); 2542 ASSERT(descendantSet); 2543 if (!descendantSet) 2544 continue; 2545 ASSERT(descendantSet->contains(descendant)); 2546 descendantSet->remove(descendant); 2547 if (descendantSet->isEmpty()) { 2548 gPercentHeightDescendantsMap->remove(container); 2549 delete descendantSet; 2550 } 2551 } 2552 2553 delete containerSet; 2554 } 2555 2556 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const 2557 { 2558 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; 2559 } 2560 2561 int RenderBlock::leftOffset() const 2562 { 2563 return borderLeft() + paddingLeft(); 2564 } 2565 2566 int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2567 { 2568 int left = fixedOffset; 2569 if (m_floatingObjects) { 2570 if ( heightRemaining ) *heightRemaining = 1; 2571 FloatingObject* r; 2572 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2573 for ( ; (r = it.current()); ++it ) 2574 { 2575 if (r->m_top <= y && r->m_bottom > y && 2576 r->type() == FloatingObject::FloatLeft && 2577 r->m_left + r->m_width > left) { 2578 left = r->m_left + r->m_width; 2579 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2580 } 2581 } 2582 } 2583 2584 if (applyTextIndent && style()->direction() == LTR) { 2585 int cw = 0; 2586 if (style()->textIndent().isPercent()) 2587 cw = containingBlock()->availableWidth(); 2588 left += style()->textIndent().calcMinValue(cw); 2589 } 2590 2591 return left; 2592 } 2593 2594 int RenderBlock::rightOffset() const 2595 { 2596 return borderLeft() + paddingLeft() + availableWidth(); 2597 } 2598 2599 int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2600 { 2601 int right = fixedOffset; 2602 2603 if (m_floatingObjects) { 2604 if (heightRemaining) *heightRemaining = 1; 2605 FloatingObject* r; 2606 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2607 for ( ; (r = it.current()); ++it ) 2608 { 2609 if (r->m_top <= y && r->m_bottom > y && 2610 r->type() == FloatingObject::FloatRight && 2611 r->m_left < right) { 2612 right = r->m_left; 2613 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2614 } 2615 } 2616 } 2617 2618 if (applyTextIndent && style()->direction() == RTL) { 2619 int cw = 0; 2620 if (style()->textIndent().isPercent()) 2621 cw = containingBlock()->availableWidth(); 2622 right -= style()->textIndent().calcMinValue(cw); 2623 } 2624 2625 return right; 2626 } 2627 2628 int 2629 RenderBlock::lineWidth(int y, bool firstLine) const 2630 { 2631 int result = rightOffset(y, firstLine) - leftOffset(y, firstLine); 2632 return (result < 0) ? 0 : result; 2633 } 2634 2635 int RenderBlock::nextFloatBottomBelow(int height) const 2636 { 2637 if (!m_floatingObjects) 2638 return 0; 2639 2640 int bottom = INT_MAX; 2641 FloatingObject* r; 2642 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2643 for ( ; (r = it.current()); ++it) { 2644 if (r->m_bottom > height) 2645 bottom = min(r->m_bottom, bottom); 2646 } 2647 2648 return bottom == INT_MAX ? 0 : bottom; 2649 } 2650 2651 int 2652 RenderBlock::floatBottom() const 2653 { 2654 if (!m_floatingObjects) return 0; 2655 int bottom = 0; 2656 FloatingObject* r; 2657 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2658 for ( ; (r = it.current()); ++it ) 2659 if (r->m_bottom>bottom) 2660 bottom = r->m_bottom; 2661 return bottom; 2662 } 2663 2664 IntRect RenderBlock::floatRect() const 2665 { 2666 IntRect result; 2667 if (!m_floatingObjects || hasOverflowClip() || hasColumns()) 2668 return result; 2669 FloatingObject* r; 2670 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2671 for (; (r = it.current()); ++it) { 2672 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 2673 IntRect childRect = r->m_renderer->visibleOverflowRect(); 2674 childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); 2675 result.unite(childRect); 2676 } 2677 } 2678 2679 return result; 2680 } 2681 2682 int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const 2683 { 2684 int bottom = includeSelf && width() > 0 ? height() : 0; 2685 2686 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2687 return bottom; 2688 2689 if (!firstChild() && (!width() || !height())) 2690 return bottom; 2691 2692 if (!hasColumns()) { 2693 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2694 // For now, we have to descend into all the children, since we may have a huge abs div inside 2695 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2696 // the abs div. 2697 // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem. 2698 // For inline children, we miss relative positioned boxes that might be buried inside <span>s. 2699 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2700 if (!c->isFloatingOrPositioned() && c->isBox()) { 2701 RenderBox* childBox = toRenderBox(c); 2702 bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); 2703 } 2704 } 2705 } 2706 2707 if (includeSelf && isRelPositioned()) 2708 bottom += relativePositionOffsetY(); 2709 if (!includeOverflowInterior && hasOverflowClip()) 2710 return bottom; 2711 2712 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0; 2713 2714 if (includeSelf) 2715 bottom = max(bottom, bottomLayoutOverflow() + relativeOffset); 2716 2717 if (m_positionedObjects) { 2718 RenderBox* r; 2719 Iterator end = m_positionedObjects->end(); 2720 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2721 r = *it; 2722 // Fixed positioned objects do not scroll and thus should not constitute 2723 // part of the lowest position. 2724 if (r->style()->position() != FixedPosition) { 2725 // FIXME: Should work for overflow sections too. 2726 // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. 2727 // Therefore we should not allow it to contribute to the lowest position. 2728 if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { 2729 int lp = r->y() + r->lowestPosition(false); 2730 bottom = max(bottom, lp + relativeOffset); 2731 } 2732 } 2733 } 2734 } 2735 2736 if (hasColumns()) { 2737 Vector<IntRect>* colRects = columnRects(); 2738 for (unsigned i = 0; i < colRects->size(); i++) 2739 bottom = max(bottom, colRects->at(i).bottom() + relativeOffset); 2740 return bottom; 2741 } 2742 2743 if (m_floatingObjects) { 2744 FloatingObject* r; 2745 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2746 for ( ; (r = it.current()); ++it ) { 2747 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2748 int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); 2749 bottom = max(bottom, lp + relativeOffset); 2750 } 2751 } 2752 } 2753 2754 if (!includeSelf) { 2755 bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset); 2756 if (childrenInline()) { 2757 if (lastRootBox()) { 2758 int childBottomEdge = lastRootBox()->selectionBottom(); 2759 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2760 } 2761 } else { 2762 // Find the last normal flow child. 2763 RenderBox* currBox = lastChildBox(); 2764 while (currBox && currBox->isFloatingOrPositioned()) 2765 currBox = currBox->previousSiblingBox(); 2766 if (currBox) { 2767 int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom(); 2768 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2769 } 2770 } 2771 } 2772 2773 return bottom; 2774 } 2775 2776 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const 2777 { 2778 int right = includeSelf && height() > 0 ? width() : 0; 2779 2780 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2781 return right; 2782 2783 if (!firstChild() && (!width() || !height())) 2784 return right; 2785 2786 if (!hasColumns()) { 2787 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2788 // For now, we have to descend into all the children, since we may have a huge abs div inside 2789 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2790 // the abs div. 2791 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2792 if (!c->isFloatingOrPositioned() && c->isBox()) { 2793 RenderBox* childBox = toRenderBox(c); 2794 right = max(right, childBox->x() + childBox->rightmostPosition(false)); 2795 } 2796 } 2797 } 2798 2799 if (includeSelf && isRelPositioned()) 2800 right