1/* 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) 4 * (C) 2007 David Smith (catfish.man@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 61using namespace std; 62using namespace WTF; 63using namespace Unicode; 64 65namespace WebCore { 66 67using namespace HTMLNames; 68 69typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap; 70static ColumnInfoMap* gColumnInfoMap = 0; 71 72typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap; 73static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0; 74 75typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap; 76static PercentHeightContainerMap* gPercentHeightContainerMap = 0; 77 78typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap; 79 80typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet; 81static int gDelayUpdateScrollInfo = 0; 82static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0; 83 84bool RenderBlock::s_canPropagateFloatIntoSibling = false; 85 86// Our MarginInfo state used when laying out block children. 87RenderBlock::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 119RenderBlock::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 130RenderBlock::~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 158void 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 (isInline() && parent()) 195 parent()->dirtyLinesFromChangedChild(this); 196 } 197 198 m_lineBoxes.deleteLineBoxes(renderArena()); 199 200 RenderBox::destroy(); 201} 202 203void 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 237void 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 305void 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 313RenderBlock* 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 338void 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 375void 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 421RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock) 422{ 423 for (RenderObject* curr = this; curr; curr = curr->parent()) { 424 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip() 425 || curr->isInlineBlockOrInlineTable()) 426 return 0; 427 428 RenderBlock* currBlock = toRenderBlock(curr); 429 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock())) 430 return currBlock; 431 432 if (currBlock->isAnonymousColumnSpanBlock()) 433 return 0; 434 } 435 return 0; 436} 437 438RenderBlock* RenderBlock::clone() const 439{ 440 RenderBlock* cloneBlock; 441 if (isAnonymousBlock()) 442 cloneBlock = createAnonymousBlock(); 443 else { 444 cloneBlock = new (renderArena()) RenderBlock(node()); 445 cloneBlock->setStyle(style()); 446 } 447 cloneBlock->setChildrenInline(childrenInline()); 448 return cloneBlock; 449} 450 451void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock, 452 RenderBlock* middleBlock, 453 RenderObject* beforeChild, RenderBoxModelObject* oldCont) 454{ 455 // Create a clone of this inline. 456 RenderBlock* cloneBlock = clone(); 457 if (!isAnonymousBlock()) 458 cloneBlock->setContinuation(oldCont); 459 460 // Now take all of the children from beforeChild to the end and remove 461 // them from |this| and place them in the clone. 462 if (!beforeChild && isAfterContent(lastChild())) 463 beforeChild = lastChild(); 464 moveChildrenTo(cloneBlock, beforeChild, 0); 465 466 // Hook |clone| up as the continuation of the middle block. 467 if (!cloneBlock->isAnonymousBlock()) 468 middleBlock->setContinuation(cloneBlock); 469 470 // We have been reparented and are now under the fromBlock. We need 471 // to walk up our block parent chain until we hit the containing anonymous columns block. 472 // Once we hit the anonymous columns block we're done. 473 RenderBoxModelObject* curr = toRenderBoxModelObject(parent()); 474 RenderBoxModelObject* currChild = this; 475 476 while (curr && curr != fromBlock) { 477 ASSERT(curr->isRenderBlock()); 478 479 RenderBlock* blockCurr = toRenderBlock(curr); 480 481 // Create a new clone. 482 RenderBlock* cloneChild = cloneBlock; 483 cloneBlock = blockCurr->clone(); 484 485 // Insert our child clone as the first child. 486 cloneBlock->children()->appendChildNode(cloneBlock, cloneChild); 487 488 // Hook the clone up as a continuation of |curr|. Note we do encounter 489 // anonymous blocks possibly as we walk up the block chain. When we split an 490 // anonymous block, there's no need to do any continuation hookup, since we haven't 491 // actually split a real element. 492 if (!blockCurr->isAnonymousBlock()) { 493 oldCont = blockCurr->continuation(); 494 blockCurr->setContinuation(cloneBlock); 495 cloneBlock->setContinuation(oldCont); 496 } 497 498 // Someone may have indirectly caused a <q> to split. When this happens, the :after content 499 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after 500 // content gets properly destroyed. 501 if (document()->usesBeforeAfterRules()) 502 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER); 503 504 // Now we need to take all of the children starting from the first child 505 // *after* currChild and append them all to the clone. 506 RenderObject* afterContent = isAfterContent(cloneBlock->lastChild()) ? cloneBlock->lastChild() : 0; 507 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, afterContent); 508 509 // Keep walking up the chain. 510 currChild = curr; 511 curr = toRenderBoxModelObject(curr->parent()); 512 } 513 514 // Now we are at the columns block level. We need to put the clone into the toBlock. 515 toBlock->children()->appendChildNode(toBlock, cloneBlock); 516 517 // Now take all the children after currChild and remove them from the fromBlock 518 // and put them in the toBlock. 519 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0); 520} 521 522void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox, 523 RenderObject* newChild, RenderBoxModelObject* oldCont) 524{ 525 RenderBlock* pre = 0; 526 RenderBlock* block = containingColumnsBlock(); 527 528 // Delete our line boxes before we do the inline split into continuations. 529 block->deleteLineBoxTree(); 530 531 bool madeNewBeforeBlock = false; 532 if (block->isAnonymousColumnsBlock()) { 533 // We can reuse this block and make it the preBlock of the next continuation. 534 pre = block; 535 pre->removePositionedObjects(0); 536 block = toRenderBlock(block->parent()); 537 } else { 538 // No anonymous block available for use. Make one. 539 pre = block->createAnonymousColumnsBlock(); 540 pre->setChildrenInline(false); 541 madeNewBeforeBlock = true; 542 } 543 544 RenderBlock* post = block->createAnonymousColumnsBlock(); 545 post->setChildrenInline(false); 546 547 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling(); 548 if (madeNewBeforeBlock) 549 block->children()->insertChildNode(block, pre, boxFirst); 550 block->children()->insertChildNode(block, newBlockBox, boxFirst); 551 block->children()->insertChildNode(block, post, boxFirst); 552 block->setChildrenInline(false); 553 554 if (madeNewBeforeBlock) 555 block->moveChildrenTo(pre, boxFirst, 0); 556 557 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont); 558 559 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting 560 // time in makeChildrenNonInline by just setting this explicitly up front. 561 newBlockBox->setChildrenInline(false); 562 563 // We delayed adding the newChild until now so that the |newBlockBox| would be fully 564 // connected, thus allowing newChild access to a renderArena should it need 565 // to wrap itself in additional boxes (e.g., table construction). 566 newBlockBox->addChild(newChild); 567 568 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) 569 // get deleted properly. Because objects moves from the pre block into the post block, we want to 570 // make new line boxes instead of leaving the old line boxes around. 571 pre->setNeedsLayoutAndPrefWidthsRecalc(); 572 block->setNeedsLayoutAndPrefWidthsRecalc(); 573 post->setNeedsLayoutAndPrefWidthsRecalc(); 574} 575 576RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild) 577{ 578 while (beforeChild->parent() != this) { 579 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent()); 580 if (blockToSplit->firstChild() != beforeChild) { 581 // We have to split the parentBlock into two blocks. 582 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit); 583 post->setChildrenInline(blockToSplit->childrenInline()); 584 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent()); 585 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling()); 586 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer()); 587 post->setNeedsLayoutAndPrefWidthsRecalc(); 588 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc(); 589 beforeChild = post; 590 } else 591 beforeChild = blockToSplit; 592 } 593 return beforeChild; 594} 595 596void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild) 597{ 598 RenderBlock* pre = 0; 599 RenderBlock* post = 0; 600 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable 601 // so that we don't have to patch all of the rest of the code later on. 602 603 // Delete the block's line boxes before we do the split. 604 block->deleteLineBoxTree(); 605 606 if (beforeChild && beforeChild->parent() != this) 607 beforeChild = splitAnonymousBlocksAroundChild(beforeChild); 608 609 if (beforeChild != firstChild()) { 610 pre = block->createAnonymousColumnsBlock(); 611 pre->setChildrenInline(block->childrenInline()); 612 } 613 614 if (beforeChild) { 615 post = block->createAnonymousColumnsBlock(); 616 post->setChildrenInline(block->childrenInline()); 617 } 618 619 RenderObject* boxFirst = block->firstChild(); 620 if (pre) 621 block->children()->insertChildNode(block, pre, boxFirst); 622 block->children()->insertChildNode(block, newBlockBox, boxFirst); 623 if (post) 624 block->children()->insertChildNode(block, post, boxFirst); 625 block->setChildrenInline(false); 626 627 // 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). 628 block->moveChildrenTo(pre, boxFirst, beforeChild, true); 629 block->moveChildrenTo(post, beforeChild, 0, true); 630 631 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting 632 // time in makeChildrenNonInline by just setting this explicitly up front. 633 newBlockBox->setChildrenInline(false); 634 635 // We delayed adding the newChild until now so that the |newBlockBox| would be fully 636 // connected, thus allowing newChild access to a renderArena should it need 637 // to wrap itself in additional boxes (e.g., table construction). 638 newBlockBox->addChild(newChild); 639 640 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images) 641 // get deleted properly. Because objects moved from the pre block into the post block, we want to 642 // make new line boxes instead of leaving the old line boxes around. 643 if (pre) 644 pre->setNeedsLayoutAndPrefWidthsRecalc(); 645 block->setNeedsLayoutAndPrefWidthsRecalc(); 646 if (post) 647 post->setNeedsLayoutAndPrefWidthsRecalc(); 648} 649 650RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild) 651{ 652 // FIXME: This function is the gateway for the addition of column-span support. It will 653 // be added to in three stages: 654 // (1) Immediate children of a multi-column block can span. 655 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span. 656 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we 657 // cross the streams and have to cope with both types of continuations mixed together). 658 // This function currently supports (1) and (2). 659 RenderBlock* columnsBlockAncestor = 0; 660 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isFloatingOrPositioned() 661 && !newChild->isInline() && !isAnonymousColumnSpanBlock()) { 662 if (style()->specifiesColumns()) 663 columnsBlockAncestor = this; 664 else if (parent() && parent()->isRenderBlock()) 665 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false); 666 } 667 return columnsBlockAncestor; 668} 669 670void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild) 671{ 672 // Make sure we don't append things after :after-generated content if we have it. 673 if (!beforeChild) { 674 RenderObject* lastRenderer = lastChild(); 675 if (isAfterContent(lastRenderer)) 676 beforeChild = lastRenderer; 677 else if (lastRenderer && lastRenderer->isAnonymousBlock() && isAfterContent(lastRenderer->lastChild())) 678 beforeChild = lastRenderer->lastChild(); 679 } 680 681 // If the requested beforeChild is not one of our children, then this is because 682 // there is an anonymous container within this object that contains the beforeChild. 683 if (beforeChild && beforeChild->parent() != this) { 684 RenderObject* anonymousChild = beforeChild->parent(); 685 ASSERT(anonymousChild); 686 687 while (anonymousChild->parent() != this) 688 anonymousChild = anonymousChild->parent(); 689 690 ASSERT(anonymousChild->isAnonymous()); 691 692 if (anonymousChild->isAnonymousBlock()) { 693 // Insert the child into the anonymous block box instead of here. 694 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild) 695 beforeChild->parent()->addChild(newChild, beforeChild); 696 else 697 addChild(newChild, beforeChild->parent()); 698 return; 699 } 700 701 ASSERT(anonymousChild->isTable()); 702 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP) 703 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION) 704 || newChild->isTableSection() 705 || newChild->isTableRow() 706 || newChild->isTableCell()) { 707 // Insert into the anonymous table. 708 anonymousChild->addChild(newChild, beforeChild); 709 return; 710 } 711 712 // Go on to insert before the anonymous table. 713 beforeChild = anonymousChild; 714 } 715 716 // Check for a spanning element in columns. 717 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild); 718 if (columnsBlockAncestor) { 719 // We are placing a column-span element inside a block. 720 RenderBlock* newBox = createAnonymousColumnSpanBlock(); 721 722 if (columnsBlockAncestor != this) { 723 // We are nested inside a multi-column element and are being split by the span. We have to break up 724 // our block into continuations. 725 RenderBoxModelObject* oldContinuation = continuation(); 726 setContinuation(newBox); 727 728 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content 729 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after 730 // content gets properly destroyed. 731 bool isLastChild = (beforeChild == lastChild()); 732 if (document()->usesBeforeAfterRules()) 733 children()->updateBeforeAfterContent(this, AFTER); 734 if (isLastChild && beforeChild != lastChild()) 735 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion 736 // point to be 0. It's just a straight append now. 737 738 splitFlow(beforeChild, newBox, newChild, oldContinuation); 739 return; 740 } 741 742 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold 743 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into 744 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block. 745 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild); 746 return; 747 } 748 749 bool madeBoxesNonInline = false; 750 751 // A block has to either have all of its children inline, or all of its children as blocks. 752 // So, if our children are currently inline and a block child has to be inserted, we move all our 753 // inline children into anonymous block boxes. 754 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) { 755 // This is a block with inline content. Wrap the inline content in anonymous blocks. 756 makeChildrenNonInline(beforeChild); 757 madeBoxesNonInline = true; 758 759 if (beforeChild && beforeChild->parent() != this) { 760 beforeChild = beforeChild->parent(); 761 ASSERT(beforeChild->isAnonymousBlock()); 762 ASSERT(beforeChild->parent() == this); 763 } 764 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) { 765 // If we're inserting an inline child but all of our children are blocks, then we have to make sure 766 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise 767 // a new one is created and inserted into our list of children in the appropriate position. 768 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild(); 769 770 if (afterChild && afterChild->isAnonymousBlock()) { 771 afterChild->addChild(newChild); 772 return; 773 } 774 775 if (newChild->isInline()) { 776 // No suitable existing anonymous box - create a new one. 777 RenderBlock* newBox = createAnonymousBlock(); 778 RenderBox::addChild(newBox, beforeChild); 779 newBox->addChild(newChild); 780 return; 781 } 782 } 783 784 RenderBox::addChild(newChild, beforeChild); 785 786 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock()) 787 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 788 // this object may be dead here 789} 790 791void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild) 792{ 793 if (continuation() && !isAnonymousBlock()) 794 return addChildToContinuation(newChild, beforeChild); 795 return addChildIgnoringContinuation(newChild, beforeChild); 796} 797 798void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild) 799{ 800 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock())) 801 return addChildToAnonymousColumnBlocks(newChild, beforeChild); 802 return addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild); 803} 804 805static void getInlineRun(RenderObject* start, RenderObject* boundary, 806 RenderObject*& inlineRunStart, 807 RenderObject*& inlineRunEnd) 808{ 809 // Beginning at |start| we find the largest contiguous run of inlines that 810 // we can. We denote the run with start and end points, |inlineRunStart| 811 // and |inlineRunEnd|. Note that these two values may be the same if 812 // we encounter only one inline. 813 // 814 // We skip any non-inlines we encounter as long as we haven't found any 815 // inlines yet. 816 // 817 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary| 818 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered 819 // a non-inline. 820 821 // Start by skipping as many non-inlines as we can. 822 RenderObject * curr = start; 823 bool sawInline; 824 do { 825 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned())) 826 curr = curr->nextSibling(); 827 828 inlineRunStart = inlineRunEnd = curr; 829 830 if (!curr) 831 return; // No more inline children to be found. 832 833 sawInline = curr->isInline(); 834 835 curr = curr->nextSibling(); 836 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) { 837 inlineRunEnd = curr; 838 if (curr->isInline()) 839 sawInline = true; 840 curr = curr->nextSibling(); 841 } 842 } while (!sawInline); 843} 844 845void RenderBlock::deleteLineBoxTree() 846{ 847 m_lineBoxes.deleteLineBoxTree(renderArena()); 848} 849 850RootInlineBox* RenderBlock::createRootInlineBox() 851{ 852 return new (renderArena()) RootInlineBox(this); 853} 854 855RootInlineBox* RenderBlock::createAndAppendRootInlineBox() 856{ 857 RootInlineBox* rootBox = createRootInlineBox(); 858 m_lineBoxes.appendLineBox(rootBox); 859 return rootBox; 860} 861 862void RenderBlock::moveChildTo(RenderBlock* to, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert) 863{ 864 ASSERT(this == child->parent()); 865 ASSERT(!beforeChild || to == beforeChild->parent()); 866 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); 867} 868 869void RenderBlock::moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert) 870{ 871 ASSERT(!beforeChild || to == beforeChild->parent()); 872 RenderObject* nextChild = startChild; 873 while (nextChild && nextChild != endChild) { 874 RenderObject* child = nextChild; 875 nextChild = child->nextSibling(); 876 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert); 877 if (child == endChild) 878 return; 879 } 880} 881 882void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint) 883{ 884 // makeChildrenNonInline takes a block whose children are *all* inline and it 885 // makes sure that inline children are coalesced under anonymous 886 // blocks. If |insertionPoint| is defined, then it represents the insertion point for 887 // the new block child that is causing us to have to wrap all the inlines. This 888 // means that we cannot coalesce inlines before |insertionPoint| with inlines following 889 // |insertionPoint|, because the new child is going to be inserted in between the inlines, 890 // splitting them. 891 ASSERT(isInlineBlockOrInlineTable() || !isInline()); 892 ASSERT(!insertionPoint || insertionPoint->parent() == this); 893 894 setChildrenInline(false); 895 896 RenderObject *child = firstChild(); 897 if (!child) 898 return; 899 900 deleteLineBoxTree(); 901 902 while (child) { 903 RenderObject *inlineRunStart, *inlineRunEnd; 904 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd); 905 906 if (!inlineRunStart) 907 break; 908 909 child = inlineRunEnd->nextSibling(); 910 911 RenderBlock* block = createAnonymousBlock(); 912 children()->insertChildNode(this, block, inlineRunStart); 913 moveChildrenTo(block, inlineRunStart, child); 914 } 915 916#ifndef NDEBUG 917 for (RenderObject *c = firstChild(); c; c = c->nextSibling()) 918 ASSERT(!c->isInline()); 919#endif 920 921 repaint(); 922} 923 924void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child) 925{ 926 ASSERT(child->isAnonymousBlock()); 927 ASSERT(!child->childrenInline()); 928 929 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock()))) 930 return; 931 932 RenderObject* firstAnChild = child->m_children.firstChild(); 933 RenderObject* lastAnChild = child->m_children.lastChild(); 934 if (firstAnChild) { 935 RenderObject* o = firstAnChild; 936 while (o) { 937 o->setParent(this); 938 o = o->nextSibling(); 939 } 940 firstAnChild->setPreviousSibling(child->previousSibling()); 941 lastAnChild->setNextSibling(child->nextSibling()); 942 if (child->previousSibling()) 943 child->previousSibling()->setNextSibling(firstAnChild); 944 if (child->nextSibling()) 945 child->nextSibling()->setPreviousSibling(lastAnChild); 946 947 if (child == m_children.firstChild()) 948 m_children.setFirstChild(firstAnChild); 949 if (child == m_children.lastChild()) 950 m_children.setLastChild(lastAnChild); 951 } else { 952 if (child == m_children.firstChild()) 953 m_children.setFirstChild(child->nextSibling()); 954 if (child == m_children.lastChild()) 955 m_children.setLastChild(child->previousSibling()); 956 957 if (child->previousSibling()) 958 child->previousSibling()->setNextSibling(child->nextSibling()); 959 if (child->nextSibling()) 960 child->nextSibling()->setPreviousSibling(child->previousSibling()); 961 } 962 child->setParent(0); 963 child->setPreviousSibling(0); 964 child->setNextSibling(0); 965 966 child->children()->setFirstChild(0); 967 child->m_next = 0; 968 969 child->destroy(); 970} 971 972static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next) 973{ 974 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation()) 975 return false; 976 977 if (oldChild->parent() && oldChild->parent()->isDetails()) 978 return false; 979 980 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed())) 981 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed()))) 982 return false; 983 984 // FIXME: This check isn't required when inline run-ins can't be split into continuations. 985 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn()) 986 return false; 987 988 if ((prev && (prev->isRubyRun() || prev->isRubyBase())) 989 || (next && (next->isRubyRun() || next->isRubyBase()))) 990 return false; 991 992 if (!prev || !next) 993 return true; 994 995 // Make sure the types of the anonymous blocks match up. 996 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock() 997 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock(); 998} 999 1000void RenderBlock::removeChild(RenderObject* oldChild) 1001{ 1002 // If this child is a block, and if our previous and next siblings are 1003 // both anonymous blocks with inline content, then we can go ahead and 1004 // fold the inline content back together. 1005 RenderObject* prev = oldChild->previousSibling(); 1006 RenderObject* next = oldChild->nextSibling(); 1007 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next); 1008 if (canMergeAnonymousBlocks && prev && next) { 1009 prev->setNeedsLayoutAndPrefWidthsRecalc(); 1010 RenderBlock* nextBlock = toRenderBlock(next); 1011 RenderBlock* prevBlock = toRenderBlock(prev); 1012 1013 if (prev->childrenInline() != next->childrenInline()) { 1014 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock; 1015 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock; 1016 1017 // Place the inline children block inside of the block children block instead of deleting it. 1018 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure 1019 // to clear out inherited column properties by just making a new style, and to also clear the 1020 // column span flag if it is set. 1021 ASSERT(!inlineChildrenBlock->continuation()); 1022 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); 1023 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer()); 1024 inlineChildrenBlock->setStyle(newStyle); 1025 1026 // Now just put the inlineChildrenBlock inside the blockChildrenBlock. 1027 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0, 1028 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer()); 1029 next->setNeedsLayoutAndPrefWidthsRecalc(); 1030 1031 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child 1032 // of "this". we null out prev or next so that is not used later in the function. 1033 if (inlineChildrenBlock == prevBlock) 1034 prev = 0; 1035 else 1036 next = 0; 1037 } else { 1038 // Take all the children out of the |next| block and put them in 1039 // the |prev| block. 1040 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer()); 1041 1042 // Delete the now-empty block's lines and nuke it. 1043 nextBlock->deleteLineBoxTree(); 1044 nextBlock->destroy(); 1045 next = 0; 1046 } 1047 } 1048 1049 RenderBox::removeChild(oldChild); 1050 1051 RenderObject* child = prev ? prev : next; 1052 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) { 1053 // The removal has knocked us down to containing only a single anonymous 1054 // box. We can go ahead and pull the content right back up into our 1055 // box. 1056 setNeedsLayoutAndPrefWidthsRecalc(); 1057 setChildrenInline(child->childrenInline()); 1058 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, child->hasLayer())); 1059 anonBlock->moveAllChildrenTo(this, child->hasLayer()); 1060 // Delete the now-empty block's lines and nuke it. 1061 anonBlock->deleteLineBoxTree(); 1062 anonBlock->destroy(); 1063 } 1064 1065 if (!firstChild() && !documentBeingDestroyed()) { 1066 // If this was our last child be sure to clear out our line boxes. 1067 if (childrenInline()) 1068 lineBoxes()->deleteLineBoxes(renderArena()); 1069 } 1070} 1071 1072bool RenderBlock::isSelfCollapsingBlock() const 1073{ 1074 // We are not self-collapsing if we 1075 // (a) have a non-zero height according to layout (an optimization to avoid wasting time) 1076 // (b) are a table, 1077 // (c) have border/padding, 1078 // (d) have a min-height 1079 // (e) have specified that one of our margins can't collapse using a CSS extension 1080 if (logicalHeight() > 0 1081 || isTable() || borderAndPaddingLogicalHeight() 1082 || style()->logicalMinHeight().isPositive() 1083 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE) 1084 return false; 1085 1086 Length logicalHeightLength = style()->logicalHeight(); 1087 bool hasAutoHeight = logicalHeightLength.isAuto(); 1088 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) { 1089 hasAutoHeight = true; 1090 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) { 1091 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell()) 1092 hasAutoHeight = false; 1093 } 1094 } 1095 1096 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends 1097 // on whether we have content that is all self-collapsing or not. 1098 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) { 1099 // If the block has inline children, see if we generated any line boxes. If we have any 1100 // line boxes, then we can't be self-collapsing, since we have content. 1101 if (childrenInline()) 1102 return !firstLineBox(); 1103 1104 // Whether or not we collapse is dependent on whether all our normal flow children 1105 // are also self-collapsing. 1106 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1107 if (child->isFloatingOrPositioned()) 1108 continue; 1109 if (!child->isSelfCollapsingBlock()) 1110 return false; 1111 } 1112 return true; 1113 } 1114 return false; 1115} 1116 1117void RenderBlock::startDelayUpdateScrollInfo() 1118{ 1119 if (gDelayUpdateScrollInfo == 0) { 1120 ASSERT(!gDelayedUpdateScrollInfoSet); 1121 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet; 1122 } 1123 ASSERT(gDelayedUpdateScrollInfoSet); 1124 ++gDelayUpdateScrollInfo; 1125} 1126 1127void RenderBlock::finishDelayUpdateScrollInfo() 1128{ 1129 --gDelayUpdateScrollInfo; 1130 ASSERT(gDelayUpdateScrollInfo >= 0); 1131 if (gDelayUpdateScrollInfo == 0) { 1132 ASSERT(gDelayedUpdateScrollInfoSet); 1133 1134 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet); 1135 gDelayedUpdateScrollInfoSet = 0; 1136 1137 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) { 1138 RenderBlock* block = *it; 1139 if (block->hasOverflowClip()) { 1140 block->layer()->updateScrollInfoAfterLayout(); 1141 } 1142 } 1143 } 1144} 1145 1146void RenderBlock::updateScrollInfoAfterLayout() 1147{ 1148 if (hasOverflowClip()) { 1149 if (gDelayUpdateScrollInfo) 1150 gDelayedUpdateScrollInfoSet->add(this); 1151 else 1152 layer()->updateScrollInfoAfterLayout(); 1153 } 1154} 1155 1156void RenderBlock::layout() 1157{ 1158 // Update our first letter info now. 1159 updateFirstLetter(); 1160 1161 // Table cells call layoutBlock directly, so don't add any logic here. Put code into 1162 // layoutBlock(). 1163 layoutBlock(false); 1164 1165 // It's safe to check for control clip here, since controls can never be table cells. 1166 // If we have a lightweight clip, there can never be any overflow from children. 1167 if (hasControlClip() && m_overflow) 1168 clearLayoutOverflow(); 1169} 1170 1171void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight) 1172{ 1173 ASSERT(needsLayout()); 1174 1175 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can 1176 return; // cause us to come in here. Just bail. 1177 1178 if (!relayoutChildren && simplifiedLayout()) 1179 return; 1180 1181 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout()); 1182 1183 int oldWidth = logicalWidth(); 1184 int oldColumnWidth = desiredColumnWidth(); 1185 1186 computeLogicalWidth(); 1187 calcColumnWidth(); 1188 1189 m_overflow.clear(); 1190 1191 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth()) 1192 relayoutChildren = true; 1193 1194#ifdef ANDROID_LAYOUT 1195 checkAndSetRelayoutChildren(&relayoutChildren); 1196#endif 1197 1198 clearFloats(); 1199 1200 int previousHeight = logicalHeight(); 1201 setLogicalHeight(0); 1202 bool hasSpecifiedPageLogicalHeight = false; 1203 bool pageLogicalHeightChanged = false; 1204 ColumnInfo* colInfo = columnInfo(); 1205 if (hasColumns()) { 1206 if (!pageLogicalHeight) { 1207 // We need to go ahead and set our explicit page height if one exists, so that we can 1208 // avoid doing two layout passes. 1209 computeLogicalHeight(); 1210 int columnHeight = contentLogicalHeight(); 1211 if (columnHeight > 0) { 1212 pageLogicalHeight = columnHeight; 1213 hasSpecifiedPageLogicalHeight = true; 1214 } 1215 setLogicalHeight(0); 1216 } 1217 if (colInfo->columnHeight() != pageLogicalHeight && m_everHadLayout) { 1218 colInfo->setColumnHeight(pageLogicalHeight); 1219 pageLogicalHeightChanged = true; 1220 } 1221 1222 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight) 1223 colInfo->clearForcedBreaks(); 1224 } 1225 1226 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo); 1227 1228 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track 1229 // our current maximal positive and negative margins. These values are used when we 1230 // are collapsed with adjacent blocks, so for example, if you have block A and B 1231 // collapsing together, then you'd take the maximal positive margin from both A and B 1232 // and subtract it from the maximal negative margin from both A and B to get the 1233 // true collapsed margin. This algorithm is recursive, so when we finish layout() 1234 // our block knows its current maximal positive/negative values. 1235 // 1236 // Start out by setting our margin values to our current margins. Table cells have 1237 // no margins, so we don't fill in the values for table cells. 1238 bool isCell = isTableCell(); 1239 if (!isCell) { 1240 initMaxMarginValues(); 1241 1242 setMarginBeforeQuirk(style()->marginBefore().quirk()); 1243 setMarginAfterQuirk(style()->marginAfter().quirk()); 1244 1245 Node* n = node(); 1246 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) { 1247 // See if this form is malformed (i.e., unclosed). If so, don't give the form 1248 // a bottom margin. 1249 setMaxMarginAfterValues(0, 0); 1250 } 1251 1252 setPaginationStrut(0); 1253 } 1254 1255 // For overflow:scroll blocks, ensure we have both scrollbars in place always. 1256 if (scrollsOverflow()) { 1257 if (style()->overflowX() == OSCROLL) 1258 layer()->setHasHorizontalScrollbar(true); 1259 if (style()->overflowY() == OSCROLL) 1260 layer()->setHasVerticalScrollbar(true); 1261 } 1262 1263 int repaintLogicalTop = 0; 1264 int repaintLogicalBottom = 0; 1265 int maxFloatLogicalBottom = 0; 1266 if (!firstChild() && !isAnonymousBlock()) 1267 setChildrenInline(true); 1268 if (childrenInline()) 1269 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom); 1270 else 1271 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom); 1272 1273 // Expand our intrinsic height to encompass floats. 1274 int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 1275 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats()) 1276 setLogicalHeight(lowestFloatLogicalBottom() + toAdd); 1277 1278 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher)) 1279 return; 1280 1281 // Calculate our new height. 1282 int oldHeight = logicalHeight(); 1283 int oldClientAfterEdge = clientLogicalBottom(); 1284 computeLogicalHeight(); 1285 int newHeight = logicalHeight(); 1286 if (oldHeight != newHeight) { 1287 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) { 1288 // One of our children's floats may have become an overhanging float for us. We need to look for it. 1289 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 1290 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) { 1291 RenderBlock* block = toRenderBlock(child); 1292 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight) 1293 addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false); 1294 } 1295 } 1296 } 1297 } 1298 1299 if (previousHeight != newHeight) 1300 relayoutChildren = true; 1301 1302 layoutPositionedObjects(relayoutChildren || isRoot()); 1303 1304 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway). 1305 computeOverflow(oldClientAfterEdge); 1306 1307 statePusher.pop(); 1308 1309 if (view()->layoutState()->m_pageLogicalHeight) 1310 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop())); 1311 1312 updateLayerTransform(); 1313 1314 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if 1315 // we overflow or not. 1316 updateScrollInfoAfterLayout(); 1317 1318 // Repaint with our new bounds if they are different from our old bounds. 1319 bool didFullRepaint = repainter.repaintAfterLayout(); 1320 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) { 1321 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines 1322 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either. 1323 int repaintLogicalLeft = logicalLeftVisualOverflow(); 1324 int repaintLogicalRight = logicalRightVisualOverflow(); 1325 if (hasOverflowClip()) { 1326 // 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. 1327 // 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. 1328 // layoutInlineChildren should be patched to compute the entire repaint rect. 1329 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow()); 1330 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow()); 1331 } 1332 1333 IntRect repaintRect; 1334 if (isHorizontalWritingMode()) 1335 repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop); 1336 else 1337 repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft); 1338 1339 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union. 1340 adjustRectForColumns(repaintRect); 1341 1342 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline)); 1343 1344 if (hasOverflowClip()) { 1345 // Adjust repaint rect for scroll offset 1346 repaintRect.move(-layer()->scrolledContentOffset()); 1347 1348 // Don't allow this rect to spill out of our overflow box. 1349 repaintRect.intersect(IntRect(0, 0, width(), height())); 1350 } 1351 1352 // Make sure the rect is still non-empty after intersecting for overflow above 1353 if (!repaintRect.isEmpty()) { 1354 repaintRectangle(repaintRect); // We need to do a partial repaint of our content. 1355 if (hasReflection()) 1356 repaintRectangle(reflectedRect(repaintRect)); 1357 } 1358 } 1359 setNeedsLayout(false); 1360} 1361 1362void RenderBlock::addOverflowFromChildren() 1363{ 1364 if (!hasColumns()) { 1365 if (childrenInline()) 1366 addOverflowFromInlineChildren(); 1367 else 1368 addOverflowFromBlockChildren(); 1369 } else { 1370 ColumnInfo* colInfo = columnInfo(); 1371 if (columnCount(colInfo)) { 1372 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); 1373 if (isHorizontalWritingMode()) { 1374 int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0; 1375 int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0; 1376 int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight(); 1377 addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight)); 1378 if (!hasOverflowClip()) 1379 addVisualOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight)); 1380 } else { 1381 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1); 1382 int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0; 1383 int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0; 1384 int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight(); 1385 addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop)); 1386 if (!hasOverflowClip()) 1387 addVisualOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop)); 1388 } 1389 } 1390 } 1391} 1392 1393void RenderBlock::computeOverflow(int oldClientAfterEdge, bool recomputeFloats) 1394{ 1395 // Add overflow from children. 1396 addOverflowFromChildren(); 1397 1398 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer())) 1399 addOverflowFromFloats(); 1400 1401 // Add in the overflow from positioned objects. 1402 addOverflowFromPositionedObjects(); 1403 1404 if (hasOverflowClip()) { 1405 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins 1406 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always 1407 // be considered reachable. 1408 IntRect clientRect(clientBoxRect()); 1409 IntRect rectToApply; 1410 if (isHorizontalWritingMode()) 1411 rectToApply = IntRect(clientRect.x(), clientRect.y(), 1, max(0, oldClientAfterEdge - clientRect.y())); 1412 else 1413 rectToApply = IntRect(clientRect.x(), clientRect.y(), max(0, oldClientAfterEdge - clientRect.x()), 1); 1414 addLayoutOverflow(rectToApply); 1415 } 1416 1417 // Add visual overflow from box-shadow and reflections. 1418 addShadowOverflow(); 1419} 1420 1421void RenderBlock::addOverflowFromBlockChildren() 1422{ 1423 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 1424 if (!child->isFloatingOrPositioned()) 1425 addOverflowFromChild(child); 1426 } 1427} 1428 1429void RenderBlock::addOverflowFromFloats() 1430{ 1431 if (!m_floatingObjects) 1432 return; 1433 1434 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 1435 FloatingObjectSetIterator end = floatingObjectSet.end(); 1436 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 1437 FloatingObject* r = *it; 1438 if (r->m_isDescendant) 1439 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); 1440 } 1441 return; 1442} 1443 1444void RenderBlock::addOverflowFromPositionedObjects() 1445{ 1446 if (!m_positionedObjects) 1447 return; 1448 1449 RenderBox* positionedObject; 1450 Iterator end = m_positionedObjects->end(); 1451 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 1452 positionedObject = *it; 1453 1454 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content. 1455 if (positionedObject->style()->position() != FixedPosition) 1456 addOverflowFromChild(positionedObject); 1457 } 1458} 1459 1460bool RenderBlock::expandsToEncloseOverhangingFloats() const 1461{ 1462 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) 1463 || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot(); 1464} 1465 1466void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo) 1467{ 1468 bool isHorizontal = isHorizontalWritingMode(); 1469 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal); 1470 RenderLayer* childLayer = child->layer(); 1471 1472 childLayer->setStaticInlinePosition(borderAndPaddingStart()); 1473 1474 int logicalTop = logicalHeight(); 1475 if (!marginInfo.canCollapseWithMarginBefore()) { 1476 child->computeBlockDirectionMargins(this); 1477 int marginBefore = marginBeforeForChild(child); 1478 int collapsedBeforePos = marginInfo.positiveMargin(); 1479 int collapsedBeforeNeg = marginInfo.negativeMargin(); 1480 if (marginBefore > 0) { 1481 if (marginBefore > collapsedBeforePos) 1482 collapsedBeforePos = marginBefore; 1483 } else { 1484 if (-marginBefore > collapsedBeforeNeg) 1485 collapsedBeforeNeg = -marginBefore; 1486 } 1487 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore; 1488 } 1489 if (childLayer->staticBlockPosition() != logicalTop) { 1490 childLayer->setStaticBlockPosition(logicalTop); 1491 if (hasStaticBlockPosition) 1492 child->setChildNeedsLayout(true, false); 1493 } 1494} 1495 1496void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo) 1497{ 1498 // The float should be positioned taking into account the bottom margin 1499 // of the previous flow. We add that margin into the height, get the 1500 // float positioned properly, and then subtract the margin out of the 1501 // height again. In the case of self-collapsing blocks, we always just 1502 // use the top margins, since the self-collapsing block collapsed its 1503 // own bottom margin into its top margin. 1504 // 1505 // Note also that the previous flow may collapse its margin into the top of 1506 // our block. If this is the case, then we do not add the margin in to our 1507 // height when computing the position of the float. This condition can be tested 1508 // for by simply calling canCollapseWithMarginBefore. See 1509 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for 1510 // an example of this scenario. 1511 int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin(); 1512 setLogicalHeight(logicalHeight() + marginOffset); 1513 positionNewFloats(); 1514 setLogicalHeight(logicalHeight() - marginOffset); 1515} 1516 1517bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo) 1518{ 1519 // Handle in the given order 1520 return handlePositionedChild(child, marginInfo) 1521 || handleFloatingChild(child, marginInfo) 1522 || handleRunInChild(child); 1523} 1524 1525 1526bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo) 1527{ 1528 if (child->isPositioned()) { 1529 child->containingBlock()->insertPositionedObject(child); 1530 adjustPositionedBlock(child, marginInfo); 1531 return true; 1532 } 1533 return false; 1534} 1535 1536bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo) 1537{ 1538 if (child->isFloating()) { 1539 insertFloatingObject(child); 1540 adjustFloatingBlock(marginInfo); 1541 return true; 1542 } 1543 return false; 1544} 1545 1546bool RenderBlock::handleRunInChild(RenderBox* child) 1547{ 1548 // See if we have a run-in element with inline children. If the 1549 // children aren't inline, then just treat the run-in as a normal 1550 // block. 1551 if (!child->isRunIn() || !child->childrenInline()) 1552 return false; 1553 // FIXME: We don't handle non-block elements with run-in for now. 1554 if (!child->isRenderBlock()) 1555 return false; 1556 1557 RenderBlock* blockRunIn = toRenderBlock(child); 1558 RenderObject* curr = blockRunIn->nextSibling(); 1559 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned()) 1560 return false; 1561 1562 RenderBlock* currBlock = toRenderBlock(curr); 1563 1564 // First we destroy any :before/:after content. It will be regenerated by the new inline. 1565 // Exception is if the run-in itself is generated. 1566 if (child->style()->styleType() != BEFORE && child->style()->styleType() != AFTER) { 1567 RenderObject* generatedContent; 1568 if (child->getCachedPseudoStyle(BEFORE) && (generatedContent = child->beforePseudoElementRenderer())) 1569 generatedContent->destroy(); 1570 if (child->getCachedPseudoStyle(AFTER) && (generatedContent = child->afterPseudoElementRenderer())) 1571 generatedContent->destroy(); 1572 } 1573 1574 // Remove the old child. 1575 children()->removeChildNode(this, blockRunIn); 1576 1577 // Create an inline. 1578 Node* runInNode = blockRunIn->node(); 1579 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document()); 1580 inlineRunIn->setStyle(blockRunIn->style()); 1581 1582 // Move the nodes from the old child to the new child 1583 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) { 1584 RenderObject* nextSibling = runInChild->nextSibling(); 1585 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false); 1586 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content. 1587 runInChild = nextSibling; 1588 } 1589 1590 // 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 1591 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228. 1592 currBlock->addChild(inlineRunIn, currBlock->firstChild()); 1593 1594 // If the run-in had an element, we need to set the new renderer. 1595 if (runInNode) 1596 runInNode->setRenderer(inlineRunIn); 1597 1598 // Destroy the block run-in, which includes deleting its line box tree. 1599 blockRunIn->deleteLineBoxTree(); 1600 blockRunIn->destroy(); 1601 1602 // The block acts like an inline, so just null out its 1603 // position. 1604 1605 return true; 1606} 1607 1608int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo) 1609{ 1610 // Get the four margin values for the child and cache them. 1611 const MarginValues childMargins = marginValuesForChild(child); 1612 1613 // Get our max pos and neg top margins. 1614 int posTop = childMargins.positiveMarginBefore(); 1615 int negTop = childMargins.negativeMarginBefore(); 1616 1617 // For self-collapsing blocks, collapse our bottom margins into our 1618 // top to get new posTop and negTop values. 1619 if (child->isSelfCollapsingBlock()) { 1620 posTop = max(posTop, childMargins.positiveMarginAfter()); 1621 negTop = max(negTop, childMargins.negativeMarginAfter()); 1622 } 1623 1624 // See if the top margin is quirky. We only care if this child has 1625 // margins that will collapse with us. 1626 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD; 1627 1628 if (marginInfo.canCollapseWithMarginBefore()) { 1629 // This child is collapsing with the top of the 1630 // block. If it has larger margin values, then we need to update 1631 // our own maximal values. 1632 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk) 1633 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore())); 1634 1635 // The minute any of the margins involved isn't a quirk, don't 1636 // collapse it away, even if the margin is smaller (www.webreference.com 1637 // has an example of this, a <dt> with 0.8em author-specified inside 1638 // a <dl> inside a <td>. 1639 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) { 1640 setMarginBeforeQuirk(false); 1641 marginInfo.setDeterminedMarginBeforeQuirk(true); 1642 } 1643 1644 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore()) 1645 // We have no top margin and our top child has a quirky margin. 1646 // We will pick up this quirky margin and pass it through. 1647 // This deals with the <td><div><p> case. 1648 // Don't do this for a block that split two inlines though. You do 1649 // still apply margins in this case. 1650 setMarginBeforeQuirk(true); 1651 } 1652 1653 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop)) 1654 marginInfo.setMarginBeforeQuirk(topQuirk); 1655 1656 int beforeCollapseLogicalTop = logicalHeight(); 1657 int logicalTop = beforeCollapseLogicalTop; 1658 if (child->isSelfCollapsingBlock()) { 1659 // This child has no height. We need to compute our 1660 // position before we collapse the child's margins together, 1661 // so that we can get an accurate position for the zero-height block. 1662 int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore()); 1663 int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore()); 1664 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg); 1665 1666 // Now collapse the child's margins together, which means examining our 1667 // bottom margin values as well. 1668 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter()); 1669 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter()); 1670 1671 if (!marginInfo.canCollapseWithMarginBefore()) 1672 // We need to make sure that the position of the self-collapsing block 1673 // is correct, since it could have overflowing content 1674 // that needs to be positioned correctly (e.g., a block that 1675 // had a specified height of 0 but that actually had subcontent). 1676 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg; 1677 } 1678 else { 1679 if (child->style()->marginBeforeCollapse() == MSEPARATE) { 1680 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child)); 1681 logicalTop = logicalHeight(); 1682 } 1683 else if (!marginInfo.atBeforeSideOfBlock() || 1684 (!marginInfo.canCollapseMarginBeforeWithChildren() 1685 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) { 1686 // We're collapsing with a previous sibling's margins and not 1687 // with the top of the block. 1688 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop)); 1689 logicalTop = logicalHeight(); 1690 } 1691 1692 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); 1693 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); 1694 1695 if (marginInfo.margin()) 1696 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD); 1697 } 1698 1699 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins 1700 // collapsed into the page edge. 1701 bool paginated = view()->layoutState()->isPaginated(); 1702 if (paginated && logicalTop > beforeCollapseLogicalTop) { 1703 int oldLogicalTop = logicalTop; 1704 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop)); 1705 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop)); 1706 } 1707 return logicalTop; 1708} 1709 1710int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos) 1711{ 1712 int heightIncrease = getClearDelta(child, yPos); 1713 if (!heightIncrease) 1714 return yPos; 1715 1716 if (child->isSelfCollapsingBlock()) { 1717 // For self-collapsing blocks that clear, they can still collapse their 1718 // margins with following siblings. Reset the current margins to represent 1719 // the self-collapsing block's margins only. 1720 // CSS2.1 states: 1721 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin. 1722 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the 1723 // self-collapsing block's bottom margin. 1724 bool atBottomOfBlock = true; 1725 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) { 1726 if (!curr->isFloatingOrPositioned()) 1727 atBottomOfBlock = false; 1728 } 1729 1730 MarginValues childMargins = marginValuesForChild(child); 1731 if (atBottomOfBlock) { 1732 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter()); 1733 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter()); 1734 } else { 1735 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter())); 1736 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter())); 1737 } 1738 1739 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom 1740 // of the parent block). 1741 setLogicalHeight(child->y() - max(0, marginInfo.margin())); 1742 } else 1743 // Increase our height by the amount we had to clear. 1744 setLogicalHeight(height() + heightIncrease); 1745 1746 if (marginInfo.canCollapseWithMarginBefore()) { 1747 // We can no longer collapse with the top of the block since a clear 1748 // occurred. The empty blocks collapse into the cleared block. 1749 // FIXME: This isn't quite correct. Need clarification for what to do 1750 // if the height the cleared block is offset by is smaller than the 1751 // margins involved. 1752 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin); 1753 marginInfo.setAtBeforeSideOfBlock(false); 1754 } 1755 1756 return yPos + heightIncrease; 1757} 1758 1759int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo) 1760{ 1761 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological 1762 // relayout if there are intruding floats. 1763 int logicalTopEstimate = logicalHeight(); 1764 if (!marginInfo.canCollapseWithMarginBefore()) { 1765 int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child); 1766 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore); 1767 } 1768 1769 bool paginated = view()->layoutState()->isPaginated(); 1770 1771 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current 1772 // page. 1773 if (paginated && logicalTopEstimate > logicalHeight()) 1774 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight())); 1775 1776 logicalTopEstimate += getClearDelta(child, logicalTopEstimate); 1777 1778 if (paginated) { 1779 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 1780 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate); 1781 1782 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 1783 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate); 1784 1785 if (!child->selfNeedsLayout() && child->isRenderBlock()) 1786 logicalTopEstimate += toRenderBlock(child)->paginationStrut(); 1787 } 1788 1789 return logicalTopEstimate; 1790} 1791 1792void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child) 1793{ 1794 int startPosition = borderStart() + paddingStart(); 1795 int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth(); 1796 1797 // Add in our start margin. 1798 int childMarginStart = marginStartForChild(child); 1799 int newPosition = startPosition + childMarginStart; 1800 1801 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need 1802 // to shift over as necessary to dodge any floats that might get in the way. 1803 if (child->avoidsFloats()) { 1804 int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false); 1805 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) { 1806 if (childMarginStart < 0) 1807 startOff += childMarginStart; 1808 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit. 1809 } else if (startOff != startPosition) { 1810 // The object is shifting to the "end" side of the block. The object might be centered, so we need to 1811 // recalculate our inline direction margins. Note that the containing block content 1812 // width computation will take into account the delta between |startOff| and |startPosition| 1813 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection| 1814 // function. 1815 child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child)); 1816 newPosition = startOff + marginStartForChild(child); 1817 } 1818 } 1819 1820 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta); 1821} 1822 1823void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo) 1824{ 1825 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) { 1826 // Update our max pos/neg bottom margins, since we collapsed our bottom margins 1827 // with our children. 1828 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin())); 1829 1830 if (!marginInfo.marginAfterQuirk()) 1831 setMarginAfterQuirk(false); 1832 1833 if (marginInfo.marginAfterQuirk() && marginAfter() == 0) 1834 // We have no bottom margin and our last child has a quirky margin. 1835 // We will pick up this quirky margin and pass it through. 1836 // This deals with the <td><div><p> case. 1837 setMarginAfterQuirk(true); 1838 } 1839} 1840 1841void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo) 1842{ 1843 marginInfo.setAtAfterSideOfBlock(true); 1844 1845 // If we can't collapse with children then go ahead and add in the bottom margin. 1846 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore() 1847 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk())) 1848 setLogicalHeight(logicalHeight() + marginInfo.margin()); 1849 1850 // Now add in our bottom border/padding. 1851 setLogicalHeight(logicalHeight() + afterSide); 1852 1853 // Negative margins can cause our height to shrink below our minimal height (border/padding). 1854 // If this happens, ensure that the computed height is increased to the minimal height. 1855 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide)); 1856 1857 // Update our bottom collapsed margin info. 1858 setCollapsedBottomMargin(marginInfo); 1859} 1860 1861void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta) 1862{ 1863 if (isHorizontalWritingMode()) { 1864 if (applyDelta == ApplyLayoutDelta) 1865 view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0)); 1866 child->setX(logicalLeft); 1867 } else { 1868 if (applyDelta == ApplyLayoutDelta) 1869 view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft)); 1870 child->setY(logicalLeft); 1871 } 1872} 1873 1874void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta) 1875{ 1876 if (isHorizontalWritingMode()) { 1877 if (applyDelta == ApplyLayoutDelta) 1878 view()->addLayoutDelta(IntSize(0, child->y() - logicalTop)); 1879 child->setY(logicalTop); 1880 } else { 1881 if (applyDelta == ApplyLayoutDelta) 1882 view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0)); 1883 child->setX(logicalTop); 1884 } 1885} 1886 1887void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom) 1888{ 1889 if (gPercentHeightDescendantsMap) { 1890 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) { 1891 HashSet<RenderBox*>::iterator end = descendants->end(); 1892 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) { 1893 RenderBox* box = *it; 1894 while (box != this) { 1895 if (box->normalChildNeedsLayout()) 1896 break; 1897 box->setChildNeedsLayout(true, false); 1898 box = box->containingBlock(); 1899 ASSERT(box); 1900 if (!box) 1901 break; 1902 } 1903 } 1904 } 1905 } 1906 1907 int beforeEdge = borderBefore() + paddingBefore(); 1908 int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 1909 1910 setLogicalHeight(beforeEdge); 1911 1912 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts, 1913 MarginInfo marginInfo(this, beforeEdge, afterEdge); 1914 1915 // Fieldsets need to find their legend and position it inside the border of the object. 1916 // The legend then gets skipped during normal layout. The same is true for ruby text. 1917 // It doesn't get included in the normal layout process but is instead skipped. 1918 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren); 1919 1920 int previousFloatLogicalBottom = 0; 1921 maxFloatLogicalBottom = 0; 1922 1923 RenderBox* next = firstChildBox(); 1924 1925 while (next) { 1926 RenderBox* child = next; 1927 next = child->nextSiblingBox(); 1928 1929 if (childToExclude == child) 1930 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs). 1931 1932 // Make sure we layout children if they need it. 1933 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into 1934 // an auto value. Add a method to determine this, so that we can avoid the relayout. 1935 if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView())) 1936 child->setChildNeedsLayout(true, false); 1937 1938 // If relayoutChildren is set and the child has percentage padding, we also need to invalidate the child's pref widths. 1939 if (relayoutChildren && (child->style()->paddingStart().isPercent() || child->style()->paddingEnd().isPercent())) 1940 child->setPreferredLogicalWidthsDirty(true, false); 1941 1942 // Handle the four types of special elements first. These include positioned content, floating content, compacts and 1943 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks. 1944 if (handleSpecialChild(child, marginInfo)) 1945 continue; 1946 1947 // Lay out the child. 1948 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom); 1949 } 1950 1951 // Now do the handling of the bottom of the block, adding in our bottom border/padding and 1952 // determining the correct collapsed bottom margin information. 1953 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo); 1954} 1955 1956void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom) 1957{ 1958 int oldPosMarginBefore = maxPositiveMarginBefore(); 1959 int oldNegMarginBefore = maxNegativeMarginBefore(); 1960 1961 // The child is a normal flow object. Compute the margins we will use for collapsing now. 1962 child->computeBlockDirectionMargins(this); 1963 1964 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE. 1965 if (child->style()->marginBeforeCollapse() == MSEPARATE) { 1966 marginInfo.setAtBeforeSideOfBlock(false); 1967 marginInfo.clearMargin(); 1968 } 1969 1970 // Try to guess our correct logical top position. In most cases this guess will 1971 // be correct. Only if we're wrong (when we compute the real logical top position) 1972 // will we have to potentially relayout. 1973 int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo); 1974 1975 // Cache our old rect so that we can dirty the proper repaint rects if the child moves. 1976 IntRect oldRect(child->x(), child->y() , child->width(), child->height()); 1977 int oldLogicalTop = logicalTopForChild(child); 1978 1979#ifndef NDEBUG 1980 IntSize oldLayoutDelta = view()->layoutDelta(); 1981#endif 1982 // Go ahead and position the child as though it didn't collapse with the top. 1983 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta); 1984 1985 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; 1986 bool markDescendantsWithFloats = false; 1987 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats()) 1988 markDescendantsWithFloats = true; 1989 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) { 1990 // If an element might be affected by the presence of floats, then always mark it for 1991 // layout. 1992 int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom()); 1993 if (fb > logicalTopEstimate) 1994 markDescendantsWithFloats = true; 1995 } 1996 1997 if (childRenderBlock) { 1998 if (markDescendantsWithFloats) 1999 childRenderBlock->markAllDescendantsWithFloatsForLayout(); 2000 if (!child->isWritingModeRoot()) 2001 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom()); 2002 } 2003 2004 if (!child->needsLayout()) 2005 child->markForPaginationRelayoutIfNeeded(); 2006 2007 bool childHadLayout = child->m_everHadLayout; 2008 bool childNeededLayout = child->needsLayout(); 2009 if (childNeededLayout) 2010 child->layout(); 2011 2012 // Cache if we are at the top of the block right now. 2013 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock(); 2014 2015 // Now determine the correct ypos based off examination of collapsing margin 2016 // values. 2017 int logicalTopBeforeClear = collapseMargins(child, marginInfo); 2018 2019 // Now check for clear. 2020 int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear); 2021 2022 bool paginated = view()->layoutState()->isPaginated(); 2023 if (paginated) { 2024 int oldTop = logicalTopAfterClear; 2025 2026 // If the object has a page or column break value of "before", then we should shift to the top of the next page. 2027 logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear); 2028 2029 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one. 2030 int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear; 2031 int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear); 2032 2033 int paginationStrut = 0; 2034 int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment; 2035 if (unsplittableAdjustmentDelta) 2036 paginationStrut = unsplittableAdjustmentDelta; 2037 else if (childRenderBlock && childRenderBlock->paginationStrut()) 2038 paginationStrut = childRenderBlock->paginationStrut(); 2039 2040 if (paginationStrut) { 2041 // We are willing to propagate out to our parent block as long as we were at the top of the block prior 2042 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination. 2043 if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) { 2044 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't 2045 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too 2046 // and pushes to the next page anyway, so not too concerned about it. 2047 setPaginationStrut(logicalTopAfterClear + paginationStrut); 2048 if (childRenderBlock) 2049 childRenderBlock->setPaginationStrut(0); 2050 } else 2051 logicalTopAfterClear += paginationStrut; 2052 } 2053 2054 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child. 2055 setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop)); 2056 } 2057 2058 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta); 2059 2060 // Now we have a final top position. See if it really does end up being different from our estimate. 2061 if (logicalTopAfterClear != logicalTopEstimate) { 2062 if (child->shrinkToAvoidFloats()) { 2063 // The child's width depends on the line width. 2064 // When the child shifts to clear an item, its width can 2065 // change (because it has more available line width). 2066 // So go ahead and mark the item as dirty. 2067 child->setChildNeedsLayout(true, false); 2068 } 2069 if (childRenderBlock) { 2070 if (!child->avoidsFloats() && childRenderBlock->containsFloats()) 2071 childRenderBlock->markAllDescendantsWithFloatsForLayout(); 2072 if (!child->needsLayout()) 2073 child->markForPaginationRelayoutIfNeeded(); 2074 } 2075 2076 // Our guess was wrong. Make the child lay itself out again. 2077 child->layoutIfNeeded(); 2078 } 2079 2080 // We are no longer at the top of the block if we encounter a non-empty child. 2081 // This has to be done after checking for clear, so that margins can be reset if a clear occurred. 2082 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock()) 2083 marginInfo.setAtBeforeSideOfBlock(false); 2084 2085 // Now place the child in the correct left position 2086 determineLogicalLeftPositionForChild(child); 2087 2088 // Update our height now that the child has been placed in the correct position. 2089 setLogicalHeight(logicalHeight() + logicalHeightForChild(child)); 2090 if (child->style()->marginAfterCollapse() == MSEPARATE) { 2091 setLogicalHeight(logicalHeight() + marginAfterForChild(child)); 2092 marginInfo.clearMargin(); 2093 } 2094 // If the child has overhanging floats that intrude into following siblings (or possibly out 2095 // of this block), then the parent gets notified of the floats now. 2096 if (childRenderBlock && childRenderBlock->containsFloats()) 2097 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout)); 2098 2099 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y()); 2100 if (childOffset.width() || childOffset.height()) { 2101 view()->addLayoutDelta(childOffset); 2102 2103 // If the child moved, we have to repaint it as well as any floating/positioned 2104 // descendants. An exception is if we need a layout. In this case, we know we're going to 2105 // repaint ourselves (and the child) anyway. 2106 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout()) 2107 child->repaintDuringLayoutIfMoved(oldRect); 2108 } 2109 2110 if (!childHadLayout && child->checkForRepaintDuringLayout()) { 2111 child->repaint(); 2112 child->repaintOverhangingFloats(true); 2113 } 2114 2115 if (paginated) { 2116 // Check for an after page/column break. 2117 int newHeight = applyAfterBreak(child, logicalHeight(), marginInfo); 2118 if (newHeight != height()) 2119 setLogicalHeight(newHeight); 2120 } 2121 2122 ASSERT(oldLayoutDelta == view()->layoutDelta()); 2123} 2124 2125void RenderBlock::simplifiedNormalFlowLayout() 2126{ 2127 if (childrenInline()) { 2128 ListHashSet<RootInlineBox*> lineBoxes; 2129 bool endOfInline = false; 2130 RenderObject* o = bidiFirst(this, 0, false); 2131 while (o) { 2132 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) { 2133 o->layoutIfNeeded(); 2134 if (toRenderBox(o)->inlineBoxWrapper()) { 2135 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root(); 2136 lineBoxes.add(box); 2137 } 2138 } else if (o->isText() || (o->isRenderInline() && !endOfInline)) 2139 o->setNeedsLayout(false); 2140 o = bidiNext(this, o, 0, false, &endOfInline); 2141 } 2142 2143 // FIXME: Glyph overflow will get lost in this case, but not really a big deal. 2144 GlyphOverflowAndFallbackFontsMap textBoxDataMap; 2145 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) { 2146 RootInlineBox* box = *it; 2147 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap); 2148 } 2149 } else { 2150 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) { 2151 if (!box->isPositioned()) 2152 box->layoutIfNeeded(); 2153 } 2154 } 2155} 2156 2157bool RenderBlock::simplifiedLayout() 2158{ 2159 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout()) 2160 return false; 2161 2162 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode()); 2163 2164 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly()) 2165 return false; 2166 2167 // Lay out positioned descendants or objects that just need to recompute overflow. 2168 if (needsSimplifiedNormalFlowLayout()) 2169 simplifiedNormalFlowLayout(); 2170 2171 // Lay out our positioned objects if our positioned child bit is set. 2172 if (posChildNeedsLayout()) 2173 layoutPositionedObjects(false); 2174 2175 // Recompute our overflow information. 2176 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only 2177 // updating our overflow if we either used to have overflow or if the new temporary object has overflow. 2178 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and 2179 // lowestPosition on every relayout so it's not a regression. 2180 m_overflow.clear(); 2181 computeOverflow(clientLogicalBottom(), true); 2182 2183 statePusher.pop(); 2184 2185 updateLayerTransform(); 2186 2187 updateScrollInfoAfterLayout(); 2188 2189 setNeedsLayout(false); 2190 return true; 2191} 2192 2193void RenderBlock::layoutPositionedObjects(bool relayoutChildren) 2194{ 2195 if (!m_positionedObjects) 2196 return; 2197 2198 if (hasColumns()) 2199 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns. 2200 2201 RenderBox* r; 2202 Iterator end = m_positionedObjects->end(); 2203 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2204 r = *it; 2205 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the 2206 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned 2207 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is 2208 // positioned explicitly) this should not incur a performance penalty. 2209 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow())) 2210 r->setChildNeedsLayout(true, false); 2211 2212 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths. 2213 if (relayoutChildren && (r->style()->paddingStart().isPercent() || r->style()->paddingEnd().isPercent())) 2214 r->setPreferredLogicalWidthsDirty(true, false); 2215 2216 if (!r->needsLayout()) 2217 r->markForPaginationRelayoutIfNeeded(); 2218 2219 // 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 2220 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout. 2221 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly()) 2222 r->setNeedsLayout(false); 2223 r->layoutIfNeeded(); 2224 } 2225 2226 if (hasColumns()) 2227 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work. 2228} 2229 2230void RenderBlock::markPositionedObjectsForLayout() 2231{ 2232 if (m_positionedObjects) { 2233 RenderBox* r; 2234 Iterator end = m_positionedObjects->end(); 2235 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 2236 r = *it; 2237 r->setChildNeedsLayout(true); 2238 } 2239 } 2240} 2241 2242void RenderBlock::markForPaginationRelayoutIfNeeded() 2243{ 2244 ASSERT(!needsLayout()); 2245 if (needsLayout()) 2246 return; 2247 2248 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset())) 2249 setChildNeedsLayout(true, false); 2250} 2251 2252void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants) 2253{ 2254 // Repaint any overhanging floats (if we know we're the one to paint them). 2255 // Otherwise, bail out. 2256 if (!hasOverhangingFloats()) 2257 return; 2258 2259 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating 2260 // in this block. Better yet would be to push extra state for the containers of other floats. 2261 view()->disableLayoutState(); 2262 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2263 FloatingObjectSetIterator end = floatingObjectSet.end(); 2264 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2265 FloatingObject* r = *it; 2266 // Only repaint the object if it is overhanging, is not in its own layer, and 2267 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter 2268 // condition is replaced with being a descendant of us. 2269 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) { 2270 r->m_renderer->repaint(); 2271 r->m_renderer->repaintOverhangingFloats(); 2272 } 2273 } 2274 view()->enableLayoutState(); 2275} 2276 2277void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty) 2278{ 2279 tx += x(); 2280 ty += y(); 2281 2282 PaintPhase phase = paintInfo.phase; 2283 2284 // Check if we need to do anything at all. 2285 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView 2286 // paints the root's background. 2287 if (!isRoot()) { 2288 IntRect overflowBox = visualOverflowRect(); 2289 flipForWritingMode(overflowBox); 2290 overflowBox.inflate(maximalOutlineSize(paintInfo.phase)); 2291 overflowBox.move(tx, ty); 2292 if (!overflowBox.intersects(paintInfo.rect)) 2293 return; 2294 } 2295 2296 bool pushedClip = pushContentsClip(paintInfo, tx, ty); 2297 paintObject(paintInfo, tx, ty); 2298 if (pushedClip) 2299 popContentsClip(paintInfo, phase, tx, ty); 2300 2301 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with 2302 // z-index. We paint after we painted the background/border, so that the scrollbars will 2303 // sit above the background/border. 2304 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this)) 2305 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect); 2306} 2307 2308void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty) 2309{ 2310 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor); 2311 bool ruleTransparent = style()->columnRuleIsTransparent(); 2312 EBorderStyle ruleStyle = style()->columnRuleStyle(); 2313 int ruleWidth = style()->columnRuleWidth(); 2314 int colGap = columnGap(); 2315 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap; 2316 if (!renderRule) 2317 return; 2318 2319 // We need to do multiple passes, breaking up our child painting into strips. 2320 ColumnInfo* colInfo = columnInfo(); 2321 unsigned colCount = columnCount(colInfo); 2322 int currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth(); 2323 int ruleAdd = logicalLeftOffsetForContent(); 2324 int ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth(); 2325 for (unsigned i = 0; i < colCount; i++) { 2326 IntRect colRect = columnRectAt(colInfo, i); 2327 2328 int inlineDirectionSize = isHorizontalWritingMode() ? colRect.width() : colRect.height(); 2329 2330 // Move to the next position. 2331 if (style()->isLeftToRightDirection()) { 2332 ruleLogicalLeft += inlineDirectionSize + colGap / 2; 2333 currLogicalLeftOffset += inlineDirectionSize + colGap; 2334 } else { 2335 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2); 2336 currLogicalLeftOffset -= (inlineDirectionSize + colGap); 2337 } 2338 2339 // Now paint the column rule. 2340 if (i < colCount - 1) { 2341 int ruleLeft = isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore(); 2342 int ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth(); 2343 int ruleTop = isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd; 2344 int ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth; 2345 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom, 2346 style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0); 2347 } 2348 2349 ruleLogicalLeft = currLogicalLeftOffset; 2350 } 2351} 2352 2353void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats) 2354{ 2355 // We need to do multiple passes, breaking up our child painting into strips. 2356 GraphicsContext* context = paintInfo.context; 2357 ColumnInfo* colInfo = columnInfo(); 2358 unsigned colCount = columnCount(colInfo); 2359 if (!colCount) 2360 return; 2361 int currLogicalTopOffset = 0; 2362 for (unsigned i = 0; i < colCount; i++) { 2363 // For each rect, we clip to the rect, and then we adjust our coords. 2364 IntRect colRect = columnRectAt(colInfo, i); 2365 flipForWritingMode(colRect); 2366 int logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent(); 2367 IntSize offset = isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset); 2368 colRect.move(tx, ty); 2369 PaintInfo info(paintInfo); 2370 info.rect.intersect(colRect); 2371 2372 if (!info.rect.isEmpty()) { 2373 context->save(); 2374 2375 // Each strip pushes a clip, since column boxes are specified as being 2376 // like overflow:hidden. 2377 context->clip(colRect); 2378 2379 // Adjust our x and y when painting. 2380 int finalX = tx + offset.width(); 2381 int finalY = ty + offset.height(); 2382 if (paintingFloats) 2383 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip); 2384 else 2385 paintContents(info, finalX, finalY); 2386 2387 context->restore(); 2388 } 2389 2390 int blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width()); 2391 if (style()->isFlippedBlocksWritingMode()) 2392 currLogicalTopOffset += blockDelta; 2393 else 2394 currLogicalTopOffset -= blockDelta; 2395 } 2396} 2397 2398void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty) 2399{ 2400 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC. 2401 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document 2402 // will do a full repaint(). 2403 if (document()->didLayoutWithPendingStylesheets() && !isRenderView()) 2404 return; 2405 2406 if (childrenInline()) 2407 m_lineBoxes.paint(this, paintInfo, tx, ty); 2408 else 2409 paintChildren(paintInfo, tx, ty); 2410} 2411 2412void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty) 2413{ 2414 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase; 2415 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase; 2416 2417 // We don't paint our own background, but we do let the kids paint their backgrounds. 2418 PaintInfo info(paintInfo); 2419 info.phase = newPhase; 2420 info.updatePaintingRootForChildren(this); 2421 2422 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit 2423 // NSViews. Do not add any more code for this. 2424 RenderView* renderView = view(); 2425 bool usePrintRect = !renderView->printRect().isEmpty(); 2426 2427 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) { 2428 // Check for page-break-before: always, and if it's set, break and bail. 2429 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS); 2430 if (checkBeforeAlways 2431 && (ty + child->y()) > paintInfo.rect.y() 2432 && (ty + child->y()) < paintInfo.rect.maxY()) { 2433 view()->setBestTruncatedAt(ty + child->y(), this, true); 2434 return; 2435 } 2436 2437 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) { 2438 // Paginate block-level replaced elements. 2439 if (ty + child->y() + child->height() > renderView->printRect().maxY()) { 2440 if (ty + child->y() < renderView->truncatedAt()) 2441 renderView->setBestTruncatedAt(ty + child->y(), child); 2442 // If we were able to truncate, don't paint. 2443 if (ty + child->y() >= renderView->truncatedAt()) 2444 break; 2445 } 2446 } 2447 2448 IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment); 2449 if (!child->hasSelfPaintingLayer() && !child->isFloating()) 2450 child->paint(info, childPoint.x(), childPoint.y()); 2451 2452 // Check for page-break-after: always, and if it's set, break and bail. 2453 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS); 2454 if (checkAfterAlways 2455 && (ty + child->y() + child->height()) > paintInfo.rect.y() 2456 && (ty + child->y() + child->height()) < paintInfo.rect.maxY()) { 2457 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginAfter()), this, true); 2458 return; 2459 } 2460 } 2461} 2462 2463void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type) 2464{ 2465 SelectionController* selection = type == CursorCaret ? frame()->selection() : frame()->page()->dragCaretController(); 2466 2467 // Paint the caret if the SelectionController says so or if caret browsing is enabled 2468 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled(); 2469 RenderObject* caretPainter = selection->caretRenderer(); 2470 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) { 2471 // Convert the painting offset into the local coordinate system of this renderer, 2472 // to match the localCaretRect computed by the SelectionController 2473 offsetForContents(tx, ty); 2474 2475 if (type == CursorCaret) 2476 frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect); 2477 else 2478 frame()->selection()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect); 2479 } 2480} 2481 2482void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty) 2483{ 2484 PaintPhase paintPhase = paintInfo.phase; 2485 2486 // 1. paint background, borders etc 2487 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) { 2488 if (hasBoxDecorations()) 2489 paintBoxDecorations(paintInfo, tx, ty); 2490 if (hasColumns()) 2491 paintColumnRules(paintInfo, tx, ty); 2492 } 2493 2494 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) { 2495 paintMask(paintInfo, tx, ty); 2496 return; 2497 } 2498 2499 // We're done. We don't bother painting any children. 2500 if (paintPhase == PaintPhaseBlockBackground) 2501 return; 2502 2503 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div). 2504 int scrolledX = tx; 2505 int scrolledY = ty; 2506 if (hasOverflowClip()) { 2507 IntSize offset = layer()->scrolledContentOffset(); 2508 scrolledX -= offset.width(); 2509 scrolledY -= offset.height(); 2510 } 2511 2512 // 2. paint contents 2513 if (paintPhase != PaintPhaseSelfOutline) { 2514 if (hasColumns()) 2515 paintColumnContents(paintInfo, scrolledX, scrolledY); 2516 else 2517 paintContents(paintInfo, scrolledX, scrolledY); 2518 } 2519 2520 // 3. paint selection 2521 // FIXME: Make this work with multi column layouts. For now don't fill gaps. 2522 bool isPrinting = document()->printing(); 2523 if (!isPrinting && !hasColumns()) 2524 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks. 2525 2526 // 4. paint floats. 2527 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) { 2528 if (hasColumns()) 2529 paintColumnContents(paintInfo, scrolledX, scrolledY, true); 2530 else 2531 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip); 2532 } 2533 2534 // 5. paint outline. 2535 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE) 2536 paintOutline(paintInfo.context, tx, ty, width(), height()); 2537 2538 // 6. paint continuation outlines. 2539 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) { 2540 RenderInline* inlineCont = inlineElementContinuation(); 2541 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) { 2542 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer()); 2543 RenderBlock* cb = containingBlock(); 2544 2545 bool inlineEnclosedInSelfPaintingLayer = false; 2546 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) { 2547 if (box->hasSelfPaintingLayer()) { 2548 inlineEnclosedInSelfPaintingLayer = true; 2549 break; 2550 } 2551 } 2552 2553 if (!inlineEnclosedInSelfPaintingLayer) 2554 cb->addContinuationWithOutline(inlineRenderer); 2555 else if (!inlineRenderer->firstLineBox()) 2556 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(), 2557 ty - y() + inlineRenderer->containingBlock()->y()); 2558 } 2559 paintContinuationOutlines(paintInfo, tx, ty); 2560 } 2561 2562 // 7. paint caret. 2563 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground, 2564 // then paint the caret. 2565 if (paintPhase == PaintPhaseForeground) { 2566 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret); 2567 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret); 2568 } 2569} 2570 2571IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const IntPoint& point) const 2572{ 2573 if (!style()->isFlippedBlocksWritingMode()) 2574 return point; 2575 2576 // This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since 2577 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped 2578 // case. 2579 if (isHorizontalWritingMode()) 2580 return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child)); 2581 return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y()); 2582} 2583 2584void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase) 2585{ 2586 if (!m_floatingObjects) 2587 return; 2588 2589 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2590 FloatingObjectSetIterator end = floatingObjectSet.end(); 2591 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2592 FloatingObject* r = *it; 2593 // Only paint the object if our m_shouldPaint flag is set. 2594 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) { 2595 PaintInfo currentPaintInfo(paintInfo); 2596 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground; 2597 IntPoint childPoint = flipFloatForWritingMode(r, IntPoint(tx + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), ty + yPositionForFloatIncludingMargin(r) - r->m_renderer->y())); 2598 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); 2599 if (!preservePhase) { 2600 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds; 2601 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); 2602 currentPaintInfo.phase = PaintPhaseFloat; 2603 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); 2604 currentPaintInfo.phase = PaintPhaseForeground; 2605 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); 2606 currentPaintInfo.phase = PaintPhaseOutline; 2607 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y()); 2608 } 2609 } 2610 } 2611} 2612 2613void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty) 2614{ 2615 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox()) 2616 return; 2617 2618 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) { 2619 // We can check the first box and last box and avoid painting if we don't 2620 // intersect. 2621 int yPos = ty + firstLineBox()->y(); 2622 int h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y(); 2623 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y()) 2624 return; 2625 2626 // See if our boxes intersect with the dirty rect. If so, then we paint 2627 // them. Note that boxes can easily overlap, so we can't make any assumptions 2628 // based off positions of our first line box or our last line box. 2629 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 2630 yPos = ty + curr->y(); 2631 h = curr->logicalHeight(); 2632 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y()) 2633 curr->paintEllipsisBox(paintInfo, tx, ty, curr->lineTop(), curr->lineBottom()); 2634 } 2635 } 2636} 2637 2638RenderInline* RenderBlock::inlineElementContinuation() const 2639{ 2640 RenderBoxModelObject* continuation = this->continuation(); 2641 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0; 2642} 2643 2644RenderBlock* RenderBlock::blockElementContinuation() const 2645{ 2646 RenderBoxModelObject* currentContinuation = continuation(); 2647 if (!currentContinuation || currentContinuation->isInline()) 2648 return 0; 2649 RenderBlock* nextContinuation = toRenderBlock(currentContinuation); 2650 if (nextContinuation->isAnonymousBlock()) 2651 return nextContinuation->blockElementContinuation(); 2652 return nextContinuation; 2653} 2654 2655static ContinuationOutlineTableMap* continuationOutlineTable() 2656{ 2657 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ()); 2658 return &table; 2659} 2660 2661void RenderBlock::addContinuationWithOutline(RenderInline* flow) 2662{ 2663 // We can't make this work if the inline is in a layer. We'll just rely on the broken 2664 // way of painting. 2665 ASSERT(!flow->layer() && !flow->isInlineElementContinuation()); 2666 2667 ContinuationOutlineTableMap* table = continuationOutlineTable(); 2668 ListHashSet<RenderInline*>* continuations = table->get(this); 2669 if (!continuations) { 2670 continuations = new ListHashSet<RenderInline*>; 2671 table->set(this, continuations); 2672 } 2673 2674 continuations->add(flow); 2675} 2676 2677bool RenderBlock::paintsContinuationOutline(RenderInline* flow) 2678{ 2679 ContinuationOutlineTableMap* table = continuationOutlineTable(); 2680 if (table->isEmpty()) 2681 return false; 2682 2683 ListHashSet<RenderInline*>* continuations = table->get(this); 2684 if (!continuations) 2685 return false; 2686 2687 return continuations->contains(flow); 2688} 2689 2690void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty) 2691{ 2692 ContinuationOutlineTableMap* table = continuationOutlineTable(); 2693 if (table->isEmpty()) 2694 return; 2695 2696 ListHashSet<RenderInline*>* continuations = table->get(this); 2697 if (!continuations) 2698 return; 2699 2700 // Paint each continuation outline. 2701 ListHashSet<RenderInline*>::iterator end = continuations->end(); 2702 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) { 2703 // Need to add in the coordinates of the intervening blocks. 2704 RenderInline* flow = *it; 2705 RenderBlock* block = flow->containingBlock(); 2706 for ( ; block && block != this; block = block->containingBlock()) { 2707 tx += block->x(); 2708 ty += block->y(); 2709 } 2710 ASSERT(block); 2711 flow->paintOutline(info.context, tx, ty); 2712 } 2713 2714 // Delete 2715 delete continuations; 2716 table->remove(this); 2717} 2718 2719bool RenderBlock::shouldPaintSelectionGaps() const 2720{ 2721 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot(); 2722} 2723 2724bool RenderBlock::isSelectionRoot() const 2725{ 2726 if (!node()) 2727 return false; 2728 2729 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases. 2730 if (isTable()) 2731 return false; 2732 2733 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() || 2734 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() || 2735 hasReflection() || hasMask() || isWritingModeRoot()) 2736 return true; 2737 2738 if (view() && view()->selectionStart()) { 2739 Node* startElement = view()->selectionStart()->node(); 2740 if (startElement && startElement->rootEditableElement() == node()) 2741 return true; 2742 } 2743 2744 return false; 2745} 2746 2747GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer) 2748{ 2749 ASSERT(!needsLayout()); 2750 2751 if (!shouldPaintSelectionGaps()) 2752 return GapRects(); 2753 2754 // FIXME: this is broken with transforms 2755 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint()); 2756 mapLocalToContainer(repaintContainer, false, false, transformState); 2757 IntPoint offsetFromRepaintContainer = roundedIntPoint(transformState.mappedPoint()); 2758 2759 if (hasOverflowClip()) 2760 offsetFromRepaintContainer -= layer()->scrolledContentOffset(); 2761 2762 int lastTop = 0; 2763 int lastLeft = logicalLeftSelectionOffset(this, lastTop); 2764 int lastRight = logicalRightSelectionOffset(this, lastTop); 2765 2766 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight); 2767} 2768 2769void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty) 2770{ 2771 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) { 2772 int lastTop = 0; 2773 int lastLeft = logicalLeftSelectionOffset(this, lastTop); 2774 int lastRight = logicalRightSelectionOffset(this, lastTop); 2775 paintInfo.context->save(); 2776 IntRect gapRectsBounds = selectionGaps(this, IntPoint(tx, ty), IntSize(), lastTop, lastLeft, lastRight, &paintInfo); 2777 if (!gapRectsBounds.isEmpty()) { 2778 if (RenderLayer* layer = enclosingLayer()) { 2779 gapRectsBounds.move(IntSize(-tx, -ty)); 2780 if (!hasLayer()) { 2781 IntRect localBounds(gapRectsBounds); 2782 flipForWritingMode(localBounds); 2783 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox(); 2784 gapRectsBounds.move(layer->scrolledContentOffset()); 2785 } 2786 layer->addBlockSelectionGapsBounds(gapRectsBounds); 2787 } 2788 } 2789 paintInfo.context->restore(); 2790 } 2791} 2792 2793static void clipOutPositionedObjects(const PaintInfo* paintInfo, const IntPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects) 2794{ 2795 if (!positionedObjects) 2796 return; 2797 2798 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end(); 2799 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) { 2800 RenderBox* r = *it; 2801 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height())); 2802 } 2803} 2804 2805static int blockDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock) 2806{ 2807 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width(); 2808} 2809 2810static int inlineDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock) 2811{ 2812 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height(); 2813} 2814 2815IntRect RenderBlock::logicalRectToPhysicalRect(const IntPoint& rootBlockPhysicalPosition, const IntRect& logicalRect) 2816{ 2817 IntRect result; 2818 if (isHorizontalWritingMode()) 2819 result = logicalRect; 2820 else 2821 result = IntRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width()); 2822 flipForWritingMode(result); 2823 result.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); 2824 return result; 2825} 2826 2827GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 2828 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo) 2829{ 2830 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore. 2831 // Clip out floating and positioned objects when painting selection gaps. 2832 if (paintInfo) { 2833 // Note that we don't clip out overflow for positioned objects. We just stick to the border box. 2834 IntRect flippedBlockRect = IntRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height()); 2835 rootBlock->flipForWritingMode(flippedBlockRect); 2836 flippedBlockRect.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); 2837 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get()); 2838 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects. 2839 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock()) 2840 clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes. 2841 if (m_floatingObjects) { 2842 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 2843 FloatingObjectSetIterator end = floatingObjectSet.end(); 2844 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 2845 FloatingObject* r = *it; 2846 IntRect floatBox = IntRect(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r), 2847 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r), 2848 r->m_renderer->width(), r->m_renderer->height()); 2849 rootBlock->flipForWritingMode(floatBox); 2850 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y()); 2851 paintInfo->context->clipOut(floatBox); 2852 } 2853 } 2854 } 2855 2856 // 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 2857 // fixed). 2858 GapRects result; 2859 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday. 2860 return result; 2861 2862 if (hasColumns() || hasTransform() || style()->columnSpan()) { 2863 // FIXME: We should learn how to gap fill multiple columns and transforms eventually. 2864 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight(); 2865 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight()); 2866 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight()); 2867 return result; 2868 } 2869 2870 if (childrenInline()) 2871 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo); 2872 else 2873 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo); 2874 2875 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block. 2876 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd)) 2877 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 2878 logicalHeight(), paintInfo)); 2879 return result; 2880} 2881 2882GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 2883 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo) 2884{ 2885 GapRects result; 2886 2887 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth; 2888 2889 if (!firstLineBox()) { 2890 if (containsStart) { 2891 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this 2892 // case. 2893 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight(); 2894 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight()); 2895 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight()); 2896 } 2897 return result; 2898 } 2899 2900 RootInlineBox* lastSelectedLine = 0; 2901 RootInlineBox* curr; 2902 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { } 2903 2904 // Now paint the gaps for the lines. 2905 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) { 2906 int selTop = curr->selectionTop(); 2907 int selHeight = curr->selectionHeight(); 2908 2909 if (!containsStart && !lastSelectedLine && 2910 selectionState() != SelectionStart && selectionState() != SelectionBoth) 2911 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 2912 selTop, paintInfo)); 2913 2914 IntRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight); 2915 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width())); 2916 IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect); 2917 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y()) 2918 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x())) 2919 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo)); 2920 2921 lastSelectedLine = curr; 2922 } 2923 2924 if (containsStart && !lastSelectedLine) 2925 // VisibleSelection must start just after our last line. 2926 lastSelectedLine = lastRootBox(); 2927 2928 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) { 2929 // Go ahead and update our lastY to be the bottom of the last selected line. 2930 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom(); 2931 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2932 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom()); 2933 } 2934 return result; 2935} 2936 2937GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 2938 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo) 2939{ 2940 GapRects result; 2941 2942 // Go ahead and jump right to the first block child that contains some selected objects. 2943 RenderBox* curr; 2944 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { } 2945 2946 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) { 2947 SelectionState childState = curr->selectionState(); 2948 if (childState == SelectionBoth || childState == SelectionEnd) 2949 sawSelectionEnd = true; 2950 2951 if (curr->isFloatingOrPositioned()) 2952 continue; // We must be a normal flow object in order to even be considered. 2953 2954 if (curr->isRelPositioned() && curr->hasLayer()) { 2955 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element. 2956 // Just disregard it completely. 2957 IntSize relOffset = curr->layer()->relativePositionOffset(); 2958 if (relOffset.width() || relOffset.height()) 2959 continue; 2960 } 2961 2962 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this. 2963 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone); 2964 if (fillBlockGaps) { 2965 // We need to fill the vertical gap above this object. 2966 if (childState == SelectionEnd || childState == SelectionInside) 2967 // Fill the gap above the object. 2968 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, 2969 curr->logicalTop(), paintInfo)); 2970 2971 // Only fill side gaps for objects that paint their own selection if we know for sure the selection is going to extend all the way *past* 2972 // our object. We know this if the selection did not end inside our object. 2973 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd)) 2974 childState = SelectionNone; 2975 2976 // Fill side gaps on this object based off its state. 2977 bool leftGap, rightGap; 2978 getSelectionGapInfo(childState, leftGap, rightGap); 2979 2980 if (leftGap) 2981 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo)); 2982 if (rightGap) 2983 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo)); 2984 2985 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as 2986 // they can without bumping into floating or positioned objects. Ideally they will go right up 2987 // to the border of the root selection block. 2988 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom(); 2989 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom()); 2990 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom()); 2991 } else if (childState != SelectionNone) 2992 // We must be a block that has some selected object inside it. Go ahead and recur. 2993 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, IntSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()), 2994 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo)); 2995 } 2996 return result; 2997} 2998 2999IntRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 3000 int lastLogicalTop, int lastLogicalLeft, int lastLogicalRight, int logicalBottom, const PaintInfo* paintInfo) 3001{ 3002 int logicalTop = lastLogicalTop; 3003 int logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop; 3004 if (logicalHeight <= 0) 3005 return IntRect(); 3006 3007 // Get the selection offsets for the bottom of the gap 3008 int logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom)); 3009 int logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom)); 3010 int logicalWidth = logicalRight - logicalLeft; 3011 if (logicalWidth <= 0) 3012 return IntRect(); 3013 3014 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(logicalLeft, logicalTop, logicalWidth, logicalHeight)); 3015 if (paintInfo) 3016 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace()); 3017 return gapRect; 3018} 3019 3020IntRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 3021 RenderObject* selObj, int logicalLeft, int logicalTop, int logicalHeight, const PaintInfo* paintInfo) 3022{ 3023 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop; 3024 int rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)); 3025 int rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalLeft, min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight))); 3026 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft; 3027 if (rootBlockLogicalWidth <= 0) 3028 return IntRect(); 3029 3030 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); 3031 if (paintInfo) 3032 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 3033 return gapRect; 3034} 3035 3036IntRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock, 3037 RenderObject* selObj, int logicalRight, int logicalTop, int logicalHeight, const PaintInfo* paintInfo) 3038{ 3039 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop; 3040 int rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight, max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight))); 3041 int rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)); 3042 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft; 3043 if (rootBlockLogicalWidth <= 0) 3044 return IntRect(); 3045 3046 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight)); 3047 if (paintInfo) 3048 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace()); 3049 return gapRect; 3050} 3051 3052void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap) 3053{ 3054 bool ltr = style()->isLeftToRightDirection(); 3055 leftGap = (state == RenderObject::SelectionInside) || 3056 (state == RenderObject::SelectionEnd && ltr) || 3057 (state == RenderObject::SelectionStart && !ltr); 3058 rightGap = (state == RenderObject::SelectionInside) || 3059 (state == RenderObject::SelectionStart && ltr) || 3060 (state == RenderObject::SelectionEnd && !ltr); 3061} 3062 3063int RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, int position) 3064{ 3065 int logicalLeft = logicalLeftOffsetForLine(position, false); 3066 if (logicalLeft == logicalLeftOffsetForContent()) { 3067 if (rootBlock != this) 3068 // The border can potentially be further extended by our containingBlock(). 3069 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop()); 3070 return logicalLeft; 3071 } else { 3072 RenderBlock* cb = this; 3073 while (cb != rootBlock) { 3074 logicalLeft += cb->logicalLeft(); 3075 cb = cb->containingBlock(); 3076 } 3077 } 3078 return logicalLeft; 3079} 3080 3081int RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, int position) 3082{ 3083 int logicalRight = logicalRightOffsetForLine(position, false); 3084 if (logicalRight == logicalRightOffsetForContent()) { 3085 if (rootBlock != this) 3086 // The border can potentially be further extended by our containingBlock(). 3087 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop()); 3088 return logicalRight; 3089 } else { 3090 RenderBlock* cb = this; 3091 while (cb != rootBlock) { 3092 logicalRight += cb->logicalLeft(); 3093 cb = cb->containingBlock(); 3094 } 3095 } 3096 return logicalRight; 3097} 3098 3099void RenderBlock::insertPositionedObject(RenderBox* o) 3100{ 3101 // Create the list of special objects if we don't aleady have one 3102 if (!m_positionedObjects) 3103 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet); 3104 3105 m_positionedObjects->add(o); 3106} 3107 3108void RenderBlock::removePositionedObject(RenderBox* o) 3109{ 3110 if (m_positionedObjects) 3111 m_positionedObjects->remove(o); 3112} 3113 3114void RenderBlock::removePositionedObjects(RenderBlock* o) 3115{ 3116 if (!m_positionedObjects) 3117 return; 3118 3119 RenderBox* r; 3120 3121 Iterator end = m_positionedObjects->end(); 3122 3123 Vector<RenderBox*, 16> deadObjects; 3124 3125 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) { 3126 r = *it; 3127 if (!o || r->isDescendantOf(o)) { 3128 if (o) 3129 r->setChildNeedsLayout(true, false); 3130 3131 // It is parent blocks job to add positioned child to positioned objects list of its containing block 3132 // Parent layout needs to be invalidated to ensure this happens. 3133 RenderObject* p = r->parent(); 3134 while (p && !p->isRenderBlock()) 3135 p = p->parent(); 3136 if (p) 3137 p->setChildNeedsLayout(true); 3138 3139 deadObjects.append(r); 3140 } 3141 } 3142 3143 for (unsigned i = 0; i < deadObjects.size(); i++) 3144 m_positionedObjects->remove(deadObjects.at(i)); 3145} 3146 3147RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o) 3148{ 3149 ASSERT(o->isFloating()); 3150 3151 // Create the list of special objects if we don't aleady have one 3152 if (!m_floatingObjects) 3153 m_floatingObjects = adoptPtr(new FloatingObjects); 3154 else { 3155 // Don't insert the object again if it's already in the list 3156 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3157 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); 3158 if (it != floatingObjectSet.end()) 3159 return *it; 3160 } 3161 3162 // Create the special object entry & append it to the list 3163 3164 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight); 3165 3166 // Our location is irrelevant if we're unsplittable or no pagination is in effect. 3167 // Just go ahead and lay out the float. 3168 bool isChildRenderBlock = o->isRenderBlock(); 3169 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged()) 3170 o->setChildNeedsLayout(true, false); 3171 3172 bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight; 3173 if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root. 3174 o->layoutIfNeeded(); 3175 else { 3176 o->computeLogicalWidth(); 3177 o->computeBlockDirectionMargins(this); 3178 } 3179 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o)); 3180 3181 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will. 3182 newObj->m_isDescendant = true; 3183 newObj->m_renderer = o; 3184 3185 m_floatingObjects->increaseObjectsCount(newObj->type()); 3186 m_floatingObjects->set().add(newObj); 3187 3188 return newObj; 3189} 3190 3191void RenderBlock::removeFloatingObject(RenderBox* o) 3192{ 3193 if (m_floatingObjects) { 3194 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3195 FloatingObjectSet::iterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o); 3196 if (it != floatingObjectSet.end()) { 3197 FloatingObject* r = *it; 3198 if (childrenInline()) { 3199 int logicalTop = logicalTopForFloat(r); 3200 int logicalBottom = logicalBottomForFloat(r); 3201 3202 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995. 3203 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<int>::max()) 3204 logicalBottom = numeric_limits<int>::max(); 3205 else { 3206 // Special-case zero- and less-than-zero-height floats: those don't touch 3207 // the line that they're on, but it still needs to be dirtied. This is 3208 // accomplished by pretending they have a height of 1. 3209 logicalBottom = max(logicalBottom, logicalTop + 1); 3210 } 3211 if (r->m_originatingLine) { 3212 ASSERT(r->m_originatingLine->renderer() == this); 3213 r->m_originatingLine->markDirty(); 3214#if !ASSERT_DISABLED 3215 r->m_originatingLine = 0; 3216#endif 3217 } 3218 markLinesDirtyInBlockRange(0, logicalBottom); 3219 } 3220 m_floatingObjects->decreaseObjectsCount(r->type()); 3221 floatingObjectSet.remove(it); 3222 ASSERT(!r->m_originatingLine); 3223 delete r; 3224 } 3225 } 3226} 3227 3228void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset) 3229{ 3230 if (!m_floatingObjects) 3231 return; 3232 3233 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3234 FloatingObject* curr = floatingObjectSet.last(); 3235 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) { 3236 m_floatingObjects->decreaseObjectsCount(curr->type()); 3237 floatingObjectSet.removeLast(); 3238 ASSERT(!curr->m_originatingLine); 3239 delete curr; 3240 curr = floatingObjectSet.last(); 3241 } 3242} 3243 3244bool RenderBlock::positionNewFloats() 3245{ 3246 if (!m_floatingObjects) 3247 return false; 3248 3249 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3250 if (floatingObjectSet.isEmpty()) 3251 return false; 3252 3253 // If all floats have already been positioned, then we have no work to do. 3254 if (floatingObjectSet.last()->isPlaced()) 3255 return false; 3256 3257 // Move backwards through our floating object list until we find a float that has 3258 // already been positioned. Then we'll be able to move forward, positioning all of 3259 // the new floats that need it. 3260 FloatingObjectSetIterator it = floatingObjectSet.end(); 3261 --it; // Go to last item. 3262 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 3263 FloatingObject* lastPlacedFloatingObject = 0; 3264 while (it != begin) { 3265 --it; 3266 if ((*it)->isPlaced()) { 3267 lastPlacedFloatingObject = *it; 3268 ++it; 3269 break; 3270 } 3271 } 3272 3273 int logicalTop = logicalHeight(); 3274 3275 // The float cannot start above the top position of the last positioned float. 3276 if (lastPlacedFloatingObject) 3277 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop); 3278 3279 FloatingObjectSetIterator end = floatingObjectSet.end(); 3280 // Now walk through the set of unpositioned floats and place them. 3281 for (; it != end; ++it) { 3282 FloatingObject* floatingObject = *it; 3283 // The containing block is responsible for positioning floats, so if we have floats in our 3284 // list that come from somewhere else, do not attempt to position them. 3285 if (floatingObject->renderer()->containingBlock() != this) 3286 continue; 3287 3288 RenderBox* childBox = floatingObject->renderer(); 3289 int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox); 3290 3291 int rightOffset = logicalRightOffsetForContent(); // Constant part of right offset. 3292 int leftOffset = logicalLeftOffsetForContent(); // Constant part of left offset. 3293 int floatLogicalWidth = logicalWidthForFloat(floatingObject); // The width we look for. 3294 if (rightOffset - leftOffset < floatLogicalWidth) 3295 floatLogicalWidth = rightOffset - leftOffset; // Never look for more than what will be available. 3296 3297 IntRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height()); 3298 3299 if (childBox->style()->clear() & CLEFT) 3300 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop); 3301 if (childBox->style()->clear() & CRIGHT) 3302 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop); 3303 3304 int floatLogicalLeft; 3305 if (childBox->style()->floating() == FLEFT) { 3306 int heightRemainingLeft = 1; 3307 int heightRemainingRight = 1; 3308 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft); 3309 while (logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) { 3310 logicalTop += min(heightRemainingLeft, heightRemainingRight); 3311 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft); 3312 } 3313 floatLogicalLeft = max(0, floatLogicalLeft); 3314 } else { 3315 int heightRemainingLeft = 1; 3316 int heightRemainingRight = 1; 3317 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight); 3318 while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft) < floatLogicalWidth) { 3319 logicalTop += min(heightRemainingLeft, heightRemainingRight); 3320 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight); 3321 } 3322 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable 3323 // |floatLogicalWidth| was capped to the available line width. 3324 // See fast/block/float/clamped-right-float.html. 3325 } 3326 3327 setLogicalLeftForFloat(floatingObject, floatLogicalLeft); 3328 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin); 3329 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox)); 3330 3331 if (view()->layoutState()->isPaginated()) { 3332 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0; 3333 3334 if (!childBox->needsLayout()) 3335 childBox->markForPaginationRelayoutIfNeeded();; 3336 childBox->layoutIfNeeded(); 3337 3338 // If we are unsplittable and don't fit, then we need to move down. 3339 // We include our margins as part of the unsplittable area. 3340 int newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, true); 3341 3342 // See if we have a pagination strut that is making us move down further. 3343 // Note that an unsplittable child can't also have a pagination strut, so this is 3344 // exclusive with the case above. 3345 if (childBlock && childBlock->paginationStrut()) { 3346 newLogicalTop += childBlock->paginationStrut(); 3347 childBlock->setPaginationStrut(0); 3348 } 3349 3350 if (newLogicalTop != logicalTop) { 3351 floatingObject->m_paginationStrut = newLogicalTop - logicalTop; 3352 logicalTop = newLogicalTop; 3353 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox)); 3354 if (childBlock) 3355 childBlock->setChildNeedsLayout(true, false); 3356 childBox->layoutIfNeeded(); 3357 } 3358 } 3359 3360 setLogicalTopForFloat(floatingObject, logicalTop); 3361 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox)); 3362 3363 floatingObject->setIsPlaced(); 3364 3365 // If the child moved, we have to repaint it. 3366 if (childBox->checkForRepaintDuringLayout()) 3367 childBox->repaintDuringLayoutIfMoved(oldRect); 3368 } 3369 return true; 3370} 3371 3372void RenderBlock::newLine(EClear clear) 3373{ 3374 positionNewFloats(); 3375 // set y position 3376 int newY = 0; 3377 switch (clear) 3378 { 3379 case CLEFT: 3380 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 3381 break; 3382 case CRIGHT: 3383 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight); 3384 break; 3385 case CBOTH: 3386 newY = lowestFloatLogicalBottom(); 3387 default: 3388 break; 3389 } 3390 if (height() < newY) 3391 setLogicalHeight(newY); 3392} 3393 3394void RenderBlock::addPercentHeightDescendant(RenderBox* descendant) 3395{ 3396 if (!gPercentHeightDescendantsMap) { 3397 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap; 3398 gPercentHeightContainerMap = new PercentHeightContainerMap; 3399 } 3400 3401 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this); 3402 if (!descendantSet) { 3403 descendantSet = new HashSet<RenderBox*>; 3404 gPercentHeightDescendantsMap->set(this, descendantSet); 3405 } 3406 bool added = descendantSet->add(descendant).second; 3407 if (!added) { 3408 ASSERT(gPercentHeightContainerMap->get(descendant)); 3409 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this)); 3410 return; 3411 } 3412 3413 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant); 3414 if (!containerSet) { 3415 containerSet = new HashSet<RenderBlock*>; 3416 gPercentHeightContainerMap->set(descendant, containerSet); 3417 } 3418 ASSERT(!containerSet->contains(this)); 3419 containerSet->add(this); 3420} 3421 3422void RenderBlock::removePercentHeightDescendant(RenderBox* descendant) 3423{ 3424 if (!gPercentHeightContainerMap) 3425 return; 3426 3427 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant); 3428 if (!containerSet) 3429 return; 3430 3431 HashSet<RenderBlock*>::iterator end = containerSet->end(); 3432 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) { 3433 RenderBlock* container = *it; 3434 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container); 3435 ASSERT(descendantSet); 3436 if (!descendantSet) 3437 continue; 3438 ASSERT(descendantSet->contains(descendant)); 3439 descendantSet->remove(descendant); 3440 if (descendantSet->isEmpty()) { 3441 gPercentHeightDescendantsMap->remove(container); 3442 delete descendantSet; 3443 } 3444 } 3445 3446 delete containerSet; 3447} 3448 3449HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const 3450{ 3451 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0; 3452} 3453 3454// FIXME: The logicalLeftOffsetForLine/logicalRightOffsetForLine functions are very slow if there are many floats 3455// present. We need to add a structure to floating objects to represent "lines" of floats. Then instead of checking 3456// each float individually, we'd just walk backwards through the "lines" and stop when we hit a line that is fully above 3457// the vertical offset that we'd like to check. Computing the "lines" would be rather complicated, but could replace the left 3458// objects and right objects count hack that is currently used here. 3459int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 3460{ 3461 int left = fixedOffset; 3462 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) { 3463 if (heightRemaining) 3464 *heightRemaining = 1; 3465 3466 // We know the list is non-empty, since we have "left" objects to search for. 3467 // Therefore we can assume that begin != end, and that we can do at least one 3468 // decrement. 3469 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3470 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 3471 FloatingObjectSetIterator it = floatingObjectSet.end(); 3472 do { 3473 --it; 3474 FloatingObject* r = *it; 3475 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop 3476 && r->type() == FloatingObject::FloatLeft 3477 && logicalRightForFloat(r) > left) { 3478 left = max(left, logicalRightForFloat(r)); 3479 if (heightRemaining) 3480 *heightRemaining = logicalBottomForFloat(r) - logicalTop; 3481 } 3482 } while (it != begin); 3483 } 3484 3485 if (applyTextIndent && style()->isLeftToRightDirection()) { 3486 int cw = 0; 3487 if (style()->textIndent().isPercent()) 3488 cw = containingBlock()->availableLogicalWidth(); 3489 left += style()->textIndent().calcMinValue(cw); 3490 } 3491 3492 return left; 3493} 3494 3495int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const 3496{ 3497 int right = fixedOffset; 3498 3499 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) { 3500 if (heightRemaining) 3501 *heightRemaining = 1; 3502 3503 // We know the list is non-empty, since we have "right" objects to search for. 3504 // Therefore we can assume that begin != end, and that we can do at least one 3505 // decrement. 3506 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3507 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 3508 FloatingObjectSetIterator it = floatingObjectSet.end(); 3509 do { 3510 --it; 3511 FloatingObject* r = *it; 3512 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop 3513 && r->type() == FloatingObject::FloatRight 3514 && logicalLeftForFloat(r) < right) { 3515 right = min(right, logicalLeftForFloat(r)); 3516 if (heightRemaining) 3517 *heightRemaining = logicalBottomForFloat(r) - logicalTop; 3518 } 3519 } while (it != begin); 3520 } 3521 3522 if (applyTextIndent && !style()->isLeftToRightDirection()) { 3523 int cw = 0; 3524 if (style()->textIndent().isPercent()) 3525 cw = containingBlock()->availableLogicalWidth(); 3526 right -= style()->textIndent().calcMinValue(cw); 3527 } 3528 3529 return right; 3530} 3531 3532int RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const 3533{ 3534 int result = logicalRightOffsetForLine(position, firstLine) - logicalLeftOffsetForLine(position, firstLine); 3535 return (result < 0) ? 0 : result; 3536} 3537 3538int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const 3539{ 3540 if (!m_floatingObjects) 3541 return 0; 3542 3543 int bottom = INT_MAX; 3544 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3545 FloatingObjectSetIterator end = floatingObjectSet.end(); 3546 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3547 FloatingObject* r = *it; 3548 int floatBottom = logicalBottomForFloat(r); 3549 if (floatBottom > logicalHeight) 3550 bottom = min(floatBottom, bottom); 3551 } 3552 3553 return bottom == INT_MAX ? 0 : bottom; 3554} 3555 3556int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const 3557{ 3558 if (!m_floatingObjects) 3559 return 0; 3560 int lowestFloatBottom = 0; 3561 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3562 FloatingObjectSetIterator end = floatingObjectSet.end(); 3563 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3564 FloatingObject* r = *it; 3565 if (r->isPlaced() && r->type() & floatType) 3566 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r)); 3567 } 3568 return lowestFloatBottom; 3569} 3570 3571void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest) 3572{ 3573 if (logicalTop >= logicalBottom) 3574 return; 3575 3576 RootInlineBox* lowestDirtyLine = lastRootBox(); 3577 RootInlineBox* afterLowest = lowestDirtyLine; 3578 while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom && logicalBottom < numeric_limits<int>::max()) { 3579 afterLowest = lowestDirtyLine; 3580 lowestDirtyLine = lowestDirtyLine->prevRootBox(); 3581 } 3582 3583 while (afterLowest && afterLowest != highest && (afterLowest->blockLogicalHeight() >= logicalTop || afterLowest->blockLogicalHeight() < 0)) { 3584 afterLowest->markDirty(); 3585 afterLowest = afterLowest->prevRootBox(); 3586 } 3587} 3588 3589void RenderBlock::clearFloats() 3590{ 3591 // Inline blocks are covered by the isReplaced() check in the avoidFloats method. 3592 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) { 3593 if (m_floatingObjects) { 3594 deleteAllValues(m_floatingObjects->set()); 3595 m_floatingObjects->clear(); 3596 } 3597 return; 3598 } 3599 3600 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap; 3601 RendererToFloatInfoMap floatMap; 3602 3603 if (m_floatingObjects) { 3604 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3605 if (childrenInline()) { 3606 FloatingObjectSet::iterator end = floatingObjectSet.end(); 3607 for (FloatingObjectSet::iterator it = floatingObjectSet.begin(); it != end; ++it) { 3608 FloatingObject* f = *it; 3609 floatMap.add(f->m_renderer, f); 3610 } 3611 } else 3612 deleteAllValues(floatingObjectSet); 3613 m_floatingObjects->clear(); 3614 } 3615 3616 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add 3617 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent. 3618 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG. 3619 if (!parent() || !parent()->isRenderBlock()) 3620 return; 3621 3622 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are 3623 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted 3624 // to avoid floats. 3625 bool parentHasFloats = false; 3626 RenderBlock* parentBlock = toRenderBlock(parent()); 3627 RenderObject* prev = previousSibling(); 3628 while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) { 3629 if (prev->isFloating()) 3630 parentHasFloats = true; 3631 prev = prev->previousSibling(); 3632 } 3633 3634 // First add in floats from the parent. 3635 int logicalTopOffset = logicalTop(); 3636 if (parentHasFloats) 3637 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset); 3638 3639 int logicalLeftOffset = 0; 3640 if (prev) 3641 logicalTopOffset -= toRenderBox(prev)->logicalTop(); 3642 else { 3643 prev = parentBlock; 3644 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent(); 3645 } 3646 3647 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space. 3648 if (!prev || !prev->isRenderBlock()) 3649 return; 3650 3651 RenderBlock* block = toRenderBlock(prev); 3652 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset) 3653 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset); 3654 3655 if (childrenInline()) { 3656 int changeLogicalTop = numeric_limits<int>::max(); 3657 int changeLogicalBottom = numeric_limits<int>::min(); 3658 if (m_floatingObjects) { 3659 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3660 FloatingObjectSetIterator end = floatingObjectSet.end(); 3661 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3662 FloatingObject* f = *it; 3663 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer); 3664 int logicalBottom = logicalBottomForFloat(f); 3665 if (oldFloatingObject) { 3666 int oldLogicalBottom = logicalBottomForFloat(oldFloatingObject); 3667 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) { 3668 changeLogicalTop = 0; 3669 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); 3670 } else if (logicalBottom != oldLogicalBottom) { 3671 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom)); 3672 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom)); 3673 } 3674 3675 floatMap.remove(f->m_renderer); 3676 if (oldFloatingObject->m_originatingLine) { 3677 ASSERT(oldFloatingObject->m_originatingLine->renderer() == this); 3678 oldFloatingObject->m_originatingLine->markDirty(); 3679 } 3680 delete oldFloatingObject; 3681 } else { 3682 changeLogicalTop = 0; 3683 changeLogicalBottom = max(changeLogicalBottom, logicalBottom); 3684 } 3685 } 3686 } 3687 3688 RendererToFloatInfoMap::iterator end = floatMap.end(); 3689 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) { 3690 FloatingObject* floatingObject = (*it).second; 3691 if (!floatingObject->m_isDescendant) { 3692 changeLogicalTop = 0; 3693 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject)); 3694 } 3695 } 3696 deleteAllValues(floatMap); 3697 3698 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom); 3699 } 3700} 3701 3702int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, int logicalTopOffset, bool makeChildPaintOtherFloats) 3703{ 3704 // Prevent floats from being added to the canvas by the root element, e.g., <html>. 3705 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot()) 3706 return 0; 3707 3708 int childLogicalTop = child->logicalTop(); 3709 int lowestFloatLogicalBottom = 0; 3710 3711 // Floats that will remain the child's responsibility to paint should factor into its 3712 // overflow. 3713 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end(); 3714 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) { 3715 FloatingObject* r = *childIt; 3716 int logicalBottomForFloat = min(this->logicalBottomForFloat(r), numeric_limits<int>::max() - childLogicalTop); 3717 int logicalBottom = childLogicalTop + logicalBottomForFloat; 3718 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom); 3719 3720 if (logicalBottom > logicalHeight()) { 3721 // If the object is not in the list, we add it now. 3722 if (!containsFloat(r->m_renderer)) { 3723 int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; 3724 int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; 3725 FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); 3726 floatingObj->m_renderer = r->m_renderer; 3727 3728 // The nearest enclosing layer always paints the float (so that zindex and stacking 3729 // behaves properly). We always want to propagate the desire to paint the float as 3730 // far out as we can, to the outermost block that overlaps the float, stopping only 3731 // if we hit a self-painting layer boundary. 3732 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer()) 3733 r->m_shouldPaint = false; 3734 else 3735 floatingObj->m_shouldPaint = false; 3736 3737 floatingObj->m_isDescendant = true; 3738 3739 // We create the floating object list lazily. 3740 if (!m_floatingObjects) 3741 m_floatingObjects = adoptPtr(new FloatingObjects); 3742 3743 m_floatingObjects->increaseObjectsCount(floatingObj->type()); 3744 m_floatingObjects->set().add(floatingObj); 3745 } 3746 } else { 3747 if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() && 3748 r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) { 3749 // The float is not overhanging from this block, so if it is a descendant of the child, the child should 3750 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing 3751 // layer. 3752 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats 3753 // it should paint. 3754 r->m_shouldPaint = true; 3755 } 3756 3757 // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the 3758 // child now. 3759 if (r->m_isDescendant) 3760 child->addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r))); 3761 } 3762 } 3763 return lowestFloatLogicalBottom; 3764} 3765 3766bool RenderBlock::hasOverhangingFloat(RenderBox* renderer) 3767{ 3768 if (!m_floatingObjects || hasColumns() || !parent()) 3769 return false; 3770 3771 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3772 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer); 3773 if (it == floatingObjectSet.end()) 3774 return false; 3775 3776 return logicalBottomForFloat(*it) > logicalHeight(); 3777} 3778 3779void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, int logicalTopOffset) 3780{ 3781 // If the parent or previous sibling doesn't have any floats to add, don't bother. 3782 if (!prev->m_floatingObjects) 3783 return; 3784 3785 logicalLeftOffset += (isHorizontalWritingMode() ? marginLeft() : marginTop()); 3786 3787 FloatingObjectSet& prevSet = prev->m_floatingObjects->set(); 3788 FloatingObjectSetIterator prevEnd = prevSet.end(); 3789 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) { 3790 FloatingObject* r = *prevIt; 3791 if (logicalBottomForFloat(r) > logicalTopOffset) { 3792 if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) { 3793 int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset; 3794 int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset; 3795 3796 FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height())); 3797 3798 // Applying the child's margin makes no sense in the case where the child was passed in. 3799 // since this margin was added already through the modification of the |logicalLeftOffset| variable 3800 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken 3801 // into account. Only apply this code if prev is the parent, since otherwise the left margin 3802 // will get applied twice. 3803 if (prev != parent()) { 3804 if (isHorizontalWritingMode()) 3805 floatingObj->setX(floatingObj->x() + prev->marginLeft()); 3806 else 3807 floatingObj->setY(floatingObj->y() + prev->marginTop()); 3808 } 3809 3810 floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it. 3811 floatingObj->m_renderer = r->m_renderer; 3812 3813 // We create the floating object list lazily. 3814 if (!m_floatingObjects) 3815 m_floatingObjects = adoptPtr(new FloatingObjects); 3816 m_floatingObjects->increaseObjectsCount(floatingObj->type()); 3817 m_floatingObjects->set().add(floatingObj); 3818 } 3819 } 3820 } 3821} 3822 3823bool RenderBlock::avoidsFloats() const 3824{ 3825 // Floats can't intrude into our box if we have a non-auto column count or width. 3826 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth(); 3827} 3828 3829bool RenderBlock::containsFloat(RenderBox* renderer) 3830{ 3831 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer); 3832} 3833 3834void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout) 3835{ 3836 if (!m_everHadLayout) 3837 return; 3838 3839 setChildNeedsLayout(true, !inLayout); 3840 3841 if (floatToRemove) 3842 removeFloatingObject(floatToRemove); 3843 3844 // Iterate over our children and mark them as needed. 3845 if (!childrenInline()) { 3846 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) { 3847 if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock()) 3848 continue; 3849 RenderBlock* childBlock = toRenderBlock(child); 3850 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats()) 3851 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout); 3852 } 3853 } 3854} 3855 3856void RenderBlock::markSiblingsWithFloatsForLayout() 3857{ 3858 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 3859 FloatingObjectSetIterator end = floatingObjectSet.end(); 3860 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 3861 if (logicalBottomForFloat(*it) > logicalHeight()) { 3862 RenderBox* floatingBox = (*it)->renderer(); 3863 3864 RenderObject* next = nextSibling(); 3865 while (next) { 3866 if (next->isRenderBlock() && !next->isFloatingOrPositioned() && !toRenderBlock(next)->avoidsFloats()) { 3867 RenderBlock* nextBlock = toRenderBlock(next); 3868 if (nextBlock->containsFloat(floatingBox)) 3869 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox); 3870 else 3871 break; 3872 } 3873 3874 next = next->nextSibling(); 3875 } 3876 } 3877 } 3878} 3879 3880int RenderBlock::getClearDelta(RenderBox* child, int yPos) 3881{ 3882 // There is no need to compute clearance if we have no floats. 3883 if (!containsFloats()) 3884 return 0; 3885 3886 // At least one float is present. We need to perform the clearance computation. 3887 bool clearSet = child->style()->clear() != CNONE; 3888 int bottom = 0; 3889 switch (child->style()->clear()) { 3890 case CNONE: 3891 break; 3892 case CLEFT: 3893 bottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft); 3894 break; 3895 case CRIGHT: 3896 bottom = lowestFloatLogicalBottom(FloatingObject::FloatRight); 3897 break; 3898 case CBOTH: 3899 bottom = lowestFloatLogicalBottom(); 3900 break; 3901 } 3902 3903 // We also clear floats if we are too big to sit on the same line as a float (and wish to avoid floats by default). 3904 int result = clearSet ? max(0, bottom - yPos) : 0; 3905 if (!result && child->avoidsFloats()) { 3906 int y = yPos; 3907 while (true) { 3908 int widthAtY = availableLogicalWidthForLine(y, false); 3909 if (widthAtY == availableLogicalWidth()) 3910 return y - yPos; 3911 3912 int oldChildY = child->y(); 3913 int oldChildWidth = child->width(); 3914 child->setY(y); 3915 child->computeLogicalWidth(); 3916 int childWidthAtY = child->width(); 3917 child->setY(oldChildY); 3918 child->setWidth(oldChildWidth); 3919 3920 if (childWidthAtY <= widthAtY) 3921 return y - yPos; 3922 3923 y = nextFloatLogicalBottomBelow(y); 3924 ASSERT(y >= yPos); 3925 if (y < yPos) 3926 break; 3927 } 3928 ASSERT_NOT_REACHED(); 3929 } 3930 return result; 3931} 3932 3933bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty) 3934{ 3935 if (!scrollsOverflow()) 3936 return false; 3937 3938 return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty)); 3939} 3940 3941bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction) 3942{ 3943 int tx = _tx + x(); 3944 int ty = _ty + y(); 3945 3946 if (!isRenderView()) { 3947 // Check if we need to do anything at all. 3948 IntRect overflowBox = visualOverflowRect(); 3949 overflowBox.move(tx, ty); 3950 if (!overflowBox.intersects(result.rectForPoint(_x, _y))) 3951 return false; 3952 } 3953 3954 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) { 3955 updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); 3956 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet. 3957 if (!result.addNodeToRectBasedTestResult(node(), _x, _y)) 3958 return true; 3959 } 3960 3961 // If we have clipping, then we can't have any spillout. 3962 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer(); 3963 bool useClip = (hasControlClip() || useOverflowClip); 3964 IntRect hitTestArea(result.rectForPoint(_x, _y)); 3965 bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty, IncludeOverlayScrollbarSize).intersects(hitTestArea)); 3966 if (checkChildren) { 3967 // Hit test descendants first. 3968 int scrolledX = tx; 3969 int scrolledY = ty; 3970 if (hasOverflowClip()) { 3971 IntSize offset = layer()->scrolledContentOffset(); 3972 scrolledX -= offset.width(); 3973 scrolledY -= offset.height(); 3974 } 3975 3976 // Hit test contents if we don't have columns. 3977 if (!hasColumns()) { 3978 if (hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) { 3979 updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); 3980 return true; 3981 } 3982 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, _x, _y, scrolledX, scrolledY)) 3983 return true; 3984 } else if (hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) { 3985 updateHitTestResult(result, IntPoint(_x - tx, _y - ty)); 3986 return true; 3987 } 3988 } 3989 3990 // Now hit test our background 3991 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) { 3992 IntRect boundsRect(tx, ty, width(), height()); 3993 if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(_x, _y))) { 3994 updateHitTestResult(result, flipForWritingMode(IntPoint(_x - tx, _y - ty))); 3995 if (!result.addNodeToRectBasedTestResult(node(), _x, _y, boundsRect)) 3996 return true; 3997 } 3998 } 3999 4000 return false; 4001} 4002 4003bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty) 4004{ 4005 if (!m_floatingObjects) 4006 return false; 4007 4008 if (isRenderView()) { 4009 tx += toRenderView(this)->frameView()->scrollX(); 4010 ty += toRenderView(this)->frameView()->scrollY(); 4011 } 4012 4013 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 4014 FloatingObjectSetIterator begin = floatingObjectSet.begin(); 4015 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) { 4016 --it; 4017 FloatingObject* floatingObject = *it; 4018 if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) { 4019 int xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x(); 4020 int yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y(); 4021 IntPoint childPoint = flipFloatForWritingMode(floatingObject, IntPoint(tx + xOffset, ty + yOffset)); 4022 if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), childPoint.x(), childPoint.y())) { 4023 updateHitTestResult(result, IntPoint(x - childPoint.x(), y - childPoint.y())); 4024 return true; 4025 } 4026 } 4027 } 4028 4029 return false; 4030} 4031 4032bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) 4033{ 4034 // We need to do multiple passes, breaking up our hit testing into strips. 4035 ColumnInfo* colInfo = columnInfo(); 4036 int colCount = columnCount(colInfo); 4037 if (!colCount) 4038 return false; 4039 int logicalLeft = logicalLeftOffsetForContent(); 4040 int currLogicalTopOffset = 0; 4041 int i; 4042 bool isHorizontal = isHorizontalWritingMode(); 4043 for (i = 0; i < colCount; i++) { 4044 IntRect colRect = columnRectAt(colInfo, i); 4045 int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); 4046 if (style()->isFlippedBlocksWritingMode()) 4047 currLogicalTopOffset += blockDelta; 4048 else 4049 currLogicalTopOffset -= blockDelta; 4050 } 4051 for (i = colCount - 1; i >= 0; i--) { 4052 IntRect colRect = columnRectAt(colInfo, i); 4053 flipForWritingMode(colRect); 4054 int currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft; 4055 int blockDelta = (isHorizontal ? colRect.height() : colRect.width()); 4056 if (style()->isFlippedBlocksWritingMode()) 4057 currLogicalTopOffset -= blockDelta; 4058 else 4059 currLogicalTopOffset += blockDelta; 4060 colRect.move(tx, ty); 4061 4062 if (colRect.intersects(result.rectForPoint(x, y))) { 4063 // The point is inside this column. 4064 // Adjust tx and ty to change where we hit test. 4065 4066 IntSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, currLogicalLeftOffset); 4067 int finalX = tx + offset.width(); 4068 int finalY = ty + offset.height(); 4069 if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(x, y))) 4070 hitTestContents(request, result, x, y, finalX, finalY, hitTestAction); 4071 else 4072 return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, x, y, finalX, finalY)); 4073 } 4074 } 4075 4076 return false; 4077} 4078 4079bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction) 4080{ 4081 if (childrenInline() && !isTable()) { 4082 // We have to hit-test our line boxes. 4083 if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) 4084 return true; 4085 } else { 4086 // Hit test our children. 4087 HitTestAction childHitTest = hitTestAction; 4088 if (hitTestAction == HitTestChildBlockBackgrounds) 4089 childHitTest = HitTestChildBlockBackground; 4090 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) { 4091 IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment); 4092 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, childPoint.x(), childPoint.y(), childHitTest)) 4093 return true; 4094 } 4095 } 4096 4097 return false; 4098} 4099 4100Position RenderBlock::positionForBox(InlineBox *box, bool start) const 4101{ 4102 if (!box) 4103 return Position(); 4104 4105 if (!box->renderer()->node()) 4106 return Position(node(), start ? caretMinOffset() : caretMaxOffset()); 4107 4108 if (!box->isInlineTextBox()) 4109 return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset()); 4110 4111 InlineTextBox *textBox = static_cast<InlineTextBox *>(box); 4112 return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len()); 4113} 4114 4115// FIXME: This function should go on RenderObject as an instance method. Then 4116// all cases in which positionForPoint recurs could call this instead to 4117// prevent crossing editable boundaries. This would require many tests. 4118static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const IntPoint& pointInParentCoordinates) 4119{ 4120 // FIXME: This is wrong if the child's writing-mode is different from the parent's. 4121 IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location()); 4122 4123 // If this is an anonymous renderer, we just recur normally 4124 Node* childNode = child->node(); 4125 if (!childNode) 4126 return child->positionForPoint(pointInChildCoordinates); 4127 4128 // Otherwise, first make sure that the editability of the parent and child agree. 4129 // If they don't agree, then we return a visible position just before or after the child 4130 RenderObject* ancestor = parent; 4131 while (ancestor && !ancestor->node()) 4132 ancestor = ancestor->parent(); 4133 4134 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal 4135 if (!ancestor || ancestor->node()->rendererIsEditable() == childNode->rendererIsEditable()) 4136 return child->positionForPoint(pointInChildCoordinates); 4137 4138 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child 4139 int childMiddle = parent->logicalWidthForChild(child) / 2; 4140 int logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y(); 4141 if (logicalLeft < childMiddle) 4142 return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM); 4143 return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM); 4144} 4145 4146VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInLogicalContents) 4147{ 4148 ASSERT(childrenInline()); 4149 4150 if (!firstRootBox()) 4151 return createVisiblePosition(0, DOWNSTREAM); 4152 4153 // look for the closest line box in the root box which is at the passed-in y coordinate 4154 InlineBox* closestBox = 0; 4155 RootInlineBox* firstRootBoxWithChildren = 0; 4156 RootInlineBox* lastRootBoxWithChildren = 0; 4157 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { 4158 if (!root->firstLeafChild()) 4159 continue; 4160 if (!firstRootBoxWithChildren) 4161 firstRootBoxWithChildren = root; 4162 lastRootBoxWithChildren = root; 4163 4164 // check if this root line box is located at this y coordinate 4165 if (pointInLogicalContents.y() < root->selectionBottom()) { 4166 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); 4167 if (closestBox) 4168 break; 4169 } 4170 } 4171 4172 bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom(); 4173 4174 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) { 4175 // y coordinate is below last root line box, pretend we hit it 4176 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x()); 4177 } 4178 4179 if (closestBox) { 4180 if (moveCaretToBoundary && pointInLogicalContents.y() < firstRootBoxWithChildren->selectionTop()) { 4181 // y coordinate is above first root line box, so return the start of the first 4182 return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM); 4183 } 4184 4185 // pass the box a top position that is inside it 4186 IntPoint point(pointInLogicalContents.x(), closestBox->logicalTop()); 4187 if (!isHorizontalWritingMode()) 4188 point = point.transposedPoint(); 4189 if (closestBox->renderer()->isReplaced()) 4190 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point); 4191 return closestBox->renderer()->positionForPoint(point); 4192 } 4193 4194 if (lastRootBoxWithChildren) { 4195 // We hit this case for Mac behavior when the Y coordinate is below the last box. 4196 ASSERT(moveCaretToBoundary); 4197 InlineBox* logicallyLastBox; 4198 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox)) 4199 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM); 4200 } 4201 4202 // Can't reach this. We have a root line box, but it has no kids. 4203 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text 4204 // seems to hit this code path. 4205 return createVisiblePosition(0, DOWNSTREAM); 4206} 4207 4208static inline bool isChildHitTestCandidate(RenderBox* box) 4209{ 4210 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned(); 4211} 4212 4213VisiblePosition RenderBlock::positionForPoint(const IntPoint& point) 4214{ 4215 if (isTable()) 4216 return RenderBox::positionForPoint(point); 4217 4218 if (isReplaced()) { 4219 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode. 4220 int pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y(); 4221 int pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x(); 4222 4223 if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0)) 4224 return createVisiblePosition(caretMinOffset(), DOWNSTREAM); 4225 if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth())) 4226 return createVisiblePosition(caretMaxOffset(), DOWNSTREAM); 4227 } 4228 4229 int contentsX = point.x(); 4230 int contentsY = point.y(); 4231 offsetForContents(contentsX, contentsY); 4232 IntPoint pointInContents(contentsX, contentsY); 4233 IntPoint pointInLogicalContents(pointInContents); 4234 if (!isHorizontalWritingMode()) 4235 pointInLogicalContents = pointInLogicalContents.transposedPoint(); 4236 4237 if (childrenInline()) 4238 return positionForPointWithInlineChildren(pointInLogicalContents); 4239 4240 if (lastChildBox() && pointInContents.y() > lastChildBox()->logicalTop()) { 4241 for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) { 4242 if (isChildHitTestCandidate(childBox)) 4243 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); 4244 } 4245 } else { 4246 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) { 4247 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3). 4248 if (isChildHitTestCandidate(childBox) && pointInContents.y() < childBox->logicalBottom()) 4249 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents); 4250 } 4251 } 4252 4253 // We only get here if there are no hit test candidate children below the click. 4254 return RenderBox::positionForPoint(point); 4255} 4256 4257void RenderBlock::offsetForContents(int& tx, int& ty) const 4258{ 4259 IntPoint contentsPoint(tx, ty); 4260 4261 if (hasOverflowClip()) 4262 contentsPoint += layer()->scrolledContentOffset(); 4263 4264 if (hasColumns()) 4265 adjustPointToColumnContents(contentsPoint); 4266 4267 tx = contentsPoint.x(); 4268 ty = contentsPoint.y(); 4269} 4270 4271int RenderBlock::availableLogicalWidth() const 4272{ 4273 // If we have multiple columns, then the available logical width is reduced to our column width. 4274 if (hasColumns()) 4275 return desiredColumnWidth(); 4276 return RenderBox::availableLogicalWidth(); 4277} 4278 4279int RenderBlock::columnGap() const 4280{ 4281 if (style()->hasNormalColumnGap()) 4282 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins. 4283 return static_cast<int>(style()->columnGap()); 4284} 4285 4286void RenderBlock::calcColumnWidth() 4287{ 4288 // Calculate our column width and column count. 4289 unsigned desiredColumnCount = 1; 4290 int desiredColumnWidth = contentLogicalWidth(); 4291 4292 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination. 4293 if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) { 4294 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 4295 return; 4296 } 4297 4298 int availWidth = desiredColumnWidth; 4299 int colGap = columnGap(); 4300 int colWidth = max(1, static_cast<int>(style()->columnWidth())); 4301 int colCount = max(1, static_cast<int>(style()->columnCount())); 4302 4303 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) { 4304 desiredColumnCount = colCount; 4305 desiredColumnWidth = max<int>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount); 4306 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) { 4307 desiredColumnCount = max<int>(1, (float)(availWidth + colGap) / (colWidth + colGap)); 4308 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; 4309 } else { 4310 desiredColumnCount = max(min<int>(colCount, (float)(availWidth + colGap) / (colWidth + colGap)), 1); 4311 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap; 4312 } 4313 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth); 4314} 4315 4316void RenderBlock::setDesiredColumnCountAndWidth(int count, int width) 4317{ 4318 bool destroyColumns = !firstChild() 4319 || (count == 1 && style()->hasAutoColumnWidth()) 4320 || firstChild()->isAnonymousColumnsBlock() 4321 || firstChild()->isAnonymousColumnSpanBlock(); 4322 if (destroyColumns) { 4323 if (hasColumns()) { 4324 delete gColumnInfoMap->take(this); 4325 setHasColumns(false); 4326 } 4327 } else { 4328 ColumnInfo* info; 4329 if (hasColumns()) 4330 info = gColumnInfoMap->get(this); 4331 else { 4332 if (!gColumnInfoMap) 4333 gColumnInfoMap = new ColumnInfoMap; 4334 info = new ColumnInfo; 4335 gColumnInfoMap->add(this, info); 4336 setHasColumns(true); 4337 } 4338 info->setDesiredColumnCount(count); 4339 info->setDesiredColumnWidth(width); 4340 } 4341} 4342 4343int RenderBlock::desiredColumnWidth() const 4344{ 4345 if (!hasColumns()) 4346 return contentLogicalWidth(); 4347 return gColumnInfoMap->get(this)->desiredColumnWidth(); 4348} 4349 4350unsigned RenderBlock::desiredColumnCount() const 4351{ 4352 if (!hasColumns()) 4353 return 1; 4354 return gColumnInfoMap->get(this)->desiredColumnCount(); 4355} 4356 4357ColumnInfo* RenderBlock::columnInfo() const 4358{ 4359 if (!hasColumns()) 4360 return 0; 4361 return gColumnInfoMap->get(this); 4362} 4363 4364unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const 4365{ 4366 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo); 4367 return colInfo->columnCount(); 4368} 4369 4370IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const 4371{ 4372 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo); 4373 4374 // Compute the appropriate rect based off our information. 4375 int colLogicalWidth = colInfo->desiredColumnWidth(); 4376 int colLogicalHeight = colInfo->columnHeight(); 4377 int colLogicalTop = borderBefore() + paddingBefore(); 4378 int colGap = columnGap(); 4379 int colLogicalLeft = style()->isLeftToRightDirection() ? 4380 logicalLeftOffsetForContent() + (index * (colLogicalWidth + colGap)) 4381 : logicalLeftOffsetForContent() + contentLogicalWidth() - colLogicalWidth - (index * (colLogicalWidth + colGap)); 4382 IntRect rect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight); 4383 if (isHorizontalWritingMode()) 4384 return IntRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight); 4385 return IntRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth); 4386} 4387 4388bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, int pageLogicalHeight, LayoutStateMaintainer& statePusher) 4389{ 4390 if (!hasColumns()) 4391 return false; 4392 4393 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what 4394 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall. 4395 ColumnInfo* colInfo = columnInfo(); 4396 int desiredColumnCount = colInfo->desiredColumnCount(); 4397 if (!hasSpecifiedPageLogicalHeight) { 4398 int columnHeight = pageLogicalHeight; 4399 int minColumnCount = colInfo->forcedBreaks() + 1; 4400 if (minColumnCount >= desiredColumnCount) { 4401 // The forced page breaks are in control of the balancing. Just set the column height to the 4402 // maximum page break distance. 4403 if (!pageLogicalHeight) { 4404 int distanceBetweenBreaks = max(colInfo->maximumDistanceBetweenForcedBreaks(), 4405 view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset()); 4406 columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks); 4407 } 4408 } else if (contentLogicalHeight() > pageLogicalHeight * desiredColumnCount) { 4409 // Now that we know the intrinsic height of the columns, we have to rebalance them. 4410 columnHeight = max(colInfo->minimumColumnHeight(), (int)ceilf((float)contentLogicalHeight() / desiredColumnCount)); 4411 } 4412 4413 if (columnHeight && columnHeight != pageLogicalHeight) { 4414 statePusher.pop(); 4415 m_everHadLayout = true; 4416 layoutBlock(false, columnHeight); 4417 return true; 4418 } 4419 } 4420 4421 if (pageLogicalHeight) 4422 colInfo->setColumnCountAndHeight(ceilf((float)contentLogicalHeight() / pageLogicalHeight), pageLogicalHeight); 4423 4424 if (columnCount(colInfo)) { 4425 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight()); 4426 m_overflow.clear(); 4427 } 4428 4429 return false; 4430} 4431 4432void RenderBlock::adjustPointToColumnContents(IntPoint& point) const 4433{ 4434 // Just bail if we have no columns. 4435 if (!hasColumns()) 4436 return; 4437 4438 ColumnInfo* colInfo = columnInfo(); 4439 if (!columnCount(colInfo)) 4440 return; 4441 4442 // Determine which columns we intersect. 4443 int colGap = columnGap(); 4444 int halfColGap = colGap / 2; 4445 IntPoint columnPoint(columnRectAt(colInfo, 0).location()); 4446 int logicalOffset = 0; 4447 for (unsigned i = 0; i < colInfo->columnCount(); i++) { 4448 // Add in half the column gap to the left and right of the rect. 4449 IntRect colRect = columnRectAt(colInfo, i); 4450 if (isHorizontalWritingMode()) { 4451 IntRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height()); 4452 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) { 4453 // FIXME: The clamping that follows is not completely right for right-to-left 4454 // content. 4455 // Clamp everything above the column to its top left. 4456 if (point.y() < gapAndColumnRect.y()) 4457 point = gapAndColumnRect.location(); 4458 // Clamp everything below the column to the next column's top left. If there is 4459 // no next column, this still maps to just after this column. 4460 else if (point.y() >= gapAndColumnRect.maxY()) { 4461 point = gapAndColumnRect.location(); 4462 point.move(0, gapAndColumnRect.height()); 4463 } 4464 4465 // We're inside the column. Translate the x and y into our column coordinate space. 4466 point.move(columnPoint.x() - colRect.x(), logicalOffset); 4467 return; 4468 } 4469 4470 // Move to the next position. 4471 logicalOffset += colRect.height(); 4472 } else { 4473 IntRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap); 4474 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) { 4475 // FIXME: The clamping that follows is not completely right for right-to-left 4476 // content. 4477 // Clamp everything above the column to its top left. 4478 if (point.x() < gapAndColumnRect.x()) 4479 point = gapAndColumnRect.location(); 4480 // Clamp everything below the column to the next column's top left. If there is 4481 // no next column, this still maps to just after this column. 4482 else if (point.x() >= gapAndColumnRect.maxX()) { 4483 point = gapAndColumnRect.location(); 4484 point.move(gapAndColumnRect.width(), 0); 4485 } 4486 4487 // We're inside the column. Translate the x and y into our column coordinate space. 4488 point.move(logicalOffset, columnPoint.y() - colRect.y()); 4489 return; 4490 } 4491 4492 // Move to the next position. 4493 logicalOffset += colRect.width(); 4494 } 4495 } 4496} 4497 4498void RenderBlock::adjustRectForColumns(IntRect& r) const 4499{ 4500 // Just bail if we have no columns. 4501 if (!hasColumns()) 4502 return; 4503 4504 ColumnInfo* colInfo = columnInfo(); 4505 4506 // Begin with a result rect that is empty. 4507 IntRect result; 4508 4509 // Determine which columns we intersect. 4510 unsigned colCount = columnCount(colInfo); 4511 if (!colCount) 4512 return; 4513 4514 int logicalLeft = logicalLeftOffsetForContent(); 4515 int currLogicalOffset = 0; 4516 4517 for (unsigned i = 0; i < colCount; i++) { 4518 IntRect colRect = columnRectAt(colInfo, i); 4519 IntRect repaintRect = r; 4520 if (isHorizontalWritingMode()) { 4521 int currXOffset = colRect.x() - logicalLeft; 4522 repaintRect.move(currXOffset, currLogicalOffset); 4523 currLogicalOffset -= colRect.height(); 4524 } else { 4525 int currYOffset = colRect.y() - logicalLeft; 4526 repaintRect.move(currLogicalOffset, currYOffset); 4527 currLogicalOffset -= colRect.width(); 4528 } 4529 repaintRect.intersect(colRect); 4530 result.unite(repaintRect); 4531 } 4532 4533 r = result; 4534} 4535 4536IntPoint RenderBlock::flipForWritingModeIncludingColumns(const IntPoint& point) const 4537{ 4538 ASSERT(hasColumns()); 4539 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) 4540 return point; 4541 ColumnInfo* colInfo = columnInfo(); 4542 int columnLogicalHeight = colInfo->columnHeight(); 4543 int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 4544 if (isHorizontalWritingMode()) 4545 return IntPoint(point.x(), expandedLogicalHeight - point.y()); 4546 return IntPoint(expandedLogicalHeight - point.x(), point.y()); 4547} 4548 4549void RenderBlock::flipForWritingModeIncludingColumns(IntRect& rect) const 4550{ 4551 ASSERT(hasColumns()); 4552 if (!hasColumns() || !style()->isFlippedBlocksWritingMode()) 4553 return; 4554 4555 ColumnInfo* colInfo = columnInfo(); 4556 int columnLogicalHeight = colInfo->columnHeight(); 4557 int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight(); 4558 if (isHorizontalWritingMode()) 4559 rect.setY(expandedLogicalHeight - rect.maxY()); 4560 else 4561 rect.setX(expandedLogicalHeight - rect.maxX()); 4562} 4563 4564void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const 4565{ 4566 if (!hasColumns()) 4567 return; 4568 4569 ColumnInfo* colInfo = columnInfo(); 4570 4571 int logicalLeft = logicalLeftOffsetForContent(); 4572 size_t colCount = columnCount(colInfo); 4573 int colLogicalWidth = colInfo->desiredColumnWidth(); 4574 int colLogicalHeight = colInfo->columnHeight(); 4575 4576 for (size_t i = 0; i < colCount; ++i) { 4577 // Compute the edges for a given column in the block progression direction. 4578 IntRect sliceRect = IntRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight); 4579 if (!isHorizontalWritingMode()) 4580 sliceRect = sliceRect.transposedRect(); 4581 4582 // If we have a flipped blocks writing mode, then convert the column so that it's coming from the after edge (either top or left edge). 4583 flipForWritingModeIncludingColumns(sliceRect); 4584 4585 int logicalOffset = style()->isFlippedBlocksWritingMode() ? (colCount - 1 - i) * colLogicalHeight : i * colLogicalHeight; 4586 4587 // Now we're in the same coordinate space as the point. See if it is inside the rectangle. 4588 if (isHorizontalWritingMode()) { 4589 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) { 4590 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset); 4591 return; 4592 } 4593 } else { 4594 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) { 4595 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft); 4596 return; 4597 } 4598 } 4599 } 4600} 4601 4602void RenderBlock::computePreferredLogicalWidths() 4603{ 4604 ASSERT(preferredLogicalWidthsDirty()); 4605 4606 updateFirstLetter(); 4607 4608 if (!isTableCell() && style()->logicalWidth().isFixed() && style()->logicalWidth().value() > 0) 4609 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->logicalWidth().value()); 4610 else { 4611 m_minPreferredLogicalWidth = 0; 4612 m_maxPreferredLogicalWidth = 0; 4613 4614 if (childrenInline()) 4615 computeInlinePreferredLogicalWidths(); 4616 else 4617 computeBlockPreferredLogicalWidths(); 4618 4619 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth); 4620 4621 if (!style()->autoWrap() && childrenInline()) { 4622 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth; 4623 4624 // A horizontal marquee with inline children has no minimum width. 4625 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal()) 4626 m_minPreferredLogicalWidth = 0; 4627 } 4628 4629 int scrollbarWidth = 0; 4630 if (hasOverflowClip() && style()->overflowY() == OSCROLL) { 4631 layer()->setHasVerticalScrollbar(true); 4632 scrollbarWidth = verticalScrollbarWidth(); 4633 m_maxPreferredLogicalWidth += scrollbarWidth; 4634 } 4635 4636 if (isTableCell()) { 4637 Length w = toRenderTableCell(this)->styleOrColLogicalWidth(); 4638 if (w.isFixed() && w.value() > 0) { 4639 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(w.value())); 4640 scrollbarWidth = 0; 4641 } 4642 } 4643 4644 m_minPreferredLogicalWidth += scrollbarWidth; 4645 } 4646 4647 if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) { 4648 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value())); 4649 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value())); 4650 } 4651 4652 if (style()->logicalMaxWidth().isFixed() && style()->logicalMaxWidth().value() != undefinedLength) { 4653 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value())); 4654 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value())); 4655 } 4656 4657 int borderAndPadding = borderAndPaddingLogicalWidth(); 4658 m_minPreferredLogicalWidth += borderAndPadding; 4659 m_maxPreferredLogicalWidth += borderAndPadding; 4660 4661 setPreferredLogicalWidthsDirty(false); 4662} 4663 4664struct InlineMinMaxIterator { 4665/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to 4666 inline min/max width calculations. Note the following about the way it walks: 4667 (1) Positioned content is skipped (since it does not contribute to min/max width of a block) 4668 (2) We do not drill into the children of floats or replaced elements, since you can't break 4669 in the middle of such an element. 4670 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have 4671 distinct borders/margin/padding that contribute to the min/max width. 4672*/ 4673 RenderObject* parent; 4674 RenderObject* current; 4675 bool endOfInline; 4676 4677 InlineMinMaxIterator(RenderObject* p, bool end = false) 4678 :parent(p), current(p), endOfInline(end) {} 4679 4680 RenderObject* next(); 4681}; 4682 4683RenderObject* InlineMinMaxIterator::next() 4684{ 4685 RenderObject* result = 0; 4686 bool oldEndOfInline = endOfInline; 4687 endOfInline = false; 4688 while (current || current == parent) { 4689 if (!oldEndOfInline && 4690 (current == parent || 4691 (!current->isFloating() && !current->isReplaced() && !current->isPositioned()))) 4692 result = current->firstChild(); 4693 if (!result) { 4694 // We hit the end of our inline. (It was empty, e.g., <span></span>.) 4695 if (!oldEndOfInline && current->isRenderInline()) { 4696 result = current; 4697 endOfInline = true; 4698 break; 4699 } 4700 4701 while (current && current != parent) { 4702 result = current->nextSibling(); 4703 if (result) break; 4704 current = current->parent(); 4705 if (current && current != parent && current->isRenderInline()) { 4706 result = current; 4707 endOfInline = true; 4708 break; 4709 } 4710 } 4711 } 4712 4713 if (!result) 4714 break; 4715 4716 if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline())) 4717 break; 4718 4719 current = result; 4720 result = 0; 4721 } 4722 4723 // Update our position. 4724 current = result; 4725 return current; 4726} 4727 4728static int getBPMWidth(int childValue, Length cssUnit) 4729{ 4730 if (cssUnit.type() != Auto) 4731 return (cssUnit.isFixed() ? cssUnit.value() : childValue); 4732 return 0; 4733} 4734 4735static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline) 4736{ 4737 RenderStyle* cstyle = child->style(); 4738 if (endOfInline) 4739 return getBPMWidth(child->marginEnd(), cstyle->marginEnd()) + 4740 getBPMWidth(child->paddingEnd(), cstyle->paddingEnd()) + 4741 child->borderEnd(); 4742 return getBPMWidth(child->marginStart(), cstyle->marginStart()) + 4743 getBPMWidth(child->paddingStart(), cstyle->paddingStart()) + 4744 child->borderStart(); 4745} 4746 4747static inline void stripTrailingSpace(float& inlineMax, float& inlineMin, 4748 RenderObject* trailingSpaceChild) 4749{ 4750 if (trailingSpaceChild && trailingSpaceChild->isText()) { 4751 // Collapse away the trailing space at the end of a block. 4752 RenderText* t = toRenderText(trailingSpaceChild); 4753 const UChar space = ' '; 4754 const Font& font = t->style()->font(); // FIXME: This ignores first-line. 4755 float spaceWidth = font.width(TextRun(&space, 1)); 4756 inlineMax -= spaceWidth + font.wordSpacing(); 4757 if (inlineMin > inlineMax) 4758 inlineMin = inlineMax; 4759 } 4760} 4761 4762static inline void updatePreferredWidth(int& preferredWidth, float& result) 4763{ 4764 int snappedResult = ceilf(result); 4765 preferredWidth = max(snappedResult, preferredWidth); 4766} 4767 4768void RenderBlock::computeInlinePreferredLogicalWidths() 4769{ 4770 float inlineMax = 0; 4771 float inlineMin = 0; 4772 4773 int cw = containingBlock()->contentLogicalWidth(); 4774 4775 // If we are at the start of a line, we want to ignore all white-space. 4776 // Also strip spaces if we previously had text that ended in a trailing space. 4777 bool stripFrontSpaces = true; 4778 RenderObject* trailingSpaceChild = 0; 4779 4780 // Firefox and Opera will allow a table cell to grow to fit an image inside it under 4781 // very specific cirucumstances (in order to match common WinIE renderings). 4782 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.) 4783 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto(); 4784 4785 bool autoWrap, oldAutoWrap; 4786 autoWrap = oldAutoWrap = style()->autoWrap(); 4787 4788 InlineMinMaxIterator childIterator(this); 4789 bool addedTextIndent = false; // Only gets added in once. 4790 RenderObject* prevFloat = 0; 4791 while (RenderObject* child = childIterator.next()) { 4792 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() : 4793 child->style()->autoWrap(); 4794 4795 if (!child->isBR()) { 4796 // Step One: determine whether or not we need to go ahead and 4797 // terminate our current line. Each discrete chunk can become 4798 // the new min-width, if it is the widest chunk seen so far, and 4799 // it can also become the max-width. 4800 4801 // Children fall into three categories: 4802 // (1) An inline flow object. These objects always have a min/max of 0, 4803 // and are included in the iteration solely so that their margins can 4804 // be added in. 4805 // 4806 // (2) An inline non-text non-flow object, e.g., an inline replaced element. 4807 // These objects can always be on a line by themselves, so in this situation 4808 // we need to go ahead and break the current line, and then add in our own 4809 // margins and min/max width on its own line, and then terminate the line. 4810 // 4811 // (3) A text object. Text runs can have breakable characters at the start, 4812 // the middle or the end. They may also lose whitespace off the front if 4813 // we're already ignoring whitespace. In order to compute accurate min-width 4814 // information, we need three pieces of information. 4815 // (a) the min-width of the first non-breakable run. Should be 0 if the text string 4816 // starts with whitespace. 4817 // (b) the min-width of the last non-breakable run. Should be 0 if the text string 4818 // ends with whitespace. 4819 // (c) the min/max width of the string (trimmed for whitespace). 4820 // 4821 // If the text string starts with whitespace, then we need to go ahead and 4822 // terminate our current line (unless we're already in a whitespace stripping 4823 // mode. 4824 // 4825 // If the text string has a breakable character in the middle, but didn't start 4826 // with whitespace, then we add the width of the first non-breakable run and 4827 // then end the current line. We then need to use the intermediate min/max width 4828 // values (if any of them are larger than our current min/max). We then look at 4829 // the width of the last non-breakable run and use that to start a new line 4830 // (unless we end in whitespace). 4831 RenderStyle* cstyle = child->style(); 4832 float childMin = 0; 4833 float childMax = 0; 4834 4835 if (!child->isText()) { 4836 // Case (1) and (2). Inline replaced and inline flow elements. 4837 if (child->isRenderInline()) { 4838 // Add in padding/border/margin from the appropriate side of 4839 // the element. 4840 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline); 4841 childMin += bpm; 4842 childMax += bpm; 4843 4844 inlineMin += childMin; 4845 inlineMax += childMax; 4846 4847 child->setPreferredLogicalWidthsDirty(false); 4848 } else { 4849 // Inline replaced elts add in their margins to their min/max values. 4850 float margins = 0; 4851 Length startMargin = cstyle->marginStart(); 4852 Length endMargin = cstyle->marginEnd(); 4853 if (startMargin.isFixed()) 4854 margins += startMargin.value(); 4855 if (endMargin.isFixed()) 4856 margins += endMargin.value(); 4857 childMin += margins; 4858 childMax += margins; 4859 } 4860 } 4861 4862 if (!child->isRenderInline() && !child->isText()) { 4863 // Case (2). Inline replaced elements and floats. 4864 // Go ahead and terminate the current line as far as 4865 // minwidth is concerned. 4866 childMin += child->minPreferredLogicalWidth(); 4867 childMax += child->maxPreferredLogicalWidth(); 4868 4869 bool clearPreviousFloat; 4870 if (child->isFloating()) { 4871 clearPreviousFloat = (prevFloat 4872 && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT)) 4873 || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT)))); 4874 prevFloat = child; 4875 } else 4876 clearPreviousFloat = false; 4877 4878 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak; 4879 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) { 4880 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4881 inlineMin = 0; 4882 } 4883 4884 // If we're supposed to clear the previous float, then terminate maxwidth as well. 4885 if (clearPreviousFloat) { 4886 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); 4887 inlineMax = 0; 4888 } 4889 4890 // Add in text-indent. This is added in only once. 4891 int ti = 0; 4892 if (!addedTextIndent) { 4893 addedTextIndent = true; 4894 ti = style()->textIndent().calcMinValue(cw); 4895 childMin += ti; 4896 childMax += ti; 4897 } 4898 4899 // Add our width to the max. 4900 inlineMax += childMax; 4901 4902 if (!autoWrap || !canBreakReplacedElement) { 4903 if (child->isFloating()) 4904 updatePreferredWidth(m_minPreferredLogicalWidth, childMin); 4905 else 4906 inlineMin += childMin; 4907 } else { 4908 // Now check our line. 4909 updatePreferredWidth(m_minPreferredLogicalWidth, childMin); 4910 4911 // Now start a new line. 4912 inlineMin = 0; 4913 } 4914 4915 // We are no longer stripping whitespace at the start of 4916 // a line. 4917 if (!child->isFloating()) { 4918 stripFrontSpaces = false; 4919 trailingSpaceChild = 0; 4920 } 4921 } else if (child->isText()) { 4922 // Case (3). Text. 4923 RenderText* t = toRenderText(child); 4924 4925 if (t->isWordBreak()) { 4926 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4927 inlineMin = 0; 4928 continue; 4929 } 4930 4931 if (t->style()->hasTextCombine() && t->isCombineText()) 4932 toRenderCombineText(t)->combineText(); 4933 4934 // Determine if we have a breakable character. Pass in 4935 // whether or not we should ignore any spaces at the front 4936 // of the string. If those are going to be stripped out, 4937 // then they shouldn't be considered in the breakable char 4938 // check. 4939 bool hasBreakableChar, hasBreak; 4940 float beginMin, endMin; 4941 bool beginWS, endWS; 4942 float beginMax, endMax; 4943 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS, 4944 hasBreakableChar, hasBreak, beginMax, endMax, 4945 childMin, childMax, stripFrontSpaces); 4946 4947 // This text object will not be rendered, but it may still provide a breaking opportunity. 4948 if (!hasBreak && childMax == 0) { 4949 if (autoWrap && (beginWS || endWS)) { 4950 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4951 inlineMin = 0; 4952 } 4953 continue; 4954 } 4955 4956 if (stripFrontSpaces) 4957 trailingSpaceChild = child; 4958 else 4959 trailingSpaceChild = 0; 4960 4961 // Add in text-indent. This is added in only once. 4962 int ti = 0; 4963 if (!addedTextIndent) { 4964 addedTextIndent = true; 4965 ti = style()->textIndent().calcMinValue(cw); 4966 childMin+=ti; beginMin += ti; 4967 childMax+=ti; beginMax += ti; 4968 } 4969 4970 // If we have no breakable characters at all, 4971 // then this is the easy case. We add ourselves to the current 4972 // min and max and continue. 4973 if (!hasBreakableChar) { 4974 inlineMin += childMin; 4975 } else { 4976 // We have a breakable character. Now we need to know if 4977 // we start and end with whitespace. 4978 if (beginWS) 4979 // Go ahead and end the current line. 4980 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4981 else { 4982 inlineMin += beginMin; 4983 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4984 childMin -= ti; 4985 } 4986 4987 inlineMin = childMin; 4988 4989 if (endWS) { 4990 // We end in whitespace, which means we can go ahead 4991 // and end our current line. 4992 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4993 inlineMin = 0; 4994 } else { 4995 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 4996 inlineMin = endMin; 4997 } 4998 } 4999 5000 if (hasBreak) { 5001 inlineMax += beginMax; 5002 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); 5003 updatePreferredWidth(m_maxPreferredLogicalWidth, childMax); 5004 inlineMax = endMax; 5005 } else 5006 inlineMax += childMax; 5007 } 5008 5009 // Ignore spaces after a list marker. 5010 if (child->isListMarker()) 5011 stripFrontSpaces = true; 5012 } else { 5013 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 5014 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); 5015 inlineMin = inlineMax = 0; 5016 stripFrontSpaces = true; 5017 trailingSpaceChild = 0; 5018 } 5019 5020 oldAutoWrap = autoWrap; 5021 } 5022 5023 if (style()->collapseWhiteSpace()) 5024 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild); 5025 5026 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin); 5027 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax); 5028} 5029 5030// Use a very large value (in effect infinite). 5031#define BLOCK_MAX_WIDTH 15000 5032 5033void RenderBlock::computeBlockPreferredLogicalWidths() 5034{ 5035 bool nowrap = style()->whiteSpace() == NOWRAP; 5036 5037 RenderObject *child = firstChild(); 5038 int floatLeftWidth = 0, floatRightWidth = 0; 5039 while (child) { 5040 // Positioned children don't affect the min/max width 5041 if (child->isPositioned()) { 5042 child = child->nextSibling(); 5043 continue; 5044 } 5045 5046 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) { 5047 int floatTotalWidth = floatLeftWidth + floatRightWidth; 5048 if (child->style()->clear() & CLEFT) { 5049 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth); 5050 floatLeftWidth = 0; 5051 } 5052 if (child->style()->clear() & CRIGHT) { 5053 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth); 5054 floatRightWidth = 0; 5055 } 5056 } 5057 5058 // A margin basically has three types: fixed, percentage, and auto (variable). 5059 // Auto and percentage margins simply become 0 when computing min/max width. 5060 // Fixed margins can be added in as is. 5061 Length startMarginLength = child->style()->marginStart(); 5062 Length endMarginLength = child->style()->marginEnd(); 5063 int margin = 0; 5064 int marginStart = 0; 5065 int marginEnd = 0; 5066 if (startMarginLength.isFixed()) 5067 marginStart += startMarginLength.value(); 5068 if (endMarginLength.isFixed()) 5069 marginEnd += endMarginLength.value(); 5070 margin = marginStart + marginEnd; 5071 5072 int w = child->minPreferredLogicalWidth() + margin; 5073 m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth); 5074 5075 // IE ignores tables for calculation of nowrap. Makes some sense. 5076 if (nowrap && !child->isTable()) 5077 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth); 5078 5079 w = child->maxPreferredLogicalWidth() + margin; 5080 5081 if (!child->isFloating()) { 5082 if (child->isBox() && toRenderBox(child)->avoidsFloats()) { 5083 // Determine a left and right max value based off whether or not the floats can fit in the 5084 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin 5085 // is smaller than the float width. 5086 bool ltr = containingBlock()->style()->isLeftToRightDirection(); 5087 int marginLogicalLeft = ltr ? marginStart : marginEnd; 5088 int marginLogicalRight = ltr ? marginEnd : marginStart; 5089 int maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft; 5090 int maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight; 5091 w = child->maxPreferredLogicalWidth() + maxLeft + maxRight; 5092 w = max(w, floatLeftWidth + floatRightWidth); 5093 } 5094 else 5095 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth); 5096 floatLeftWidth = floatRightWidth = 0; 5097 } 5098 5099 if (child->isFloating()) { 5100 if (style()->floating() == FLEFT) 5101 floatLeftWidth += w; 5102 else 5103 floatRightWidth += w; 5104 } else 5105 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth); 5106 5107 // A very specific WinIE quirk. 5108 // Example: 5109 /* 5110 <div style="position:absolute; width:100px; top:50px;"> 5111 <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green"> 5112 <table style="width:100%"><tr><td></table> 5113 </div> 5114 </div> 5115 */ 5116 // In the above example, the inner absolute positioned block should have a computed width 5117 // of 100px because of the table. 5118 // We can achieve this effect by making the maxwidth of blocks that contain tables 5119 // with percentage widths be infinite (as long as they are not inside a table cell). 5120 if (document()->inQuirksMode() && child->style()->logicalWidth().isPercent() && 5121 !isTableCell() && child->isTable() && m_maxPreferredLogicalWidth < BLOCK_MAX_WIDTH) { 5122 RenderBlock* cb = containingBlock(); 5123 while (!cb->isRenderView() && !cb->isTableCell()) 5124 cb = cb->containingBlock(); 5125 if (!cb->isTableCell()) 5126 m_maxPreferredLogicalWidth = BLOCK_MAX_WIDTH; 5127 } 5128 5129 child = child->nextSibling(); 5130 } 5131 5132 // Always make sure these values are non-negative. 5133 m_minPreferredLogicalWidth = max(0, m_minPreferredLogicalWidth); 5134 m_maxPreferredLogicalWidth = max(0, m_maxPreferredLogicalWidth); 5135 5136 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth); 5137} 5138 5139bool RenderBlock::hasLineIfEmpty() const 5140{ 5141 if (!node()) 5142 return false; 5143 5144 if (node()->rendererIsEditable() && node()->rootEditableElement() == node()) 5145 return true; 5146 5147 if (node()->isShadowRoot() && (node()->shadowHost()->hasTagName(inputTag))) 5148 return true; 5149 5150 return false; 5151} 5152 5153int RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const 5154{ 5155 // Inline blocks are replaced elements. Otherwise, just pass off to 5156 // the base class. If we're being queried as though we're the root line 5157 // box, then the fact that we're an inline-block is irrelevant, and we behave 5158 // just like a block. 5159 if (isReplaced() && linePositionMode == PositionOnContainingLine) 5160 return RenderBox::lineHeight(firstLine, direction, linePositionMode); 5161 5162 if (firstLine && document()->usesFirstLineRules()) { 5163 RenderStyle* s = style(firstLine); 5164 if (s != style()) 5165 return s->computedLineHeight(); 5166 } 5167 5168 if (m_lineHeight == -1) 5169 m_lineHeight = style()->computedLineHeight(); 5170 5171 return m_lineHeight; 5172} 5173 5174int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const 5175{ 5176 // Inline blocks are replaced elements. Otherwise, just pass off to 5177 // the base class. If we're being queried as though we're the root line 5178 // box, then the fact that we're an inline-block is irrelevant, and we behave 5179 // just like a block. 5180 if (isReplaced() && linePositionMode == PositionOnContainingLine) { 5181 // For "leaf" theme objects, let the theme decide what the baseline position is. 5182 // FIXME: Might be better to have a custom CSS property instead, so that if the theme 5183 // is turned off, checkboxes/radios will still have decent baselines. 5184 // FIXME: Need to patch form controls to deal with vertical lines. 5185 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance())) 5186 return theme()->baselinePosition(this); 5187 5188 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in 5189 // the normal flow. We make an exception for marquees, since their baselines are meaningless 5190 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them. 5191 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled 5192 // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside 5193 // of our content box. 5194 bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0) 5195 : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun()); 5196 5197 int baselinePos = ignoreBaseline ? -1 : lastLineBoxBaseline(); 5198 5199 int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth(); 5200 if (baselinePos != -1 && baselinePos <= bottomOfContent) 5201 return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos; 5202 5203 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode); 5204 } 5205 5206 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics(); 5207 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2; 5208} 5209 5210int RenderBlock::firstLineBoxBaseline() const 5211{ 5212 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun())) 5213 return -1; 5214 5215 if (childrenInline()) { 5216 if (firstLineBox()) 5217 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType()); 5218 else 5219 return -1; 5220 } 5221 else { 5222 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) { 5223 if (!curr->isFloatingOrPositioned()) { 5224 int result = curr->firstLineBoxBaseline(); 5225 if (result != -1) 5226 return curr->logicalTop() + result; // Translate to our coordinate space. 5227 } 5228 } 5229 } 5230 5231 return -1; 5232} 5233 5234int RenderBlock::lastLineBoxBaseline() const 5235{ 5236 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun())) 5237 return -1; 5238 5239 LineDirectionMode lineDirection = isHorizontalWritingMode() ? HorizontalLine : VerticalLine; 5240 5241 if (childrenInline()) { 5242 if (!firstLineBox() && hasLineIfEmpty()) { 5243 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); 5244 return fontMetrics.ascent() 5245 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 5246 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); 5247 } 5248 if (lastLineBox()) 5249 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType()); 5250 return -1; 5251 } else { 5252 bool haveNormalFlowChild = false; 5253 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) { 5254 if (!curr->isFloatingOrPositioned()) { 5255 haveNormalFlowChild = true; 5256 int result = curr->lastLineBoxBaseline(); 5257 if (result != -1) 5258 return curr->logicalTop() + result; // Translate to our coordinate space. 5259 } 5260 } 5261 if (!haveNormalFlowChild && hasLineIfEmpty()) { 5262 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics(); 5263 return fontMetrics.ascent() 5264 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2 5265 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight()); 5266 } 5267 } 5268 5269 return -1; 5270} 5271 5272bool RenderBlock::containsNonZeroBidiLevel() const 5273{ 5274 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) { 5275 for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) { 5276 if (box->bidiLevel()) 5277 return true; 5278 } 5279 } 5280 return false; 5281} 5282 5283RenderBlock* RenderBlock::firstLineBlock() const 5284{ 5285 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this); 5286 bool hasPseudo = false; 5287 while (true) { 5288 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE); 5289 if (hasPseudo) 5290 break; 5291 RenderObject* parentBlock = firstLineBlock->parent(); 5292 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() || 5293 !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow()) 5294 break; 5295 ASSERT(parentBlock->isRenderBlock()); 5296 firstLineBlock = toRenderBlock(parentBlock); 5297 } 5298 5299 if (!hasPseudo) 5300 return 0; 5301 5302 return firstLineBlock; 5303} 5304 5305static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer) 5306{ 5307 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle()); 5308 // Force inline display (except for floating first-letters). 5309 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE); 5310 // CSS2 says first-letter can't be positioned. 5311 pseudoStyle->setPosition(StaticPosition); 5312 return pseudoStyle; 5313} 5314 5315// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter 5316// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe), 5317// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included" 5318static inline bool isPunctuationForFirstLetter(UChar c) 5319{ 5320 CharCategory charCategory = category(c); 5321 return charCategory == Punctuation_Open 5322 || charCategory == Punctuation_Close 5323 || charCategory == Punctuation_InitialQuote 5324 || charCategory == Punctuation_FinalQuote 5325 || charCategory == Punctuation_Other; 5326} 5327 5328static inline bool shouldSkipForFirstLetter(UChar c) 5329{ 5330 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c); 5331} 5332 5333void RenderBlock::updateFirstLetter() 5334{ 5335 if (!document()->usesFirstLetterRules()) 5336 return; 5337 // Don't recur 5338 if (style()->styleType() == FIRST_LETTER) 5339 return; 5340 5341 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find 5342 // an efficient way to check for that situation though before implementing anything. 5343 RenderObject* firstLetterBlock = this; 5344 bool hasPseudoStyle = false; 5345 while (true) { 5346 // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly 5347 // prevents form controls from honoring first-letter. 5348 hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER) 5349 && firstLetterBlock->canHaveChildren(); 5350 if (hasPseudoStyle) 5351 break; 5352 RenderObject* parentBlock = firstLetterBlock->parent(); 5353 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock || 5354 !parentBlock->isBlockFlow()) 5355 break; 5356 firstLetterBlock = parentBlock; 5357 } 5358 5359 if (!hasPseudoStyle) 5360 return; 5361 5362 // Drill into inlines looking for our first text child. 5363 RenderObject* currChild = firstLetterBlock->firstChild(); 5364 while (currChild && ((!currChild->isReplaced() && !currChild->isRenderButton() && !currChild->isMenuList()) || currChild->isFloatingOrPositioned()) && !currChild->isText()) { 5365 if (currChild->isFloatingOrPositioned()) { 5366 if (currChild->style()->styleType() == FIRST_LETTER) { 5367 currChild = currChild->firstChild(); 5368 break; 5369 } 5370 currChild = currChild->nextSibling(); 5371 } else 5372 currChild = currChild->firstChild(); 5373 } 5374 5375 // Get list markers out of the way. 5376 while (currChild && currChild->isListMarker()) 5377 currChild = currChild->nextSibling(); 5378 5379 if (!currChild) 5380 return; 5381 5382 // If the child already has style, then it has already been created, so we just want 5383 // to update it. 5384 if (currChild->parent()->style()->styleType() == FIRST_LETTER) { 5385 RenderObject* firstLetter = currChild->parent(); 5386 RenderObject* firstLetterContainer = firstLetter->parent(); 5387 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); 5388 5389 if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) { 5390 // The first-letter renderer needs to be replaced. Create a new renderer of the right type. 5391 RenderObject* newFirstLetter; 5392 if (pseudoStyle->display() == INLINE) 5393 newFirstLetter = new (renderArena()) RenderInline(document()); 5394 else 5395 newFirstLetter = new (renderArena()) RenderBlock(document()); 5396 newFirstLetter->setStyle(pseudoStyle); 5397 5398 // Move the first letter into the new renderer. 5399 view()->disableLayoutState(); 5400 while (RenderObject* child = firstLetter->firstChild()) { 5401 if (child->isText()) 5402 toRenderText(child)->removeAndDestroyTextBoxes(); 5403 firstLetter->removeChild(child); 5404 newFirstLetter->addChild(child, 0); 5405 } 5406 5407 RenderTextFragment* remainingText = 0; 5408 RenderObject* nextSibling = firstLetter->nextSibling(); 5409 RenderObject* next = nextSibling; 5410 while (next) { 5411 if (next->isText() && toRenderText(next)->isTextFragment()) { 5412 remainingText = toRenderTextFragment(next); 5413 break; 5414 } 5415 next = next->nextSibling(); 5416 } 5417 if (remainingText) { 5418 ASSERT(remainingText->node()->renderer() == remainingText); 5419 // Replace the old renderer with the new one. 5420 remainingText->setFirstLetter(newFirstLetter); 5421 } 5422 firstLetter->destroy(); 5423 firstLetter = newFirstLetter; 5424 firstLetterContainer->addChild(firstLetter, nextSibling); 5425 view()->enableLayoutState(); 5426 } else 5427 firstLetter->setStyle(pseudoStyle); 5428 5429 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) { 5430 if (genChild->isText()) 5431 genChild->setStyle(pseudoStyle); 5432 } 5433 5434 return; 5435 } 5436 5437 if (!currChild->isText() || currChild->isBR()) 5438 return; 5439 5440 // If the child does not already have style, we create it here. 5441 RenderObject* firstLetterContainer = currChild->parent(); 5442 5443 // Our layout state is not valid for the repaints we are going to trigger by 5444 // adding and removing children of firstLetterContainer. 5445 view()->disableLayoutState(); 5446 5447 RenderText* textObj = toRenderText(currChild); 5448 5449 // Create our pseudo style now that we have our firstLetterContainer determined. 5450 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer); 5451 5452 RenderObject* firstLetter = 0; 5453 if (pseudoStyle->display() == INLINE) 5454 firstLetter = new (renderArena()) RenderInline(document()); 5455 else 5456 firstLetter = new (renderArena()) RenderBlock(document()); 5457 firstLetter->setStyle(pseudoStyle); 5458 firstLetterContainer->addChild(firstLetter, currChild); 5459 5460 // The original string is going to be either a generated content string or a DOM node's 5461 // string. We want the original string before it got transformed in case first-letter has 5462 // no text-transform or a different text-transform applied to it. 5463 RefPtr<StringImpl> oldText = textObj->originalText(); 5464 ASSERT(oldText); 5465 5466 if (oldText && oldText->length() > 0) { 5467 unsigned length = 0; 5468 5469 // Account for leading spaces and punctuation. 5470 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length])) 5471 length++; 5472 5473 // Account for first letter. 5474 length++; 5475 5476 // Keep looking for whitespace and allowed punctuation, but avoid 5477 // accumulating just whitespace into the :first-letter. 5478 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) { 5479 UChar c = (*oldText)[scanLength]; 5480 5481 if (!shouldSkipForFirstLetter(c)) 5482 break; 5483 5484 if (isPunctuationForFirstLetter(c)) 5485 length = scanLength + 1; 5486 } 5487 5488 // Construct a text fragment for the text after the first letter. 5489 // This text fragment might be empty. 5490 RenderTextFragment* remainingText = 5491 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length); 5492 remainingText->setStyle(textObj->style()); 5493 if (remainingText->node()) 5494 remainingText->node()->setRenderer(remainingText); 5495 5496 firstLetterContainer->addChild(remainingText, textObj); 5497 firstLetterContainer->removeChild(textObj); 5498 remainingText->setFirstLetter(firstLetter); 5499 5500 // construct text fragment for the first letter 5501 RenderTextFragment* letter = 5502 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length); 5503 letter->setStyle(pseudoStyle); 5504 firstLetter->addChild(letter); 5505 5506 textObj->destroy(); 5507 } 5508 view()->enableLayoutState(); 5509} 5510 5511// Helper methods for obtaining the last line, computing line counts and heights for line counts 5512// (crawling into blocks). 5513static bool shouldCheckLines(RenderObject* obj) 5514{ 5515 return !obj->isFloatingOrPositioned() && !obj->isRunIn() && 5516 obj->isBlockFlow() && obj->style()->height().isAuto() && 5517 (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL); 5518} 5519 5520static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count) 5521{ 5522 if (block->style()->visibility() == VISIBLE) { 5523 if (block->childrenInline()) { 5524 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { 5525 if (count++ == i) 5526 return box; 5527 } 5528 } 5529 else { 5530 for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) { 5531 if (shouldCheckLines(obj)) { 5532 RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count); 5533 if (box) 5534 return box; 5535 } 5536 } 5537 } 5538 } 5539 return 0; 5540} 5541 5542static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count) 5543{ 5544 if (block->style()->visibility() == VISIBLE) { 5545 if (block->childrenInline()) { 5546 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) { 5547 if (++count == l) 5548 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); 5549 } 5550 } 5551 else { 5552 RenderBox* normalFlowChildWithoutLines = 0; 5553 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) { 5554 if (shouldCheckLines(obj)) { 5555 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count); 5556 if (result != -1) 5557 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0); 5558 } 5559 else if (!obj->isFloatingOrPositioned() && !obj->isRunIn()) 5560 normalFlowChildWithoutLines = obj; 5561 } 5562 if (normalFlowChildWithoutLines && l == 0) 5563 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height(); 5564 } 5565 } 5566 5567 return -1; 5568} 5569 5570RootInlineBox* RenderBlock::lineAtIndex(int i) 5571{ 5572 int count = 0; 5573 return getLineAtIndex(this, i, count); 5574} 5575 5576int RenderBlock::lineCount() 5577{ 5578 int count = 0; 5579 if (style()->visibility() == VISIBLE) { 5580 if (childrenInline()) 5581 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 5582 count++; 5583 else 5584 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) 5585 if (shouldCheckLines(obj)) 5586 count += toRenderBlock(obj)->lineCount(); 5587 } 5588 return count; 5589} 5590 5591int RenderBlock::heightForLineCount(int l) 5592{ 5593 int count = 0; 5594 return getHeightForLineCount(this, l, true, count); 5595} 5596 5597void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const 5598{ 5599 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting 5600 // for either overflow or translations via relative positioning. 5601 if (style()->visibility() == VISIBLE) { 5602 if (childrenInline()) { 5603 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) { 5604 if (box->firstChild()) 5605 left = min(left, x + static_cast<int>(box->firstChild()->x())); 5606 if (box->lastChild()) 5607 right = max(right, x + static_cast<int>(ceilf(box->lastChild()->logicalRight()))); 5608 } 5609 } 5610 else { 5611 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) { 5612 if (!obj->isFloatingOrPositioned()) { 5613 if (obj->isBlockFlow() && !obj->hasOverflowClip()) 5614 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right); 5615 else if (obj->style()->visibility() == VISIBLE) { 5616 // We are a replaced element or some kind of non-block-flow object. 5617 left = min(left, x + obj->x()); 5618 right = max(right, x + obj->x() + obj->width()); 5619 } 5620 } 5621 } 5622 } 5623 5624 if (m_floatingObjects) { 5625 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set(); 5626 FloatingObjectSetIterator end = floatingObjectSet.end(); 5627 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) { 5628 FloatingObject* r = *it; 5629 // Only examine the object if our m_shouldPaint flag is set. 5630 if (r->m_shouldPaint) { 5631 int floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x(); 5632 int floatRight = floatLeft + r->m_renderer->width(); 5633 left = min(left, floatLeft); 5634 right = max(right, floatRight); 5635 } 5636 } 5637 } 5638 } 5639} 5640 5641void RenderBlock::borderFitAdjust(int& x, int& w) const 5642{ 5643 if (style()->borderFit() == BorderFitBorder) 5644 return; 5645 5646 // Walk any normal flow lines to snugly fit. 5647 int left = INT_MAX; 5648 int right = INT_MIN; 5649 int oldWidth = w; 5650 adjustForBorderFit(0, left, right); 5651 if (left != INT_MAX) { 5652 left -= (borderLeft() + paddingLeft()); 5653 if (left > 0) { 5654 x += left; 5655 w -= left; 5656 } 5657 } 5658 if (right != INT_MIN) { 5659 right += (borderRight() + paddingRight()); 5660 if (right < oldWidth) 5661 w -= (oldWidth - right); 5662 } 5663} 5664 5665void RenderBlock::clearTruncation() 5666{ 5667 if (style()->visibility() == VISIBLE) { 5668 if (childrenInline() && hasMarkupTruncation()) { 5669 setHasMarkupTruncation(false); 5670 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) 5671 box->clearTruncation(); 5672 } 5673 else 5674 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) 5675 if (shouldCheckLines(obj)) 5676 toRenderBlock(obj)->clearTruncation(); 5677 } 5678} 5679 5680void RenderBlock::setMaxMarginBeforeValues(int pos, int neg) 5681{ 5682 if (!m_rareData) { 5683 if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this)) 5684 return; 5685 m_rareData = new RenderBlockRareData(this); 5686 } 5687 m_rareData->m_margins.setPositiveMarginBefore(pos); 5688 m_rareData->m_margins.setNegativeMarginBefore(neg); 5689} 5690 5691void RenderBlock::setMaxMarginAfterValues(int pos, int neg) 5692{ 5693 if (!m_rareData) { 5694 if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this)) 5695 return; 5696 m_rareData = new RenderBlockRareData(this); 5697 } 5698 m_rareData->m_margins.setPositiveMarginAfter(pos); 5699 m_rareData->m_margins.setNegativeMarginAfter(neg); 5700} 5701 5702void RenderBlock::setPaginationStrut(int strut) 5703{ 5704 if (!m_rareData) { 5705 if (!strut) 5706 return; 5707 m_rareData = new RenderBlockRareData(this); 5708 } 5709 m_rareData->m_paginationStrut = strut; 5710} 5711 5712void RenderBlock::setPageLogicalOffset(int logicalOffset) 5713{ 5714 if (!m_rareData) { 5715 if (!logicalOffset) 5716 return; 5717 m_rareData = new RenderBlockRareData(this); 5718 } 5719 m_rareData->m_pageLogicalOffset = logicalOffset; 5720} 5721 5722void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty) 5723{ 5724 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 5725 // inline boxes above and below us (thus getting merged with them to form a single irregular 5726 // shape). 5727 if (isAnonymousBlockContinuation()) { 5728 // FIXME: This is wrong for block-flows that are horizontal. 5729 // https://bugs.webkit.org/show_bug.cgi?id=46781 5730 rects.append(IntRect(tx, ty - collapsedMarginBefore(), 5731 width(), height() + collapsedMarginBefore() + collapsedMarginAfter())); 5732 continuation()->absoluteRects(rects, 5733 tx - x() + inlineElementContinuation()->containingBlock()->x(), 5734 ty - y() + inlineElementContinuation()->containingBlock()->y()); 5735 } else 5736 rects.append(IntRect(tx, ty, width(), height())); 5737} 5738 5739void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads) 5740{ 5741 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 5742 // inline boxes above and below us (thus getting merged with them to form a single irregular 5743 // shape). 5744 if (isAnonymousBlockContinuation()) { 5745 // FIXME: This is wrong for block-flows that are horizontal. 5746 // https://bugs.webkit.org/show_bug.cgi?id=46781 5747 FloatRect localRect(0, -collapsedMarginBefore(), 5748 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()); 5749 quads.append(localToAbsoluteQuad(localRect)); 5750 continuation()->absoluteQuads(quads); 5751 } else 5752 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()))); 5753} 5754 5755IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth) 5756{ 5757 IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth)); 5758 if (isAnonymousBlockContinuation()) 5759 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal. 5760 return r; 5761} 5762 5763RenderObject* RenderBlock::hoverAncestor() const 5764{ 5765 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor(); 5766} 5767 5768void RenderBlock::updateDragState(bool dragOn) 5769{ 5770 RenderBox::updateDragState(dragOn); 5771 if (continuation()) 5772 continuation()->updateDragState(dragOn); 5773} 5774 5775RenderStyle* RenderBlock::outlineStyleForRepaint() const 5776{ 5777 return isAnonymousBlockContinuation() ? continuation()->style() : style(); 5778} 5779 5780void RenderBlock::childBecameNonInline(RenderObject*) 5781{ 5782 makeChildrenNonInline(); 5783 if (isAnonymousBlock() && parent() && parent()->isRenderBlock()) 5784 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this); 5785 // |this| may be dead here 5786} 5787 5788void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point) 5789{ 5790 if (result.innerNode()) 5791 return; 5792 5793 Node* n = node(); 5794 if (isAnonymousBlockContinuation()) 5795 // We are in the margins of block elements that are part of a continuation. In 5796 // this case we're actually still inside the enclosing element that was 5797 // split. Go ahead and set our inner node accordingly. 5798 n = continuation()->node(); 5799 5800 if (n) { 5801 result.setInnerNode(n); 5802 if (!result.innerNonSharedNode()) 5803 result.setInnerNonSharedNode(n); 5804 result.setLocalPoint(point); 5805 } 5806} 5807 5808IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine) 5809{ 5810 // Do the normal calculation in most cases. 5811 if (firstChild()) 5812 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine); 5813 5814 // This is a special case: 5815 // The element is not an inline element, and it's empty. So we have to 5816 // calculate a fake position to indicate where objects are to be inserted. 5817 5818 // FIXME: This does not take into account either :first-line or :first-letter 5819 // However, as soon as some content is entered, the line boxes will be 5820 // constructed and this kludge is not called any more. So only the caret size 5821 // of an empty :first-line'd block is wrong. I think we can live with that. 5822 RenderStyle* currentStyle = firstLineStyle(); 5823 int height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine); 5824 5825 enum CaretAlignment { alignLeft, alignRight, alignCenter }; 5826 5827 CaretAlignment alignment = alignLeft; 5828 5829 switch (currentStyle->textAlign()) { 5830 case TAAUTO: 5831 case JUSTIFY: 5832 if (!currentStyle->isLeftToRightDirection()) 5833 alignment = alignRight; 5834 break; 5835 case LEFT: 5836 case WEBKIT_LEFT: 5837 break; 5838 case CENTER: 5839 case WEBKIT_CENTER: 5840 alignment = alignCenter; 5841 break; 5842 case RIGHT: 5843 case WEBKIT_RIGHT: 5844 alignment = alignRight; 5845 break; 5846 case TASTART: 5847 if (!currentStyle->isLeftToRightDirection()) 5848 alignment = alignRight; 5849 break; 5850 case TAEND: 5851 if (currentStyle->isLeftToRightDirection()) 5852 alignment = alignRight; 5853 break; 5854 } 5855 5856 int x = borderLeft() + paddingLeft(); 5857 int w = width(); 5858 5859 switch (alignment) { 5860 case alignLeft: 5861 break; 5862 case alignCenter: 5863 x = (x + w - (borderRight() + paddingRight())) / 2; 5864 break; 5865 case alignRight: 5866 x = w - (borderRight() + paddingRight()) - caretWidth; 5867 break; 5868 } 5869 5870 if (extraWidthToEndOfLine) { 5871 if (isRenderBlock()) { 5872 *extraWidthToEndOfLine = w - (x + caretWidth); 5873 } else { 5874 // FIXME: This code looks wrong. 5875 // myRight and containerRight are set up, but then clobbered. 5876 // So *extraWidthToEndOfLine will always be 0 here. 5877 5878 int myRight = x + caretWidth; 5879 // FIXME: why call localToAbsoluteForContent() twice here, too? 5880 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0)); 5881 5882 int containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent(); 5883 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0)); 5884 5885 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x(); 5886 } 5887 } 5888 5889 int y = paddingTop() + borderTop(); 5890 5891 return IntRect(x, y, caretWidth, height); 5892} 5893 5894void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty) 5895{ 5896 // For blocks inside inlines, we go ahead and include margins so that we run right up to the 5897 // inline boxes above and below us (thus getting merged with them to form a single irregular 5898 // shape). 5899 if (inlineElementContinuation()) { 5900 // FIXME: This check really isn't accurate. 5901 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox(); 5902 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block. 5903 // FIXME: This is wrong for block-flows that are horizontal. 5904 // https://bugs.webkit.org/show_bug.cgi?id=46781 5905 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox(); 5906 int topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : 0; 5907 int bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : 0; 5908 IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin); 5909 if (!rect.isEmpty()) 5910 rects.append(rect); 5911 } else if (width() && height()) 5912 rects.append(IntRect(tx, ty, width(), height())); 5913 5914 if (!hasOverflowClip() && !hasControlClip()) { 5915 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) { 5916 int top = max(curr->lineTop(), curr->logicalTop()); 5917 int bottom = min(curr->lineBottom(), curr->logicalTop() + curr->logicalHeight()); 5918 IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top); 5919 if (!rect.isEmpty()) 5920 rects.append(rect); 5921 } 5922 5923 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) { 5924 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) { 5925 RenderBox* box = toRenderBox(curr); 5926 FloatPoint pos; 5927 // FIXME: This doesn't work correctly with transforms. 5928 if (box->layer()) 5929 pos = curr->localToAbsolute(); 5930 else 5931 pos = FloatPoint(tx + box->x(), ty + box->y()); 5932 box->addFocusRingRects(rects, pos.x(), pos.y()); 5933 } 5934 } 5935 } 5936 5937 if (inlineElementContinuation()) 5938 inlineElementContinuation()->addFocusRingRects(rects, 5939 tx - x() + inlineElementContinuation()->containingBlock()->x(), 5940 ty - y() + inlineElementContinuation()->containingBlock()->y()); 5941} 5942 5943RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const 5944{ 5945 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); 5946 5947 RenderBlock* newBox = 0; 5948 if (isFlexibleBox) { 5949 newStyle->setDisplay(BOX); 5950 newBox = new (renderArena()) RenderFlexibleBox(document() /* anonymous box */); 5951 } else { 5952 newStyle->setDisplay(BLOCK); 5953 newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); 5954 } 5955 5956 newBox->setStyle(newStyle.release()); 5957 return newBox; 5958} 5959 5960RenderBlock* RenderBlock::createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const 5961{ 5962 if (otherAnonymousBlock->isAnonymousColumnsBlock()) 5963 return createAnonymousColumnsBlock(); 5964 if (otherAnonymousBlock->isAnonymousColumnSpanBlock()) 5965 return createAnonymousColumnSpanBlock(); 5966 return createAnonymousBlock(otherAnonymousBlock->style()->display() == BOX); 5967} 5968 5969RenderBlock* RenderBlock::createAnonymousColumnsBlock() const 5970{ 5971 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); 5972 newStyle->inheritColumnPropertiesFrom(style()); 5973 newStyle->setDisplay(BLOCK); 5974 5975 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); 5976 newBox->setStyle(newStyle.release()); 5977 return newBox; 5978} 5979 5980RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const 5981{ 5982 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style()); 5983 newStyle->setColumnSpan(true); 5984 newStyle->setDisplay(BLOCK); 5985 5986 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */); 5987 newBox->setStyle(newStyle.release()); 5988 return newBox; 5989} 5990 5991int RenderBlock::nextPageLogicalTop(int logicalOffset) const 5992{ 5993 LayoutState* layoutState = view()->layoutState(); 5994 if (!layoutState->m_pageLogicalHeight) 5995 return logicalOffset; 5996 5997 // The logicalOffset is in our coordinate space. We can add in our pushed offset. 5998 int pageLogicalHeight = layoutState->m_pageLogicalHeight; 5999 IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset; 6000 int offset = isHorizontalWritingMode() ? delta.height() : delta.width(); 6001 int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight; 6002 return logicalOffset + remainingLogicalHeight; 6003} 6004 6005static bool inNormalFlow(RenderBox* child) 6006{ 6007 RenderBlock* curr = child->containingBlock(); 6008 RenderBlock* initialBlock = child->view(); 6009 while (curr && curr != initialBlock) { 6010 if (curr->hasColumns()) 6011 return true; 6012 if (curr->isFloatingOrPositioned()) 6013 return false; 6014 curr = curr->containingBlock(); 6015 } 6016 return true; 6017} 6018 6019int RenderBlock::applyBeforeBreak(RenderBox* child, int logicalOffset) 6020{ 6021 // FIXME: Add page break checking here when we support printing. 6022 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); 6023 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. 6024 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS); 6025 if (checkBeforeAlways && inNormalFlow(child)) { 6026 if (checkColumnBreaks) 6027 view()->layoutState()->addForcedColumnBreak(logicalOffset); 6028 return nextPageLogicalTop(logicalOffset); 6029 } 6030 return logicalOffset; 6031} 6032 6033int RenderBlock::applyAfterBreak(RenderBox* child, int logicalOffset, MarginInfo& marginInfo) 6034{ 6035 // FIXME: Add page break checking here when we support printing. 6036 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns(); 6037 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this. 6038 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS); 6039 if (checkAfterAlways && inNormalFlow(child)) { 6040 marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content. 6041 if (checkColumnBreaks) 6042 view()->layoutState()->addForcedColumnBreak(logicalOffset); 6043 return nextPageLogicalTop(logicalOffset); 6044 } 6045 return logicalOffset; 6046} 6047 6048int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int logicalOffset, bool includeMargins) 6049{ 6050 bool isUnsplittable = child->isReplaced() || child->scrollsOverflow(); 6051 if (!isUnsplittable) 6052 return logicalOffset; 6053 int childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : 0); 6054 LayoutState* layoutState = view()->layoutState(); 6055 if (layoutState->m_columnInfo) 6056 layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight); 6057 int pageLogicalHeight = layoutState->m_pageLogicalHeight; 6058 if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight) 6059 return logicalOffset; 6060 IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset; 6061 int offset = isHorizontalWritingMode() ? delta.height() : delta.width(); 6062 int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight; 6063 if (remainingLogicalHeight < childLogicalHeight) 6064 return logicalOffset + remainingLogicalHeight; 6065 return logicalOffset; 6066} 6067 6068void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& delta) 6069{ 6070 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we 6071 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since 6072 // the line on the top of the next page will appear too far down relative to the same kind of line at the top 6073 // of the first column. 6074 // 6075 // The rendering we would like to see is one where the lineTop is at the top of the column, and any line overflow 6076 // simply spills out above the top of the column. This effect would match what happens at the top of the first column. 6077 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing 6078 // for overflow to occur), and then cache visible overflow for each column rect. 6079 // 6080 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude 6081 // content that paints in a previous column (and content that paints in the following column). 6082 // 6083 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats). 6084 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the 6085 // line and all following lines. 6086 LayoutState* layoutState = view()->layoutState(); 6087 int pageLogicalHeight = layoutState->m_pageLogicalHeight; 6088 IntRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom()); 6089 int logicalOffset = logicalVisualOverflow.y(); 6090 int lineHeight = logicalVisualOverflow.maxY() - logicalOffset; 6091 if (layoutState->m_columnInfo) 6092 layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight); 6093 logicalOffset += delta; 6094 lineBox->setPaginationStrut(0); 6095 if (!pageLogicalHeight || lineHeight > pageLogicalHeight) 6096 return; 6097 IntSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset; 6098 int offset = isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width(); 6099 int remainingLogicalHeight = pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight; 6100 if (remainingLogicalHeight < lineHeight) { 6101 int totalLogicalHeight = lineHeight + max(0, logicalOffset); 6102 if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeight && !isPositioned() && !isTableCell()) 6103 setPaginationStrut(remainingLogicalHeight + max(0, logicalOffset)); 6104 else { 6105 delta += remainingLogicalHeight; 6106 lineBox->setPaginationStrut(remainingLogicalHeight); 6107 } 6108 } 6109} 6110 6111int RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const 6112{ 6113 // If the child has the same directionality as we do, then we can just return its 6114 // collapsed margin. 6115 if (!child->isWritingModeRoot()) 6116 return child->collapsedMarginBefore(); 6117 6118 // The child has a different directionality. If the child is parallel, then it's just 6119 // flipped relative to us. We can use the collapsed margin for the opposite edge. 6120 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 6121 return child->collapsedMarginAfter(); 6122 6123 // The child is perpendicular to us, which means its margins don't collapse but are on the 6124 // "logical left/right" sides of the child box. We can just return the raw margin in this case. 6125 return marginBeforeForChild(child); 6126} 6127 6128int RenderBlock::collapsedMarginAfterForChild(RenderBox* child) const 6129{ 6130 // If the child has the same directionality as we do, then we can just return its 6131 // collapsed margin. 6132 if (!child->isWritingModeRoot()) 6133 return child->collapsedMarginAfter(); 6134 6135 // The child has a different directionality. If the child is parallel, then it's just 6136 // flipped relative to us. We can use the collapsed margin for the opposite edge. 6137 if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) 6138 return child->collapsedMarginBefore(); 6139 6140 // The child is perpendicular to us, which means its margins don't collapse but are on the 6141 // "logical left/right" side of the child box. We can just return the raw margin in this case. 6142 return marginAfterForChild(child); 6143} 6144 6145int RenderBlock::marginBeforeForChild(RenderBoxModelObject* child) const 6146{ 6147 switch (style()->writingMode()) { 6148 case TopToBottomWritingMode: 6149 return child->marginTop(); 6150 case BottomToTopWritingMode: 6151 return child->marginBottom(); 6152 case LeftToRightWritingMode: 6153 return child->marginLeft(); 6154 case RightToLeftWritingMode: 6155 return child->marginRight(); 6156 } 6157 ASSERT_NOT_REACHED(); 6158 return child->marginTop(); 6159} 6160 6161int RenderBlock::marginAfterForChild(RenderBoxModelObject* child) const 6162{ 6163 switch (style()->writingMode()) { 6164 case TopToBottomWritingMode: 6165 return child->marginBottom(); 6166 case BottomToTopWritingMode: 6167 return child->marginTop(); 6168 case LeftToRightWritingMode: 6169 return child->marginRight(); 6170 case RightToLeftWritingMode: 6171 return child->marginLeft(); 6172 } 6173 ASSERT_NOT_REACHED(); 6174 return child->marginBottom(); 6175} 6176 6177int RenderBlock::marginStartForChild(RenderBoxModelObject* child) const 6178{ 6179 if (isHorizontalWritingMode()) 6180 return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight(); 6181 return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom(); 6182} 6183 6184int RenderBlock::marginEndForChild(RenderBoxModelObject* child) const 6185{ 6186 if (isHorizontalWritingMode()) 6187 return style()->isLeftToRightDirection() ? child->marginRight() : child->marginLeft(); 6188 return style()->isLeftToRightDirection() ? child->marginBottom() : child->marginTop(); 6189} 6190 6191void RenderBlock::setMarginStartForChild(RenderBox* child, int margin) 6192{ 6193 if (isHorizontalWritingMode()) { 6194 if (style()->isLeftToRightDirection()) 6195 child->setMarginLeft(margin); 6196 else 6197 child->setMarginRight(margin); 6198 } else { 6199 if (style()->isLeftToRightDirection()) 6200 child->setMarginTop(margin); 6201 else 6202 child->setMarginBottom(margin); 6203 } 6204} 6205 6206void RenderBlock::setMarginEndForChild(RenderBox* child, int margin) 6207{ 6208 if (isHorizontalWritingMode()) { 6209 if (style()->isLeftToRightDirection()) 6210 child->setMarginRight(margin); 6211 else 6212 child->setMarginLeft(margin); 6213 } else { 6214 if (style()->isLeftToRightDirection()) 6215 child->setMarginBottom(margin); 6216 else 6217 child->setMarginTop(margin); 6218 } 6219} 6220 6221void RenderBlock::setMarginBeforeForChild(RenderBox* child, int margin) 6222{ 6223 switch (style()->writingMode()) { 6224 case TopToBottomWritingMode: 6225 child->setMarginTop(margin); 6226 break; 6227 case BottomToTopWritingMode: 6228 child->setMarginBottom(margin); 6229 break; 6230 case LeftToRightWritingMode: 6231 child->setMarginLeft(margin); 6232 break; 6233 case RightToLeftWritingMode: 6234 child->setMarginRight(margin); 6235 break; 6236 } 6237} 6238 6239void RenderBlock::setMarginAfterForChild(RenderBox* child, int margin) 6240{ 6241 switch (style()->writingMode()) { 6242 case TopToBottomWritingMode: 6243 child->setMarginBottom(margin); 6244 break; 6245 case BottomToTopWritingMode: 6246 child->setMarginTop(margin); 6247 break; 6248 case LeftToRightWritingMode: 6249 child->setMarginRight(margin); 6250 break; 6251 case RightToLeftWritingMode: 6252 child->setMarginLeft(margin); 6253 break; 6254 } 6255} 6256 6257RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) 6258{ 6259 int childBeforePositive = 0; 6260 int childBeforeNegative = 0; 6261 int childAfterPositive = 0; 6262 int childAfterNegative = 0; 6263 6264 int beforeMargin = 0; 6265 int afterMargin = 0; 6266 6267 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0; 6268 6269 // If the child has the same directionality as we do, then we can just return its 6270 // margins in the same direction. 6271 if (!child->isWritingModeRoot()) { 6272 if (childRenderBlock) { 6273 childBeforePositive = childRenderBlock->maxPositiveMarginBefore(); 6274 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore(); 6275 childAfterPositive = childRenderBlock->maxPositiveMarginAfter(); 6276 childAfterNegative = childRenderBlock->maxNegativeMarginAfter(); 6277 } else { 6278 beforeMargin = child->marginBefore(); 6279 afterMargin = child->marginAfter(); 6280 } 6281 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) { 6282 // The child has a different directionality. If the child is parallel, then it's just 6283 // flipped relative to us. We can use the margins for the opposite edges. 6284 if (childRenderBlock) { 6285 childBeforePositive = childRenderBlock->maxPositiveMarginAfter(); 6286 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter(); 6287 childAfterPositive = childRenderBlock->maxPositiveMarginBefore(); 6288 childAfterNegative = childRenderBlock->maxNegativeMarginBefore(); 6289 } else { 6290 beforeMargin = child->marginAfter(); 6291 afterMargin = child->marginBefore(); 6292 } 6293 } else { 6294 // The child is perpendicular to us, which means its margins don't collapse but are on the 6295 // "logical left/right" sides of the child box. We can just return the raw margin in this case. 6296 beforeMargin = marginBeforeForChild(child); 6297 afterMargin = marginAfterForChild(child); 6298 } 6299 6300 // Resolve uncollapsing margins into their positive/negative buckets. 6301 if (beforeMargin) { 6302 if (beforeMargin > 0) 6303 childBeforePositive = beforeMargin; 6304 else 6305 childBeforeNegative = -beforeMargin; 6306 } 6307 if (afterMargin) { 6308 if (afterMargin > 0) 6309 childAfterPositive = afterMargin; 6310 else 6311 childAfterNegative = -afterMargin; 6312 } 6313 6314 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative); 6315} 6316 6317const char* RenderBlock::renderName() const 6318{ 6319 if (isBody()) 6320 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass. 6321 6322 if (isFloating()) 6323 return "RenderBlock (floating)"; 6324 if (isPositioned()) 6325 return "RenderBlock (positioned)"; 6326 if (isAnonymousColumnsBlock()) 6327 return "RenderBlock (anonymous multi-column)"; 6328 if (isAnonymousColumnSpanBlock()) 6329 return "RenderBlock (anonymous multi-column span)"; 6330 if (isAnonymousBlock()) 6331 return "RenderBlock (anonymous)"; 6332 else if (isAnonymous()) 6333 return "RenderBlock (generated)"; 6334 if (isRelPositioned()) 6335 return "RenderBlock (relative positioned)"; 6336 if (isRunIn()) 6337 return "RenderBlock (run-in)"; 6338 return "RenderBlock"; 6339} 6340 6341inline void RenderBlock::FloatingObjects::clear() 6342{ 6343 m_set.clear(); 6344 m_leftObjectsCount = 0; 6345 m_rightObjectsCount = 0; 6346} 6347 6348inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type) 6349{ 6350 if (type == FloatingObject::FloatLeft) 6351 m_leftObjectsCount++; 6352 else 6353 m_rightObjectsCount++; 6354} 6355 6356inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type) 6357{ 6358 if (type == FloatingObject::FloatLeft) 6359 m_leftObjectsCount--; 6360 else 6361 m_rightObjectsCount--; 6362} 6363 6364} // namespace WebCore 6365