1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2007 David Smith (catfish.man (at) gmail.com) 5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Library General Public 9 * License as published by the Free Software Foundation; either 10 * version 2 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Library General Public License for more details. 16 * 17 * You should have received a copy of the GNU Library General Public License 18 * along with this library; see the file COPYING.LIB. If not, write to 19 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 20 * Boston, MA 02110-1301, USA. 21 */ 22 23 #include "config.h" 24 #include "RenderBlock.h" 25 26 #include "Document.h" 27 #include "Element.h" 28 #include "FloatQuad.h" 29 #include "Frame.h" 30 #include "FrameView.h" 31 #include "GraphicsContext.h" 32 #include "HTMLFormElement.h" 33 #include "HTMLNames.h" 34 #include "HitTestResult.h" 35 #include "InlineTextBox.h" 36 #include "RenderFlexibleBox.h" 37 #include "RenderImage.h" 38 #include "RenderInline.h" 39 #include "RenderMarquee.h" 40 #include "RenderReplica.h" 41 #include "RenderTableCell.h" 42 #include "RenderTextFragment.h" 43 #include "RenderTheme.h" 44 #include "RenderView.h" 45 #include "SelectionController.h" 46 #include "Settings.h" 47 #include "TransformState.h" 48 #include <wtf/StdLibExtras.h> 49 50 #ifdef ANDROID_LAYOUT 51 #include "Settings.h" 52 #endif 53 54 using namespace std; 55 using namespace WTF; 56 using namespace Unicode; 57 58 namespace WebCore { 59 60 // Number of pixels to allow as a fudge factor when clicking above or below a line. 61 // clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line. 62 static const int verticalLineClickFudgeFactor = 3; 63 64 using namespace HTMLNames; 65 66 struct ColumnInfo : public Noncopyable { 67 ColumnInfo() 68 : m_desiredColumnWidth(0) 69 , m_desiredColumnCount(1) 70 { } 71 int m_desiredColumnWidth; 72 unsigned m_desiredColumnCount; 73 Vector<IntRect> m_columnRects; 74 }; 75 76 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap; 77 static ColumnInfoMap* gColumnInfoMap = 0; 78 79 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap; 80 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; 81 82 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; 83 static PercentHeightContainerMap* gPercentHeightContainerMap = 0; 84 85 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; 86 87 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet; 88 static int gDelayUpdateScrollInfo = 0; 89 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; 90 91 // Our MarginInfo state used when laying out block children. 92 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom) 93 { 94 // Whether or not we can collapse our own margins with our children. We don't do this 95 // if we had any border/padding (obviously), if we're the root or HTML elements, or if 96 // we're positioned, floating, a table cell. 97 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() && 98 !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable(); 99 100 m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE; 101 102 // If any height other than auto is specified in CSS, then we don't collapse our bottom 103 // margins with our children's margins. To do otherwise would be to risk odd visual 104 // effects when the children overflow out of the parent block and yet still collapse 105 // with it. We also don't collapse if we have any bottom border/padding. 106 m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) && 107 (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE; 108 109 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD || 110 block->style()->marginBottomCollapse() == MDISCARD; 111 112 m_atTopOfBlock = true; 113 m_atBottomOfBlock = false; 114 115 m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0; 116 m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0; 117 118 m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false; 119 } 120 121 // ------------------------------------------------------------------------------------------------------- 122 123 RenderBlock::RenderBlock(Node* node) 124 : RenderBox(node) 125 , m_floatingObjects(0) 126 , m_positionedObjects(0) 127 , m_inlineContinuation(0) 128 , m_maxMargin(0) 129 , m_lineHeight(-1) 130 { 131 setChildrenInline(true); 132 } 133 134 RenderBlock::~RenderBlock() 135 { 136 delete m_floatingObjects; 137 delete m_positionedObjects; 138 delete m_maxMargin; 139 140 if (hasColumns()) 141 delete gColumnInfoMap->take(this); 142 143 if (gPercentHeightDescendantsMap) { 144 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) { 145 HashSet<RenderBox*>::iterator end = descendantSet->end(); 146 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) { 147 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant); 148 ASSERT(containerSet); 149 if (!containerSet) 150 continue; 151 ASSERT(containerSet->contains(this)); 152 containerSet->remove(this); 153 if (containerSet->isEmpty()) { 154 gPercentHeightContainerMap->remove(*descendant); 155 delete containerSet; 156 } 157 } 158 delete descendantSet; 159 } 160 } 161 } 162 163 void RenderBlock::destroy() 164 { 165 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will 166 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise. 167 children()->destroyLeftoverChildren(); 168 169 // Destroy our continuation before anything other than anonymous children. 170 // The reason we don't destroy it before anonymous children is that they may 171 // have continuations of their own that are anonymous children of our continuation. 172 if (m_inlineContinuation) { 173 m_inlineContinuation->destroy(); 174 m_inlineContinuation = 0; 175 } 176 177 if (!documentBeingDestroyed()) { 178 if (firstLineBox()) { 179 // We can't wait for RenderBox::destroy to clear the selection, 180 // because by then we will have nuked the line boxes. 181 // FIXME: The SelectionController should be responsible for this when it 182 // is notified of DOM mutations. 183 if (isSelectionBorder()) 184 view()->clearSelection(); 185 186 // If we are an anonymous block, then our line boxes might have children 187 // that will outlast this block. In the non-anonymous block case those 188 // children will be destroyed by the time we return from this function. 189 if (isAnonymousBlock()) { 190 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) { 191 while (InlineBox* childBox = box->firstChild()) 192 childBox->remove(); 193 } 194 } 195 } else if (isInline() && parent()) 196 parent()->dirtyLinesFromChangedChild(this); 197 } 198 199 m_lineBoxes.deleteLineBoxes(renderArena()); 200 201 RenderBox::destroy(); 202 } 203 204 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle) 205 { 206 setReplaced(newStyle->isDisplayReplacedType()); 207 208 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) { 209 if (newStyle->position() == StaticPosition) 210 // Clear our positioned objects list. Our absolutely positioned descendants will be 211 // inserted into our containing block's positioned objects list during layout. 212 removePositionedObjects(0); 213 else if (style()->position() == StaticPosition) { 214 // Remove our absolutely positioned descendants from their current containing block. 215 // They will be inserted into our positioned objects list during layout. 216 RenderObject* cb = parent(); 217 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) { 218 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) { 219 cb = cb->containingBlock(); 220 break; 221 } 222 cb = cb->parent(); 223 } 224 225 if (cb->isRenderBlock()) 226 toRenderBlock(cb)->removePositionedObjects(this); 227 } 228 } 229 230 RenderBox::styleWillChange(diff, newStyle); 231 } 232 233 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle) 234 { 235 RenderBox::styleDidChange(diff, oldStyle); 236 237 // FIXME: We could save this call when the change only affected non-inherited properties 238 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 239 if (child->isAnonymousBlock()) { 240 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 241 newStyle->inheritFrom(style()); 242 newStyle->setDisplay(BLOCK); 243 child->setStyle(newStyle.release()); 244 } 245 } 246 247 m_lineHeight = -1; 248 249 // Update pseudos for :before and :after now. 250 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) { 251 updateBeforeAfterContent(BEFORE); 252 updateBeforeAfterContent(AFTER); 253 } 254 updateFirstLetter(); 255 } 256 257 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId) 258 { 259 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it. 260 if (parent() && parent()->createsAnonymousWrapper()) 261 return; 262 return children()->updateBeforeAfterContent(this, pseudoId); 263 } 264 265 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) 266 { 267 // Make sure we don't append things after :after-generated content if we have it. 268 if (!beforeChild && isAfterContent(lastChild())) 269 beforeChild = lastChild(); 270 271 bool madeBoxesNonInline = false; 272 273 // If the requested beforeChild is not one of our children, then this is because 274 // there is an anonymous container within this object that contains the beforeChild. 275 if (beforeChild && beforeChild->parent() != this) { 276 RenderObject* anonymousChild = beforeChild->parent(); 277 ASSERT(anonymousChild); 278 279 while (anonymousChild->parent() != this) 280 anonymousChild = anonymousChild->parent(); 281 282 ASSERT(anonymousChild->isAnonymous()); 283 284 if (anonymousChild->isAnonymousBlock()) { 285 // Insert the child into the anonymous block box instead of here. 286 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) 287 beforeChild->parent()->addChild(newChild, beforeChild); 288 else 289 addChild(newChild, beforeChild->parent()); 290 return; 291 } 292 293 ASSERT(anonymousChild->isTable()); 294 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) 295 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) 296 || newChild->isTableSection() 297 || newChild->isTableRow() 298 || newChild->isTableCell()) { 299 // Insert into the anonymous table. 300 anonymousChild->addChild(newChild, beforeChild); 301 return; 302 } 303 304 // Go on to insert before the anonymous table. 305 beforeChild = anonymousChild; 306 } 307 308 // A block has to either have all of its children inline, or all of its children as blocks. 309 // So, if our children are currently inline and a block child has to be inserted, we move all our 310 // inline children into anonymous block boxes. 311 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { 312 // This is a block with inline content. Wrap the inline content in anonymous blocks. 313 makeChildrenNonInline(beforeChild); 314 madeBoxesNonInline = true; 315 316 if (beforeChild && beforeChild->parent() != this) { 317 beforeChild = beforeChild->parent(); 318 ASSERT(beforeChild->isAnonymousBlock()); 319 ASSERT(beforeChild->parent() == this); 320 } 321 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) { 322 // If we're inserting an inline child but all of our children are blocks, then we have to make sure 323 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise 324 // a new one is created and inserted into our list of children in the appropriate position. 325 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild(); 326 327 if (afterChild && afterChild->isAnonymousBlock()) { 328 afterChild->addChild(newChild); 329 return; 330 } 331 332 if (newChild->isInline()) { 333 // No suitable existing anonymous box - create a new one. 334 RenderBlock* newBox = createAnonymousBlock(); 335 RenderBox::addChild(newBox, beforeChild); 336 newBox->addChild(newChild); 337 return; 338 } 339 } 340 341 RenderBox::addChild(newChild, beforeChild); 342 343 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) 344 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 345 // this object may be dead here 346 } 347 348 static void getInlineRun(RenderObject* start, RenderObject* boundary, 349 RenderObject*& inlineRunStart, 350 RenderObject*& inlineRunEnd) 351 { 352 // Beginning at |start| we find the largest contiguous run of inlines that 353 // we can. We denote the run with start and end points, |inlineRunStart| 354 // and |inlineRunEnd|. Note that these two values may be the same if 355 // we encounter only one inline. 356 // 357 // We skip any non-inlines we encounter as long as we haven't found any 358 // inlines yet. 359 // 360 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary| 361 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered 362 // a non-inline. 363 364 // Start by skipping as many non-inlines as we can. 365 RenderObject * curr = start; 366 bool sawInline; 367 do { 368 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) 369 curr = curr->nextSibling(); 370 371 inlineRunStart = inlineRunEnd = curr; 372 373 if (!curr) 374 return; // No more inline children to be found. 375 376 sawInline = curr->isInline(); 377 378 curr = curr->nextSibling(); 379 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) { 380 inlineRunEnd = curr; 381 if (curr->isInline()) 382 sawInline = true; 383 curr = curr->nextSibling(); 384 } 385 } while (!sawInline); 386 } 387 388 void RenderBlock::deleteLineBoxTree() 389 { 390 m_lineBoxes.deleteLineBoxTree(renderArena()); 391 } 392 393 RootInlineBox* RenderBlock::createRootInlineBox() 394 { 395 return new (renderArena()) RootInlineBox(this); 396 } 397 398 RootInlineBox* RenderBlock::createAndAppendRootInlineBox() 399 { 400 RootInlineBox* rootBox = createRootInlineBox(); 401 m_lineBoxes.appendLineBox(rootBox); 402 return rootBox; 403 } 404 405 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child) 406 { 407 ASSERT(this == child->parent()); 408 toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); 409 } 410 411 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child) 412 { 413 ASSERT(this == child->parent()); 414 ASSERT(!beforeChild || to == beforeChild->parent()); 415 toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); 416 } 417 418 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList) 419 { 420 RenderObject* nextChild = children()->firstChild(); 421 while (nextChild) { 422 RenderObject* child = nextChild; 423 nextChild = child->nextSibling(); 424 toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false); 425 } 426 } 427 428 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild) 429 { 430 ASSERT(!beforeChild || to == beforeChild->parent()); 431 if (!beforeChild) { 432 moveAllChildrenTo(to, toChildList); 433 return; 434 } 435 RenderObject* nextChild = children()->firstChild(); 436 while (nextChild) { 437 RenderObject* child = nextChild; 438 nextChild = child->nextSibling(); 439 toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false); 440 } 441 } 442 443 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) 444 { 445 // makeChildrenNonInline takes a block whose children are *all* inline and it 446 // makes sure that inline children are coalesced under anonymous 447 // blocks. If |insertionPoint| is defined, then it represents the insertion point for 448 // the new block child that is causing us to have to wrap all the inlines. This 449 // means that we cannot coalesce inlines before |insertionPoint| with inlines following 450 // |insertionPoint|, because the new child is going to be inserted in between the inlines, 451 // splitting them. 452 ASSERT(isInlineBlockOrInlineTable() || !isInline()); 453 ASSERT(!insertionPoint || insertionPoint->parent() == this); 454 455 setChildrenInline(false); 456 457 RenderObject *child = firstChild(); 458 if (!child) 459 return; 460 461 deleteLineBoxTree(); 462 463 while (child) { 464 RenderObject *inlineRunStart, *inlineRunEnd; 465 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); 466 467 if (!inlineRunStart) 468 break; 469 470 child = inlineRunEnd->nextSibling(); 471 472 RenderBlock* block = createAnonymousBlock(); 473 children()->insertChildNode(this, block, inlineRunStart); 474 RenderObject* o = inlineRunStart; 475 while (o != inlineRunEnd) { 476 RenderObject* no = o; 477 o = no->nextSibling(); 478 479 moveChildTo(block, block->children(), no); 480 } 481 moveChildTo(block, block->children(), inlineRunEnd); 482 } 483 484 #ifndef NDEBUG 485 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) 486 ASSERT(!c->isInline()); 487 #endif 488 489 repaint(); 490 } 491 492 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) 493 { 494 ASSERT(child->isAnonymousBlock()); 495 ASSERT(!child->childrenInline()); 496 497 if (child->inlineContinuation()) 498 return; 499 500 RenderObject* firstAnChild = child->m_children.firstChild(); 501 RenderObject* lastAnChild = child->m_children.lastChild(); 502 if (firstAnChild) { 503 RenderObject* o = firstAnChild; 504 while (o) { 505 o->setParent(this); 506 o = o->nextSibling(); 507 } 508 firstAnChild->setPreviousSibling(child->previousSibling()); 509 lastAnChild->setNextSibling(child->nextSibling()); 510 if (child->previousSibling()) 511 child->previousSibling()->setNextSibling(firstAnChild); 512 if (child->nextSibling()) 513 child->nextSibling()->setPreviousSibling(lastAnChild); 514 } else { 515 if (child->previousSibling()) 516 child->previousSibling()->setNextSibling(child->nextSibling()); 517 if (child->nextSibling()) 518 child->nextSibling()->setPreviousSibling(child->previousSibling()); 519 } 520 if (child == m_children.firstChild()) 521 m_children.setFirstChild(firstAnChild); 522 if (child == m_children.lastChild()) 523 m_children.setLastChild(lastAnChild); 524 child->setParent(0); 525 child->setPreviousSibling(0); 526 child->setNextSibling(0); 527 528 child->children()->setFirstChild(0); 529 child->m_next = 0; 530 531 child->destroy(); 532 } 533 534 void RenderBlock::removeChild(RenderObject* oldChild) 535 { 536 // If this child is a block, and if our previous and next siblings are 537 // both anonymous blocks with inline content, then we can go ahead and 538 // fold the inline content back together. 539 RenderObject* prev = oldChild->previousSibling(); 540 RenderObject* next = oldChild->nextSibling(); 541 bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() && 542 (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) && 543 (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) && 544 (!next || (next->isAnonymousBlock() && next->childrenInline())); 545 if (canDeleteAnonymousBlocks && prev && next) { 546 // Take all the children out of the |next| block and put them in 547 // the |prev| block. 548 prev->setNeedsLayoutAndPrefWidthsRecalc(); 549 RenderBlock* nextBlock = toRenderBlock(next); 550 RenderBlock* prevBlock = toRenderBlock(prev); 551 nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children()); 552 // Delete the now-empty block's lines and nuke it. 553 nextBlock->deleteLineBoxTree(); 554 nextBlock->destroy(); 555 } 556 557 RenderBox::removeChild(oldChild); 558 559 RenderObject* child = prev ? prev : next; 560 if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { 561 // The removal has knocked us down to containing only a single anonymous 562 // box. We can go ahead and pull the content right back up into our 563 // box. 564 setNeedsLayoutAndPrefWidthsRecalc(); 565 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false)); 566 setChildrenInline(true); 567 anonBlock->moveAllChildrenTo(this, children()); 568 // Delete the now-empty block's lines and nuke it. 569 anonBlock->deleteLineBoxTree(); 570 anonBlock->destroy(); 571 } 572 573 // If this was our last child be sure to clear out our line boxes. 574 if (childrenInline() && !firstChild()) 575 lineBoxes()->deleteLineBoxes(renderArena()); 576 } 577 578 bool RenderBlock::isSelfCollapsingBlock() const 579 { 580 // We are not self-collapsing if we 581 // (a) have a non-zero height according to layout (an optimization to avoid wasting time) 582 // (b) are a table, 583 // (c) have border/padding, 584 // (d) have a min-height 585 // (e) have specified that one of our margins can't collapse using a CSS extension 586 if (height() > 0 || 587 isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 || 588 style()->minHeight().isPositive() || 589 style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE) 590 return false; 591 592 bool hasAutoHeight = style()->height().isAuto(); 593 if (style()->height().isPercent() && !style()->htmlHacks()) { 594 hasAutoHeight = true; 595 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { 596 if (cb->style()->height().isFixed() || cb->isTableCell()) 597 hasAutoHeight = false; 598 } 599 } 600 601 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends 602 // on whether we have content that is all self-collapsing or not. 603 if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) { 604 // If the block has inline children, see if we generated any line boxes. If we have any 605 // line boxes, then we can't be self-collapsing, since we have content. 606 if (childrenInline()) 607 return !firstLineBox(); 608 609 // Whether or not we collapse is dependent on whether all our normal flow children 610 // are also self-collapsing. 611 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 612 if (child->isFloatingOrPositioned()) 613 continue; 614 if (!child->isSelfCollapsingBlock()) 615 return false; 616 } 617 return true; 618 } 619 return false; 620 } 621 622 void RenderBlock::startDelayUpdateScrollInfo() 623 { 624 if (gDelayUpdateScrollInfo == 0) { 625 ASSERT(!gDelayedUpdateScrollInfoSet); 626 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; 627 } 628 ASSERT(gDelayedUpdateScrollInfoSet); 629 ++gDelayUpdateScrollInfo; 630 } 631 632 void RenderBlock::finishDelayUpdateScrollInfo() 633 { 634 --gDelayUpdateScrollInfo; 635 ASSERT(gDelayUpdateScrollInfo >= 0); 636 if (gDelayUpdateScrollInfo == 0) { 637 ASSERT(gDelayedUpdateScrollInfoSet); 638 639 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet); 640 gDelayedUpdateScrollInfoSet = 0; 641 642 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { 643 RenderBlock* block = *it; 644 if (block->hasOverflowClip()) { 645 block->layer()->updateScrollInfoAfterLayout(); 646 } 647 } 648 } 649 } 650 651 void RenderBlock::updateScrollInfoAfterLayout() 652 { 653 if (hasOverflowClip()) { 654 if (gDelayUpdateScrollInfo) 655 gDelayedUpdateScrollInfoSet->add(this); 656 else 657 layer()->updateScrollInfoAfterLayout(); 658 } 659 } 660 661 void RenderBlock::layout() 662 { 663 // Update our first letter info now. 664 updateFirstLetter(); 665 666 // Table cells call layoutBlock directly, so don't add any logic here. Put code into 667 // layoutBlock(). 668 layoutBlock(false); 669 670 // It's safe to check for control clip here, since controls can never be table cells. 671 // If we have a lightweight clip, there can never be any overflow from children. 672 if (hasControlClip() && m_overflow) 673 clearLayoutOverflow(); 674 } 675 676 void RenderBlock::layoutBlock(bool relayoutChildren) 677 { 678 ASSERT(needsLayout()); 679 680 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can 681 return; // cause us to come in here. Just bail. 682 683 if (!relayoutChildren && layoutOnlyPositionedObjects()) 684 return; 685 686 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); 687 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 688 689 int oldWidth = width(); 690 int oldColumnWidth = desiredColumnWidth(); 691 692 #ifdef ANDROID_LAYOUT 693 int oldVisibleWidth = m_visibleWidth; 694 #endif 695 696 calcWidth(); 697 calcColumnWidth(); 698 699 m_overflow.clear(); 700 701 if (oldWidth != width() || oldColumnWidth != desiredColumnWidth()) 702 relayoutChildren = true; 703 704 #ifdef ANDROID_LAYOUT 705 const Settings* settings = document()->settings(); 706 ASSERT(settings); 707 if (oldVisibleWidth != m_visibleWidth 708 && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen) 709 relayoutChildren = true; 710 #endif 711 712 clearFloats(); 713 714 int previousHeight = height(); 715 setHeight(0); 716 717 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 718 // our current maximal positive and negative margins. These values are used when we 719 // are collapsed with adjacent blocks, so for example, if you have block A and B 720 // collapsing together, then you'd take the maximal positive margin from both A and B 721 // and subtract it from the maximal negative margin from both A and B to get the 722 // true collapsed margin. This algorithm is recursive, so when we finish layout() 723 // our block knows its current maximal positive/negative values. 724 // 725 // Start out by setting our margin values to our current margins. Table cells have 726 // no margins, so we don't fill in the values for table cells. 727 bool isCell = isTableCell(); 728 if (!isCell) { 729 initMaxMarginValues(); 730 731 setTopMarginQuirk(style()->marginTop().quirk()); 732 setBottomMarginQuirk(style()->marginBottom().quirk()); 733 734 Node* n = node(); 735 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { 736 // See if this form is malformed (i.e., unclosed). If so, don't give the form 737 // a bottom margin. 738 setMaxBottomMargins(0, 0); 739 } 740 } 741 742 // For overflow:scroll blocks, ensure we have both scrollbars in place always. 743 if (scrollsOverflow()) { 744 if (style()->overflowX() == OSCROLL) 745 layer()->setHasHorizontalScrollbar(true); 746 if (style()->overflowY() == OSCROLL) 747 layer()->setHasVerticalScrollbar(true); 748 } 749 750 int repaintTop = 0; 751 int repaintBottom = 0; 752 int maxFloatBottom = 0; 753 if (childrenInline()) 754 layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom); 755 else 756 layoutBlockChildren(relayoutChildren, maxFloatBottom); 757 758 // Expand our intrinsic height to encompass floats. 759 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 760 if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats()) 761 setHeight(floatBottom() + toAdd); 762 763 // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as 764 // we adjust for clean column breaks. 765 int singleColumnBottom = layoutColumns(); 766 767 // Calculate our new height. 768 int oldHeight = height(); 769 calcHeight(); 770 if (oldHeight != height()) { 771 if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) { 772 // One of our children's floats may have become an overhanging float for us. We need to look for it. 773 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 774 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { 775 RenderBlock* block = toRenderBlock(child); 776 if (block->floatBottom() + block->y() > height()) 777 addOverhangingFloats(block, -block->x(), -block->y(), false); 778 } 779 } 780 } 781 782 // We have to rebalance columns to the new height. 783 layoutColumns(singleColumnBottom); 784 } 785 786 if (previousHeight != height()) 787 relayoutChildren = true; 788 789 // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't 790 // able to be propagated up the render tree yet. Overflow information is however. This check is designed to catch anyone 791 // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor. 792 if (isRoot() || expandsToEncloseOverhangingFloats()) 793 addOverflowFromFloats(); 794 795 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 796 if (!hasColumns()) { 797 if (childrenInline()) 798 addOverflowFromInlineChildren(); 799 else 800 addOverflowFromBlockChildren(); 801 } 802 803 // Add visual overflow from box-shadow and reflections. 804 addShadowOverflow(); 805 806 layoutPositionedObjects(relayoutChildren || isRoot()); 807 808 positionListMarker(); 809 810 statePusher.pop(); 811 812 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 813 // we overflow or not. 814 updateScrollInfoAfterLayout(); 815 816 // Repaint with our new bounds if they are different from our old bounds. 817 bool didFullRepaint = repainter.repaintAfterLayout(); 818 if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { 819 int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow()); 820 int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow()); 821 IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop); 822 823 // FIXME: Deal with multiple column repainting. We have to split the repaint 824 // rect up into multiple rects if it spans columns. 825 826 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); 827 828 if (hasOverflowClip()) { 829 // Adjust repaint rect for scroll offset 830 int x = repaintRect.x(); 831 int y = repaintRect.y(); 832 layer()->subtractScrolledContentOffset(x, y); 833 repaintRect.setX(x); 834 repaintRect.setY(y); 835 836 // Don't allow this rect to spill out of our overflow box. 837 repaintRect.intersect(IntRect(0, 0, width(), height())); 838 } 839 840 // Make sure the rect is still non-empty after intersecting for overflow above 841 if (!repaintRect.isEmpty()) { 842 repaintRectangle(repaintRect); // We need to do a partial repaint of our content. 843 if (hasReflection()) 844 repaintRectangle(reflectedRect(repaintRect)); 845 } 846 } 847 setNeedsLayout(false); 848 } 849 850 void RenderBlock::addOverflowFromBlockChildren() 851 { 852 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 853 if (!child->isFloatingOrPositioned()) 854 addOverflowFromChild(child); 855 } 856 } 857 858 void RenderBlock::addOverflowFromFloats() 859 { 860 IntRect result; 861 if (!m_floatingObjects) 862 return; 863 FloatingObject* r; 864 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 865 for (; (r = it.current()); ++it) { 866 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) 867 addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); 868 } 869 return; 870 } 871 872 bool RenderBlock::expandsToEncloseOverhangingFloats() const 873 { 874 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset(); 875 } 876 877 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 878 { 879 if (child->style()->hasStaticX()) { 880 if (style()->direction() == LTR) 881 child->layer()->setStaticX(borderLeft() + paddingLeft()); 882 else 883 child->layer()->setStaticX(borderRight() + paddingRight()); 884 } 885 886 if (child->style()->hasStaticY()) { 887 int y = height(); 888 if (!marginInfo.canCollapseWithTop()) { 889 child->calcVerticalMargins(); 890 int marginTop = child->marginTop(); 891 int collapsedTopPos = marginInfo.posMargin(); 892 int collapsedTopNeg = marginInfo.negMargin(); 893 if (marginTop > 0) { 894 if (marginTop > collapsedTopPos) 895 collapsedTopPos = marginTop; 896 } else { 897 if (-marginTop > collapsedTopNeg) 898 collapsedTopNeg = -marginTop; 899 } 900 y += (collapsedTopPos - collapsedTopNeg) - marginTop; 901 } 902 RenderLayer* childLayer = child->layer(); 903 if (childLayer->staticY() != y) { 904 child->layer()->setStaticY(y); 905 child->setChildNeedsLayout(true, false); 906 } 907 } 908 } 909 910 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) 911 { 912 // The float should be positioned taking into account the bottom margin 913 // of the previous flow. We add that margin into the height, get the 914 // float positioned properly, and then subtract the margin out of the 915 // height again. In the case of self-collapsing blocks, we always just 916 // use the top margins, since the self-collapsing block collapsed its 917 // own bottom margin into its top margin. 918 // 919 // Note also that the previous flow may collapse its margin into the top of 920 // our block. If this is the case, then we do not add the margin in to our 921 // height when computing the position of the float. This condition can be tested 922 // for by simply calling canCollapseWithTop. See 923 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 924 // an example of this scenario. 925 int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin(); 926 setHeight(height() + marginOffset); 927 positionNewFloats(); 928 setHeight(height() - marginOffset); 929 } 930 931 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) 932 { 933 // Handle in the given order 934 return handlePositionedChild(child, marginInfo) 935 || handleFloatingChild(child, marginInfo) 936 || handleRunInChild(child); 937 } 938 939 940 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) 941 { 942 if (child->isPositioned()) { 943 child->containingBlock()->insertPositionedObject(child); 944 adjustPositionedBlock(child, marginInfo); 945 return true; 946 } 947 return false; 948 } 949 950 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) 951 { 952 if (child->isFloating()) { 953 insertFloatingObject(child); 954 adjustFloatingBlock(marginInfo); 955 return true; 956 } 957 return false; 958 } 959 960 bool RenderBlock::handleRunInChild(RenderBox* child) 961 { 962 // See if we have a run-in element with inline children. If the 963 // children aren't inline, then just treat the run-in as a normal 964 // block. 965 if (!child->isRunIn() || !child->childrenInline()) 966 return false; 967 // FIXME: We don't handle non-block elements with run-in for now. 968 if (!child->isRenderBlock()) 969 return false; 970 971 // Get the next non-positioned/non-floating RenderBlock. 972 RenderBlock* blockRunIn = toRenderBlock(child); 973 RenderObject* curr = blockRunIn->nextSibling(); 974 while (curr && curr->isFloatingOrPositioned()) 975 curr = curr->nextSibling(); 976 977 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous()) 978 return false; 979 980 RenderBlock* currBlock = toRenderBlock(curr); 981 982 // Remove the old child. 983 children()->removeChildNode(this, blockRunIn); 984 985 // Create an inline. 986 Node* runInNode = blockRunIn->node(); 987 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); 988 inlineRunIn->setStyle(blockRunIn->style()); 989 990 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER; 991 992 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already 993 // been regenerated by the new inline. 994 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) { 995 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) { 996 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); 997 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. 998 } 999 } 1000 1001 // Now insert the new child under |currBlock|. 1002 currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild()); 1003 1004 // If the run-in had an element, we need to set the new renderer. 1005 if (runInNode) 1006 runInNode->setRenderer(inlineRunIn); 1007 1008 // Destroy the block run-in, which includes deleting its line box tree. 1009 blockRunIn->deleteLineBoxTree(); 1010 blockRunIn->destroy(); 1011 1012 // The block acts like an inline, so just null out its 1013 // position. 1014 1015 return true; 1016 } 1017 1018 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) 1019 { 1020 // Get our max pos and neg top margins. 1021 int posTop = child->maxTopMargin(true); 1022 int negTop = child->maxTopMargin(false); 1023 1024 // For self-collapsing blocks, collapse our bottom margins into our 1025 // top to get new posTop and negTop values. 1026 if (child->isSelfCollapsingBlock()) { 1027 posTop = max(posTop, child->maxBottomMargin(true)); 1028 negTop = max(negTop, child->maxBottomMargin(false)); 1029 } 1030 1031 // See if the top margin is quirky. We only care if this child has 1032 // margins that will collapse with us. 1033 bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD; 1034 1035 if (marginInfo.canCollapseWithTop()) { 1036 // This child is collapsing with the top of the 1037 // block. If it has larger margin values, then we need to update 1038 // our own maximal values. 1039 if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk) 1040 setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin())); 1041 1042 // The minute any of the margins involved isn't a quirk, don't 1043 // collapse it away, even if the margin is smaller (www.webreference.com 1044 // has an example of this, a <dt> with 0.8em author-specified inside 1045 // a <dl> inside a <td>. 1046 if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) { 1047 setTopMarginQuirk(false); 1048 marginInfo.setDeterminedTopQuirk(true); 1049 } 1050 1051 if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0) 1052 // We have no top margin and our top child has a quirky margin. 1053 // We will pick up this quirky margin and pass it through. 1054 // This deals with the <td><div><p> case. 1055 // Don't do this for a block that split two inlines though. You do 1056 // still apply margins in this case. 1057 setTopMarginQuirk(true); 1058 } 1059 1060 if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop)) 1061 marginInfo.setTopQuirk(topQuirk); 1062 1063 int ypos = height(); 1064 if (child->isSelfCollapsingBlock()) { 1065 // This child has no height. We need to compute our 1066 // position before we collapse the child's margins together, 1067 // so that we can get an accurate position for the zero-height block. 1068 int collapsedTopPos = max(marginInfo.posMargin(), child->maxTopMargin(true)); 1069 int collapsedTopNeg = max(marginInfo.negMargin(), child->maxTopMargin(false)); 1070 marginInfo.setMargin(collapsedTopPos, collapsedTopNeg); 1071 1072 // Now collapse the child's margins together, which means examining our 1073 // bottom margin values as well. 1074 marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true)); 1075 marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false)); 1076 1077 if (!marginInfo.canCollapseWithTop()) 1078 // We need to make sure that the position of the self-collapsing block 1079 // is correct, since it could have overflowing content 1080 // that needs to be positioned correctly (e.g., a block that 1081 // had a specified height of 0 but that actually had subcontent). 1082 ypos = height() + collapsedTopPos - collapsedTopNeg; 1083 } 1084 else { 1085 if (child->style()->marginTopCollapse() == MSEPARATE) { 1086 setHeight(height() + marginInfo.margin() + child->marginTop()); 1087 ypos = height(); 1088 } 1089 else if (!marginInfo.atTopOfBlock() || 1090 (!marginInfo.canCollapseTopWithChildren() 1091 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) { 1092 // We're collapsing with a previous sibling's margins and not 1093 // with the top of the block. 1094 setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop)); 1095 ypos = height(); 1096 } 1097 1098 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1099 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1100 1101 if (marginInfo.margin()) 1102 marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD); 1103 } 1104 1105 return ypos; 1106 } 1107 1108 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) 1109 { 1110 int heightIncrease = getClearDelta(child, yPos); 1111 if (!heightIncrease) 1112 return yPos; 1113 1114 if (child->isSelfCollapsingBlock()) { 1115 // For self-collapsing blocks that clear, they can still collapse their 1116 // margins with following siblings. Reset the current margins to represent 1117 // the self-collapsing block's margins only. 1118 // CSS2.1 states: 1119 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin. 1120 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the 1121 // self-collapsing block's bottom margin. 1122 bool atBottomOfBlock = true; 1123 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) { 1124 if (!curr->isFloatingOrPositioned()) 1125 atBottomOfBlock = false; 1126 } 1127 if (atBottomOfBlock) { 1128 marginInfo.setPosMargin(child->maxBottomMargin(true)); 1129 marginInfo.setNegMargin(child->maxBottomMargin(false)); 1130 } else { 1131 marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true))); 1132 marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false))); 1133 } 1134 1135 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom 1136 // of the parent block). 1137 setHeight(child->y() - max(0, marginInfo.margin())); 1138 } else 1139 // Increase our height by the amount we had to clear. 1140 setHeight(height() + heightIncrease); 1141 1142 if (marginInfo.canCollapseWithTop()) { 1143 // We can no longer collapse with the top of the block since a clear 1144 // occurred. The empty blocks collapse into the cleared block. 1145 // FIXME: This isn't quite correct. Need clarification for what to do 1146 // if the height the cleared block is offset by is smaller than the 1147 // margins involved. 1148 setMaxTopMargins(oldTopPosMargin, oldTopNegMargin); 1149 marginInfo.setAtTopOfBlock(false); 1150 } 1151 1152 return yPos + heightIncrease; 1153 } 1154 1155 int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo) 1156 { 1157 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 1158 // relayout if there are intruding floats. 1159 int yPosEstimate = height(); 1160 if (!marginInfo.canCollapseWithTop()) { 1161 int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop(); 1162 yPosEstimate += max(marginInfo.margin(), childMarginTop); 1163 } 1164 yPosEstimate += getClearDelta(child, yPosEstimate); 1165 return yPosEstimate; 1166 } 1167 1168 void RenderBlock::determineHorizontalPosition(RenderBox* child) 1169 { 1170 if (style()->direction() == LTR) { 1171 int xPos = borderLeft() + paddingLeft(); 1172 1173 // Add in our left margin. 1174 int chPos = xPos + child->marginLeft(); 1175 1176 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need 1177 // to shift over as necessary to dodge any floats that might get in the way. 1178 if (child->avoidsFloats()) { 1179 int leftOff = leftOffset(height(), false); 1180 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) { 1181 if (child->marginLeft() < 0) 1182 leftOff += child->marginLeft(); 1183 chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit. 1184 } 1185 else if (leftOff != xPos) { 1186 // The object is shifting right. The object might be centered, so we need to 1187 // recalculate our horizontal margins. Note that the containing block content 1188 // width computation will take into account the delta between |leftOff| and |xPos| 1189 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1190 // function. 1191 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1192 chPos = leftOff + child->marginLeft(); 1193 } 1194 } 1195 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1196 child->setLocation(chPos, child->y()); 1197 } else { 1198 int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth(); 1199 int chPos = xPos - (child->width() + child->marginRight()); 1200 if (child->avoidsFloats()) { 1201 int rightOff = rightOffset(height(), false); 1202 if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) { 1203 if (child->marginRight() < 0) 1204 rightOff -= child->marginRight(); 1205 chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit. 1206 } else if (rightOff != xPos) { 1207 // The object is shifting left. The object might be centered, so we need to 1208 // recalculate our horizontal margins. Note that the containing block content 1209 // width computation will take into account the delta between |rightOff| and |xPos| 1210 // so that we can just pass the content width in directly to the |calcHorizontalMargins| 1211 // function. 1212 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false)); 1213 chPos = rightOff - child->marginRight() - child->width(); 1214 } 1215 } 1216 view()->addLayoutDelta(IntSize(child->x() - chPos, 0)); 1217 child->setLocation(chPos, child->y()); 1218 } 1219 } 1220 1221 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) 1222 { 1223 if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) { 1224 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 1225 // with our children. 1226 setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin())); 1227 1228 if (!marginInfo.bottomQuirk()) 1229 setBottomMarginQuirk(false); 1230 1231 if (marginInfo.bottomQuirk() && marginBottom() == 0) 1232 // We have no bottom margin and our last child has a quirky margin. 1233 // We will pick up this quirky margin and pass it through. 1234 // This deals with the <td><div><p> case. 1235 setBottomMarginQuirk(true); 1236 } 1237 } 1238 1239 void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo) 1240 { 1241 marginInfo.setAtBottomOfBlock(true); 1242 1243 // If we can't collapse with children then go ahead and add in the bottom margin. 1244 if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop() 1245 && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk())) 1246 setHeight(height() + marginInfo.margin()); 1247 1248 // Now add in our bottom border/padding. 1249 setHeight(height() + bottom); 1250 1251 // Negative margins can cause our height to shrink below our minimal height (border/padding). 1252 // If this happens, ensure that the computed height is increased to the minimal height. 1253 setHeight(max(height(), top + bottom)); 1254 1255 // Update our bottom collapsed margin info. 1256 setCollapsedBottomMargin(marginInfo); 1257 } 1258 1259 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom) 1260 { 1261 if (gPercentHeightDescendantsMap) { 1262 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { 1263 HashSet<RenderBox*>::iterator end = descendants->end(); 1264 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) { 1265 RenderBox* box = *it; 1266 while (box != this) { 1267 if (box->normalChildNeedsLayout()) 1268 break; 1269 box->setChildNeedsLayout(true, false); 1270 box = box->containingBlock(); 1271 ASSERT(box); 1272 if (!box) 1273 break; 1274 } 1275 } 1276 } 1277 } 1278 1279 int top = borderTop() + paddingTop(); 1280 int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 1281 1282 setHeight(top); 1283 1284 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 1285 MarginInfo marginInfo(this, top, bottom); 1286 1287 // Fieldsets need to find their legend and position it inside the border of the object. 1288 // The legend then gets skipped during normal layout. 1289 RenderObject* legend = layoutLegend(relayoutChildren); 1290 1291 int previousFloatBottom = 0; 1292 maxFloatBottom = 0; 1293 1294 RenderBox* next = firstChildBox(); 1295 1296 while (next) { 1297 RenderBox* child = next; 1298 next = child->nextSiblingBox(); 1299 1300 if (legend == child) 1301 continue; // Skip the legend, since it has already been positioned up in the fieldset's border. 1302 1303 // Make sure we layout children if they need it. 1304 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into 1305 // an auto value. Add a method to determine this, so that we can avoid the relayout. 1306 if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView())) 1307 child->setChildNeedsLayout(true, false); 1308 1309 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1310 if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent())) 1311 child->setPrefWidthsDirty(true, false); 1312 1313 // Handle the four types of special elements first. These include positioned content, floating content, compacts and 1314 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. 1315 if (handleSpecialChild(child, marginInfo)) 1316 continue; 1317 1318 // Lay out the child. 1319 layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom); 1320 } 1321 1322 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 1323 // determining the correct collapsed bottom margin information. 1324 handleBottomOfBlock(top, bottom, marginInfo); 1325 } 1326 1327 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom) 1328 { 1329 int oldTopPosMargin = maxTopPosMargin(); 1330 int oldTopNegMargin = maxTopNegMargin(); 1331 1332 // The child is a normal flow object. Compute its vertical margins now. 1333 child->calcVerticalMargins(); 1334 1335 // Do not allow a collapse if the margin top collapse style is set to SEPARATE. 1336 if (child->style()->marginTopCollapse() == MSEPARATE) { 1337 marginInfo.setAtTopOfBlock(false); 1338 marginInfo.clearMargin(); 1339 } 1340 1341 // Try to guess our correct y position. In most cases this guess will 1342 // be correct. Only if we're wrong (when we compute the real y position) 1343 // will we have to potentially relayout. 1344 int yPosEstimate = estimateVerticalPosition(child, marginInfo); 1345 1346 // Cache our old rect so that we can dirty the proper repaint rects if the child moves. 1347 IntRect oldRect(child->x(), child->y() , child->width(), child->height()); 1348 #ifndef NDEBUG 1349 IntSize oldLayoutDelta = view()->layoutDelta(); 1350 #endif 1351 // Go ahead and position the child as though it didn't collapse with the top. 1352 view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate)); 1353 child->setLocation(child->x(), yPosEstimate); 1354 1355 bool markDescendantsWithFloats = false; 1356 if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1357 markDescendantsWithFloats = true; 1358 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 1359 // If an element might be affected by the presence of floats, then always mark it for 1360 // layout. 1361 int fb = max(previousFloatBottom, floatBottom()); 1362 if (fb > yPosEstimate) 1363 markDescendantsWithFloats = true; 1364 } 1365 1366 if (child->isRenderBlock()) { 1367 if (markDescendantsWithFloats) 1368 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1369 1370 previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom()); 1371 } 1372 1373 bool childHadLayout = child->m_everHadLayout; 1374 bool childNeededLayout = child->needsLayout(); 1375 if (childNeededLayout) 1376 child->layout(); 1377 1378 // Now determine the correct ypos based off examination of collapsing margin 1379 // values. 1380 int yBeforeClear = collapseMargins(child, marginInfo); 1381 1382 // Now check for clear. 1383 int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear); 1384 1385 view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear)); 1386 child->setLocation(child->x(), yAfterClear); 1387 1388 // Now we have a final y position. See if it really does end up being different from our estimate. 1389 if (yAfterClear != yPosEstimate) { 1390 if (child->shrinkToAvoidFloats()) { 1391 // The child's width depends on the line width. 1392 // When the child shifts to clear an item, its width can 1393 // change (because it has more available line width). 1394 // So go ahead and mark the item as dirty. 1395 child->setChildNeedsLayout(true, false); 1396 } 1397 if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1398 toRenderBlock(child)->markAllDescendantsWithFloatsForLayout(); 1399 // Our guess was wrong. Make the child lay itself out again. 1400 child->layoutIfNeeded(); 1401 } 1402 1403 // We are no longer at the top of the block if we encounter a non-empty child. 1404 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 1405 if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock()) 1406 marginInfo.setAtTopOfBlock(false); 1407 1408 // Now place the child in the correct horizontal position 1409 determineHorizontalPosition(child); 1410 1411 // Update our height now that the child has been placed in the correct position. 1412 setHeight(height() + child->height()); 1413 if (child->style()->marginBottomCollapse() == MSEPARATE) { 1414 setHeight(height() + child->marginBottom()); 1415 marginInfo.clearMargin(); 1416 } 1417 // If the child has overhanging floats that intrude into following siblings (or possibly out 1418 // of this block), then the parent gets notified of the floats now. 1419 if (child->isBlockFlow() && toRenderBlock(child)->containsFloats()) 1420 maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout)); 1421 1422 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); 1423 if (childOffset.width() || childOffset.height()) { 1424 view()->addLayoutDelta(childOffset); 1425 1426 // If the child moved, we have to repaint it as well as any floating/positioned 1427 // descendants. An exception is if we need a layout. In this case, we know we're going to 1428 // repaint ourselves (and the child) anyway. 1429 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) 1430 child->repaintDuringLayoutIfMoved(oldRect); 1431 } 1432 1433 if (!childHadLayout && child->checkForRepaintDuringLayout()) { 1434 child->repaint(); 1435 child->repaintOverhangingFloats(true); 1436 } 1437 1438 ASSERT(oldLayoutDelta == view()->layoutDelta()); 1439 } 1440 1441 bool RenderBlock::layoutOnlyPositionedObjects() 1442 { 1443 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1444 return false; 1445 1446 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection()); 1447 1448 if (needsPositionedMovementLayout()) { 1449 tryLayoutDoingPositionedMovementOnly(); 1450 if (needsLayout()) 1451 return false; 1452 } 1453 1454 // All we have to is lay out our positioned objects. 1455 layoutPositionedObjects(false); 1456 1457 statePusher.pop(); 1458 1459 updateScrollInfoAfterLayout(); 1460 1461 #ifdef ANDROID_FIX 1462 // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks, 1463 // which may make us need to layout again 1464 if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout()) 1465 return false; 1466 #endif 1467 1468 setNeedsLayout(false); 1469 return true; 1470 } 1471 1472 void RenderBlock::layoutPositionedObjects(bool relayoutChildren) 1473 { 1474 if (m_positionedObjects) { 1475 RenderBox* r; 1476 Iterator end = m_positionedObjects->end(); 1477 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1478 r = *it; 1479 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the 1480 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned 1481 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is 1482 // positioned explicitly) this should not incur a performance penalty. 1483 if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow())) 1484 r->setChildNeedsLayout(true, false); 1485 1486 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 1487 //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent())) 1488 r->setPrefWidthsDirty(true, false); 1489 1490 // 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 1491 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. 1492 if (r->needsPositionedMovementLayoutOnly()) 1493 r->tryLayoutDoingPositionedMovementOnly(); 1494 r->layoutIfNeeded(); 1495 } 1496 } 1497 } 1498 1499 void RenderBlock::markPositionedObjectsForLayout() 1500 { 1501 if (m_positionedObjects) { 1502 RenderBox* r; 1503 Iterator end = m_positionedObjects->end(); 1504 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1505 r = *it; 1506 r->setChildNeedsLayout(true); 1507 } 1508 } 1509 } 1510 1511 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) 1512 { 1513 // Repaint any overhanging floats (if we know we're the one to paint them). 1514 if (hasOverhangingFloats()) { 1515 // We think that we must be in a bad state if m_floatingObjects is nil at this point, so 1516 // we assert on Debug builds and nil-check Release builds. 1517 ASSERT(m_floatingObjects); 1518 if (!m_floatingObjects) 1519 return; 1520 1521 FloatingObject* r; 1522 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1523 1524 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating 1525 // in this block. Better yet would be to push extra state for the containers of other floats. 1526 view()->disableLayoutState(); 1527 for ( ; (r = it.current()); ++it) { 1528 // Only repaint the object if it is overhanging, is not in its own layer, and 1529 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 1530 // condition is replaced with being a descendant of us. 1531 if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { 1532 r->m_renderer->repaint(); 1533 r->m_renderer->repaintOverhangingFloats(); 1534 } 1535 } 1536 view()->enableLayoutState(); 1537 } 1538 } 1539 1540 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) 1541 { 1542 tx += x(); 1543 ty += y(); 1544 1545 PaintPhase phase = paintInfo.phase; 1546 1547 // Check if we need to do anything at all. 1548 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 1549 // paints the root's background. 1550 if (!isRoot()) { 1551 IntRect overflowBox = visibleOverflowRect(); 1552 overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); 1553 overflowBox.move(tx, ty); 1554 if (!overflowBox.intersects(paintInfo.rect)) 1555 return; 1556 } 1557 1558 bool pushedClip = pushContentsClip(paintInfo, tx, ty); 1559 paintObject(paintInfo, tx, ty); 1560 if (pushedClip) 1561 popContentsClip(paintInfo, phase, tx, ty); 1562 1563 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with 1564 // z-index. We paint after we painted the background/border, so that the scrollbars will 1565 // sit above the background/border. 1566 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo)) 1567 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); 1568 } 1569 1570 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) 1571 { 1572 const Color& ruleColor = style()->columnRuleColor(); 1573 bool ruleTransparent = style()->columnRuleIsTransparent(); 1574 EBorderStyle ruleStyle = style()->columnRuleStyle(); 1575 int ruleWidth = style()->columnRuleWidth(); 1576 int colGap = columnGap(); 1577 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; 1578 if (!renderRule) 1579 return; 1580 1581 // We need to do multiple passes, breaking up our child painting into strips. 1582 int currXOffset = 0; 1583 int ruleAdd = borderLeft() + paddingLeft(); 1584 int ruleX = 0; 1585 Vector<IntRect>* colRects = columnRects(); 1586 unsigned colCount = colRects->size(); 1587 for (unsigned i = 0; i < colCount; i++) { 1588 // For each rect, we clip to the rect, and then we adjust our coords. 1589 IntRect colRect = colRects->at(i); 1590 1591 // Move to the next position. 1592 if (style()->direction() == LTR) { 1593 ruleX += colRect.width() + colGap / 2; 1594 currXOffset += colRect.width() + colGap; 1595 } else { 1596 ruleX -= (colRect.width() + colGap / 2); 1597 currXOffset -= (colRect.width() + colGap); 1598 } 1599 1600 // Now paint the column rule. 1601 if (i < colCount - 1) { 1602 int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd; 1603 int ruleEnd = ruleStart + ruleWidth; 1604 int ruleTop = ty + borderTop() + paddingTop(); 1605 int ruleBottom = ruleTop + contentHeight(); 1606 drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom, 1607 style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0); 1608 } 1609 1610 ruleX = currXOffset; 1611 } 1612 } 1613 1614 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) 1615 { 1616 // We need to do multiple passes, breaking up our child painting into strips. 1617 GraphicsContext* context = paintInfo.context; 1618 int currXOffset = 0; 1619 int currYOffset = 0; 1620 int colGap = columnGap(); 1621 Vector<IntRect>* colRects = columnRects(); 1622 unsigned colCount = colRects->size(); 1623 for (unsigned i = 0; i < colCount; i++) { 1624 // For each rect, we clip to the rect, and then we adjust our coords. 1625 IntRect colRect = colRects->at(i); 1626 colRect.move(tx, ty); 1627 context->save(); 1628 1629 // Each strip pushes a clip, since column boxes are specified as being 1630 // like overflow:hidden. 1631 context->clip(colRect); 1632 1633 // Adjust tx and ty to change where we paint. 1634 PaintInfo info(paintInfo); 1635 info.rect.intersect(colRect); 1636 1637 // Adjust our x and y when painting. 1638 int finalX = tx + currXOffset; 1639 int finalY = ty + currYOffset; 1640 if (paintingFloats) 1641 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); 1642 else 1643 paintContents(info, finalX, finalY); 1644 1645 // Move to the next position. 1646 if (style()->direction() == LTR) 1647 currXOffset += colRect.width() + colGap; 1648 else 1649 currXOffset -= (colRect.width() + colGap); 1650 1651 currYOffset -= colRect.height(); 1652 1653 context->restore(); 1654 } 1655 } 1656 1657 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) 1658 { 1659 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. 1660 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 1661 // will do a full repaint(). 1662 if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) 1663 return; 1664 1665 if (childrenInline()) 1666 m_lineBoxes.paint(this, paintInfo, tx, ty); 1667 else 1668 paintChildren(paintInfo, tx, ty); 1669 } 1670 1671 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) 1672 { 1673 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 1674 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 1675 1676 // We don't paint our own background, but we do let the kids paint their backgrounds. 1677 PaintInfo info(paintInfo); 1678 info.phase = newPhase; 1679 info.paintingRoot = paintingRootForChildren(paintInfo); 1680 bool isPrinting = document()->printing(); 1681 1682 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1683 // Check for page-break-before: always, and if it's set, break and bail. 1684 if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS && 1685 inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() && 1686 (ty + child->y()) < paintInfo.rect.bottom()) { 1687 view()->setBestTruncatedAt(ty + child->y(), this, true); 1688 return; 1689 } 1690 1691 if (!child->hasSelfPaintingLayer() && !child->isFloating()) 1692 child->paint(info, tx, ty); 1693 1694 // Check for page-break-after: always, and if it's set, break and bail. 1695 if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS && 1696 inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() && 1697 (ty + child->y() + child->height()) < paintInfo.rect.bottom()) { 1698 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true); 1699 return; 1700 } 1701 } 1702 } 1703 1704 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type) 1705 { 1706 SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController(); 1707 1708 // Paint the caret if the SelectionController says so or if caret browsing is enabled 1709 bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled(); 1710 RenderObject* caretPainter = selection->caretRenderer(); 1711 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { 1712 // Convert the painting offset into the local coordinate system of this renderer, 1713 // to match the localCaretRect computed by the SelectionController 1714 offsetForContents(tx, ty); 1715 1716 if (type == CursorCaret) 1717 document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); 1718 else 1719 document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); 1720 } 1721 } 1722 1723 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) 1724 { 1725 PaintPhase paintPhase = paintInfo.phase; 1726 1727 // 1. paint background, borders etc 1728 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { 1729 if (hasBoxDecorations()) 1730 paintBoxDecorations(paintInfo, tx, ty); 1731 if (hasColumns()) 1732 paintColumnRules(paintInfo, tx, ty); 1733 } 1734 1735 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { 1736 paintMask(paintInfo, tx, ty); 1737 return; 1738 } 1739 1740 // We're done. We don't bother painting any children. 1741 if (paintPhase == PaintPhaseBlockBackground) 1742 return; 1743 1744 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s 1745 int scrolledX = tx; 1746 int scrolledY = ty; 1747 if (hasOverflowClip()) 1748 layer()->subtractScrolledContentOffset(scrolledX, scrolledY); 1749 1750 // 2. paint contents 1751 if (paintPhase != PaintPhaseSelfOutline) { 1752 if (hasColumns()) 1753 paintColumnContents(paintInfo, scrolledX, scrolledY); 1754 else 1755 paintContents(paintInfo, scrolledX, scrolledY); 1756 } 1757 1758 // 3. paint selection 1759 // FIXME: Make this work with multi column layouts. For now don't fill gaps. 1760 bool isPrinting = document()->printing(); 1761 if (!isPrinting && !hasColumns()) 1762 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. 1763 1764 // 4. paint floats. 1765 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { 1766 if (hasColumns()) 1767 paintColumnContents(paintInfo, scrolledX, scrolledY, true); 1768 else 1769 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); 1770 } 1771 1772 // 5. paint outline. 1773 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) 1774 paintOutline(paintInfo.context, tx, ty, width(), height(), style()); 1775 1776 // 6. paint continuation outlines. 1777 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { 1778 if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) { 1779 RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer()); 1780 RenderBlock* cb = containingBlock(); 1781 1782 bool inlineEnclosedInSelfPaintingLayer = false; 1783 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) { 1784 if (box->hasSelfPaintingLayer()) { 1785 inlineEnclosedInSelfPaintingLayer = true; 1786 break; 1787 } 1788 } 1789 1790 if (!inlineEnclosedInSelfPaintingLayer) 1791 cb->addContinuationWithOutline(inlineRenderer); 1792 else if (!inlineRenderer->firstLineBox()) 1793 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), 1794 ty - y() + inlineRenderer->containingBlock()->y()); 1795 } 1796 paintContinuationOutlines(paintInfo, tx, ty); 1797 } 1798 1799 // 7. paint caret. 1800 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, 1801 // then paint the caret. 1802 if (paintPhase == PaintPhaseForeground) { 1803 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); 1804 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); 1805 } 1806 } 1807 1808 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase) 1809 { 1810 if (!m_floatingObjects) 1811 return; 1812 1813 FloatingObject* r; 1814 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 1815 for (; (r = it.current()); ++it) { 1816 // Only paint the object if our m_shouldPaint flag is set. 1817 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 1818 PaintInfo currentPaintInfo(paintInfo); 1819 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 1820 int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); 1821 int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop(); 1822 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1823 if (!preservePhase) { 1824 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 1825 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1826 currentPaintInfo.phase = PaintPhaseFloat; 1827 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1828 currentPaintInfo.phase = PaintPhaseForeground; 1829 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1830 currentPaintInfo.phase = PaintPhaseOutline; 1831 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY); 1832 } 1833 } 1834 } 1835 } 1836 1837 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) 1838 { 1839 if (!shouldPaintWithinRoot(paintInfo) || !firstLineBox()) 1840 return; 1841 1842 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { 1843 // We can check the first box and last box and avoid painting if we don't 1844 // intersect. 1845 int yPos = ty + firstLineBox()->y(); 1846 int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y(); 1847 if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y()) 1848 return; 1849 1850 // See if our boxes intersect with the dirty rect. If so, then we paint 1851 // them. Note that boxes can easily overlap, so we can't make any assumptions 1852 // based off positions of our first line box or our last line box. 1853 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 1854 yPos = ty + curr->y(); 1855 h = curr->height(); 1856 if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y()) 1857 curr->paintEllipsisBox(paintInfo, tx, ty); 1858 } 1859 } 1860 } 1861 1862 static ContinuationOutlineTableMap* continuationOutlineTable() 1863 { 1864 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); 1865 return &table; 1866 } 1867 1868 void RenderBlock::addContinuationWithOutline(RenderInline* flow) 1869 { 1870 // We can't make this work if the inline is in a layer. We'll just rely on the broken 1871 // way of painting. 1872 ASSERT(!flow->layer() && !flow->isInlineContinuation()); 1873 1874 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1875 ListHashSet<RenderInline*>* continuations = table->get(this); 1876 if (!continuations) { 1877 continuations = new ListHashSet<RenderInline*>; 1878 table->set(this, continuations); 1879 } 1880 1881 continuations->add(flow); 1882 } 1883 1884 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) 1885 { 1886 ContinuationOutlineTableMap* table = continuationOutlineTable(); 1887 if (table->isEmpty()) 1888 return; 1889 1890 ListHashSet<RenderInline*>* continuations = table->get(this); 1891 if (!continuations) 1892 return; 1893 1894 // Paint each continuation outline. 1895 ListHashSet<RenderInline*>::iterator end = continuations->end(); 1896 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { 1897 // Need to add in the coordinates of the intervening blocks. 1898 RenderInline* flow = *it; 1899 RenderBlock* block = flow->containingBlock(); 1900 for ( ; block && block != this; block = block->containingBlock()) { 1901 tx += block->x(); 1902 ty += block->y(); 1903 } 1904 ASSERT(block); 1905 flow->paintOutline(info.context, tx, ty); 1906 } 1907 1908 // Delete 1909 delete continuations; 1910 table->remove(this); 1911 } 1912 1913 void RenderBlock::setSelectionState(SelectionState s) 1914 { 1915 if (selectionState() == s) 1916 return; 1917 1918 if (s == SelectionInside && selectionState() != SelectionNone) 1919 return; 1920 1921 if ((s == SelectionStart && selectionState() == SelectionEnd) || 1922 (s == SelectionEnd && selectionState() == SelectionStart)) 1923 RenderBox::setSelectionState(SelectionBoth); 1924 else 1925 RenderBox::setSelectionState(s); 1926 1927 RenderBlock* cb = containingBlock(); 1928 if (cb && !cb->isRenderView()) 1929 cb->setSelectionState(s); 1930 } 1931 1932 bool RenderBlock::shouldPaintSelectionGaps() const 1933 { 1934 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); 1935 } 1936 1937 bool RenderBlock::isSelectionRoot() const 1938 { 1939 if (!node()) 1940 return false; 1941 1942 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. 1943 if (isTable()) 1944 return false; 1945 1946 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() || 1947 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() || 1948 hasReflection() || hasMask()) 1949 return true; 1950 1951 if (view() && view()->selectionStart()) { 1952 Node* startElement = view()->selectionStart()->node(); 1953 if (startElement && startElement->rootEditableElement() == node()) 1954 return true; 1955 } 1956 1957 return false; 1958 } 1959 1960 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer) 1961 { 1962 ASSERT(!needsLayout()); 1963 1964 if (!shouldPaintSelectionGaps()) 1965 return GapRects(); 1966 1967 // FIXME: this is broken with transforms 1968 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); 1969 mapLocalToContainer(repaintContainer, false, false, transformState); 1970 FloatPoint offsetFromRepaintContainer = transformState.mappedPoint(); 1971 int x = offsetFromRepaintContainer.x(); 1972 int y = offsetFromRepaintContainer.y(); 1973 1974 if (hasOverflowClip()) 1975 layer()->subtractScrolledContentOffset(x, y); 1976 1977 int lastTop = 0; 1978 int lastLeft = leftSelectionOffset(this, lastTop); 1979 int lastRight = rightSelectionOffset(this, lastTop); 1980 1981 return fillSelectionGaps(this, x, y, x, y, lastTop, lastLeft, lastRight); 1982 } 1983 1984 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) 1985 { 1986 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { 1987 int lastTop = 0; 1988 int lastLeft = leftSelectionOffset(this, lastTop); 1989 int lastRight = rightSelectionOffset(this, lastTop); 1990 paintInfo.context->save(); 1991 IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo); 1992 if (!gapRectsBounds.isEmpty()) { 1993 if (RenderLayer* layer = enclosingLayer()) { 1994 gapRectsBounds.move(IntSize(-tx, -ty)); 1995 if (!hasLayer()) { 1996 FloatRect localBounds(gapRectsBounds); 1997 gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox(); 1998 } 1999 layer->addBlockSelectionGapsBounds(gapRectsBounds); 2000 } 2001 } 2002 paintInfo.context->restore(); 2003 } 2004 } 2005 2006 #ifndef BUILDING_ON_TIGER 2007 static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects) 2008 { 2009 if (!positionedObjects) 2010 return; 2011 2012 ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end(); 2013 for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) { 2014 RenderBox* r = *it; 2015 paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height())); 2016 } 2017 } 2018 #endif 2019 2020 GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2021 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2022 { 2023 #ifndef BUILDING_ON_TIGER 2024 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. 2025 // Clip out floating and positioned objects when painting selection gaps. 2026 if (paintInfo) { 2027 // Note that we don't clip out overflow for positioned objects. We just stick to the border box. 2028 clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects); 2029 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. 2030 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) 2031 clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects); 2032 if (m_floatingObjects) { 2033 for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) { 2034 FloatingObject* r = it.current(); 2035 paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(), 2036 ty + r->m_top + r->m_renderer->marginTop(), 2037 r->m_renderer->width(), r->m_renderer->height())); 2038 } 2039 } 2040 } 2041 #endif 2042 2043 // 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 2044 // fixed). 2045 GapRects result; 2046 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. 2047 return result; 2048 2049 if (hasColumns() || hasTransform()) { 2050 // FIXME: We should learn how to gap fill multiple columns and transforms eventually. 2051 lastTop = (ty - blockY) + height(); 2052 lastLeft = leftSelectionOffset(rootBlock, height()); 2053 lastRight = rightSelectionOffset(rootBlock, height()); 2054 return result; 2055 } 2056 2057 if (childrenInline()) 2058 result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2059 else 2060 result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo); 2061 2062 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. 2063 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) 2064 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(), 2065 rootBlock, blockX, blockY, paintInfo)); 2066 return result; 2067 } 2068 2069 GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2070 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2071 { 2072 GapRects result; 2073 2074 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 2075 2076 if (!firstLineBox()) { 2077 if (containsStart) { 2078 // Go ahead and update our lastY to be the bottom of the block. <hr>s or empty blocks with height can trip this 2079 // case. 2080 lastTop = (ty - blockY) + height(); 2081 lastLeft = leftSelectionOffset(rootBlock, height()); 2082 lastRight = rightSelectionOffset(rootBlock, height()); 2083 } 2084 return result; 2085 } 2086 2087 RootInlineBox* lastSelectedLine = 0; 2088 RootInlineBox* curr; 2089 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 2090 2091 // Now paint the gaps for the lines. 2092 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 2093 int selTop = curr->selectionTop(); 2094 int selHeight = curr->selectionHeight(); 2095 2096 if (!containsStart && !lastSelectedLine && 2097 selectionState() != SelectionStart && selectionState() != SelectionBoth) 2098 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop, 2099 rootBlock, blockX, blockY, paintInfo)); 2100 2101 if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y())) 2102 result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo)); 2103 2104 lastSelectedLine = curr; 2105 } 2106 2107 if (containsStart && !lastSelectedLine) 2108 // VisibleSelection must start just after our last line. 2109 lastSelectedLine = lastRootBox(); 2110 2111 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 2112 // Go ahead and update our lastY to be the bottom of the last selected line. 2113 lastTop = (ty - blockY) + lastSelectedLine->selectionBottom(); 2114 lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2115 lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2116 } 2117 return result; 2118 } 2119 2120 GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty, 2121 int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo) 2122 { 2123 GapRects result; 2124 2125 // Go ahead and jump right to the first block child that contains some selected objects. 2126 RenderBox* curr; 2127 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } 2128 2129 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { 2130 SelectionState childState = curr->selectionState(); 2131 if (childState == SelectionBoth || childState == SelectionEnd) 2132 sawSelectionEnd = true; 2133 2134 if (curr->isFloatingOrPositioned()) 2135 continue; // We must be a normal flow object in order to even be considered. 2136 2137 if (curr->isRelPositioned() && curr->hasLayer()) { 2138 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. 2139 // Just disregard it completely. 2140 IntSize relOffset = curr->layer()->relativePositionOffset(); 2141 if (relOffset.width() || relOffset.height()) 2142 continue; 2143 } 2144 2145 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this. 2146 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone); 2147 if (fillBlockGaps) { 2148 // We need to fill the vertical gap above this object. 2149 if (childState == SelectionEnd || childState == SelectionInside) 2150 // Fill the gap above the object. 2151 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, 2152 ty + curr->y(), rootBlock, blockX, blockY, paintInfo)); 2153 2154 // 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* 2155 // our object. We know this if the selection did not end inside our object. 2156 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd)) 2157 childState = SelectionNone; 2158 2159 // Fill side gaps on this object based off its state. 2160 bool leftGap, rightGap; 2161 getHorizontalSelectionGapInfo(childState, leftGap, rightGap); 2162 2163 if (leftGap) 2164 result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2165 if (rightGap) 2166 result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo)); 2167 2168 // Update lastTop to be just underneath the object. lastLeft and lastRight extend as far as 2169 // they can without bumping into floating or positioned objects. Ideally they will go right up 2170 // to the border of the root selection block. 2171 lastTop = (ty - blockY) + (curr->y() + curr->height()); 2172 lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height()); 2173 lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height()); 2174 } else if (childState != SelectionNone) 2175 // We must be a block that has some selected object inside it. Go ahead and recur. 2176 result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(), 2177 lastTop, lastLeft, lastRight, paintInfo)); 2178 } 2179 return result; 2180 } 2181 2182 IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo* paintInfo) 2183 { 2184 if (width <= 0 || height <= 0) 2185 return IntRect(); 2186 IntRect gapRect(xPos, yPos, width, height); 2187 if (paintInfo && selObj->style()->visibility() == VISIBLE) 2188 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2189 return gapRect; 2190 } 2191 2192 IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock, 2193 int blockX, int blockY, const PaintInfo* paintInfo) 2194 { 2195 int top = blockY + lastTop; 2196 int height = bottomY - top; 2197 if (height <= 0) 2198 return IntRect(); 2199 2200 // Get the selection offsets for the bottom of the gap 2201 int left = blockX + max(lastLeft, leftSelectionOffset(rootBlock, bottomY)); 2202 int right = blockX + min(lastRight, rightSelectionOffset(rootBlock, bottomY)); 2203 int width = right - left; 2204 if (width <= 0) 2205 return IntRect(); 2206 2207 IntRect gapRect(left, top, width, height); 2208 if (paintInfo) 2209 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace()); 2210 return gapRect; 2211 } 2212 2213 IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2214 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2215 { 2216 int top = yPos + ty; 2217 int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)); 2218 int right = min(xPos + tx, blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height))); 2219 int width = right - left; 2220 if (width <= 0) 2221 return IntRect(); 2222 2223 IntRect gapRect(left, top, width, height); 2224 if (paintInfo) 2225 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2226 return gapRect; 2227 } 2228 2229 IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock, 2230 int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo) 2231 { 2232 int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height))); 2233 int top = yPos + ty; 2234 int right = blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height)); 2235 int width = right - left; 2236 if (width <= 0) 2237 return IntRect(); 2238 2239 IntRect gapRect(left, top, width, height); 2240 if (paintInfo) 2241 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 2242 return gapRect; 2243 } 2244 2245 void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) 2246 { 2247 bool ltr = style()->direction() == LTR; 2248 leftGap = (state == RenderObject::SelectionInside) || 2249 (state == RenderObject::SelectionEnd && ltr) || 2250 (state == RenderObject::SelectionStart && !ltr); 2251 rightGap = (state == RenderObject::SelectionInside) || 2252 (state == RenderObject::SelectionStart && ltr) || 2253 (state == RenderObject::SelectionEnd && !ltr); 2254 } 2255 2256 int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos) 2257 { 2258 int left = leftOffset(yPos, false); 2259 if (left == borderLeft() + paddingLeft()) { 2260 if (rootBlock != this) 2261 // The border can potentially be further extended by our containingBlock(). 2262 return containingBlock()->leftSelectionOffset(rootBlock, yPos + y()); 2263 return left; 2264 } 2265 else { 2266 RenderBlock* cb = this; 2267 while (cb != rootBlock) { 2268 left += cb->x(); 2269 cb = cb->containingBlock(); 2270 } 2271 } 2272 2273 return left; 2274 } 2275 2276 int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos) 2277 { 2278 int right = rightOffset(yPos, false); 2279 if (right == (contentWidth() + (borderLeft() + paddingLeft()))) { 2280 if (rootBlock != this) 2281 // The border can potentially be further extended by our containingBlock(). 2282 return containingBlock()->rightSelectionOffset(rootBlock, yPos + y()); 2283 return right; 2284 } 2285 else { 2286 RenderBlock* cb = this; 2287 while (cb != rootBlock) { 2288 right += cb->x(); 2289 cb = cb->containingBlock(); 2290 } 2291 } 2292 return right; 2293 } 2294 2295 void RenderBlock::insertPositionedObject(RenderBox* o) 2296 { 2297 // Create the list of special objects if we don't aleady have one 2298 if (!m_positionedObjects) 2299 m_positionedObjects = new ListHashSet<RenderBox*>; 2300 2301 m_positionedObjects->add(o); 2302 } 2303 2304 void RenderBlock::removePositionedObject(RenderBox* o) 2305 { 2306 if (m_positionedObjects) 2307 m_positionedObjects->remove(o); 2308 } 2309 2310 void RenderBlock::removePositionedObjects(RenderBlock* o) 2311 { 2312 if (!m_positionedObjects) 2313 return; 2314 2315 RenderBox* r; 2316 2317 Iterator end = m_positionedObjects->end(); 2318 2319 Vector<RenderBox*, 16> deadObjects; 2320 2321 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2322 r = *it; 2323 if (!o || r->isDescendantOf(o)) { 2324 if (o) 2325 r->setChildNeedsLayout(true, false); 2326 2327 // It is parent blocks job to add positioned child to positioned objects list of its containing block 2328 // Parent layout needs to be invalidated to ensure this happens. 2329 RenderObject* p = r->parent(); 2330 while (p && !p->isRenderBlock()) 2331 p = p->parent(); 2332 if (p) 2333 p->setChildNeedsLayout(true); 2334 2335 deadObjects.append(r); 2336 } 2337 } 2338 2339 for (unsigned i = 0; i < deadObjects.size(); i++) 2340 m_positionedObjects->remove(deadObjects.at(i)); 2341 } 2342 2343 void RenderBlock::insertFloatingObject(RenderBox* o) 2344 { 2345 ASSERT(o->isFloating()); 2346 2347 // Create the list of special objects if we don't aleady have one 2348 if (!m_floatingObjects) { 2349 m_floatingObjects = new DeprecatedPtrList<FloatingObject>; 2350 m_floatingObjects->setAutoDelete(true); 2351 } else { 2352 // Don't insert the object again if it's already in the list 2353 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2354 FloatingObject* f; 2355 while ( (f = it.current()) ) { 2356 if (f->m_renderer == o) return; 2357 ++it; 2358 } 2359 } 2360 2361 // Create the special object entry & append it to the list 2362 2363 o->layoutIfNeeded(); 2364 2365 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight); 2366 2367 newObj->m_top = -1; 2368 newObj->m_bottom = -1; 2369 newObj->m_width = o->width() + o->marginLeft() + o->marginRight(); 2370 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. 2371 newObj->m_isDescendant = true; 2372 newObj->m_renderer = o; 2373 2374 m_floatingObjects->append(newObj); 2375 } 2376 2377 void RenderBlock::removeFloatingObject(RenderBox* o) 2378 { 2379 if (m_floatingObjects) { 2380 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2381 while (it.current()) { 2382 if (it.current()->m_renderer == o) { 2383 if (childrenInline()) 2384 markLinesDirtyInVerticalRange(0, it.current()->m_bottom); 2385 m_floatingObjects->removeRef(it.current()); 2386 } 2387 ++it; 2388 } 2389 } 2390 } 2391 2392 bool RenderBlock::positionNewFloats() 2393 { 2394 if (!m_floatingObjects) 2395 return false; 2396 2397 FloatingObject* f = m_floatingObjects->last(); 2398 2399 // If all floats have already been positioned, then we have no work to do. 2400 if (!f || f->m_top != -1) 2401 return false; 2402 2403 // Move backwards through our floating object list until we find a float that has 2404 // already been positioned. Then we'll be able to move forward, positioning all of 2405 // the new floats that need it. 2406 FloatingObject* lastFloat = m_floatingObjects->getPrev(); 2407 while (lastFloat && lastFloat->m_top == -1) { 2408 f = m_floatingObjects->prev(); 2409 lastFloat = m_floatingObjects->getPrev(); 2410 } 2411 2412 int y = height(); 2413 2414 // The float cannot start above the y position of the last positioned float. 2415 if (lastFloat) 2416 y = max(lastFloat->m_top, y); 2417 2418 // Now walk through the set of unpositioned floats and place them. 2419 while (f) { 2420 // The containing block is responsible for positioning floats, so if we have floats in our 2421 // list that come from somewhere else, do not attempt to position them. 2422 if (f->m_renderer->containingBlock() != this) { 2423 f = m_floatingObjects->next(); 2424 continue; 2425 } 2426 2427 RenderBox* o = f->m_renderer; 2428 int _height = o->height() + o->marginTop() + o->marginBottom(); 2429 2430 int ro = rightOffset(); // Constant part of right offset. 2431 int lo = leftOffset(); // Constat part of left offset. 2432 int fwidth = f->m_width; // The width we look for. 2433 if (ro - lo < fwidth) 2434 fwidth = ro - lo; // Never look for more than what will be available. 2435 2436 IntRect oldRect(o->x(), o->y() , o->width(), o->height()); 2437 2438 if (o->style()->clear() & CLEFT) 2439 y = max(leftBottom(), y); 2440 if (o->style()->clear() & CRIGHT) 2441 y = max(rightBottom(), y); 2442 2443 if (o->style()->floating() == FLEFT) { 2444 int heightRemainingLeft = 1; 2445 int heightRemainingRight = 1; 2446 int fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2447 while (rightRelOffset(y, ro, false, &heightRemainingRight)-fx < fwidth) { 2448 y += min(heightRemainingLeft, heightRemainingRight); 2449 fx = leftRelOffset(y, lo, false, &heightRemainingLeft); 2450 } 2451 fx = max(0, fx); 2452 f->m_left = fx; 2453 o->setLocation(fx + o->marginLeft(), y + o->marginTop()); 2454 } else { 2455 int heightRemainingLeft = 1; 2456 int heightRemainingRight = 1; 2457 int fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2458 while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) { 2459 y += min(heightRemainingLeft, heightRemainingRight); 2460 fx = rightRelOffset(y, ro, false, &heightRemainingRight); 2461 } 2462 f->m_left = fx - f->m_width; 2463 o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop()); 2464 } 2465 2466 f->m_top = y; 2467 f->m_bottom = f->m_top + _height; 2468 2469 // If the child moved, we have to repaint it. 2470 if (o->checkForRepaintDuringLayout()) 2471 o->repaintDuringLayoutIfMoved(oldRect); 2472 2473 f = m_floatingObjects->next(); 2474 } 2475 return true; 2476 } 2477 2478 void RenderBlock::newLine(EClear clear) 2479 { 2480 positionNewFloats(); 2481 // set y position 2482 int newY = 0; 2483 switch (clear) 2484 { 2485 case CLEFT: 2486 newY = leftBottom(); 2487 break; 2488 case CRIGHT: 2489 newY = rightBottom(); 2490 break; 2491 case CBOTH: 2492 newY = floatBottom(); 2493 default: 2494 break; 2495 } 2496 if (height() < newY) 2497 setHeight(newY); 2498 } 2499 2500 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) 2501 { 2502 if (!gPercentHeightDescendantsMap) { 2503 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap; 2504 gPercentHeightContainerMap = new PercentHeightContainerMap; 2505 } 2506 2507 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this); 2508 if (!descendantSet) { 2509 descendantSet = new HashSet<RenderBox*>; 2510 gPercentHeightDescendantsMap->set(this, descendantSet); 2511 } 2512 bool added = descendantSet->add(descendant).second; 2513 if (!added) { 2514 ASSERT(gPercentHeightContainerMap->get(descendant)); 2515 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this)); 2516 return; 2517 } 2518 2519 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant); 2520 if (!containerSet) { 2521 containerSet = new HashSet<RenderBlock*>; 2522 gPercentHeightContainerMap->set(descendant, containerSet); 2523 } 2524 ASSERT(!containerSet->contains(this)); 2525 containerSet->add(this); 2526 } 2527 2528 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) 2529 { 2530 if (!gPercentHeightContainerMap) 2531 return; 2532 2533 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant); 2534 if (!containerSet) 2535 return; 2536 2537 HashSet<RenderBlock*>::iterator end = containerSet->end(); 2538 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) { 2539 RenderBlock* container = *it; 2540 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container); 2541 ASSERT(descendantSet); 2542 if (!descendantSet) 2543 continue; 2544 ASSERT(descendantSet->contains(descendant)); 2545 descendantSet->remove(descendant); 2546 if (descendantSet->isEmpty()) { 2547 gPercentHeightDescendantsMap->remove(container); 2548 delete descendantSet; 2549 } 2550 } 2551 2552 delete containerSet; 2553 } 2554 2555 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const 2556 { 2557 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; 2558 } 2559 2560 int RenderBlock::leftOffset() const 2561 { 2562 return borderLeft() + paddingLeft(); 2563 } 2564 2565 int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2566 { 2567 int left = fixedOffset; 2568 if (m_floatingObjects) { 2569 if ( heightRemaining ) *heightRemaining = 1; 2570 FloatingObject* r; 2571 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2572 for ( ; (r = it.current()); ++it ) 2573 { 2574 if (r->m_top <= y && r->m_bottom > y && 2575 r->type() == FloatingObject::FloatLeft && 2576 r->m_left + r->m_width > left) { 2577 left = r->m_left + r->m_width; 2578 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2579 } 2580 } 2581 } 2582 2583 if (applyTextIndent && style()->direction() == LTR) { 2584 int cw = 0; 2585 if (style()->textIndent().isPercent()) 2586 cw = containingBlock()->availableWidth(); 2587 left += style()->textIndent().calcMinValue(cw); 2588 } 2589 2590 return left; 2591 } 2592 2593 int RenderBlock::rightOffset() const 2594 { 2595 return borderLeft() + paddingLeft() + availableWidth(); 2596 } 2597 2598 int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 2599 { 2600 int right = fixedOffset; 2601 2602 if (m_floatingObjects) { 2603 if (heightRemaining) *heightRemaining = 1; 2604 FloatingObject* r; 2605 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2606 for ( ; (r = it.current()); ++it ) 2607 { 2608 if (r->m_top <= y && r->m_bottom > y && 2609 r->type() == FloatingObject::FloatRight && 2610 r->m_left < right) { 2611 right = r->m_left; 2612 if ( heightRemaining ) *heightRemaining = r->m_bottom - y; 2613 } 2614 } 2615 } 2616 2617 if (applyTextIndent && style()->direction() == RTL) { 2618 int cw = 0; 2619 if (style()->textIndent().isPercent()) 2620 cw = containingBlock()->availableWidth(); 2621 right -= style()->textIndent().calcMinValue(cw); 2622 } 2623 2624 return right; 2625 } 2626 2627 int 2628 RenderBlock::lineWidth(int y, bool firstLine) const 2629 { 2630 int result = rightOffset(y, firstLine) - leftOffset(y, firstLine); 2631 return (result < 0) ? 0 : result; 2632 } 2633 2634 int RenderBlock::nextFloatBottomBelow(int height) const 2635 { 2636 if (!m_floatingObjects) 2637 return 0; 2638 2639 int bottom = INT_MAX; 2640 FloatingObject* r; 2641 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2642 for ( ; (r = it.current()); ++it) { 2643 if (r->m_bottom > height) 2644 bottom = min(r->m_bottom, bottom); 2645 } 2646 2647 return bottom == INT_MAX ? 0 : bottom; 2648 } 2649 2650 int 2651 RenderBlock::floatBottom() const 2652 { 2653 if (!m_floatingObjects) return 0; 2654 int bottom = 0; 2655 FloatingObject* r; 2656 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2657 for ( ; (r = it.current()); ++it ) 2658 if (r->m_bottom>bottom) 2659 bottom = r->m_bottom; 2660 return bottom; 2661 } 2662 2663 IntRect RenderBlock::floatRect() const 2664 { 2665 IntRect result; 2666 if (!m_floatingObjects || hasOverflowClip() || hasColumns()) 2667 return result; 2668 FloatingObject* r; 2669 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2670 for (; (r = it.current()); ++it) { 2671 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 2672 IntRect childRect = r->m_renderer->visibleOverflowRect(); 2673 childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()); 2674 result.unite(childRect); 2675 } 2676 } 2677 2678 return result; 2679 } 2680 2681 int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const 2682 { 2683 int bottom = includeSelf && width() > 0 ? height() : 0; 2684 2685 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2686 return bottom; 2687 2688 if (!firstChild() && (!width() || !height())) 2689 return bottom; 2690 2691 if (!hasColumns()) { 2692 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2693 // For now, we have to descend into all the children, since we may have a huge abs div inside 2694 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2695 // the abs div. 2696 // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem. 2697 // For inline children, we miss relative positioned boxes that might be buried inside <span>s. 2698 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2699 if (!c->isFloatingOrPositioned() && c->isBox()) { 2700 RenderBox* childBox = toRenderBox(c); 2701 bottom = max(bottom, childBox->y() + childBox->lowestPosition(false)); 2702 } 2703 } 2704 } 2705 2706 if (includeSelf && isRelPositioned()) 2707 bottom += relativePositionOffsetY(); 2708 if (!includeOverflowInterior && hasOverflowClip()) 2709 return bottom; 2710 2711 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0; 2712 2713 if (includeSelf) 2714 bottom = max(bottom, bottomLayoutOverflow() + relativeOffset); 2715 2716 if (m_positionedObjects) { 2717 RenderBox* r; 2718 Iterator end = m_positionedObjects->end(); 2719 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2720 r = *it; 2721 // Fixed positioned objects do not scroll and thus should not constitute 2722 // part of the lowest position. 2723 if (r->style()->position() != FixedPosition) { 2724 // FIXME: Should work for overflow sections too. 2725 // If a positioned object lies completely to the left of the root it will be unreachable via scrolling. 2726 // Therefore we should not allow it to contribute to the lowest position. 2727 if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) { 2728 int lp = r->y() + r->lowestPosition(false); 2729 bottom = max(bottom, lp + relativeOffset); 2730 } 2731 } 2732 } 2733 } 2734 2735 if (hasColumns()) { 2736 Vector<IntRect>* colRects = columnRects(); 2737 for (unsigned i = 0; i < colRects->size(); i++) 2738 bottom = max(bottom, colRects->at(i).bottom() + relativeOffset); 2739 return bottom; 2740 } 2741 2742 if (m_floatingObjects) { 2743 FloatingObject* r; 2744 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2745 for ( ; (r = it.current()); ++it ) { 2746 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2747 int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false); 2748 bottom = max(bottom, lp + relativeOffset); 2749 } 2750 } 2751 } 2752 2753 if (!includeSelf) { 2754 bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset); 2755 if (childrenInline()) { 2756 if (lastRootBox()) { 2757 int childBottomEdge = lastRootBox()->selectionBottom(); 2758 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2759 } 2760 } else { 2761 // Find the last normal flow child. 2762 RenderBox* currBox = lastChildBox(); 2763 while (currBox && currBox->isFloatingOrPositioned()) 2764 currBox = currBox->previousSiblingBox(); 2765 if (currBox) { 2766 int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom(); 2767 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset); 2768 } 2769 } 2770 } 2771 2772 return bottom; 2773 } 2774 2775 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const 2776 { 2777 int right = includeSelf && height() > 0 ? width() : 0; 2778 2779 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2780 return right; 2781 2782 if (!firstChild() && (!width() || !height())) 2783 return right; 2784 2785 if (!hasColumns()) { 2786 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2787 // For now, we have to descend into all the children, since we may have a huge abs div inside 2788 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2789 // the abs div. 2790 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2791 if (!c->isFloatingOrPositioned() && c->isBox()) { 2792 RenderBox* childBox = toRenderBox(c); 2793 right = max(right, childBox->x() + childBox->rightmostPosition(false)); 2794 } 2795 } 2796 } 2797 2798 if (includeSelf && isRelPositioned()) 2799 right += relativePositionOffsetX(); 2800 2801 if (!includeOverflowInterior && hasOverflowClip()) 2802 return right; 2803 2804 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0; 2805 2806 if (includeSelf) 2807 right = max(right, rightLayoutOverflow() + relativeOffset); 2808 2809 if (m_positionedObjects) { 2810 RenderBox* r; 2811 Iterator end = m_positionedObjects->end(); 2812 for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) { 2813 r = *it; 2814 // Fixed positioned objects do not scroll and thus should not constitute 2815 // part of the rightmost position. 2816 if (r->style()->position() != FixedPosition) { 2817 // FIXME: Should work for overflow sections too. 2818 // If a positioned object lies completely above the root it will be unreachable via scrolling. 2819 // Therefore we should not allow it to contribute to the rightmost position. 2820 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { 2821 int rp = r->x() + r->rightmostPosition(false); 2822 right = max(right, rp + relativeOffset); 2823 } 2824 } 2825 } 2826 } 2827 2828 if (hasColumns()) { 2829 // This only matters for LTR 2830 if (style()->direction() == LTR) 2831 right = max(columnRects()->last().right() + relativeOffset, right); 2832 return right; 2833 } 2834 2835 if (m_floatingObjects) { 2836 FloatingObject* r; 2837 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2838 for ( ; (r = it.current()); ++it ) { 2839 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2840 int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false); 2841 right = max(right, rp + relativeOffset); 2842 } 2843 } 2844 } 2845 2846 if (!includeSelf) { 2847 right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset); 2848 if (childrenInline()) { 2849 for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) { 2850 int childRightEdge = currBox->x() + currBox->width(); 2851 2852 // If this node is a root editable element, then the rightmostPosition should account for a caret at the end. 2853 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to. 2854 if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight()) 2855 childRightEdge += 1; 2856 right = max(right, childRightEdge + paddingRight() + relativeOffset); 2857 } 2858 } else { 2859 // Walk all normal flow children. 2860 for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) { 2861 if (currBox->isFloatingOrPositioned()) 2862 continue; 2863 int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight(); 2864 right = max(right, childRightEdge + paddingRight() + relativeOffset); 2865 } 2866 } 2867 } 2868 2869 return right; 2870 } 2871 2872 int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const 2873 { 2874 int left = includeSelf && height() > 0 ? 0 : width(); 2875 2876 if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip())) 2877 return left; 2878 2879 if (!firstChild() && (!width() || !height())) 2880 return left; 2881 2882 if (!hasColumns()) { 2883 // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids. 2884 // For now, we have to descend into all the children, since we may have a huge abs div inside 2885 // a tiny rel div buried somewhere deep in our child tree. In this case we have to get to 2886 // the abs div. 2887 for (RenderObject* c = firstChild(); c; c = c->nextSibling()) { 2888 if (!c->isFloatingOrPositioned() && c->isBox()) { 2889 RenderBox* childBox = toRenderBox(c); 2890 left = min(left, childBox->x() + childBox->leftmostPosition(false)); 2891 } 2892 } 2893 } 2894 2895 if (includeSelf && isRelPositioned()) 2896 left += relativePositionOffsetX(); 2897 2898 if (!includeOverflowInterior && hasOverflowClip()) 2899 return left; 2900 2901 int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0; 2902 2903 if (includeSelf) 2904 left = min(left, leftLayoutOverflow() + relativeOffset); 2905 2906 if (m_positionedObjects) { 2907 RenderBox* r; 2908 Iterator end = m_positionedObjects->end(); 2909 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2910 r = *it; 2911 // Fixed positioned objects do not scroll and thus should not constitute 2912 // part of the leftmost position. 2913 if (r->style()->position() != FixedPosition) { 2914 // FIXME: Should work for overflow sections too. 2915 // If a positioned object lies completely above the root it will be unreachable via scrolling. 2916 // Therefore we should not allow it to contribute to the leftmost position. 2917 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) { 2918 int lp = r->x() + r->leftmostPosition(false); 2919 left = min(left, lp + relativeOffset); 2920 } 2921 } 2922 } 2923 } 2924 2925 if (hasColumns()) { 2926 // This only matters for RTL 2927 if (style()->direction() == RTL) 2928 left = min(columnRects()->last().x() + relativeOffset, left); 2929 return left; 2930 } 2931 2932 if (m_floatingObjects) { 2933 FloatingObject* r; 2934 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2935 for ( ; (r = it.current()); ++it ) { 2936 if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) { 2937 int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false); 2938 left = min(left, lp + relativeOffset); 2939 } 2940 } 2941 } 2942 2943 if (!includeSelf && firstLineBox()) { 2944 for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) 2945 left = min(left, (int)currBox->x() + relativeOffset); 2946 } 2947 2948 return left; 2949 } 2950 2951 int 2952 RenderBlock::leftBottom() 2953 { 2954 if (!m_floatingObjects) return 0; 2955 int bottom = 0; 2956 FloatingObject* r; 2957 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2958 for ( ; (r = it.current()); ++it ) 2959 if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft) 2960 bottom = r->m_bottom; 2961 2962 return bottom; 2963 } 2964 2965 int 2966 RenderBlock::rightBottom() 2967 { 2968 if (!m_floatingObjects) return 0; 2969 int bottom = 0; 2970 FloatingObject* r; 2971 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 2972 for ( ; (r = it.current()); ++it ) 2973 if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight) 2974 bottom = r->m_bottom; 2975 2976 return bottom; 2977 } 2978 2979 void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest) 2980 { 2981 if (top >= bottom) 2982 return; 2983 2984 RootInlineBox* lowestDirtyLine = lastRootBox(); 2985 RootInlineBox* afterLowest = lowestDirtyLine; 2986 while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) { 2987 afterLowest = lowestDirtyLine; 2988 lowestDirtyLine = lowestDirtyLine->prevRootBox(); 2989 } 2990 2991 while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) { 2992 afterLowest->markDirty(); 2993 afterLowest = afterLowest->prevRootBox(); 2994 } 2995 } 2996 2997 void RenderBlock::clearFloats() 2998 { 2999 // Inline blocks are covered by the isReplaced() check in the avoidFloats method. 3000 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) { 3001 if (m_floatingObjects) 3002 m_floatingObjects->clear(); 3003 return; 3004 } 3005 3006 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap; 3007 RendererToFloatInfoMap floatMap; 3008 3009 if (m_floatingObjects) { 3010 if (childrenInline()) { 3011 m_floatingObjects->first(); 3012 while (FloatingObject* f = m_floatingObjects->take()) 3013 floatMap.add(f->m_renderer, f); 3014 } else 3015 m_floatingObjects->clear(); 3016 } 3017 3018 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are 3019 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted 3020 // to avoid floats. 3021 bool parentHasFloats = false; 3022 RenderObject* prev = previousSibling(); 3023 while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { 3024 if (prev->isFloating()) 3025 parentHasFloats = true; 3026 prev = prev->previousSibling(); 3027 } 3028 3029 // First add in floats from the parent. 3030 int offset = y(); 3031 if (parentHasFloats) { 3032 RenderBlock* parentBlock = toRenderBlock(parent()); 3033 addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset); 3034 } 3035 3036 int xoffset = 0; 3037 if (prev) 3038 offset -= toRenderBox(prev)->y(); 3039 else if (parent()->isBox()) { 3040 prev = parent(); 3041 xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft(); 3042 } 3043 3044 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. 3045 if (!prev || !prev->isRenderBlock()) 3046 return; 3047 3048 RenderBlock* block = toRenderBlock(prev); 3049 if (block->m_floatingObjects && block->floatBottom() > offset) 3050 addIntrudingFloats(block, xoffset, offset); 3051 3052 if (childrenInline()) { 3053 int changeTop = INT_MAX; 3054 int changeBottom = INT_MIN; 3055 if (m_floatingObjects) { 3056 for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) { 3057 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); 3058 if (oldFloatingObject) { 3059 if (f->m_width != oldFloatingObject->m_width || f->m_left != oldFloatingObject->m_left) { 3060 changeTop = 0; 3061 changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom)); 3062 } else if (f->m_bottom != oldFloatingObject->m_bottom) { 3063 changeTop = min(changeTop, min(f->m_bottom, oldFloatingObject->m_bottom)); 3064 changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom)); 3065 } 3066 3067 floatMap.remove(f->m_renderer); 3068 delete oldFloatingObject; 3069 } else { 3070 changeTop = 0; 3071 changeBottom = max(changeBottom, f->m_bottom); 3072 } 3073 } 3074 } 3075 3076 RendererToFloatInfoMap::iterator end = floatMap.end(); 3077 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { 3078 FloatingObject* floatingObject = (*it).second; 3079 if (!floatingObject->m_isDescendant) { 3080 changeTop = 0; 3081 changeBottom = max(changeBottom, floatingObject->m_bottom); 3082 } 3083 } 3084 deleteAllValues(floatMap); 3085 3086 markLinesDirtyInVerticalRange(changeTop, changeBottom); 3087 } 3088 } 3089 3090 int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bool makeChildPaintOtherFloats) 3091 { 3092 // Prevent floats from being added to the canvas by the root element, e.g., <html>. 3093 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot()) 3094 return 0; 3095 3096 int lowestFloatBottom = 0; 3097 3098 // Floats that will remain the child's responsibility to paint should factor into its 3099 // overflow. 3100 DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects); 3101 for (FloatingObject* r; (r = it.current()); ++it) { 3102 int bottom = child->y() + r->m_bottom; 3103 lowestFloatBottom = max(lowestFloatBottom, bottom); 3104 3105 if (bottom > height()) { 3106 // If the object is not in the list, we add it now. 3107 if (!containsFloat(r->m_renderer)) { 3108 FloatingObject *floatingObj = new FloatingObject(r->type()); 3109 floatingObj->m_top = r->m_top - yoff; 3110 floatingObj->m_bottom = r->m_bottom - yoff; 3111 floatingObj->m_left = r->m_left - xoff; 3112 floatingObj->m_width = r->m_width; 3113 floatingObj->m_renderer = r->m_renderer; 3114 3115 // The nearest enclosing layer always paints the float (so that zindex and stacking 3116 // behaves properly). We always want to propagate the desire to paint the float as 3117 // far out as we can, to the outermost block that overlaps the float, stopping only 3118 // if we hit a self-painting layer boundary. 3119 if (r->m_renderer->enclosingSelfPaintingLayer() == enclosingSelfPaintingLayer()) 3120 r->m_shouldPaint = false; 3121 else 3122 floatingObj->m_shouldPaint = false; 3123 3124 // We create the floating object list lazily. 3125 if (!m_floatingObjects) { 3126 m_floatingObjects = new DeprecatedPtrList<FloatingObject>; 3127 m_floatingObjects->setAutoDelete(true); 3128 } 3129 m_floatingObjects->append(floatingObj); 3130 } 3131 } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && 3132 r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer()) 3133 // The float is not overhanging from this block, so if it is a descendant of the child, the child should 3134 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing 3135 // layer. 3136 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats 3137 // it should paint. 3138 r->m_shouldPaint = true; 3139 3140 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) 3141 child->addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop())); 3142 } 3143 return lowestFloatBottom; 3144 } 3145 3146 void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff) 3147 { 3148 // If the parent or previous sibling doesn't have any floats to add, don't bother. 3149 if (!prev->m_floatingObjects) 3150 return; 3151 3152 DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects); 3153 for (FloatingObject *r; (r = it.current()); ++it) { 3154 if (r->m_bottom > yoff) { 3155 // The object may already be in our list. Check for it up front to avoid 3156 // creating duplicate entries. 3157 FloatingObject* f = 0; 3158 if (m_floatingObjects) { 3159 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 3160 while ((f = it.current())) { 3161 if (f->m_renderer == r->m_renderer) break; 3162 ++it; 3163 } 3164 } 3165 if (!f) { 3166 FloatingObject *floatingObj = new FloatingObject(r->type()); 3167 floatingObj->m_top = r->m_top - yoff; 3168 floatingObj->m_bottom = r->m_bottom - yoff; 3169 floatingObj->m_left = r->m_left - xoff; 3170 // Applying the child's margin makes no sense in the case where the child was passed in. 3171 // since his own margin was added already through the subtraction of the |xoff| variable 3172 // above. |xoff| will equal -flow->marginLeft() in this case, so it's already been taken 3173 // into account. Only apply this code if |child| is false, since otherwise the left margin 3174 // will get applied twice. 3175 if (prev != parent()) 3176 floatingObj->m_left += prev->marginLeft(); 3177 floatingObj->m_left -= marginLeft(); 3178 floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it. 3179 floatingObj->m_width = r->m_width; 3180 floatingObj->m_renderer = r->m_renderer; 3181 3182 // We create the floating object list lazily. 3183 if (!m_floatingObjects) { 3184 m_floatingObjects = new DeprecatedPtrList<FloatingObject>; 3185 m_floatingObjects->setAutoDelete(true); 3186 } 3187 m_floatingObjects->append(floatingObj); 3188 } 3189 } 3190 } 3191 } 3192 3193 bool RenderBlock::avoidsFloats() const 3194 { 3195 // Floats can't intrude into our box if we have a non-auto column count or width. 3196 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); 3197 } 3198 3199 bool RenderBlock::containsFloat(RenderObject* o) 3200 { 3201 if (m_floatingObjects) { 3202 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 3203 while (it.current()) { 3204 if (it.current()->m_renderer == o) 3205 return true; 3206 ++it; 3207 } 3208 } 3209 return false; 3210 } 3211 3212 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) 3213 { 3214 setChildNeedsLayout(true, !inLayout); 3215 3216 if (floatToRemove) 3217 removeFloatingObject(floatToRemove); 3218 3219 // Iterate over our children and mark them as needed. 3220 if (!childrenInline()) { 3221 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 3222 if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock()) 3223 continue; 3224 RenderBlock* childBlock = toRenderBlock(child); 3225 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats()) 3226 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); 3227 } 3228 } 3229 } 3230 3231 int RenderBlock::getClearDelta(RenderBox* child, int yPos) 3232 { 3233 // There is no need to compute clearance if we have no floats. 3234 if (!containsFloats()) 3235 return 0; 3236 3237 // At least one float is present. We need to perform the clearance computation. 3238 bool clearSet = child->style()->clear() != CNONE; 3239 int bottom = 0; 3240 switch (child->style()->clear()) { 3241 case CNONE: 3242 break; 3243 case CLEFT: 3244 bottom = leftBottom(); 3245 break; 3246 case CRIGHT: 3247 bottom = rightBottom(); 3248 break; 3249 case CBOTH: 3250 bottom = floatBottom(); 3251 break; 3252 } 3253 3254 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default). 3255 int result = clearSet ? max(0, bottom - yPos) : 0; 3256 if (!result && child->avoidsFloats()) { 3257 int availableWidth = this->availableWidth(); 3258 if (child->minPrefWidth() > availableWidth) 3259 return 0; 3260 3261 int y = yPos; 3262 while (true) { 3263 int widthAtY = lineWidth(y, false); 3264 if (widthAtY == availableWidth) 3265 return y - yPos; 3266 3267 int oldChildY = child->y(); 3268 int oldChildWidth = child->width(); 3269 child->setY(y); 3270 child->calcWidth(); 3271 int childWidthAtY = child->width(); 3272 child->setY(oldChildY); 3273 child->setWidth(oldChildWidth); 3274 3275 if (childWidthAtY <= widthAtY) 3276 return y - yPos; 3277 3278 y = nextFloatBottomBelow(y); 3279 ASSERT(y >= yPos); 3280 if (y < yPos) 3281 break; 3282 } 3283 ASSERT_NOT_REACHED(); 3284 } 3285 return result; 3286 } 3287 3288 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty) 3289 { 3290 if (!scrollsOverflow()) 3291 return false; 3292 3293 return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty)); 3294 } 3295 3296 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) 3297 { 3298 int tx = _tx + x(); 3299 int ty = _ty + y(); 3300 3301 if (!isRenderView()) { 3302 // Check if we need to do anything at all. 3303 IntRect overflowBox = visibleOverflowRect(); 3304 overflowBox.move(tx, ty); 3305 if (!overflowBox.contains(_x, _y)) 3306 return false; 3307 } 3308 3309 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) { 3310 updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); 3311 return true; 3312 } 3313 3314 // If we have clipping, then we can't have any spillout. 3315 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); 3316 bool useClip = (hasControlClip() || useOverflowClip); 3317 bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).contains(_x, _y) : overflowClipRect(tx, ty).contains(_x, _y)); 3318 if (checkChildren) { 3319 // Hit test descendants first. 3320 int scrolledX = tx; 3321 int scrolledY = ty; 3322 if (hasOverflowClip()) 3323 layer()->subtractScrolledContentOffset(scrolledX, scrolledY); 3324 3325 // Hit test contents if we don't have columns. 3326 if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) 3327 return true; 3328 3329 // Hit test our columns if we do have them. 3330 if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) 3331 return true; 3332 3333 // Hit test floats. 3334 if (hitTestAction == HitTestFloat && m_floatingObjects) { 3335 if (isRenderView()) { 3336 scrolledX += toRenderView(this)->frameView()->scrollX(); 3337 scrolledY += toRenderView(this)->frameView()->scrollY(); 3338 } 3339 3340 FloatingObject* o; 3341 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 3342 for (it.toLast(); (o = it.current()); --it) { 3343 if (o->m_shouldPaint && !o->m_renderer->hasSelfPaintingLayer()) { 3344 int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->x(); 3345 int yoffset = scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->y(); 3346 if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) { 3347 updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset)); 3348 return true; 3349 } 3350 } 3351 } 3352 } 3353 } 3354 3355 // Now hit test our background 3356 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { 3357 IntRect boundsRect(tx, ty, width(), height()); 3358 if (visibleToHitTesting() && boundsRect.contains(_x, _y)) { 3359 updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); 3360 return true; 3361 } 3362 } 3363 3364 return false; 3365 } 3366 3367 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) 3368 { 3369 // We need to do multiple passes, breaking up our hit testing into strips. 3370 // We can always go left to right, since column contents are clipped (meaning that there 3371 // can't be any overlap). 3372 int currXOffset = 0; 3373 int currYOffset = 0; 3374 int colGap = columnGap(); 3375 Vector<IntRect>* colRects = columnRects(); 3376 for (unsigned i = 0; i < colRects->size(); i++) { 3377 IntRect colRect = colRects->at(i); 3378 colRect.move(tx, ty); 3379 3380 if (colRect.contains(x, y)) { 3381 // The point is inside this column. 3382 // Adjust tx and ty to change where we hit test. 3383 3384 int finalX = tx + currXOffset; 3385 int finalY = ty + currYOffset; 3386 return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction); 3387 } 3388 3389 // Move to the next position. 3390 if (style()->direction() == LTR) 3391 currXOffset += colRect.width() + colGap; 3392 else 3393 currXOffset -= (colRect.width() + colGap); 3394 3395 currYOffset -= colRect.height(); 3396 } 3397 3398 return false; 3399 } 3400 3401 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) 3402 { 3403 if (childrenInline() && !isTable()) { 3404 // We have to hit-test our line boxes. 3405 if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) { 3406 updateHitTestResult(result, IntPoint(x - tx, y - ty)); 3407 return true; 3408 } 3409 } else { 3410 // Hit test our children. 3411 HitTestAction childHitTest = hitTestAction; 3412 if (hitTestAction == HitTestChildBlockBackgrounds) 3413 childHitTest = HitTestChildBlockBackground; 3414 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { 3415 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) { 3416 updateHitTestResult(result, IntPoint(x - tx, y - ty)); 3417 return true; 3418 } 3419 } 3420 } 3421 3422 return false; 3423 } 3424 3425 Position RenderBlock::positionForBox(InlineBox *box, bool start) const 3426 { 3427 if (!box) 3428 return Position(); 3429 3430 if (!box->renderer()->node()) 3431 return Position(node(), start ? caretMinOffset() : caretMaxOffset()); 3432 3433 if (!box->isInlineTextBox()) 3434 return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); 3435 3436 InlineTextBox *textBox = static_cast<InlineTextBox *>(box); 3437 return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len()); 3438 } 3439 3440 Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const 3441 { 3442 if (!renderer) 3443 return Position(node(), 0); 3444 3445 Node* n = renderer->node() ? renderer->node() : node(); 3446 if (!n) 3447 return Position(); 3448 3449 ASSERT(renderer == n->renderer()); 3450 3451 int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset(); 3452 3453 // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now. 3454 ASSERT(!n->isCharacterDataNode() || renderer->isText()); 3455 3456 return Position(n, offset); 3457 } 3458 3459 // FIXME: This function should go on RenderObject as an instance method. Then 3460 // all cases in which positionForPoint recurs could call this instead to 3461 // prevent crossing editable boundaries. This would require many tests. 3462 static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& pointInParentCoordinates) 3463 { 3464 IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location()); 3465 3466 // If this is an anonymous renderer, we just recur normally 3467 Node* childNode = child->node(); 3468 if (!childNode) 3469 return child->positionForPoint(pointInChildCoordinates); 3470 3471 // Otherwise, first make sure that the editability of the parent and child agree. 3472 // If they don't agree, then we return a visible position just before or after the child 3473 RenderObject* ancestor = parent; 3474 while (ancestor && !ancestor->node()) 3475 ancestor = ancestor->parent(); 3476 3477 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal 3478 if (!ancestor || ancestor->node()->isContentEditable() == childNode->isContentEditable()) 3479 return child->positionForPoint(pointInChildCoordinates); 3480 3481 // Otherwise return before or after the child, depending on if the click was left or right of the child 3482 int childMidX = child->width() / 2; 3483 if (pointInChildCoordinates.x() < childMidX) 3484 return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM); 3485 return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM); 3486 } 3487 3488 VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInContents) 3489 { 3490 ASSERT(childrenInline()); 3491 3492 if (!firstRootBox()) 3493 return createVisiblePosition(0, DOWNSTREAM); 3494 3495 // look for the closest line box in the root box which is at the passed-in y coordinate 3496 InlineBox* closestBox = 0; 3497 RootInlineBox* firstRootBoxWithChildren = 0; 3498 RootInlineBox* lastRootBoxWithChildren = 0; 3499 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { 3500 if (!root->firstLeafChild()) 3501 continue; 3502 if (!firstRootBoxWithChildren) 3503 firstRootBoxWithChildren = root; 3504 lastRootBoxWithChildren = root; 3505 3506 // set the bottom based on whether there is a next root box 3507 // FIXME: This will consider nextRootBox even if it has no children, and maybe it shouldn't. 3508 int bottom; 3509 if (root->nextRootBox()) { 3510 // FIXME: We would prefer to make the break point halfway between the bottom 3511 // of the previous root box and the top of the next root box. 3512 bottom = root->nextRootBox()->lineTop(); 3513 } else 3514 bottom = root->lineBottom() + verticalLineClickFudgeFactor; 3515 3516 // check if this root line box is located at this y coordinate 3517 if (pointInContents.y() < bottom) { 3518 closestBox = root->closestLeafChildForXPos(pointInContents.x()); 3519 if (closestBox) 3520 break; 3521 } 3522 } 3523 3524 Settings* settings = document()->settings(); 3525 bool useWindowsBehavior = settings && settings->editingBehavior() == EditingWindowsBehavior; 3526 3527 if (useWindowsBehavior && !closestBox && lastRootBoxWithChildren) { 3528 // y coordinate is below last root line box, pretend we hit it 3529 closestBox = lastRootBoxWithChildren->closestLeafChildForXPos(pointInContents.x()); 3530 } 3531 3532 if (closestBox) { 3533 if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->lineTop() - verticalLineClickFudgeFactor) { 3534 // y coordinate is above first root line box, so return the start of the first 3535 return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM); 3536 } 3537 3538 // pass the box a y position that is inside it 3539 return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y)); 3540 } 3541 3542 if (lastRootBoxWithChildren) { 3543 // We hit this case for Mac behavior when the Y coordinate is below the last box. 3544 ASSERT(!useWindowsBehavior); 3545 return VisiblePosition(positionForBox(lastRootBoxWithChildren->lastLeafChild(), false), DOWNSTREAM); 3546 } 3547 3548 // Can't reach this. We have a root line box, but it has no kids. 3549 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text 3550 // seems to hit this code path. 3551 return createVisiblePosition(0, DOWNSTREAM); 3552 } 3553 3554 static inline bool isChildHitTestCandidate(RenderBox* box) 3555 { 3556 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned(); 3557 } 3558 3559 VisiblePosition RenderBlock::positionForPoint(const IntPoint& point) 3560 { 3561 if (isTable()) 3562 return RenderBox::positionForPoint(point); 3563 3564 if (isReplaced()) { 3565 if (point.y() < 0 || (point.y() < height() && point.x() < 0)) 3566 return createVisiblePosition(caretMinOffset(), DOWNSTREAM); 3567 if (point.y() >= height() || (point.y() >= 0 && point.x() >= width())) 3568 return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); 3569 } 3570 3571 int contentsX = point.x(); 3572 int contentsY = point.y(); 3573 offsetForContents(contentsX, contentsY); 3574 IntPoint pointInContents(contentsX, contentsY); 3575 3576 if (childrenInline()) 3577 return positionForPointWithInlineChildren(pointInContents); 3578 3579 if (lastChildBox() && contentsY > lastChildBox()->y()) { 3580 for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) { 3581 if (isChildHitTestCandidate(childBox)) 3582 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); 3583 } 3584 } else { 3585 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { 3586 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3). 3587 if (isChildHitTestCandidate(childBox) && contentsY < childBox->frameRect().bottom()) 3588 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); 3589 } 3590 } 3591 3592 // We only get here if there are no hit test candidate children below the click. 3593 return RenderBox::positionForPoint(point); 3594 } 3595 3596 void RenderBlock::offsetForContents(int& tx, int& ty) const 3597 { 3598 if (hasOverflowClip()) 3599 layer()->addScrolledContentOffset(tx, ty); 3600 3601 if (hasColumns()) { 3602 IntPoint contentsPoint(tx, ty); 3603 adjustPointToColumnContents(contentsPoint); 3604 tx = contentsPoint.x(); 3605 ty = contentsPoint.y(); 3606 } 3607 } 3608 3609 int RenderBlock::availableWidth() const 3610 { 3611 // If we have multiple columns, then the available width is reduced to our column width. 3612 if (hasColumns()) 3613 return desiredColumnWidth(); 3614 return contentWidth(); 3615 } 3616 3617 int RenderBlock::columnGap() const 3618 { 3619 if (style()->hasNormalColumnGap()) 3620 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins. 3621 return static_cast<int>(style()->columnGap()); 3622 } 3623 3624 void RenderBlock::calcColumnWidth() 3625 { 3626 // Calculate our column width and column count. 3627 unsigned desiredColumnCount = 1; 3628 int desiredColumnWidth = contentWidth(); 3629 3630 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination. 3631 if (document()->printing() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) { 3632 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 3633 return; 3634 } 3635 3636 int availWidth = desiredColumnWidth; 3637 int colGap = columnGap(); 3638 int colWidth = max(1, static_cast<int>(style()->columnWidth())); 3639 int colCount = max(1, static_cast<int>(style()->columnCount())); 3640 3641 if (style()->hasAutoColumnWidth()) { 3642 if ((colCount - 1) * colGap < availWidth) { 3643 desiredColumnCount = colCount; 3644 desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; 3645 } else if (colGap < availWidth) { 3646 desiredColumnCount = availWidth / colGap; 3647 if (desiredColumnCount < 1) 3648 desiredColumnCount = 1; 3649 desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; 3650 } 3651 } else if (style()->hasAutoColumnCount()) { 3652 if (colWidth < availWidth) { 3653 desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); 3654 if (desiredColumnCount < 1) 3655 desiredColumnCount = 1; 3656 desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; 3657 } 3658 } else { 3659 // Both are set. 3660 if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) { 3661 desiredColumnCount = colCount; 3662 desiredColumnWidth = colWidth; 3663 } else if (colWidth < availWidth) { 3664 desiredColumnCount = (availWidth + colGap) / (colWidth + colGap); 3665 if (desiredColumnCount < 1) 3666 desiredColumnCount = 1; 3667 desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount; 3668 } 3669 } 3670 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 3671 } 3672 3673 void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) 3674 { 3675 if (count == 1 && style()->hasAutoColumnWidth()) { 3676 if (hasColumns()) { 3677 delete gColumnInfoMap->take(this); 3678 setHasColumns(false); 3679 } 3680 } else { 3681 ColumnInfo* info; 3682 if (hasColumns()) 3683 info = gColumnInfoMap->get(this); 3684 else { 3685 if (!gColumnInfoMap) 3686 gColumnInfoMap = new ColumnInfoMap; 3687 info = new ColumnInfo; 3688 gColumnInfoMap->add(this, info); 3689 setHasColumns(true); 3690 } 3691 info->m_desiredColumnCount = count; 3692 info->m_desiredColumnWidth = width; 3693 } 3694 } 3695 3696 int RenderBlock::desiredColumnWidth() const 3697 { 3698 if (!hasColumns()) 3699 return contentWidth(); 3700 return gColumnInfoMap->get(this)->m_desiredColumnWidth; 3701 } 3702 3703 unsigned RenderBlock::desiredColumnCount() const 3704 { 3705 if (!hasColumns()) 3706 return 1; 3707 return gColumnInfoMap->get(this)->m_desiredColumnCount; 3708 } 3709 3710 Vector<IntRect>* RenderBlock::columnRects() const 3711 { 3712 if (!hasColumns()) 3713 return 0; 3714 return &gColumnInfoMap->get(this)->m_columnRects; 3715 } 3716 3717 int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight) 3718 { 3719 // Don't do anything if we have no columns 3720 if (!hasColumns()) 3721 return -1; 3722 3723 ColumnInfo* info = gColumnInfoMap->get(this); 3724 int desiredColumnWidth = info->m_desiredColumnWidth; 3725 int desiredColumnCount = info->m_desiredColumnCount; 3726 Vector<IntRect>* columnRects = &info->m_columnRects; 3727 3728 bool computeIntrinsicHeight = (endOfContent == -1); 3729 3730 // Fill the columns in to the available height. Attempt to balance the height of the columns. 3731 // Add in half our line-height to help with best-guess initial balancing. 3732 int columnSlop = lineHeight(false) / 2; 3733 int remainingSlopSpace = columnSlop * desiredColumnCount; 3734 int availableHeight = contentHeight(); 3735 int colHeight; 3736 if (computeIntrinsicHeight && requestedColumnHeight >= 0) 3737 colHeight = requestedColumnHeight; 3738 else if (computeIntrinsicHeight) 3739 colHeight = availableHeight / desiredColumnCount + columnSlop; 3740 else 3741 colHeight = availableHeight; 3742 int originalColHeight = colHeight; 3743 3744 int colGap = columnGap(); 3745 3746 // Compute a collection of column rects. 3747 columnRects->clear(); 3748 3749 // Then we do a simulated "paint" into the column slices and allow the content to slightly adjust our individual column rects. 3750 // FIXME: We need to take into account layers that are affected by the columns as well here so that they can have an opportunity 3751 // to adjust column rects also. 3752 RenderView* v = view(); 3753 int left = borderLeft() + paddingLeft(); 3754 int top = borderTop() + paddingTop(); 3755 int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - desiredColumnWidth; 3756 int currY = top; 3757 unsigned colCount = desiredColumnCount; 3758 int maxColBottom = borderTop() + paddingTop(); 3759 int contentBottom = top + availableHeight; 3760 int minimumColumnHeight = -1; 3761 for (unsigned i = 0; i < colCount; i++) { 3762 // If we aren't constrained, then the last column can just get all the remaining space. 3763 if (computeIntrinsicHeight && i == colCount - 1) 3764 colHeight = availableHeight; 3765 3766 // This represents the real column position. 3767 IntRect colRect(currX, top, desiredColumnWidth, colHeight); 3768 3769 // For the simulated paint, we pretend like everything is in one long strip. 3770 IntRect pageRect(left, currY, desiredColumnWidth, colHeight); 3771 v->setPrintRect(pageRect); 3772 v->setTruncatedAt(currY + colHeight); 3773 GraphicsContext context((PlatformGraphicsContext*)0); 3774 RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0); 3775 3776 setHasColumns(false); 3777 paintObject(paintInfo, 0, 0); 3778 setHasColumns(true); 3779 3780 if (computeIntrinsicHeight && v->minimumColumnHeight() > originalColHeight) { 3781 // The initial column height was too small to contain one line of text. 3782 minimumColumnHeight = max(minimumColumnHeight, v->minimumColumnHeight()); 3783 } 3784 3785 int adjustedBottom = v->bestTruncatedAt(); 3786 if (adjustedBottom <= currY) 3787 adjustedBottom = currY + colHeight; 3788 3789 colRect.setHeight(adjustedBottom - currY); 3790 3791 // Add in the lost space to the subsequent columns. 3792 // FIXME: This will create a "staircase" effect if there are enough columns, but the effect should be pretty subtle. 3793 if (computeIntrinsicHeight) { 3794 int lostSpace = colHeight - colRect.height(); 3795 if (lostSpace > remainingSlopSpace) { 3796 // Redestribute the space among the remaining columns. 3797 int spaceToRedistribute = lostSpace - remainingSlopSpace; 3798 int remainingColumns = colCount - i + 1; 3799 colHeight += spaceToRedistribute / remainingColumns; 3800 } 3801 remainingSlopSpace = max(0, remainingSlopSpace - lostSpace); 3802 } 3803 3804 if (style()->direction() == LTR) 3805 currX += desiredColumnWidth + colGap; 3806 else 3807 currX -= (desiredColumnWidth + colGap); 3808 3809 currY += colRect.height(); 3810 availableHeight -= colRect.height(); 3811 3812 maxColBottom = max(colRect.bottom(), maxColBottom); 3813 3814 columnRects->append(colRect); 3815 3816 // Start adding in more columns as long as there's still content left. 3817 if (currY < endOfContent && i == colCount - 1 && (computeIntrinsicHeight || contentHeight())) 3818 colCount++; 3819 } 3820 3821 if (minimumColumnHeight >= 0) { 3822 // If originalColHeight was too small, we need to try to layout again. 3823 return layoutColumns(endOfContent, minimumColumnHeight); 3824 } 3825 3826 int overflowRight = max(width(), currX - colGap); 3827 int overflowLeft = min(0, currX + desiredColumnWidth + colGap); 3828 int overflowHeight = maxColBottom; 3829 int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight(); 3830 3831 if (computeIntrinsicHeight) 3832 setHeight(maxColBottom + toAdd); 3833 3834 m_overflow.clear(); 3835 addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight)); 3836 3837 v->setPrintRect(IntRect()); 3838 v->setTruncatedAt(0); 3839 3840 ASSERT(colCount == columnRects->size()); 3841 3842 return contentBottom; 3843 } 3844 3845 void RenderBlock::adjustPointToColumnContents(IntPoint& point) const 3846 { 3847 // Just bail if we have no columns. 3848 if (!hasColumns()) 3849 return; 3850 3851 Vector<IntRect>* colRects = columnRects(); 3852 3853 // Determine which columns we intersect. 3854 int colGap = columnGap(); 3855 int leftGap = colGap / 2; 3856 IntPoint columnPoint(colRects->at(0).location()); 3857 int yOffset = 0; 3858 for (unsigned i = 0; i < colRects->size(); i++) { 3859 // Add in half the column gap to the left and right of the rect. 3860 IntRect colRect = colRects->at(i); 3861 IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height()); 3862 3863 if (gapAndColumnRect.contains(point)) { 3864 // We're inside the column. Translate the x and y into our column coordinate space. 3865 point.move(columnPoint.x() - colRect.x(), yOffset); 3866 return; 3867 } 3868 3869 // Move to the next position. 3870 yOffset += colRect.height(); 3871 } 3872 } 3873 3874 void RenderBlock::adjustRectForColumns(IntRect& r) const 3875 { 3876 // Just bail if we have no columns. 3877 if (!hasColumns()) 3878 return; 3879 3880 Vector<IntRect>* colRects = columnRects(); 3881 3882 // Begin with a result rect that is empty. 3883 IntRect result; 3884 3885 // Determine which columns we intersect. 3886 int currXOffset = 0; 3887 int currYOffset = 0; 3888 int colGap = columnGap(); 3889 for (unsigned i = 0; i < colRects->size(); i++) { 3890 IntRect colRect = colRects->at(i); 3891 3892 IntRect repaintRect = r; 3893 repaintRect.move(currXOffset, currYOffset); 3894 3895 repaintRect.intersect(colRect); 3896 3897 result.unite(repaintRect); 3898 3899 // Move to the next position. 3900 if (style()->direction() == LTR) 3901 currXOffset += colRect.width() + colGap; 3902 else 3903 currXOffset -= (colRect.width() + colGap); 3904 3905 currYOffset -= colRect.height(); 3906 } 3907 3908 r = result; 3909 } 3910 3911 void RenderBlock::calcPrefWidths() 3912 { 3913 ASSERT(prefWidthsDirty()); 3914 3915 updateFirstLetter(); 3916 3917 if (!isTableCell() && style()->width().isFixed() && style()->width().value() > 0) 3918 m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value()); 3919 else { 3920 m_minPrefWidth = 0; 3921 m_maxPrefWidth = 0; 3922 3923 if (childrenInline()) 3924 calcInlinePrefWidths(); 3925 else 3926 calcBlockPrefWidths(); 3927 3928 m_maxPrefWidth = max(m_minPrefWidth, m_maxPrefWidth); 3929 3930 if (!style()->autoWrap() && childrenInline()) { 3931 m_minPrefWidth = m_maxPrefWidth; 3932 3933 // A horizontal marquee with inline children has no minimum width. 3934 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal()) 3935 m_minPrefWidth = 0; 3936 } 3937 3938 if (isTableCell()) { 3939 Length w = toRenderTableCell(this)->styleOrColWidth(); 3940 if (w.isFixed() && w.value() > 0) 3941 m_maxPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(w.value())); 3942 } 3943 } 3944 3945 if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) { 3946 m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value())); 3947 m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value())); 3948 } 3949 3950 if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) { 3951 m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); 3952 m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value())); 3953 } 3954 3955 int toAdd = 0; 3956 toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight(); 3957 3958 if (hasOverflowClip() && style()->overflowY() == OSCROLL) 3959 toAdd += verticalScrollbarWidth(); 3960 3961 m_minPrefWidth += toAdd; 3962 m_maxPrefWidth += toAdd; 3963 3964 setPrefWidthsDirty(false); 3965 } 3966 3967 struct InlineMinMaxIterator { 3968 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to 3969 inline min/max width calculations. Note the following about the way it walks: 3970 (1) Positioned content is skipped (since it does not contribute to min/max width of a block) 3971 (2) We do not drill into the children of floats or replaced elements, since you can't break 3972 in the middle of such an element. 3973 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have 3974 distinct borders/margin/padding that contribute to the min/max width. 3975 */ 3976 RenderObject* parent; 3977 RenderObject* current; 3978 bool endOfInline; 3979 3980 InlineMinMaxIterator(RenderObject* p, bool end = false) 3981 :parent(p), current(p), endOfInline(end) {} 3982 3983 RenderObject* next(); 3984 }; 3985 3986 RenderObject* InlineMinMaxIterator::next() 3987 { 3988 RenderObject* result = 0; 3989 bool oldEndOfInline = endOfInline; 3990 endOfInline = false; 3991 while (current || current == parent) { 3992 if (!oldEndOfInline && 3993 (current == parent || 3994 (!current->isFloating() && !current->isReplaced() && !current->isPositioned()))) 3995 result = current->firstChild(); 3996 if (!result) { 3997 // We hit the end of our inline. (It was empty, e.g., <span></span>.) 3998 if (!oldEndOfInline && current->isRenderInline()) { 3999 result = current; 4000 endOfInline = true; 4001 break; 4002 } 4003 4004 while (current && current != parent) { 4005 result = current->nextSibling(); 4006 if (result) break; 4007 current = current->parent(); 4008 if (current && current != parent && current->isRenderInline()) { 4009 result = current; 4010 endOfInline = true; 4011 break; 4012 } 4013 } 4014 } 4015 4016 if (!result) 4017 break; 4018 4019 if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) 4020 break; 4021 4022 current = result; 4023 result = 0; 4024 } 4025 4026 // Update our position. 4027 current = result; 4028 return current; 4029 } 4030 4031 static int getBPMWidth(int childValue, Length cssUnit) 4032 { 4033 if (cssUnit.type() != Auto) 4034 return (cssUnit.isFixed() ? cssUnit.value() : childValue); 4035 return 0; 4036 } 4037 4038 static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) 4039 { 4040 RenderStyle* cstyle = child->style(); 4041 int result = 0; 4042 bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline; 4043 result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()), 4044 (leftSide ? cstyle->marginLeft() : 4045 cstyle->marginRight())); 4046 result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()), 4047 (leftSide ? cstyle->paddingLeft() : 4048 cstyle->paddingRight())); 4049 result += leftSide ? child->borderLeft() : child->borderRight(); 4050 return result; 4051 } 4052 4053 static inline void stripTrailingSpace(int& inlineMax, int& inlineMin, 4054 RenderObject* trailingSpaceChild) 4055 { 4056 if (trailingSpaceChild && trailingSpaceChild->isText()) { 4057 // Collapse away the trailing space at the end of a block. 4058 RenderText* t = toRenderText(trailingSpaceChild); 4059 const UChar space = ' '; 4060 const Font& font = t->style()->font(); // FIXME: This ignores first-line. 4061 int spaceWidth = font.width(TextRun(&space, 1)); 4062 inlineMax -= spaceWidth + font.wordSpacing(); 4063 if (inlineMin > inlineMax) 4064 inlineMin = inlineMax; 4065 } 4066 } 4067 4068 void RenderBlock::calcInlinePrefWidths() 4069 { 4070 int inlineMax = 0; 4071 int inlineMin = 0; 4072 4073 int cw = containingBlock()->contentWidth(); 4074 4075 // If we are at the start of a line, we want to ignore all white-space. 4076 // Also strip spaces if we previously had text that ended in a trailing space. 4077 bool stripFrontSpaces = true; 4078 RenderObject* trailingSpaceChild = 0; 4079 4080 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 4081 // very specific cirucumstances (in order to match common WinIE renderings). 4082 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 4083 bool allowImagesToBreak = !style()->htmlHacks() || !isTableCell() || !style()->width().isIntrinsicOrAuto(); 4084 4085 bool autoWrap, oldAutoWrap; 4086 autoWrap = oldAutoWrap = style()->autoWrap(); 4087 4088 InlineMinMaxIterator childIterator(this); 4089 bool addedTextIndent = false; // Only gets added in once. 4090 RenderObject* prevFloat = 0; 4091 RenderObject* previousLeaf = 0; 4092 while (RenderObject* child = childIterator.next()) { 4093 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : 4094 child->style()->autoWrap(); 4095 4096 if (!child->isBR()) { 4097 // Step One: determine whether or not we need to go ahead and 4098 // terminate our current line. Each discrete chunk can become 4099 // the new min-width, if it is the widest chunk seen so far, and 4100 // it can also become the max-width. 4101 4102 // Children fall into three categories: 4103 // (1) An inline flow object. These objects always have a min/max of 0, 4104 // and are included in the iteration solely so that their margins can 4105 // be added in. 4106 // 4107 // (2) An inline non-text non-flow object, e.g., an inline replaced element. 4108 // These objects can always be on a line by themselves, so in this situation 4109 // we need to go ahead and break the current line, and then add in our own 4110 // margins and min/max width on its own line, and then terminate the line. 4111 // 4112 // (3) A text object. Text runs can have breakable characters at the start, 4113 // the middle or the end. They may also lose whitespace off the front if 4114 // we're already ignoring whitespace. In order to compute accurate min-width 4115 // information, we need three pieces of information. 4116 // (a) the min-width of the first non-breakable run. Should be 0 if the text string 4117 // starts with whitespace. 4118 // (b) the min-width of the last non-breakable run. Should be 0 if the text string 4119 // ends with whitespace. 4120 // (c) the min/max width of the string (trimmed for whitespace). 4121 // 4122 // If the text string starts with whitespace, then we need to go ahead and 4123 // terminate our current line (unless we're already in a whitespace stripping 4124 // mode. 4125 // 4126 // If the text string has a breakable character in the middle, but didn't start 4127 // with whitespace, then we add the width of the first non-breakable run and 4128 // then end the current line. We then need to use the intermediate min/max width 4129 // values (if any of them are larger than our current min/max). We then look at 4130 // the width of the last non-breakable run and use that to start a new line 4131 // (unless we end in whitespace). 4132 RenderStyle* cstyle = child->style(); 4133 int childMin = 0; 4134 int childMax = 0; 4135 4136 if (!child->isText()) { 4137 // Case (1) and (2). Inline replaced and inline flow elements. 4138 if (child->isRenderInline()) { 4139 // Add in padding/border/margin from the appropriate side of 4140 // the element. 4141 int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); 4142 childMin += bpm; 4143 childMax += bpm; 4144 4145 inlineMin += childMin; 4146 inlineMax += childMax; 4147 4148 child->setPrefWidthsDirty(false); 4149 } else { 4150 // Inline replaced elts add in their margins to their min/max values. 4151 int margins = 0; 4152 Length leftMargin = cstyle->marginLeft(); 4153 Length rightMargin = cstyle->marginRight(); 4154 if (leftMargin.isFixed()) 4155 margins += leftMargin.value(); 4156 if (rightMargin.isFixed()) 4157 margins += rightMargin.value(); 4158 childMin += margins; 4159 childMax += margins; 4160 } 4161 } 4162 4163 if (!child->isRenderInline() && !child->isText()) { 4164 // Case (2). Inline replaced elements and floats. 4165 // Go ahead and terminate the current line as far as 4166 // minwidth is concerned. 4167 childMin += child->minPrefWidth(); 4168 childMax += child->maxPrefWidth(); 4169 4170 bool clearPreviousFloat; 4171 if (child->isFloating()) { 4172 clearPreviousFloat = (prevFloat 4173 && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT)) 4174 || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT)))); 4175 prevFloat = child; 4176 } else 4177 clearPreviousFloat = false; 4178 4179 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; 4180 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) { 4181 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4182 inlineMin = 0; 4183 } 4184 4185 // If we're supposed to clear the previous float, then terminate maxwidth as well. 4186 if (clearPreviousFloat) { 4187 m_maxPrefWidth = max(inlineMax, m_maxPrefWidth); 4188 inlineMax = 0; 4189 } 4190 4191 // Add in text-indent. This is added in only once. 4192 int ti = 0; 4193 if (!addedTextIndent) { 4194 addedTextIndent = true; 4195 ti = style()->textIndent().calcMinValue(cw); 4196 childMin+=ti; 4197 childMax+=ti; 4198 } 4199 4200 // Add our width to the max. 4201 inlineMax += childMax; 4202 4203 if (!autoWrap || !canBreakReplacedElement) { 4204 if (child->isFloating()) 4205 m_minPrefWidth = max(childMin, m_minPrefWidth); 4206 else 4207 inlineMin += childMin; 4208 } else { 4209 // Now check our line. 4210 m_minPrefWidth = max(childMin, m_minPrefWidth); 4211 4212 // Now start a new line. 4213 inlineMin = 0; 4214 } 4215 4216 // We are no longer stripping whitespace at the start of 4217 // a line. 4218 if (!child->isFloating()) { 4219 stripFrontSpaces = false; 4220 trailingSpaceChild = 0; 4221 } 4222 } else if (child->isText()) { 4223 // Case (3). Text. 4224 RenderText* t = toRenderText(child); 4225 4226 if (t->isWordBreak()) { 4227 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4228 inlineMin = 0; 4229 continue; 4230 } 4231 4232 // Determine if we have a breakable character. Pass in 4233 // whether or not we should ignore any spaces at the front 4234 // of the string. If those are going to be stripped out, 4235 // then they shouldn't be considered in the breakable char 4236 // check. 4237 bool hasBreakableChar, hasBreak; 4238 int beginMin, endMin; 4239 bool beginWS, endWS; 4240 int beginMax, endMax; 4241 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS, 4242 hasBreakableChar, hasBreak, beginMax, endMax, 4243 childMin, childMax, stripFrontSpaces); 4244 4245 // This text object will not be rendered, but it may still provide a breaking opportunity. 4246 if (!hasBreak && childMax == 0) { 4247 if (autoWrap && (beginWS || endWS)) { 4248 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4249 inlineMin = 0; 4250 } 4251 continue; 4252 } 4253 4254 if (stripFrontSpaces) 4255 trailingSpaceChild = child; 4256 else 4257 trailingSpaceChild = 0; 4258 4259 // Add in text-indent. This is added in only once. 4260 int ti = 0; 4261 if (!addedTextIndent) { 4262 addedTextIndent = true; 4263 ti = style()->textIndent().calcMinValue(cw); 4264 childMin+=ti; beginMin += ti; 4265 childMax+=ti; beginMax += ti; 4266 } 4267 4268 // If we have no breakable characters at all, 4269 // then this is the easy case. We add ourselves to the current 4270 // min and max and continue. 4271 if (!hasBreakableChar) { 4272 inlineMin += childMin; 4273 } else { 4274 // We have a breakable character. Now we need to know if 4275 // we start and end with whitespace. 4276 if (beginWS) 4277 // Go ahead and end the current line. 4278 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4279 else { 4280 inlineMin += beginMin; 4281 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4282 childMin -= ti; 4283 } 4284 4285 inlineMin = childMin; 4286 4287 if (endWS) { 4288 // We end in whitespace, which means we can go ahead 4289 // and end our current line. 4290 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4291 inlineMin = 0; 4292 } else { 4293 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4294 inlineMin = endMin; 4295 } 4296 } 4297 4298 if (hasBreak) { 4299 inlineMax += beginMax; 4300 m_maxPrefWidth = max(inlineMax, m_maxPrefWidth); 4301 m_maxPrefWidth = max(childMax, m_maxPrefWidth); 4302 inlineMax = endMax; 4303 } else 4304 inlineMax += childMax; 4305 } 4306 4307 // Ignore spaces after a list marker. 4308 if (child->isListMarker()) 4309 stripFrontSpaces = true; 4310 } else { 4311 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4312 m_maxPrefWidth = max(inlineMax, m_maxPrefWidth); 4313 inlineMin = inlineMax = 0; 4314 stripFrontSpaces = true; 4315 trailingSpaceChild = 0; 4316 } 4317 4318 oldAutoWrap = autoWrap; 4319 if (!child->isRenderInline()) 4320 previousLeaf = child; 4321 } 4322 4323 if (style()->collapseWhiteSpace()) 4324 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); 4325 4326 m_minPrefWidth = max(inlineMin, m_minPrefWidth); 4327 m_maxPrefWidth = max(inlineMax, m_maxPrefWidth); 4328 } 4329 4330 // Use a very large value (in effect infinite). 4331 #define BLOCK_MAX_WIDTH 15000 4332 4333 void RenderBlock::calcBlockPrefWidths() 4334 { 4335 bool nowrap = style()->whiteSpace() == NOWRAP; 4336 4337 RenderObject *child = firstChild(); 4338 int floatLeftWidth = 0, floatRightWidth = 0; 4339 while (child) { 4340 // Positioned children don't affect the min/max width 4341 if (child->isPositioned()) { 4342 child = child->nextSibling(); 4343 continue; 4344 } 4345 4346 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) { 4347 int floatTotalWidth = floatLeftWidth + floatRightWidth; 4348 if (child->style()->clear() & CLEFT) { 4349 m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth); 4350 floatLeftWidth = 0; 4351 } 4352 if (child->style()->clear() & CRIGHT) { 4353 m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth); 4354 floatRightWidth = 0; 4355 } 4356 } 4357 4358 // A margin basically has three types: fixed, percentage, and auto (variable). 4359 // Auto and percentage margins simply become 0 when computing min/max width. 4360 // Fixed margins can be added in as is. 4361 Length ml = child->style()->marginLeft(); 4362 Length mr = child->style()->marginRight(); 4363 int margin = 0, marginLeft = 0, marginRight = 0; 4364 if (ml.isFixed()) 4365 marginLeft += ml.value(); 4366 if (mr.isFixed()) 4367 marginRight += mr.value(); 4368 margin = marginLeft + marginRight; 4369 4370 int w = child->minPrefWidth() + margin; 4371 m_minPrefWidth = max(w, m_minPrefWidth); 4372 4373 // IE ignores tables for calculation of nowrap. Makes some sense. 4374 if (nowrap && !child->isTable()) 4375 m_maxPrefWidth = max(w, m_maxPrefWidth); 4376 4377 w = child->maxPrefWidth() + margin; 4378 4379 if (!child->isFloating()) { 4380 if (child->isBox() && toRenderBox(child)->avoidsFloats()) { 4381 // Determine a left and right max value based off whether or not the floats can fit in the 4382 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin 4383 // is smaller than the float width. 4384 int maxLeft = marginLeft > 0 ? max(floatLeftWidth, marginLeft) : floatLeftWidth + marginLeft; 4385 int maxRight = marginRight > 0 ? max(floatRightWidth, marginRight) : floatRightWidth + marginRight; 4386 w = child->maxPrefWidth() + maxLeft + maxRight; 4387 w = max(w, floatLeftWidth + floatRightWidth); 4388 } 4389 else 4390 m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth); 4391 floatLeftWidth = floatRightWidth = 0; 4392 } 4393 4394 if (child->isFloating()) { 4395 if (style()->floating() == FLEFT) 4396 floatLeftWidth += w; 4397 else 4398 floatRightWidth += w; 4399 } else 4400 m_maxPrefWidth = max(w, m_maxPrefWidth); 4401 4402 // A very specific WinIE quirk. 4403 // Example: 4404 /* 4405 <div style="position:absolute; width:100px; top:50px;"> 4406 <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green"> 4407 <table style="width:100%"><tr><td></table> 4408 </div> 4409 </div> 4410 */ 4411 // In the above example, the inner absolute positioned block should have a computed width 4412 // of 100px because of the table. 4413 // We can achieve this effect by making the maxwidth of blocks that contain tables 4414 // with percentage widths be infinite (as long as they are not inside a table cell). 4415 if (style()->htmlHacks() && child->style()->width().isPercent() && 4416 !isTableCell() && child->isTable() && m_maxPrefWidth < BLOCK_MAX_WIDTH) { 4417 RenderBlock* cb = containingBlock(); 4418 while (!cb->isRenderView() && !cb->isTableCell()) 4419 cb = cb->containingBlock(); 4420 if (!cb->isTableCell()) 4421 m_maxPrefWidth = BLOCK_MAX_WIDTH; 4422 } 4423 4424 child = child->nextSibling(); 4425 } 4426 4427 // Always make sure these values are non-negative. 4428 m_minPrefWidth = max(0, m_minPrefWidth); 4429 m_maxPrefWidth = max(0, m_maxPrefWidth); 4430 4431 m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth); 4432 } 4433 4434 bool RenderBlock::hasLineIfEmpty() const 4435 { 4436 if (!node()) 4437 return false; 4438 4439 if (node()->isContentEditable() && node()->rootEditableElement() == node()) 4440 return true; 4441 4442 if (node()->isShadowNode() && (node()->shadowParentNode()->hasTagName(inputTag) || node()->shadowParentNode()->hasTagName(textareaTag))) 4443 return true; 4444 4445 return false; 4446 } 4447 4448 int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const 4449 { 4450 // Inline blocks are replaced elements. Otherwise, just pass off to 4451 // the base class. If we're being queried as though we're the root line 4452 // box, then the fact that we're an inline-block is irrelevant, and we behave 4453 // just like a block. 4454 if (isReplaced() && !isRootLineBox) 4455 return height() + marginTop() + marginBottom(); 4456 4457 if (firstLine && document()->usesFirstLineRules()) { 4458 RenderStyle* s = style(firstLine); 4459 if (s != style()) 4460 return s->computedLineHeight(); 4461 } 4462 4463 if (m_lineHeight == -1) 4464 m_lineHeight = style()->computedLineHeight(); 4465 4466 return m_lineHeight; 4467 } 4468 4469 int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const 4470 { 4471 // Inline blocks are replaced elements. Otherwise, just pass off to 4472 // the base class. If we're being queried as though we're the root line 4473 // box, then the fact that we're an inline-block is irrelevant, and we behave 4474 // just like a block. 4475 if (isReplaced() && !isRootLineBox) { 4476 // For "leaf" theme objects, let the theme decide what the baseline position is. 4477 // FIXME: Might be better to have a custom CSS property instead, so that if the theme 4478 // is turned off, checkboxes/radios will still have decent baselines. 4479 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance())) 4480 return theme()->baselinePosition(this); 4481 4482 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in 4483 // the normal flow. We make an exception for marquees, since their baselines are meaningless 4484 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them. 4485 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled 4486 // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside 4487 // of our content box. 4488 int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline(); 4489 if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight()) 4490 return marginTop() + baselinePos; 4491 return height() + marginTop() + marginBottom(); 4492 } 4493 return RenderBox::baselinePosition(b, isRootLineBox); 4494 } 4495 4496 int RenderBlock::firstLineBoxBaseline() const 4497 { 4498 if (!isBlockFlow()) 4499 return -1; 4500 4501 if (childrenInline()) { 4502 if (firstLineBox()) 4503 return firstLineBox()->y() + style(true)->font().ascent(); 4504 else 4505 return -1; 4506 } 4507 else { 4508 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { 4509 if (!curr->isFloatingOrPositioned()) { 4510 int result = curr->firstLineBoxBaseline(); 4511 if (result != -1) 4512 return curr->y() + result; // Translate to our coordinate space. 4513 } 4514 } 4515 } 4516 4517 return -1; 4518 } 4519 4520 int RenderBlock::lastLineBoxBaseline() const 4521 { 4522 if (!isBlockFlow()) 4523 return -1; 4524 4525 if (childrenInline()) { 4526 if (!firstLineBox() && hasLineIfEmpty()) 4527 return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); 4528 if (lastLineBox()) 4529 return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent(); 4530 return -1; 4531 } 4532 else { 4533 bool haveNormalFlowChild = false; 4534 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { 4535 if (!curr->isFloatingOrPositioned()) { 4536 haveNormalFlowChild = true; 4537 int result = curr->lastLineBoxBaseline(); 4538 if (result != -1) 4539 return curr->y() + result; // Translate to our coordinate space. 4540 } 4541 } 4542 if (!haveNormalFlowChild && hasLineIfEmpty()) 4543 return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop(); 4544 } 4545 4546 return -1; 4547 } 4548 4549 bool RenderBlock::containsNonZeroBidiLevel() const 4550 { 4551 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { 4552 for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) { 4553 if (box->bidiLevel()) 4554 return true; 4555 } 4556 } 4557 return false; 4558 } 4559 4560 RenderBlock* RenderBlock::firstLineBlock() const 4561 { 4562 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); 4563 bool hasPseudo = false; 4564 while (true) { 4565 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE); 4566 if (hasPseudo) 4567 break; 4568 RenderObject* parentBlock = firstLineBlock->parent(); 4569 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() || 4570 !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()) 4571 break; 4572 ASSERT(parentBlock->isRenderBlock()); 4573 firstLineBlock = toRenderBlock(parentBlock); 4574 } 4575 4576 if (!hasPseudo) 4577 return 0; 4578 4579 return firstLineBlock; 4580 } 4581 4582 void RenderBlock::updateFirstLetter() 4583 { 4584 if (!document()->usesFirstLetterRules()) 4585 return; 4586 // Don't recur 4587 if (style()->styleType() == FIRST_LETTER) 4588 return; 4589 4590 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find 4591 // an efficient way to check for that situation though before implementing anything. 4592 RenderObject* firstLetterBlock = this; 4593 bool hasPseudoStyle = false; 4594 while (true) { 4595 // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly 4596 // prevents form controls from honoring first-letter. 4597 hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER) 4598 && firstLetterBlock->canHaveChildren(); 4599 if (hasPseudoStyle) 4600 break; 4601 RenderObject* parentBlock = firstLetterBlock->parent(); 4602 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock || 4603 !parentBlock->isBlockFlow()) 4604 break; 4605 firstLetterBlock = parentBlock; 4606 } 4607 4608 if (!hasPseudoStyle) 4609 return; 4610 4611 // Drill into inlines looking for our first text child. 4612 RenderObject* currChild = firstLetterBlock->firstChild(); 4613 while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) { 4614 if (currChild->isFloatingOrPositioned()) { 4615 if (currChild->style()->styleType() == FIRST_LETTER) 4616 break; 4617 currChild = currChild->nextSibling(); 4618 } else 4619 currChild = currChild->firstChild(); 4620 } 4621 4622 // Get list markers out of the way. 4623 while (currChild && currChild->isListMarker()) 4624 currChild = currChild->nextSibling(); 4625 4626 if (!currChild) 4627 return; 4628 4629 RenderObject* firstLetterContainer = currChild->parent(); 4630 4631 // If the child already has style, then it has already been created, so we just want 4632 // to update it. 4633 if (currChild->style()->styleType() == FIRST_LETTER) { 4634 RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, 4635 firstLetterContainer->firstLineStyle()); 4636 currChild->setStyle(pseudo); 4637 for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) { 4638 if (genChild->isText()) 4639 genChild->setStyle(pseudo); 4640 } 4641 return; 4642 } 4643 4644 // If the child does not already have style, we create it here. 4645 if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) { 4646 // Our layout state is not valid for the repaints we are going to trigger by 4647 // adding and removing children of firstLetterContainer. 4648 view()->disableLayoutState(); 4649 4650 RenderText* textObj = toRenderText(currChild); 4651 4652 // Create our pseudo style now that we have our firstLetterContainer determined. 4653 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, 4654 firstLetterContainer->firstLineStyle()); 4655 4656 // Force inline display (except for floating first-letters) 4657 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); 4658 pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned. 4659 4660 RenderObject* firstLetter = 0; 4661 if (pseudoStyle->display() == INLINE) 4662 firstLetter = new (renderArena()) RenderInline(document()); 4663 else 4664 firstLetter = new (renderArena()) RenderBlock(document()); 4665 firstLetter->setStyle(pseudoStyle); 4666 firstLetterContainer->addChild(firstLetter, currChild); 4667 4668 // The original string is going to be either a generated content string or a DOM node's 4669 // string. We want the original string before it got transformed in case first-letter has 4670 // no text-transform or a different text-transform applied to it. 4671 RefPtr<StringImpl> oldText = textObj->originalText(); 4672 ASSERT(oldText); 4673 4674 if (oldText && oldText->length() > 0) { 4675 unsigned int length = 0; 4676 4677 // account for leading spaces and punctuation 4678 while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length]))) 4679 length++; 4680 4681 // account for first letter 4682 length++; 4683 4684 // construct text fragment for the text after the first letter 4685 // NOTE: this might empty 4686 RenderTextFragment* remainingText = 4687 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); 4688 remainingText->setStyle(textObj->style()); 4689 if (remainingText->node()) 4690 remainingText->node()->setRenderer(remainingText); 4691 4692 RenderObject* nextObj = textObj->nextSibling(); 4693 firstLetterContainer->removeChild(textObj); 4694 firstLetterContainer->addChild(remainingText, nextObj); 4695 remainingText->setFirstLetter(firstLetter); 4696 4697 // construct text fragment for the first letter 4698 RenderTextFragment* letter = 4699 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); 4700 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 4701 newStyle->inheritFrom(pseudoStyle); 4702 letter->setStyle(newStyle.release()); 4703 firstLetter->addChild(letter); 4704 4705 textObj->destroy(); 4706 } 4707 view()->enableLayoutState(); 4708 } 4709 } 4710 4711 bool RenderBlock::inRootBlockContext() const 4712 { 4713 if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip()) 4714 return false; 4715 4716 if (isRoot() || isRenderView()) 4717 return true; 4718 4719 return containingBlock()->inRootBlockContext(); 4720 } 4721 4722 // Helper methods for obtaining the last line, computing line counts and heights for line counts 4723 // (crawling into blocks). 4724 static bool shouldCheckLines(RenderObject* obj) 4725 { 4726 return !obj->isFloatingOrPositioned() && !obj->isRunIn() && 4727 obj->isBlockFlow() && obj->style()->height().isAuto() && 4728 (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); 4729 } 4730 4731 static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) 4732 { 4733 if (block->style()->visibility() == VISIBLE) { 4734 if (block->childrenInline()) { 4735 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { 4736 if (count++ == i) 4737 return box; 4738 } 4739 } 4740 else { 4741 for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { 4742 if (shouldCheckLines(obj)) { 4743 RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count); 4744 if (box) 4745 return box; 4746 } 4747 } 4748 } 4749 } 4750 return 0; 4751 } 4752 4753 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) 4754 { 4755 if (block->style()->visibility() == VISIBLE) { 4756 if (block->childrenInline()) { 4757 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { 4758 if (++count == l) 4759 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); 4760 } 4761 } 4762 else { 4763 RenderBox* normalFlowChildWithoutLines = 0; 4764 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { 4765 if (shouldCheckLines(obj)) { 4766 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); 4767 if (result != -1) 4768 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); 4769 } 4770 else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) 4771 normalFlowChildWithoutLines = obj; 4772 } 4773 if (normalFlowChildWithoutLines && l == 0) 4774 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); 4775 } 4776 } 4777 4778 return -1; 4779 } 4780 4781 RootInlineBox* RenderBlock::lineAtIndex(int i) 4782 { 4783 int count = 0; 4784 return getLineAtIndex(this, i, count); 4785 } 4786 4787 int RenderBlock::lineCount() 4788 { 4789 int count = 0; 4790 if (style()->visibility() == VISIBLE) { 4791 if (childrenInline()) 4792 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 4793 count++; 4794 else 4795 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) 4796 if (shouldCheckLines(obj)) 4797 count += toRenderBlock(obj)->lineCount(); 4798 } 4799 return count; 4800 } 4801 4802 int RenderBlock::heightForLineCount(int l) 4803 { 4804 int count = 0; 4805 return getHeightForLineCount(this, l, true, count); 4806 } 4807 4808 void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const 4809 { 4810 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting 4811 // for either overflow or translations via relative positioning. 4812 if (style()->visibility() == VISIBLE) { 4813 if (childrenInline()) { 4814 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { 4815 if (box->firstChild()) 4816 left = min(left, x + box->firstChild()->x()); 4817 if (box->lastChild()) 4818 right = max(right, x + box->lastChild()->x() + box->lastChild()->width()); 4819 } 4820 } 4821 else { 4822 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { 4823 if (!obj->isFloatingOrPositioned()) { 4824 if (obj->isBlockFlow() && !obj->hasOverflowClip()) 4825 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right); 4826 else if (obj->style()->visibility() == VISIBLE) { 4827 // We are a replaced element or some kind of non-block-flow object. 4828 left = min(left, x + obj->x()); 4829 right = max(right, x + obj->x() + obj->width()); 4830 } 4831 } 4832 } 4833 } 4834 4835 if (m_floatingObjects) { 4836 FloatingObject* r; 4837 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); 4838 for (; (r = it.current()); ++it) { 4839 // Only examine the object if our m_shouldPaint flag is set. 4840 if (r->m_shouldPaint) { 4841 int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft(); 4842 int floatRight = floatLeft + r->m_renderer->width(); 4843 left = min(left, floatLeft); 4844 right = max(right, floatRight); 4845 } 4846 } 4847 } 4848 } 4849 } 4850 4851 void RenderBlock::borderFitAdjust(int& x, int& w) const 4852 { 4853 if (style()->borderFit() == BorderFitBorder) 4854 return; 4855 4856 // Walk any normal flow lines to snugly fit. 4857 int left = INT_MAX; 4858 int right = INT_MIN; 4859 int oldWidth = w; 4860 adjustForBorderFit(0, left, right); 4861 if (left != INT_MAX) { 4862 left -= (borderLeft() + paddingLeft()); 4863 if (left > 0) { 4864 x += left; 4865 w -= left; 4866 } 4867 } 4868 if (right != INT_MIN) { 4869 right += (borderRight() + paddingRight()); 4870 if (right < oldWidth) 4871 w -= (oldWidth - right); 4872 } 4873 } 4874 4875 void RenderBlock::clearTruncation() 4876 { 4877 if (style()->visibility() == VISIBLE) { 4878 if (childrenInline() && hasMarkupTruncation()) { 4879 setHasMarkupTruncation(false); 4880 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 4881 box->clearTruncation(); 4882 } 4883 else 4884 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) 4885 if (shouldCheckLines(obj)) 4886 toRenderBlock(obj)->clearTruncation(); 4887 } 4888 } 4889 4890 void RenderBlock::setMaxTopMargins(int pos, int neg) 4891 { 4892 if (!m_maxMargin) { 4893 if (pos == MaxMargin::topPosDefault(this) && neg == MaxMargin::topNegDefault(this)) 4894 return; 4895 m_maxMargin = new MaxMargin(this); 4896 } 4897 m_maxMargin->m_topPos = pos; 4898 m_maxMargin->m_topNeg = neg; 4899 } 4900 4901 void RenderBlock::setMaxBottomMargins(int pos, int neg) 4902 { 4903 if (!m_maxMargin) { 4904 if (pos == MaxMargin::bottomPosDefault(this) && neg == MaxMargin::bottomNegDefault(this)) 4905 return; 4906 m_maxMargin = new MaxMargin(this); 4907 } 4908 m_maxMargin->m_bottomPos = pos; 4909 m_maxMargin->m_bottomNeg = neg; 4910 } 4911 4912 void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty) 4913 { 4914 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 4915 // inline boxes above and below us (thus getting merged with them to form a single irregular 4916 // shape). 4917 if (inlineContinuation()) { 4918 rects.append(IntRect(tx, ty - collapsedMarginTop(), 4919 width(), height() + collapsedMarginTop() + collapsedMarginBottom())); 4920 inlineContinuation()->absoluteRects(rects, 4921 tx - x() + inlineContinuation()->containingBlock()->x(), 4922 ty - y() + inlineContinuation()->containingBlock()->y()); 4923 } else 4924 rects.append(IntRect(tx, ty, width(), height())); 4925 } 4926 4927 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads) 4928 { 4929 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 4930 // inline boxes above and below us (thus getting merged with them to form a single irregular 4931 // shape). 4932 if (inlineContinuation()) { 4933 FloatRect localRect(0, -collapsedMarginTop(), 4934 width(), height() + collapsedMarginTop() + collapsedMarginBottom()); 4935 quads.append(localToAbsoluteQuad(localRect)); 4936 inlineContinuation()->absoluteQuads(quads); 4937 } else 4938 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); 4939 } 4940 4941 IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) 4942 { 4943 IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); 4944 if (inlineContinuation()) 4945 r.inflateY(collapsedMarginTop()); 4946 return r; 4947 } 4948 4949 RenderObject* RenderBlock::hoverAncestor() const 4950 { 4951 return inlineContinuation() ? inlineContinuation() : RenderBox::hoverAncestor(); 4952 } 4953 4954 void RenderBlock::updateDragState(bool dragOn) 4955 { 4956 RenderBox::updateDragState(dragOn); 4957 if (inlineContinuation()) 4958 inlineContinuation()->updateDragState(dragOn); 4959 } 4960 4961 RenderStyle* RenderBlock::outlineStyleForRepaint() const 4962 { 4963 return inlineContinuation() ? inlineContinuation()->style() : style(); 4964 } 4965 4966 void RenderBlock::childBecameNonInline(RenderObject*) 4967 { 4968 makeChildrenNonInline(); 4969 if (isAnonymousBlock() && parent() && parent()->isRenderBlock()) 4970 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 4971 // |this| may be dead here 4972 } 4973 4974 void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point) 4975 { 4976 if (result.innerNode()) 4977 return; 4978 4979 Node* n = node(); 4980 if (inlineContinuation()) 4981 // We are in the margins of block elements that are part of a continuation. In 4982 // this case we're actually still inside the enclosing inline element that was 4983 // split. Go ahead and set our inner node accordingly. 4984 n = inlineContinuation()->node(); 4985 4986 if (n) { 4987 result.setInnerNode(n); 4988 if (!result.innerNonSharedNode()) 4989 result.setInnerNonSharedNode(n); 4990 result.setLocalPoint(point); 4991 } 4992 } 4993 4994 IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) 4995 { 4996 // Do the normal calculation in most cases. 4997 if (firstChild()) 4998 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); 4999 5000 // This is a special case: 5001 // The element is not an inline element, and it's empty. So we have to 5002 // calculate a fake position to indicate where objects are to be inserted. 5003 5004 // FIXME: This does not take into account either :first-line or :first-letter 5005 // However, as soon as some content is entered, the line boxes will be 5006 // constructed and this kludge is not called any more. So only the caret size 5007 // of an empty :first-line'd block is wrong. I think we can live with that. 5008 RenderStyle* currentStyle = firstLineStyle(); 5009 int height = lineHeight(true); 5010 5011 enum CaretAlignment { alignLeft, alignRight, alignCenter }; 5012 5013 CaretAlignment alignment = alignLeft; 5014 5015 switch (currentStyle->textAlign()) { 5016 case TAAUTO: 5017 case JUSTIFY: 5018 if (currentStyle->direction() == RTL) 5019 alignment = alignRight; 5020 break; 5021 case LEFT: 5022 case WEBKIT_LEFT: 5023 break; 5024 case CENTER: 5025 case WEBKIT_CENTER: 5026 alignment = alignCenter; 5027 break; 5028 case RIGHT: 5029 case WEBKIT_RIGHT: 5030 alignment = alignRight; 5031 break; 5032 } 5033 5034 int x = borderLeft() + paddingLeft(); 5035 int w = width(); 5036 5037 switch (alignment) { 5038 case alignLeft: 5039 break; 5040 case alignCenter: 5041 x = (x + w - (borderRight() + paddingRight())) / 2; 5042 break; 5043 case alignRight: 5044 x = w - (borderRight() + paddingRight()) - caretWidth; 5045 break; 5046 } 5047 5048 if (extraWidthToEndOfLine) { 5049 if (isRenderBlock()) { 5050 *extraWidthToEndOfLine = w - (x + caretWidth); 5051 } else { 5052 // FIXME: This code looks wrong. 5053 // myRight and containerRight are set up, but then clobbered. 5054 // So *extraWidthToEndOfLine will always be 0 here. 5055 5056 int myRight = x + caretWidth; 5057 // FIXME: why call localToAbsoluteForContent() twice here, too? 5058 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); 5059 5060 int containerRight = containingBlock()->x() + containingBlockWidthForContent(); 5061 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); 5062 5063 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); 5064 } 5065 } 5066 5067 int y = paddingTop() + borderTop(); 5068 5069 return IntRect(x, y, caretWidth, height); 5070 } 5071 5072 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) 5073 { 5074 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 5075 // inline boxes above and below us (thus getting merged with them to form a single irregular 5076 // shape). 5077 if (inlineContinuation()) { 5078 // FIXME: This check really isn't accurate. 5079 bool nextInlineHasLineBox = inlineContinuation()->firstLineBox(); 5080 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block. 5081 bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox(); 5082 int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0; 5083 int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0; 5084 IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin); 5085 if (!rect.isEmpty()) 5086 rects.append(rect); 5087 } else if (width() && height()) 5088 rects.append(IntRect(tx, ty, width(), height())); 5089 5090 if (!hasOverflowClip() && !hasControlClip()) { 5091 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 5092 int top = max(curr->lineTop(), curr->y()); 5093 int bottom = min(curr->lineBottom(), curr->y() + curr->height()); 5094 IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top); 5095 if (!rect.isEmpty()) 5096 rects.append(rect); 5097 } 5098 5099 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { 5100 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { 5101 RenderBox* box = toRenderBox(curr); 5102 FloatPoint pos; 5103 // FIXME: This doesn't work correctly with transforms. 5104 if (box->layer()) 5105 pos = curr->localToAbsolute(); 5106 else 5107 pos = FloatPoint(tx + box->x(), ty + box->y()); 5108 box->addFocusRingRects(rects, pos.x(), pos.y()); 5109 } 5110 } 5111 } 5112 5113 if (inlineContinuation()) 5114 inlineContinuation()->addFocusRingRects(rects, 5115 tx - x() + inlineContinuation()->containingBlock()->x(), 5116 ty - y() + inlineContinuation()->containingBlock()->y()); 5117 } 5118 5119 RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const 5120 { 5121 RefPtr<RenderStyle> newStyle = RenderStyle::create(); 5122 newStyle->inheritFrom(style()); 5123 5124 RenderBlock* newBox = 0; 5125 if (isFlexibleBox) { 5126 newStyle->setDisplay(BOX); 5127 newBox = new (renderArena()) RenderFlexibleBox(document() /* anonymous box */); 5128 } else { 5129 newStyle->setDisplay(BLOCK); 5130 newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); 5131 } 5132 5133 newBox->setStyle(newStyle.release()); 5134 return newBox; 5135 } 5136 5137 const char* RenderBlock::renderName() const 5138 { 5139 if (isBody()) 5140 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass. 5141 5142 if (isFloating()) 5143 return "RenderBlock (floating)"; 5144 if (isPositioned()) 5145 return "RenderBlock (positioned)"; 5146 if (isAnonymousBlock()) 5147 return "RenderBlock (anonymous)"; 5148 else if (isAnonymous()) 5149 return "RenderBlock (generated)"; 5150 if (isRelPositioned()) 5151 return "RenderBlock (relative positioned)"; 5152 if (isRunIn()) 5153 return "RenderBlock (run-in)"; 5154 return "RenderBlock"; 5155 } 5156 5157 } // namespace WebCore 5158