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