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