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