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