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