2
* Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3
* (C) 1999 Antti Koivisto (koivisto@kde.org)
4
* (C) 2007 David Smith (catfish.man@gmail.com)
5
* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
6
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
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.
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.
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.
25
#include "RenderBlock.h"
27
#include "AXObjectCache.h"
28
#include "ColumnInfo.h"
31
#include "FloatQuad.h"
33
#include "FrameSelection.h"
34
#include "FrameView.h"
35
#include "GraphicsContext.h"
36
#include "HTMLFormElement.h"
37
#include "HTMLNames.h"
38
#include "HitTestResult.h"
39
#include "InlineIterator.h"
40
#include "InlineTextBox.h"
41
#include "LayoutRepainter.h"
42
#include "OverflowEvent.h"
43
#include "PODFreeListArena.h"
45
#include "PaintInfo.h"
46
#include "RenderBoxRegionInfo.h"
47
#include "RenderCombineText.h"
48
#include "RenderDeprecatedFlexibleBox.h"
49
#include "RenderImage.h"
50
#include "RenderInline.h"
51
#include "RenderLayer.h"
52
#include "RenderMarquee.h"
53
#include "RenderNamedFlowThread.h"
54
#include "RenderRegion.h"
55
#include "RenderReplica.h"
56
#include "RenderTableCell.h"
57
#include "RenderTextFragment.h"
58
#include "RenderTheme.h"
59
#include "RenderView.h"
61
#include "SVGTextRunRenderingContext.h"
62
#include "ShadowRoot.h"
63
#include "TransformState.h"
64
#include <wtf/StdLibExtras.h>
65
#include <wtf/TemporaryChange.h>
66
#if ENABLE(CSS_EXCLUSIONS)
67
#include "ExclusionShapeInsideInfo.h"
72
using namespace Unicode;
76
using namespace HTMLNames;
78
struct SameSizeAsRenderBlock : public RenderBox {
80
RenderObjectChildList children;
81
RenderLineBoxList lineBoxes;
85
COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
87
struct SameSizeAsFloatingObject {
91
uint32_t bitfields : 8;
94
COMPILE_ASSERT(sizeof(RenderBlock::MarginValues) == sizeof(LayoutUnit[4]), MarginValues_should_stay_small);
96
struct SameSizeAsMarginInfo {
97
uint32_t bitfields : 16;
98
LayoutUnit margins[2];
101
typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
102
static ColumnInfoMap* gColumnInfoMap = 0;
104
static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
105
static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
107
static TrackedContainerMap* gPositionedContainerMap = 0;
108
static TrackedContainerMap* gPercentHeightContainerMap = 0;
110
typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
112
typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
113
static int gDelayUpdateScrollInfo = 0;
114
static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
116
static bool gIsInColumnFlowSplit = false;
118
bool RenderBlock::s_canPropagateFloatIntoSibling = false;
120
// This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
121
// only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes.
122
class OverflowEventDispatcher {
123
WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
125
OverflowEventDispatcher(const RenderBlock* block)
127
, m_hadHorizontalLayoutOverflow(false)
128
, m_hadVerticalLayoutOverflow(false)
130
m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
131
if (m_shouldDispatchEvent) {
132
m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
133
m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
137
~OverflowEventDispatcher()
139
if (!m_shouldDispatchEvent)
142
bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
143
bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
145
bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
146
bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
147
if (horizontalLayoutOverflowChanged || verticalLayoutOverflowChanged) {
148
if (FrameView* frameView = m_block->document()->view())
149
frameView->scheduleEvent(OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow), m_block->node());
154
const RenderBlock* m_block;
155
bool m_shouldDispatchEvent;
156
bool m_hadHorizontalLayoutOverflow;
157
bool m_hadVerticalLayoutOverflow;
160
// Our MarginInfo state used when laying out block children.
161
RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
162
: m_atBeforeSideOfBlock(true)
163
, m_atAfterSideOfBlock(false)
164
, m_marginBeforeQuirk(false)
165
, m_marginAfterQuirk(false)
166
, m_determinedMarginBeforeQuirk(false)
168
RenderStyle* blockStyle = block->style();
169
ASSERT(block->isRenderView() || block->parent());
170
m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isOutOfFlowPositioned()
171
&& !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
172
&& !block->isWritingModeRoot() && !block->parent()->isFlexibleBox() && blockStyle->hasAutoColumnCount() && blockStyle->hasAutoColumnWidth()
173
&& !blockStyle->columnSpan();
175
m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && !beforeBorderPadding && blockStyle->marginBeforeCollapse() != MSEPARATE;
177
// If any height other than auto is specified in CSS, then we don't collapse our bottom
178
// margins with our children's margins. To do otherwise would be to risk odd visual
179
// effects when the children overflow out of the parent block and yet still collapse
180
// with it. We also don't collapse if we have any bottom border/padding.
181
m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
182
(blockStyle->logicalHeight().isAuto() && !blockStyle->logicalHeight().value()) && blockStyle->marginAfterCollapse() != MSEPARATE;
184
m_quirkContainer = block->isTableCell() || block->isBody() || blockStyle->marginBeforeCollapse() == MDISCARD
185
|| blockStyle->marginAfterCollapse() == MDISCARD;
187
m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : LayoutUnit();
188
m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : LayoutUnit();
191
// -------------------------------------------------------------------------------------------------------
193
RenderBlock::RenderBlock(Node* node)
196
, m_beingDestroyed(false)
197
, m_hasMarkupTruncation(false)
199
setChildrenInline(true);
200
COMPILE_ASSERT(sizeof(RenderBlock::FloatingObject) == sizeof(SameSizeAsFloatingObject), FloatingObject_should_stay_small);
201
COMPILE_ASSERT(sizeof(RenderBlock::MarginInfo) == sizeof(SameSizeAsMarginInfo), MarginInfo_should_stay_small);
204
static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
206
if (TrackedRendererListHashSet* descendantSet = descendantMap->take(block)) {
207
TrackedRendererListHashSet::iterator end = descendantSet->end();
208
for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
209
HashSet<RenderBlock*>* containerSet = containerMap->get(*descendant);
210
ASSERT(containerSet);
213
ASSERT(containerSet->contains(block));
214
containerSet->remove(block);
215
if (containerSet->isEmpty()) {
216
containerMap->remove(*descendant);
220
delete descendantSet;
224
RenderBlock::~RenderBlock()
226
if (m_floatingObjects)
227
deleteAllValues(m_floatingObjects->set());
230
delete gColumnInfoMap->take(this);
232
if (gPercentHeightDescendantsMap)
233
removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
234
if (gPositionedDescendantsMap)
235
removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
238
void RenderBlock::willBeDestroyed()
240
// Mark as being destroyed to avoid trouble with merges in removeChild().
241
m_beingDestroyed = true;
243
// Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
244
// properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
245
children()->destroyLeftoverChildren();
247
// Destroy our continuation before anything other than anonymous children.
248
// The reason we don't destroy it before anonymous children is that they may
249
// have continuations of their own that are anonymous children of our continuation.
250
RenderBoxModelObject* continuation = this->continuation();
252
continuation->destroy();
256
if (!documentBeingDestroyed()) {
257
if (firstLineBox()) {
258
// We can't wait for RenderBox::destroy to clear the selection,
259
// because by then we will have nuked the line boxes.
260
// FIXME: The FrameSelection should be responsible for this when it
261
// is notified of DOM mutations.
262
if (isSelectionBorder())
263
view()->clearSelection();
265
// If we are an anonymous block, then our line boxes might have children
266
// that will outlast this block. In the non-anonymous block case those
267
// children will be destroyed by the time we return from this function.
268
if (isAnonymousBlock()) {
269
for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
270
while (InlineBox* childBox = box->firstChild())
275
parent()->dirtyLinesFromChangedChild(this);
278
m_lineBoxes.deleteLineBoxes(renderArena());
281
lineGridBox()->destroy(renderArena());
283
#if ENABLE(CSS_EXCLUSIONS)
284
ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
287
if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
288
gDelayedUpdateScrollInfoSet->remove(this);
290
RenderBox::willBeDestroyed();
293
void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
295
RenderStyle* oldStyle = style();
296
s_canPropagateFloatIntoSibling = oldStyle ? !isFloatingOrOutOfFlowPositioned() && !avoidsFloats() : false;
298
setReplaced(newStyle->isDisplayInlineType());
300
if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
301
if (newStyle->position() == StaticPosition)
302
// Clear our positioned objects list. Our absolutely positioned descendants will be
303
// inserted into our containing block's positioned objects list during layout.
304
removePositionedObjects(0, NewContainingBlock);
305
else if (oldStyle->position() == StaticPosition) {
306
// Remove our absolutely positioned descendants from their current containing block.
307
// They will be inserted into our positioned objects list during layout.
308
RenderObject* cb = parent();
309
while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
310
if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
311
cb = cb->containingBlock();
317
if (cb->isRenderBlock())
318
toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock);
321
if (containsFloats() && !isFloating() && !isOutOfFlowPositioned() && newStyle->hasOutOfFlowPosition())
322
markAllDescendantsWithFloatsForLayout();
325
RenderBox::styleWillChange(diff, newStyle);
328
void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
330
RenderBox::styleDidChange(diff, oldStyle);
332
#if ENABLE(CSS_EXCLUSIONS)
333
// FIXME: Bug 89993: Style changes should affect the ExclusionShapeInsideInfos for other render blocks that
334
// share the same ExclusionShapeInsideInfo
335
updateExclusionShapeInsideInfoAfterStyleChange(style()->shapeInside(), oldStyle ? oldStyle->shapeInside() : 0);
338
if (!isAnonymousBlock()) {
339
// Ensure that all of our continuation blocks pick up the new style.
340
for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
341
RenderBoxModelObject* nextCont = currCont->continuation();
342
currCont->setContinuation(0);
343
currCont->setStyle(style());
344
currCont->setContinuation(nextCont);
348
propagateStyleToAnonymousChildren(true);
351
// Update pseudos for :before and :after now.
352
if (!isAnonymous() && document()->styleSheetCollection()->usesBeforeAfterRules() && canHaveGeneratedChildren()) {
353
updateBeforeAfterContent(BEFORE);
354
updateBeforeAfterContent(AFTER);
357
// After our style changed, if we lose our ability to propagate floats into next sibling
358
// blocks, then we need to find the top most parent containing that overhanging float and
359
// then mark its descendants with floats for layout and clear all floats from its next
360
// sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
361
bool canPropagateFloatIntoSibling = !isFloatingOrOutOfFlowPositioned() && !avoidsFloats();
362
if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
363
RenderBlock* parentBlock = this;
364
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
365
FloatingObjectSetIterator end = floatingObjectSet.end();
367
for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
368
if (curr->isRenderBlock()) {
369
RenderBlock* currBlock = toRenderBlock(curr);
371
if (currBlock->hasOverhangingFloats()) {
372
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
373
RenderBox* renderer = (*it)->renderer();
374
if (currBlock->hasOverhangingFloat(renderer)) {
375
parentBlock = currBlock;
383
parentBlock->markAllDescendantsWithFloatsForLayout();
384
parentBlock->markSiblingsWithFloatsForLayout();
388
void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
390
// If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
391
if (parent() && parent()->createsAnonymousWrapper())
393
children()->updateBeforeAfterContent(this, pseudoId);
396
RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
398
if (beforeChild && beforeChild->parent() == this)
401
RenderBlock* curr = toRenderBlock(continuation());
402
RenderBlock* nextToLast = this;
403
RenderBlock* last = this;
405
if (beforeChild && beforeChild->parent() == curr) {
406
if (curr->firstChild() == beforeChild)
413
curr = toRenderBlock(curr->continuation());
416
if (!beforeChild && !last->firstChild())
421
void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
423
RenderBlock* flow = continuationBefore(beforeChild);
424
ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
425
RenderBoxModelObject* beforeChildParent = 0;
427
beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
429
RenderBoxModelObject* cont = flow->continuation();
431
beforeChildParent = cont;
433
beforeChildParent = flow;
436
if (newChild->isFloatingOrOutOfFlowPositioned()) {
437
beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
441
// A continuation always consists of two potential candidates: a block or an anonymous
442
// column span box holding column span children.
443
bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
444
bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
445
bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
447
if (flow == beforeChildParent) {
448
flow->addChildIgnoringContinuation(newChild, beforeChild);
452
// The goal here is to match up if we can, so that we can coalesce and create the
453
// minimal # of continuations needed for the inline.
454
if (childIsNormal == bcpIsNormal) {
455
beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
458
if (flowIsNormal == childIsNormal) {
459
flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
462
beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
466
void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
468
ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
470
// The goal is to locate a suitable box in which to place our child.
471
RenderBlock* beforeChildParent = 0;
473
RenderObject* curr = beforeChild;
474
while (curr && curr->parent() != this)
475
curr = curr->parent();
476
beforeChildParent = toRenderBlock(curr);
477
ASSERT(beforeChildParent);
478
ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock());
480
beforeChildParent = toRenderBlock(lastChild());
482
// If the new child is floating or positioned it can just go in that block.
483
if (newChild->isFloatingOrOutOfFlowPositioned()) {
484
beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
488
// See if the child can be placed in the box.
489
bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
490
bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
492
if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
493
beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
498
// Create a new block of the correct type.
499
RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
500
children()->appendChildNode(this, newBox);
501
newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
505
RenderObject* immediateChild = beforeChild;
506
bool isPreviousBlockViable = true;
507
while (immediateChild->parent() != this) {
508
if (isPreviousBlockViable)
509
isPreviousBlockViable = !immediateChild->previousSibling();
510
immediateChild = immediateChild->parent();
512
if (isPreviousBlockViable && immediateChild->previousSibling()) {
513
toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
517
// Split our anonymous blocks.
518
RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild);
521
// Create a new anonymous box of the appropriate type.
522
RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
523
children()->insertChildNode(this, newBox, newBeforeChild);
524
newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
528
RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
530
RenderBlock* firstChildIgnoringAnonymousWrappers = 0;
531
for (RenderObject* curr = this; curr; curr = curr->parent()) {
532
if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
533
|| curr->isInlineBlockOrInlineTable())
536
// FIXME: Table manages its own table parts, most of which are RenderBoxes.
537
// Multi-column code cannot handle splitting the flow in table. Disabling it
538
// to prevent crashes.
539
// Similarly, RenderButton maintains an anonymous block child and overrides
540
// addChild() to prevent itself from having additional direct children. This
541
// causes problems for split flows.
542
if (curr->isTable() || curr->isRenderButton())
545
RenderBlock* currBlock = toRenderBlock(curr);
546
if (!currBlock->createsAnonymousWrapper())
547
firstChildIgnoringAnonymousWrappers = currBlock;
549
if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
550
return firstChildIgnoringAnonymousWrappers;
552
if (currBlock->isAnonymousColumnSpanBlock())
558
RenderBlock* RenderBlock::clone() const
560
RenderBlock* cloneBlock;
561
if (isAnonymousBlock()) {
562
cloneBlock = createAnonymousBlock();
563
cloneBlock->setChildrenInline(childrenInline());
566
RenderObject* cloneRenderer = toElement(node())->createRenderer(renderArena(), style());
567
cloneBlock = toRenderBlock(cloneRenderer);
568
cloneBlock->setStyle(style());
570
// This takes care of setting the right value of childrenInline in case
571
// generated content is added to cloneBlock and 'this' does not have
572
// generated content added yet.
573
cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
575
cloneBlock->setInRenderFlowThread(inRenderFlowThread());
579
void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
580
RenderBlock* middleBlock,
581
RenderObject* beforeChild, RenderBoxModelObject* oldCont)
583
// Create a clone of this inline.
584
RenderBlock* cloneBlock = clone();
585
if (!isAnonymousBlock())
586
cloneBlock->setContinuation(oldCont);
588
if (!beforeChild && isAfterContent(lastChild()))
589
beforeChild = lastChild();
591
// If we are moving inline children from |this| to cloneBlock, then we need
592
// to clear our line box tree.
593
if (beforeChild && childrenInline())
596
// Now take all of the children from beforeChild to the end and remove
597
// them from |this| and place them in the clone.
598
moveChildrenTo(cloneBlock, beforeChild, 0, true);
600
// Hook |clone| up as the continuation of the middle block.
601
if (!cloneBlock->isAnonymousBlock())
602
middleBlock->setContinuation(cloneBlock);
604
// We have been reparented and are now under the fromBlock. We need
605
// to walk up our block parent chain until we hit the containing anonymous columns block.
606
// Once we hit the anonymous columns block we're done.
607
RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
608
RenderBoxModelObject* currChild = this;
609
RenderObject* currChildNextSibling = currChild->nextSibling();
610
bool documentUsesBeforeAfterRules = document()->styleSheetCollection()->usesBeforeAfterRules();
612
// Note: |this| can be destroyed inside this loop if it is an empty anonymous
613
// block and we try to call updateBeforeAfterContent inside which removes the
614
// generated content and additionally cleans up |this| empty anonymous block.
615
// See RenderBlock::removeChild(). DO NOT reference any local variables to |this|
617
while (curr && curr != fromBlock) {
618
ASSERT(curr->isRenderBlock());
620
RenderBlock* blockCurr = toRenderBlock(curr);
622
// Create a new clone.
623
RenderBlock* cloneChild = cloneBlock;
624
cloneBlock = blockCurr->clone();
626
// Insert our child clone as the first child.
627
cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
629
// Hook the clone up as a continuation of |curr|. Note we do encounter
630
// anonymous blocks possibly as we walk up the block chain. When we split an
631
// anonymous block, there's no need to do any continuation hookup, since we haven't
632
// actually split a real element.
633
if (!blockCurr->isAnonymousBlock()) {
634
oldCont = blockCurr->continuation();
635
blockCurr->setContinuation(cloneBlock);
636
cloneBlock->setContinuation(oldCont);
639
// Someone may have indirectly caused a <q> to split. When this happens, the :after content
640
// has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
641
// content gets properly destroyed.
642
bool isLastChild = (currChildNextSibling == blockCurr->lastChild());
643
if (documentUsesBeforeAfterRules)
644
blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
645
if (isLastChild && currChildNextSibling != blockCurr->lastChild())
646
currChildNextSibling = 0; // We destroyed the last child, so now we need to update
647
// the value of currChildNextSibling.
649
// Now we need to take all of the children starting from the first child
650
// *after* currChild and append them all to the clone.
651
blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
653
// Keep walking up the chain.
655
currChildNextSibling = currChild->nextSibling();
656
curr = toRenderBoxModelObject(curr->parent());
659
// Now we are at the columns block level. We need to put the clone into the toBlock.
660
toBlock->children()->appendChildNode(toBlock, cloneBlock);
662
// Now take all the children after currChild and remove them from the fromBlock
663
// and put them in the toBlock.
664
fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true);
667
void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
668
RenderObject* newChild, RenderBoxModelObject* oldCont)
670
RenderBlock* pre = 0;
671
RenderBlock* block = containingColumnsBlock();
673
// Delete our line boxes before we do the inline split into continuations.
674
block->deleteLineBoxTree();
676
bool madeNewBeforeBlock = false;
677
if (block->isAnonymousColumnsBlock()) {
678
// We can reuse this block and make it the preBlock of the next continuation.
680
pre->removePositionedObjects(0);
681
pre->removeFloatingObjects();
682
block = toRenderBlock(block->parent());
684
// No anonymous block available for use. Make one.
685
pre = block->createAnonymousColumnsBlock();
686
pre->setChildrenInline(false);
687
madeNewBeforeBlock = true;
690
RenderBlock* post = block->createAnonymousColumnsBlock();
691
post->setChildrenInline(false);
693
RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
694
if (madeNewBeforeBlock)
695
block->children()->insertChildNode(block, pre, boxFirst);
696
block->children()->insertChildNode(block, newBlockBox, boxFirst);
697
block->children()->insertChildNode(block, post, boxFirst);
698
block->setChildrenInline(false);
700
if (madeNewBeforeBlock)
701
block->moveChildrenTo(pre, boxFirst, 0, true);
703
splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
705
// We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
706
// time in makeChildrenNonInline by just setting this explicitly up front.
707
newBlockBox->setChildrenInline(false);
709
// We delayed adding the newChild until now so that the |newBlockBox| would be fully
710
// connected, thus allowing newChild access to a renderArena should it need
711
// to wrap itself in additional boxes (e.g., table construction).
712
newBlockBox->addChild(newChild);
714
// Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
715
// get deleted properly. Because objects moves from the pre block into the post block, we want to
716
// make new line boxes instead of leaving the old line boxes around.
717
pre->setNeedsLayoutAndPrefWidthsRecalc();
718
block->setNeedsLayoutAndPrefWidthsRecalc();
719
post->setNeedsLayoutAndPrefWidthsRecalc();
722
void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
724
RenderBlock* pre = 0;
725
RenderBlock* post = 0;
726
RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
727
// so that we don't have to patch all of the rest of the code later on.
729
// Delete the block's line boxes before we do the split.
730
block->deleteLineBoxTree();
732
if (beforeChild && beforeChild->parent() != this)
733
beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
735
if (beforeChild != firstChild()) {
736
pre = block->createAnonymousColumnsBlock();
737
pre->setChildrenInline(block->childrenInline());
741
post = block->createAnonymousColumnsBlock();
742
post->setChildrenInline(block->childrenInline());
745
RenderObject* boxFirst = block->firstChild();
747
block->children()->insertChildNode(block, pre, boxFirst);
748
block->children()->insertChildNode(block, newBlockBox, boxFirst);
750
block->children()->insertChildNode(block, post, boxFirst);
751
block->setChildrenInline(false);
753
// 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).
754
block->moveChildrenTo(pre, boxFirst, beforeChild, true);
755
block->moveChildrenTo(post, beforeChild, 0, true);
757
// We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
758
// time in makeChildrenNonInline by just setting this explicitly up front.
759
newBlockBox->setChildrenInline(false);
761
// We delayed adding the newChild until now so that the |newBlockBox| would be fully
762
// connected, thus allowing newChild access to a renderArena should it need
763
// to wrap itself in additional boxes (e.g., table construction).
764
newBlockBox->addChild(newChild);
766
// Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
767
// get deleted properly. Because objects moved from the pre block into the post block, we want to
768
// make new line boxes instead of leaving the old line boxes around.
770
pre->setNeedsLayoutAndPrefWidthsRecalc();
771
block->setNeedsLayoutAndPrefWidthsRecalc();
773
post->setNeedsLayoutAndPrefWidthsRecalc();
776
RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
778
// FIXME: This function is the gateway for the addition of column-span support. It will
779
// be added to in three stages:
780
// (1) Immediate children of a multi-column block can span.
781
// (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
782
// (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
783
// cross the streams and have to cope with both types of continuations mixed together).
784
// This function currently supports (1) and (2).
785
RenderBlock* columnsBlockAncestor = 0;
786
if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
787
&& !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
788
columnsBlockAncestor = containingColumnsBlock(false);
789
if (columnsBlockAncestor) {
790
// Make sure that none of the parent ancestors have a continuation.
791
// If yes, we do not want split the block into continuations.
792
RenderObject* curr = this;
793
while (curr && curr != columnsBlockAncestor) {
794
if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
795
columnsBlockAncestor = 0;
798
curr = curr->parent();
802
return columnsBlockAncestor;
805
void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
807
// Make sure we don't append things after :after-generated content if we have it.
809
beforeChild = afterPseudoElementRenderer();
811
if (beforeChild && beforeChild->parent() != this) {
812
RenderObject* beforeChildContainer = beforeChild->parent();
813
while (beforeChildContainer->parent() != this)
814
beforeChildContainer = beforeChildContainer->parent();
815
ASSERT(beforeChildContainer);
817
if (beforeChildContainer->isAnonymous()) {
818
// If the requested beforeChild is not one of our children, then this is because
819
// there is an anonymous container within this object that contains the beforeChild.
820
RenderObject* beforeChildAnonymousContainer = beforeChildContainer;
821
if (beforeChildAnonymousContainer->isAnonymousBlock()
822
#if ENABLE(FULLSCREEN_API)
823
// Full screen renderers and full screen placeholders act as anonymous blocks, not tables:
824
|| beforeChildAnonymousContainer->isRenderFullScreen()
825
|| beforeChildAnonymousContainer->isRenderFullScreenPlaceholder()
828
// Insert the child into the anonymous block box instead of here.
829
if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
830
beforeChild->parent()->addChild(newChild, beforeChild);
832
addChild(newChild, beforeChild->parent());
836
ASSERT(beforeChildAnonymousContainer->isTable());
837
if (newChild->isTablePart()) {
838
// Insert into the anonymous table.
839
beforeChildAnonymousContainer->addChild(newChild, beforeChild);
843
beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
845
ASSERT(beforeChild->parent() == this);
846
if (beforeChild->parent() != this) {
847
// We should never reach here. If we do, we need to use the
848
// safe fallback to use the topmost beforeChild container.
849
beforeChild = beforeChildContainer;
852
// We will reach here when beforeChild is a run-in element.
853
// If run-in element precedes a block-level element, it becomes the
854
// the first inline child of that block level element. The insertion
855
// point will be before that block-level element.
856
ASSERT(beforeChild->isRunIn());
857
beforeChild = beforeChildContainer;
861
// Nothing goes before the intruded run-in.
862
if (beforeChild && beforeChild->isRunIn() && runInIsPlacedIntoSiblingBlock(beforeChild))
863
beforeChild = beforeChild->nextSibling();
865
if (!gIsInColumnFlowSplit) {
866
RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
867
if (columnsBlockAncestor) {
868
TemporaryChange<bool> isInColumnFlowSplit(gIsInColumnFlowSplit, true);
869
// We are placing a column-span element inside a block.
870
RenderBlock* newBox = createAnonymousColumnSpanBlock();
872
if (columnsBlockAncestor != this) {
873
// We are nested inside a multi-column element and are being split by the span. We have to break up
874
// our block into continuations.
875
RenderBoxModelObject* oldContinuation = continuation();
877
// When we split an anonymous block, there's no need to do any continuation hookup,
878
// since we haven't actually split a real element.
879
if (!isAnonymousBlock())
880
setContinuation(newBox);
882
// Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
883
// has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
884
// content gets properly destroyed.
885
bool isFirstChild = (beforeChild == firstChild());
886
bool isLastChild = (beforeChild == lastChild());
887
if (document()->styleSheetCollection()->usesBeforeAfterRules())
888
children()->updateBeforeAfterContent(this, AFTER);
889
if (isLastChild && beforeChild != lastChild()) {
890
// We destroyed the last child, so now we need to update our insertion
891
// point to be 0. It's just a straight append now.
893
} else if (isFirstChild && beforeChild != firstChild()) {
894
// If beforeChild was the last anonymous block that collapsed,
895
// then we need to update its value.
896
beforeChild = firstChild();
899
splitFlow(beforeChild, newBox, newChild, oldContinuation);
903
// We have to perform a split of this block's children. This involves creating an anonymous block box to hold
904
// the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
905
// one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
906
makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
911
bool madeBoxesNonInline = false;
913
// A block has to either have all of its children inline, or all of its children as blocks.
914
// So, if our children are currently inline and a block child has to be inserted, we move all our
915
// inline children into anonymous block boxes.
916
if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
917
// This is a block with inline content. Wrap the inline content in anonymous blocks.
918
makeChildrenNonInline(beforeChild);
919
madeBoxesNonInline = true;
921
if (beforeChild && beforeChild->parent() != this) {
922
beforeChild = beforeChild->parent();
923
ASSERT(beforeChild->isAnonymousBlock());
924
ASSERT(beforeChild->parent() == this);
926
} else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
927
// If we're inserting an inline child but all of our children are blocks, then we have to make sure
928
// it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
929
// a new one is created and inserted into our list of children in the appropriate position.
930
RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
932
if (afterChild && afterChild->isAnonymousBlock()) {
933
afterChild->addChild(newChild);
937
if (newChild->isInline()) {
938
// No suitable existing anonymous box - create a new one.
939
RenderBlock* newBox = createAnonymousBlock();
940
RenderBox::addChild(newBox, beforeChild);
941
newBox->addChild(newChild);
946
RenderBox::addChild(newChild, beforeChild);
948
// Handle placement of run-ins.
949
placeRunInIfNeeded(newChild, DoNotPlaceGeneratedRunIn);
951
if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
952
toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
953
// this object may be dead here
956
void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
958
if (continuation() && !isAnonymousBlock())
959
addChildToContinuation(newChild, beforeChild);
961
addChildIgnoringContinuation(newChild, beforeChild);
964
void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
966
if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
967
addChildToAnonymousColumnBlocks(newChild, beforeChild);
969
addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
972
static void getInlineRun(RenderObject* start, RenderObject* boundary,
973
RenderObject*& inlineRunStart,
974
RenderObject*& inlineRunEnd)
976
// Beginning at |start| we find the largest contiguous run of inlines that
977
// we can. We denote the run with start and end points, |inlineRunStart|
978
// and |inlineRunEnd|. Note that these two values may be the same if
979
// we encounter only one inline.
981
// We skip any non-inlines we encounter as long as we haven't found any
984
// |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
985
// is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
988
// Start by skipping as many non-inlines as we can.
989
RenderObject * curr = start;
992
while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
993
curr = curr->nextSibling();
995
inlineRunStart = inlineRunEnd = curr;
998
return; // No more inline children to be found.
1000
sawInline = curr->isInline();
1002
curr = curr->nextSibling();
1003
while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
1004
inlineRunEnd = curr;
1005
if (curr->isInline())
1007
curr = curr->nextSibling();
1009
} while (!sawInline);
1012
void RenderBlock::deleteLineBoxTree()
1014
if (containsFloats()) {
1015
// Clear references to originating lines, since the lines are being deleted
1016
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1017
FloatingObjectSetIterator end = floatingObjectSet.end();
1018
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1019
ASSERT(!((*it)->m_originatingLine) || (*it)->m_originatingLine->renderer() == this);
1020
(*it)->m_originatingLine = 0;
1023
m_lineBoxes.deleteLineBoxTree(renderArena());
1024
if (UNLIKELY(AXObjectCache::accessibilityEnabled()))
1025
document()->axObjectCache()->recomputeIsIgnored(this);
1028
RootInlineBox* RenderBlock::createRootInlineBox()
1030
return new (renderArena()) RootInlineBox(this);
1033
RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
1035
RootInlineBox* rootBox = createRootInlineBox();
1036
m_lineBoxes.appendLineBox(rootBox);
1038
if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox)
1039
document()->axObjectCache()->recomputeIsIgnored(this);
1044
void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
1046
// makeChildrenNonInline takes a block whose children are *all* inline and it
1047
// makes sure that inline children are coalesced under anonymous
1048
// blocks. If |insertionPoint| is defined, then it represents the insertion point for
1049
// the new block child that is causing us to have to wrap all the inlines. This
1050
// means that we cannot coalesce inlines before |insertionPoint| with inlines following
1051
// |insertionPoint|, because the new child is going to be inserted in between the inlines,
1053
ASSERT(isInlineBlockOrInlineTable() || !isInline());
1054
ASSERT(!insertionPoint || insertionPoint->parent() == this);
1056
setChildrenInline(false);
1058
RenderObject *child = firstChild();
1062
deleteLineBoxTree();
1064
// Since we are going to have block children, we have to move
1065
// back the run-in to its original place.
1066
if (child->isRunIn()) {
1067
moveRunInToOriginalPosition(child);
1068
child = firstChild();
1072
RenderObject *inlineRunStart, *inlineRunEnd;
1073
getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
1075
if (!inlineRunStart)
1078
child = inlineRunEnd->nextSibling();
1080
RenderBlock* block = createAnonymousBlock();
1081
children()->insertChildNode(this, block, inlineRunStart);
1082
moveChildrenTo(block, inlineRunStart, child);
1086
for (RenderObject *c = firstChild(); c; c = c->nextSibling())
1087
ASSERT(!c->isInline());
1093
void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
1095
ASSERT(child->isAnonymousBlock());
1096
ASSERT(!child->childrenInline());
1098
if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
1101
RenderObject* firstAnChild = child->m_children.firstChild();
1102
RenderObject* lastAnChild = child->m_children.lastChild();
1104
RenderObject* o = firstAnChild;
1107
o = o->nextSibling();
1109
firstAnChild->setPreviousSibling(child->previousSibling());
1110
lastAnChild->setNextSibling(child->nextSibling());
1111
if (child->previousSibling())
1112
child->previousSibling()->setNextSibling(firstAnChild);
1113
if (child->nextSibling())
1114
child->nextSibling()->setPreviousSibling(lastAnChild);
1116
if (child == m_children.firstChild())
1117
m_children.setFirstChild(firstAnChild);
1118
if (child == m_children.lastChild())
1119
m_children.setLastChild(lastAnChild);
1121
if (child == m_children.firstChild())
1122
m_children.setFirstChild(child->nextSibling());
1123
if (child == m_children.lastChild())
1124
m_children.setLastChild(child->previousSibling());
1126
if (child->previousSibling())
1127
child->previousSibling()->setNextSibling(child->nextSibling());
1128
if (child->nextSibling())
1129
child->nextSibling()->setPreviousSibling(child->previousSibling());
1131
child->setParent(0);
1132
child->setPreviousSibling(0);
1133
child->setNextSibling(0);
1135
child->children()->setFirstChild(0);
1141
static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
1143
if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
1146
if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1147
|| (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1150
// FIXME: This check isn't required when inline run-ins can't be split into continuations.
1151
if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
1154
if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1155
|| (next && (next->isRubyRun() || next->isRubyBase())))
1161
// Make sure the types of the anonymous blocks match up.
1162
return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1163
&& prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1166
void RenderBlock::collapseAnonymousBoxChild(RenderBlock* parent, RenderObject* child)
1168
parent->setNeedsLayoutAndPrefWidthsRecalc();
1169
parent->setChildrenInline(child->childrenInline());
1170
RenderObject* nextSibling = child->nextSibling();
1172
RenderFlowThread* childFlowThread = child->enclosingRenderFlowThread();
1173
CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
1175
RenderBlock* anonBlock = toRenderBlock(parent->children()->removeChildNode(parent, child, child->hasLayer()));
1176
anonBlock->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1177
// Delete the now-empty block's lines and nuke it.
1178
anonBlock->deleteLineBoxTree();
1179
if (childFlowThread && childFlowThread->isRenderNamedFlowThread())
1180
toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(anonBlock);
1181
anonBlock->destroy();
1184
void RenderBlock::removeChild(RenderObject* oldChild)
1186
// No need to waste time in merging or removing empty anonymous blocks.
1187
// We can just bail out if our document is getting destroyed.
1188
if (documentBeingDestroyed()) {
1189
RenderBox::removeChild(oldChild);
1193
// If this child is a block, and if our previous and next siblings are
1194
// both anonymous blocks with inline content, then we can go ahead and
1195
// fold the inline content back together.
1196
RenderObject* prev = oldChild->previousSibling();
1197
RenderObject* next = oldChild->nextSibling();
1198
bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1199
if (canMergeAnonymousBlocks && prev && next) {
1200
prev->setNeedsLayoutAndPrefWidthsRecalc();
1201
RenderBlock* nextBlock = toRenderBlock(next);
1202
RenderBlock* prevBlock = toRenderBlock(prev);
1204
if (prev->childrenInline() != next->childrenInline()) {
1205
RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1206
RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1208
// Place the inline children block inside of the block children block instead of deleting it.
1209
// In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1210
// to clear out inherited column properties by just making a new style, and to also clear the
1211
// column span flag if it is set.
1212
ASSERT(!inlineChildrenBlock->continuation());
1213
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1214
// Cache this value as it might get changed in setStyle() call.
1215
bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
1216
inlineChildrenBlock->setStyle(newStyle);
1217
children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer);
1219
// Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1220
blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1221
inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer());
1222
next->setNeedsLayoutAndPrefWidthsRecalc();
1224
// inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1225
// of "this". we null out prev or next so that is not used later in the function.
1226
if (inlineChildrenBlock == prevBlock)
1231
// Take all the children out of the |next| block and put them in
1232
// the |prev| block.
1233
nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1235
// Delete the now-empty block's lines and nuke it.
1236
nextBlock->deleteLineBoxTree();
1237
nextBlock->destroy();
1242
RenderBox::removeChild(oldChild);
1244
RenderObject* child = prev ? prev : next;
1245
if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
1246
// The removal has knocked us down to containing only a single anonymous
1247
// box. We can go ahead and pull the content right back up into our
1249
collapseAnonymousBoxChild(this, child);
1250
} else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
1251
// It's possible that the removal has knocked us down to a single anonymous
1252
// block with pseudo-style element siblings (e.g. first-letter). If these
1253
// are floating, then we need to pull the content up also.
1254
RenderBlock* anonBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1255
if ((anonBlock->previousSibling() || anonBlock->nextSibling())
1256
&& (!anonBlock->previousSibling() || (anonBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonBlock->previousSibling()->isFloating() && !anonBlock->previousSibling()->previousSibling()))
1257
&& (!anonBlock->nextSibling() || (anonBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonBlock->nextSibling()->isFloating() && !anonBlock->nextSibling()->nextSibling()))) {
1258
collapseAnonymousBoxChild(this, anonBlock);
1262
if (!firstChild()) {
1263
// If this was our last child be sure to clear out our line boxes.
1264
if (childrenInline())
1265
deleteLineBoxTree();
1267
// If we are an empty anonymous block in the continuation chain,
1268
// we need to remove ourself and fix the continuation chain.
1269
if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
1270
RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1271
while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1272
containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1273
for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1274
if (curr->virtualContinuation() != this)
1277
// Found our previous continuation. We just need to point it to
1278
// |this|'s next continuation.
1279
RenderBoxModelObject* nextContinuation = continuation();
1280
if (curr->isRenderInline())
1281
toRenderInline(curr)->setContinuation(nextContinuation);
1282
else if (curr->isRenderBlock())
1283
toRenderBlock(curr)->setContinuation(nextContinuation);
1285
ASSERT_NOT_REACHED();
1295
bool RenderBlock::isSelfCollapsingBlock() const
1297
// We are not self-collapsing if we
1298
// (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1300
// (c) have border/padding,
1301
// (d) have a min-height
1302
// (e) have specified that one of our margins can't collapse using a CSS extension
1303
if (logicalHeight() > 0
1304
|| isTable() || borderAndPaddingLogicalHeight()
1305
|| style()->logicalMinHeight().isPositive()
1306
|| style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1309
Length logicalHeightLength = style()->logicalHeight();
1310
bool hasAutoHeight = logicalHeightLength.isAuto();
1311
if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1312
hasAutoHeight = true;
1313
for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1314
if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1315
hasAutoHeight = false;
1319
// If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1320
// on whether we have content that is all self-collapsing or not.
1321
if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1322
// If the block has inline children, see if we generated any line boxes. If we have any
1323
// line boxes, then we can't be self-collapsing, since we have content.
1324
if (childrenInline())
1325
return !firstLineBox();
1327
// Whether or not we collapse is dependent on whether all our normal flow children
1328
// are also self-collapsing.
1329
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1330
if (child->isFloatingOrOutOfFlowPositioned())
1332
if (!child->isSelfCollapsingBlock())
1340
void RenderBlock::startDelayUpdateScrollInfo()
1342
if (gDelayUpdateScrollInfo == 0) {
1343
ASSERT(!gDelayedUpdateScrollInfoSet);
1344
gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1346
ASSERT(gDelayedUpdateScrollInfoSet);
1347
++gDelayUpdateScrollInfo;
1350
void RenderBlock::finishDelayUpdateScrollInfo()
1352
--gDelayUpdateScrollInfo;
1353
ASSERT(gDelayUpdateScrollInfo >= 0);
1354
if (gDelayUpdateScrollInfo == 0) {
1355
ASSERT(gDelayedUpdateScrollInfoSet);
1357
OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1358
gDelayedUpdateScrollInfoSet = 0;
1360
for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1361
RenderBlock* block = *it;
1362
if (block->hasOverflowClip()) {
1363
block->layer()->updateScrollInfoAfterLayout();
1369
void RenderBlock::updateScrollInfoAfterLayout()
1371
if (hasOverflowClip()) {
1372
if (style()->isFlippedBlocksWritingMode()) {
1373
// FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
1374
// Workaround for now. We cannot delay the scroll info for overflow
1375
// for items with opposite writing directions, as the contents needs
1376
// to overflow in that direction
1377
layer()->updateScrollInfoAfterLayout();
1381
if (gDelayUpdateScrollInfo)
1382
gDelayedUpdateScrollInfoSet->add(this);
1384
layer()->updateScrollInfoAfterLayout();
1388
void RenderBlock::layout()
1390
StackStats::LayoutCheckPoint layoutCheckPoint;
1391
OverflowEventDispatcher dispatcher(this);
1393
// Update our first letter info now.
1394
updateFirstLetter();
1396
// Table cells call layoutBlock directly, so don't add any logic here. Put code into
1400
// It's safe to check for control clip here, since controls can never be table cells.
1401
// If we have a lightweight clip, there can never be any overflow from children.
1402
if (hasControlClip() && m_overflow)
1403
clearLayoutOverflow();
1406
#if ENABLE(CSS_EXCLUSIONS)
1407
void RenderBlock::updateExclusionShapeInsideInfoAfterStyleChange(const ExclusionShapeValue* shapeInside, const ExclusionShapeValue* oldShapeInside)
1409
// FIXME: A future optimization would do a deep comparison for equality.
1410
if (shapeInside == oldShapeInside)
1414
ExclusionShapeInsideInfo* exclusionShapeInsideInfo = ExclusionShapeInsideInfo::ensureExclusionShapeInsideInfoForRenderBlock(this);
1415
exclusionShapeInsideInfo->dirtyShapeSize();
1417
ExclusionShapeInsideInfo::removeExclusionShapeInsideInfoForRenderBlock(this);
1421
void RenderBlock::updateRegionsAndExclusionsLogicalSize()
1423
#if ENABLE(CSS_EXCLUSIONS)
1424
if (!inRenderFlowThread() && !exclusionShapeInsideInfo())
1426
if (!inRenderFlowThread())
1430
LayoutUnit oldHeight = logicalHeight();
1431
LayoutUnit oldTop = logicalTop();
1433
// Compute the maximum logical height content may cause this block to expand to
1434
// FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
1435
setLogicalHeight(LayoutUnit::max() / 2);
1436
updateLogicalHeight();
1438
#if ENABLE(CSS_EXCLUSIONS)
1439
computeExclusionShapeSize();
1442
// Set our start and end regions. No regions above or below us will be considered by our children. They are
1443
// effectively clamped to our region range.
1444
computeRegionRangeForBlock();
1446
setLogicalHeight(oldHeight);
1447
setLogicalTop(oldTop);
1450
#if ENABLE(CSS_EXCLUSIONS)
1451
void RenderBlock::computeExclusionShapeSize()
1453
ExclusionShapeInsideInfo* exclusionShapeInsideInfo = this->exclusionShapeInsideInfo();
1454
if (exclusionShapeInsideInfo) {
1455
bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
1456
exclusionShapeInsideInfo->computeShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
1461
void RenderBlock::computeRegionRangeForBlock()
1463
if (inRenderFlowThread())
1464
enclosingRenderFlowThread()->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1467
bool RenderBlock::updateLogicalWidthAndColumnWidth()
1469
LayoutUnit oldWidth = logicalWidth();
1470
LayoutUnit oldColumnWidth = desiredColumnWidth();
1472
updateLogicalWidth();
1475
return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth();
1478
void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
1480
ColumnInfo* colInfo = columnInfo();
1482
if (!pageLogicalHeight) {
1483
// We need to go ahead and set our explicit page height if one exists, so that we can
1484
// avoid doing two layout passes.
1485
updateLogicalHeight();
1486
LayoutUnit columnHeight = contentLogicalHeight();
1487
if (columnHeight > 0) {
1488
pageLogicalHeight = columnHeight;
1489
hasSpecifiedPageLogicalHeight = true;
1491
setLogicalHeight(0);
1493
if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
1494
colInfo->setColumnHeight(pageLogicalHeight);
1495
pageLogicalHeightChanged = true;
1498
if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1499
colInfo->clearForcedBreaks();
1501
colInfo->setPaginationUnit(paginationUnit());
1502
} else if (isRenderFlowThread()) {
1503
pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
1504
pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalHeightChanged();
1508
void RenderBlock::layoutBlock(bool relayoutChildren, LayoutUnit pageLogicalHeight)
1510
ASSERT(needsLayout());
1512
if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1513
return; // cause us to come in here. Just bail.
1515
if (!relayoutChildren && simplifiedLayout())
1518
LayoutRepainter repainter(*this, checkForRepaintDuringLayout());
1520
if (updateLogicalWidthAndColumnWidth())
1521
relayoutChildren = true;
1527
LayoutUnit previousHeight = logicalHeight();
1528
setLogicalHeight(0);
1530
bool pageLogicalHeightChanged = false;
1531
bool hasSpecifiedPageLogicalHeight = false;
1532
checkForPaginationLogicalHeightChange(pageLogicalHeight, pageLogicalHeightChanged, hasSpecifiedPageLogicalHeight);
1534
RenderView* renderView = view();
1535
RenderStyle* styleToUse = style();
1536
LayoutStateMaintainer statePusher(renderView, this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || styleToUse->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, columnInfo());
1538
if (inRenderFlowThread()) {
1539
// Regions changing widths can force us to relayout our children.
1540
if (logicalWidthChangedInRegions())
1541
relayoutChildren = true;
1543
updateRegionsAndExclusionsLogicalSize();
1545
// We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1546
// our current maximal positive and negative margins. These values are used when we
1547
// are collapsed with adjacent blocks, so for example, if you have block A and B
1548
// collapsing together, then you'd take the maximal positive margin from both A and B
1549
// and subtract it from the maximal negative margin from both A and B to get the
1550
// true collapsed margin. This algorithm is recursive, so when we finish layout()
1551
// our block knows its current maximal positive/negative values.
1553
// Start out by setting our margin values to our current margins. Table cells have
1554
// no margins, so we don't fill in the values for table cells.
1555
bool isCell = isTableCell();
1557
initMaxMarginValues();
1559
setMarginBeforeQuirk(styleToUse->marginBefore().quirk());
1560
setMarginAfterQuirk(styleToUse->marginAfter().quirk());
1561
setPaginationStrut(0);
1564
LayoutUnit repaintLogicalTop = 0;
1565
LayoutUnit repaintLogicalBottom = 0;
1566
LayoutUnit maxFloatLogicalBottom = 0;
1567
if (!firstChild() && !isAnonymousBlock())
1568
setChildrenInline(true);
1569
if (childrenInline())
1570
layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1572
layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1574
// Expand our intrinsic height to encompass floats.
1575
LayoutUnit toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1576
if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1577
setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1579
if (relayoutForPagination(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1582
// Calculate our new height.
1583
LayoutUnit oldHeight = logicalHeight();
1584
LayoutUnit oldClientAfterEdge = clientLogicalBottom();
1585
updateLogicalHeight();
1586
LayoutUnit newHeight = logicalHeight();
1587
if (oldHeight != newHeight) {
1588
if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1589
// One of our children's floats may have become an overhanging float for us. We need to look for it.
1590
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1591
if (child->isBlockFlow() && !child->isFloatingOrOutOfFlowPositioned()) {
1592
RenderBlock* block = toRenderBlock(child);
1593
if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
1594
addOverhangingFloats(block, false);
1600
if (previousHeight != newHeight)
1601
relayoutChildren = true;
1603
layoutPositionedObjects(relayoutChildren || isRoot());
1605
computeRegionRangeForBlock();
1607
// Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1608
computeOverflow(oldClientAfterEdge);
1612
if (renderView->layoutState()->m_pageLogicalHeight)
1613
setPageLogicalOffset(renderView->layoutState()->pageLogicalOffset(this, logicalTop()));
1615
updateLayerTransform();
1617
// Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1618
// we overflow or not.
1619
updateScrollInfoAfterLayout();
1621
// FIXME: This repaint logic should be moved into a separate helper function!
1622
// Repaint with our new bounds if they are different from our old bounds.
1623
bool didFullRepaint = repainter.repaintAfterLayout();
1624
if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (styleToUse->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1625
// FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1626
// it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1627
LayoutUnit repaintLogicalLeft = logicalLeftVisualOverflow();
1628
LayoutUnit repaintLogicalRight = logicalRightVisualOverflow();
1629
if (hasOverflowClip()) {
1630
// 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.
1631
// 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.
1632
// layoutInlineChildren should be patched to compute the entire repaint rect.
1633
repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1634
repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1637
LayoutRect repaintRect;
1638
if (isHorizontalWritingMode())
1639
repaintRect = LayoutRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1641
repaintRect = LayoutRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1643
// The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1644
adjustRectForColumns(repaintRect);
1646
repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1648
if (hasOverflowClip()) {
1649
// Adjust repaint rect for scroll offset
1650
repaintRect.move(-scrolledContentOffset());
1652
// Don't allow this rect to spill out of our overflow box.
1653
repaintRect.intersect(LayoutRect(LayoutPoint(), size()));
1656
// Make sure the rect is still non-empty after intersecting for overflow above
1657
if (!repaintRect.isEmpty()) {
1658
repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1659
if (hasReflection())
1660
repaintRectangle(reflectedRect(repaintRect));
1664
setNeedsLayout(false);
1667
void RenderBlock::addOverflowFromChildren()
1669
if (!hasColumns()) {
1670
if (childrenInline())
1671
addOverflowFromInlineChildren();
1673
addOverflowFromBlockChildren();
1675
ColumnInfo* colInfo = columnInfo();
1676
if (columnCount(colInfo)) {
1677
LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1678
addLayoutOverflow(lastRect);
1679
if (!hasOverflowClip())
1680
addVisualOverflow(lastRect);
1685
void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool recomputeFloats)
1687
// Add overflow from children.
1688
addOverflowFromChildren();
1690
if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1691
addOverflowFromFloats();
1693
// Add in the overflow from positioned objects.
1694
addOverflowFromPositionedObjects();
1696
if (hasOverflowClip()) {
1697
// When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1698
// and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1699
// be considered reachable.
1700
LayoutRect clientRect(clientBoxRect());
1701
LayoutRect rectToApply;
1702
if (isHorizontalWritingMode())
1703
rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1705
rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1706
addLayoutOverflow(rectToApply);
1709
// Add visual overflow from box-shadow and border-image-outset.
1710
addVisualEffectOverflow();
1712
// Add visual overflow from theme.
1713
addVisualOverflowFromTheme();
1715
if (isRenderFlowThread())
1716
enclosingRenderFlowThread()->computeOverflowStateForRegions(oldClientAfterEdge);
1719
void RenderBlock::addOverflowFromBlockChildren()
1721
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1722
if (!child->isFloatingOrOutOfFlowPositioned())
1723
addOverflowFromChild(child);
1727
void RenderBlock::addOverflowFromFloats()
1729
if (!m_floatingObjects)
1732
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1733
FloatingObjectSetIterator end = floatingObjectSet.end();
1734
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1735
FloatingObject* r = *it;
1736
if (r->isDescendant())
1737
addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1742
void RenderBlock::addOverflowFromPositionedObjects()
1744
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1745
if (!positionedDescendants)
1748
RenderBox* positionedObject;
1749
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1750
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1751
positionedObject = *it;
1753
// Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1754
if (positionedObject->style()->position() != FixedPosition) {
1755
LayoutUnit x = positionedObject->x();
1756
if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1757
x -= verticalScrollbarWidth();
1758
addOverflowFromChild(positionedObject, LayoutSize(x, positionedObject->y()));
1763
void RenderBlock::addVisualOverflowFromTheme()
1765
if (!style()->hasAppearance())
1768
IntRect inflatedRect = pixelSnappedBorderBoxRect();
1769
theme()->adjustRepaintRect(this, inflatedRect);
1770
addVisualOverflow(inflatedRect);
1773
bool RenderBlock::expandsToEncloseOverhangingFloats() const
1775
return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isDeprecatedFlexibleBox())
1776
|| hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1779
void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1781
bool isHorizontal = isHorizontalWritingMode();
1782
bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1784
LayoutUnit logicalTop = logicalHeight();
1785
setStaticInlinePositionForChild(child, logicalTop, startOffsetForContent(logicalTop));
1787
if (!marginInfo.canCollapseWithMarginBefore()) {
1788
// Positioned blocks don't collapse margins, so add the margin provided by
1789
// the container now. The child's own margin is added later when calculating its logical top.
1790
LayoutUnit collapsedBeforePos = marginInfo.positiveMargin();
1791
LayoutUnit collapsedBeforeNeg = marginInfo.negativeMargin();
1792
logicalTop += collapsedBeforePos - collapsedBeforeNeg;
1795
RenderLayer* childLayer = child->layer();
1796
if (childLayer->staticBlockPosition() != logicalTop) {
1797
childLayer->setStaticBlockPosition(logicalTop);
1798
if (hasStaticBlockPosition)
1799
child->setChildNeedsLayout(true, MarkOnlyThis);
1803
void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1805
// The float should be positioned taking into account the bottom margin
1806
// of the previous flow. We add that margin into the height, get the
1807
// float positioned properly, and then subtract the margin out of the
1808
// height again. In the case of self-collapsing blocks, we always just
1809
// use the top margins, since the self-collapsing block collapsed its
1810
// own bottom margin into its top margin.
1812
// Note also that the previous flow may collapse its margin into the top of
1813
// our block. If this is the case, then we do not add the margin in to our
1814
// height when computing the position of the float. This condition can be tested
1815
// for by simply calling canCollapseWithMarginBefore. See
1816
// http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1817
// an example of this scenario.
1818
LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
1819
setLogicalHeight(logicalHeight() + marginOffset);
1820
positionNewFloats();
1821
setLogicalHeight(logicalHeight() - marginOffset);
1824
bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1826
// Handle in the given order
1827
return handlePositionedChild(child, marginInfo)
1828
|| handleFloatingChild(child, marginInfo);
1832
bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1834
if (child->isOutOfFlowPositioned()) {
1835
child->containingBlock()->insertPositionedObject(child);
1836
adjustPositionedBlock(child, marginInfo);
1842
bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1844
if (child->isFloating()) {
1845
insertFloatingObject(child);
1846
adjustFloatingBlock(marginInfo);
1852
static void destroyRunIn(RenderBoxModelObject* runIn)
1854
ASSERT(runIn->isRunIn());
1855
ASSERT(!runIn->firstChild());
1857
// Delete our line box tree. This is needed as our children got moved
1858
// and our line box tree is no longer valid.
1859
if (runIn->isRenderBlock())
1860
toRenderBlock(runIn)->deleteLineBoxTree();
1861
else if (runIn->isRenderInline())
1862
toRenderInline(runIn)->deleteLineBoxTree();
1864
ASSERT_NOT_REACHED();
1869
void RenderBlock::placeRunInIfNeeded(RenderObject* newChild, PlaceGeneratedRunInFlag flag)
1871
if (newChild->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
1872
moveRunInUnderSiblingBlockIfNeeded(newChild);
1873
else if (RenderObject* prevSibling = newChild->previousSibling()) {
1874
if (prevSibling->isRunIn() && (flag == PlaceGeneratedRunIn || !newChild->isBeforeOrAfterContent()))
1875
moveRunInUnderSiblingBlockIfNeeded(prevSibling);
1879
RenderBoxModelObject* RenderBlock::createReplacementRunIn(RenderBoxModelObject* runIn)
1881
ASSERT(runIn->isRunIn());
1883
// First we destroy any :before/:after content. It will be regenerated by the new run-in.
1884
// Exception is if the run-in itself is generated.
1885
if (runIn->style()->styleType() != BEFORE && runIn->style()->styleType() != AFTER) {
1886
RenderObject* generatedContent;
1887
if (runIn->getCachedPseudoStyle(BEFORE) && (generatedContent = runIn->beforePseudoElementRenderer()))
1888
generatedContent->destroy();
1889
if (runIn->getCachedPseudoStyle(AFTER) && (generatedContent = runIn->afterPseudoElementRenderer()))
1890
generatedContent->destroy();
1893
bool newRunInShouldBeBlock = !runIn->isRenderBlock();
1894
Node* runInNode = runIn->node();
1895
RenderBoxModelObject* newRunIn = 0;
1896
if (newRunInShouldBeBlock)
1897
newRunIn = new (renderArena()) RenderBlock(runInNode ? runInNode : document());
1899
newRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1900
newRunIn->setStyle(runIn->style());
1902
runIn->moveAllChildrenTo(newRunIn, true);
1904
// If the run-in had an element, we need to set the new renderer.
1906
runInNode->setRenderer(newRunIn);
1911
void RenderBlock::moveRunInUnderSiblingBlockIfNeeded(RenderObject* runIn)
1913
ASSERT(runIn->isRunIn());
1915
// See if we have inline children. If the children aren't inline,
1916
// then just treat the run-in as a normal block.
1917
if (!runIn->childrenInline())
1920
// FIXME: We don't handle non-block elements with run-in for now.
1921
if (!runIn->isRenderBlock())
1924
// FIXME: We don't support run-ins with or as part of a continuation
1925
// as it makes the back-and-forth placing complex.
1926
if (runIn->isElementContinuation() || runIn->virtualContinuation())
1929
// Check if this node is allowed to run-in. E.g. <select> expects its renderer to
1930
// be a RenderListBox or RenderMenuList, and hence cannot be a RenderInline run-in.
1931
if (!runIn->canBeReplacedWithInlineRunIn())
1934
RenderObject* curr = runIn->nextSibling();
1935
if (!curr || !curr->isRenderBlock() || !curr->childrenInline())
1938
// Per CSS3, "A run-in cannot run in to a block that already starts with a
1939
// run-in or that itself is a run-in".
1940
if (curr->isRunIn() || (curr->firstChild() && curr->firstChild()->isRunIn()))
1943
if (curr->isAnonymous() || curr->isFloatingOrOutOfFlowPositioned())
1946
RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1947
RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1948
destroyRunIn(oldRunIn);
1950
// Now insert the new child under |curr| block. Use addChild instead of insertChildNode
1951
// since it handles correct placement of the children, especially where we cannot insert
1952
// anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1953
curr->addChild(newRunIn, curr->firstChild());
1955
// Make sure that |this| get a layout since its run-in child moved.
1956
curr->setNeedsLayoutAndPrefWidthsRecalc();
1959
bool RenderBlock::runInIsPlacedIntoSiblingBlock(RenderObject* runIn)
1961
ASSERT(runIn->isRunIn());
1963
// If we don't have a parent, we can't be moved into our sibling block.
1967
// An intruded run-in needs to be an inline.
1968
if (!runIn->isRenderInline())
1974
void RenderBlock::moveRunInToOriginalPosition(RenderObject* runIn)
1976
ASSERT(runIn->isRunIn());
1978
if (!runInIsPlacedIntoSiblingBlock(runIn))
1981
// FIXME: Run-in that are now placed in sibling block can break up into continuation
1982
// chains when new children are added to it. We cannot easily send them back to their
1983
// original place since that requires writing integration logic with RenderInline::addChild
1984
// and all other places that might cause continuations to be created (without blowing away
1985
// |this|). Disabling this feature for now to prevent crashes.
1986
if (runIn->isElementContinuation() || runIn->virtualContinuation())
1989
RenderBoxModelObject* oldRunIn = toRenderBoxModelObject(runIn);
1990
RenderBoxModelObject* newRunIn = createReplacementRunIn(oldRunIn);
1991
destroyRunIn(oldRunIn);
1993
// Add the run-in block as our previous sibling.
1994
parent()->addChild(newRunIn, this);
1996
// Make sure that the parent holding the new run-in gets layout.
1997
parent()->setNeedsLayoutAndPrefWidthsRecalc();
2000
LayoutUnit RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
2002
// Get the four margin values for the child and cache them.
2003
const MarginValues childMargins = marginValuesForChild(child);
2005
// Get our max pos and neg top margins.
2006
LayoutUnit posTop = childMargins.positiveMarginBefore();
2007
LayoutUnit negTop = childMargins.negativeMarginBefore();
2009
// For self-collapsing blocks, collapse our bottom margins into our
2010
// top to get new posTop and negTop values.
2011
if (child->isSelfCollapsingBlock()) {
2012
posTop = max(posTop, childMargins.positiveMarginAfter());
2013
negTop = max(negTop, childMargins.negativeMarginAfter());
2016
// See if the top margin is quirky. We only care if this child has
2017
// margins that will collapse with us.
2018
bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
2020
if (marginInfo.canCollapseWithMarginBefore()) {
2021
// This child is collapsing with the top of the
2022
// block. If it has larger margin values, then we need to update
2023
// our own maximal values.
2024
if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
2025
setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
2027
// The minute any of the margins involved isn't a quirk, don't
2028
// collapse it away, even if the margin is smaller (www.webreference.com
2029
// has an example of this, a <dt> with 0.8em author-specified inside
2030
// a <dl> inside a <td>.
2031
if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
2032
setMarginBeforeQuirk(false);
2033
marginInfo.setDeterminedMarginBeforeQuirk(true);
2036
if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
2037
// We have no top margin and our top child has a quirky margin.
2038
// We will pick up this quirky margin and pass it through.
2039
// This deals with the <td><div><p> case.
2040
// Don't do this for a block that split two inlines though. You do
2041
// still apply margins in this case.
2042
setMarginBeforeQuirk(true);
2045
if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
2046
marginInfo.setMarginBeforeQuirk(topQuirk);
2048
LayoutUnit beforeCollapseLogicalTop = logicalHeight();
2049
LayoutUnit logicalTop = beforeCollapseLogicalTop;
2050
if (child->isSelfCollapsingBlock()) {
2051
// This child has no height. We need to compute our
2052
// position before we collapse the child's margins together,
2053
// so that we can get an accurate position for the zero-height block.
2054
LayoutUnit collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
2055
LayoutUnit collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
2056
marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
2058
// Now collapse the child's margins together, which means examining our
2059
// bottom margin values as well.
2060
marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
2061
marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
2063
if (!marginInfo.canCollapseWithMarginBefore())
2064
// We need to make sure that the position of the self-collapsing block
2065
// is correct, since it could have overflowing content
2066
// that needs to be positioned correctly (e.g., a block that
2067
// had a specified height of 0 but that actually had subcontent).
2068
logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
2071
if (child->style()->marginBeforeCollapse() == MSEPARATE) {
2072
setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
2073
logicalTop = logicalHeight();
2075
else if (!marginInfo.atBeforeSideOfBlock() ||
2076
(!marginInfo.canCollapseMarginBeforeWithChildren()
2077
&& (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
2078
// We're collapsing with a previous sibling's margins and not
2079
// with the top of the block.
2080
setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
2081
logicalTop = logicalHeight();
2084
marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
2085
marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
2087
if (marginInfo.margin())
2088
marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
2091
// If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
2092
// collapsed into the page edge.
2093
LayoutState* layoutState = view()->layoutState();
2094
if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTop > beforeCollapseLogicalTop
2095
&& hasNextPage(beforeCollapseLogicalTop)) {
2096
LayoutUnit oldLogicalTop = logicalTop;
2097
logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
2098
setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
2101
// If we have collapsed into a previous sibling and so reduced the height of the parent, ensure any floats that now
2102
// overhang from the previous sibling are added to our parent. If the child's previous sibling itself is a float the child will avoid
2103
// or clear it anyway, so don't worry about any floating children it may contain.
2104
RenderObject* prev = child->previousSibling();
2105
if (prev && prev->isBlockFlow() && !prev->isFloatingOrOutOfFlowPositioned()) {
2106
RenderBlock* block = toRenderBlock(prev);
2107
if (block->containsFloats() && !block->avoidsFloats() && (block->logicalTop() + block->lowestFloatLogicalBottom()) > logicalTop)
2108
addOverhangingFloats(block, false);
2114
LayoutUnit RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, LayoutUnit oldTopPosMargin, LayoutUnit oldTopNegMargin, LayoutUnit yPos)
2116
LayoutUnit heightIncrease = getClearDelta(child, yPos);
2117
if (!heightIncrease)
2120
if (child->isSelfCollapsingBlock()) {
2121
// For self-collapsing blocks that clear, they can still collapse their
2122
// margins with following siblings. Reset the current margins to represent
2123
// the self-collapsing block's margins only.
2124
MarginValues childMargins = marginValuesForChild(child);
2125
marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
2126
marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
2129
// "If the top and bottom margins of an element with clearance are adjoining, its margins collapse with
2130
// the adjoining margins of following siblings but that resulting margin does not collapse with the bottom margin of the parent block."
2131
// So the parent's bottom margin cannot collapse through this block or any subsequent self-collapsing blocks. Check subsequent siblings
2132
// for a block with height - if none is found then don't allow the margins to collapse with the parent.
2133
bool wouldCollapseMarginsWithParent = marginInfo.canCollapseMarginAfterWithChildren();
2134
for (RenderBox* curr = child->nextSiblingBox(); curr && wouldCollapseMarginsWithParent; curr = curr->nextSiblingBox()) {
2135
if (!curr->isFloatingOrOutOfFlowPositioned() && !curr->isSelfCollapsingBlock())
2136
wouldCollapseMarginsWithParent = false;
2138
if (wouldCollapseMarginsWithParent)
2139
marginInfo.setCanCollapseMarginAfterWithChildren(false);
2141
// CSS2.1: "the amount of clearance is set so that clearance + margin-top = [height of float], i.e., clearance = [height of float] - margin-top"
2142
// Move the top of the child box to the bottom of the float ignoring the child's top margin.
2143
LayoutUnit collapsedMargin = collapsedMarginBeforeForChild(child);
2144
setLogicalHeight(child->logicalTop() - collapsedMargin);
2145
heightIncrease -= collapsedMargin;
2147
// Increase our height by the amount we had to clear.
2148
setLogicalHeight(logicalHeight() + heightIncrease);
2150
if (marginInfo.canCollapseWithMarginBefore()) {
2151
// We can no longer collapse with the top of the block since a clear
2152
// occurred. The empty blocks collapse into the cleared block.
2153
// FIXME: This isn't quite correct. Need clarification for what to do
2154
// if the height the cleared block is offset by is smaller than the
2155
// margins involved.
2156
setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
2157
marginInfo.setAtBeforeSideOfBlock(false);
2160
LayoutUnit logicalTop = yPos + heightIncrease;
2161
// After margin collapsing, one of our floats may now intrude into the child. If the child doesn't contain floats of its own it
2162
// won't get picked up for relayout even though the logical top estimate was wrong - so add the newly intruding float now.
2163
if (containsFloats() && child->isRenderBlock() && !toRenderBlock(child)->containsFloats() && !child->avoidsFloats() && lowestFloatLogicalBottom() > logicalTop)
2164
toRenderBlock(child)->addIntrudingFloats(this, logicalLeftOffsetForContent(), logicalTop);
2169
void RenderBlock::marginBeforeEstimateForChild(RenderBox* child, LayoutUnit& positiveMarginBefore, LayoutUnit& negativeMarginBefore) const
2171
// FIXME: We should deal with the margin-collapse-* style extensions that prevent collapsing and that discard margins.
2172
// Give up if in quirks mode and we're a body/table cell and the top margin of the child box is quirky.
2173
if (document()->inQuirksMode() && child->isMarginBeforeQuirk() && (isTableCell() || isBody()))
2176
LayoutUnit beforeChildMargin = marginBeforeForChild(child);
2177
positiveMarginBefore = max(positiveMarginBefore, beforeChildMargin);
2178
negativeMarginBefore = max(negativeMarginBefore, -beforeChildMargin);
2180
if (!child->isRenderBlock())
2183
RenderBlock* childBlock = toRenderBlock(child);
2184
if (childBlock->childrenInline() || childBlock->isWritingModeRoot())
2187
MarginInfo childMarginInfo(childBlock, childBlock->borderBefore() + childBlock->paddingBefore(), childBlock->borderAfter() + childBlock->paddingAfter());
2188
if (!childMarginInfo.canCollapseMarginBeforeWithChildren())
2191
RenderBox* grandchildBox = childBlock->firstChildBox();
2192
for ( ; grandchildBox; grandchildBox = grandchildBox->nextSiblingBox()) {
2193
if (!grandchildBox->isFloatingOrOutOfFlowPositioned())
2197
// Give up if there is clearance on the box, since it probably won't collapse into us.
2198
if (!grandchildBox || grandchildBox->style()->clear() != CNONE)
2201
// Make sure to update the block margins now for the grandchild box so that we're looking at current values.
2202
if (grandchildBox->needsLayout()) {
2203
grandchildBox->computeAndSetBlockDirectionMargins(this);
2204
grandchildBox->setMarginBeforeQuirk(grandchildBox->style()->marginBefore().quirk());
2205
grandchildBox->setMarginAfterQuirk(grandchildBox->style()->marginAfter().quirk());
2208
// Collapse the margin of the grandchild box with our own to produce an estimate.
2209
childBlock->marginBeforeEstimateForChild(grandchildBox, positiveMarginBefore, negativeMarginBefore);
2212
LayoutUnit RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo, LayoutUnit& estimateWithoutPagination)
2214
// FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
2215
// relayout if there are intruding floats.
2216
LayoutUnit logicalTopEstimate = logicalHeight();
2217
if (!marginInfo.canCollapseWithMarginBefore()) {
2218
LayoutUnit positiveMarginBefore = 0;
2219
LayoutUnit negativeMarginBefore = 0;
2220
if (child->selfNeedsLayout()) {
2221
// Try to do a basic estimation of how the collapse is going to go.
2222
marginBeforeEstimateForChild(child, positiveMarginBefore, negativeMarginBefore);
2224
// Use the cached collapsed margin values from a previous layout. Most of the time they
2226
MarginValues marginValues = marginValuesForChild(child);
2227
positiveMarginBefore = max(positiveMarginBefore, marginValues.positiveMarginBefore());
2228
negativeMarginBefore = max(negativeMarginBefore, marginValues.negativeMarginBefore());
2231
// Collapse the result with our current margins.
2232
logicalTopEstimate += max(marginInfo.positiveMargin(), positiveMarginBefore) - max(marginInfo.negativeMargin(), negativeMarginBefore);
2235
// Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
2237
LayoutState* layoutState = view()->layoutState();
2238
if (layoutState->isPaginated() && layoutState->pageLogicalHeight() && logicalTopEstimate > logicalHeight()
2239
&& hasNextPage(logicalHeight()))
2240
logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
2242
logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
2244
estimateWithoutPagination = logicalTopEstimate;
2246
if (layoutState->isPaginated()) {
2247
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
2248
logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
2250
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
2251
logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
2253
if (!child->selfNeedsLayout() && child->isRenderBlock())
2254
logicalTopEstimate += toRenderBlock(child)->paginationStrut();
2257
return logicalTopEstimate;
2260
LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart,
2261
RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage)
2263
LayoutUnit startPosition = startOffsetForContent(region, offsetFromLogicalTopOfFirstPage);
2265
// Add in our start margin.
2266
LayoutUnit oldPosition = startPosition + childMarginStart;
2267
LayoutUnit newPosition = oldPosition;
2269
LayoutUnit blockOffset = logicalTopForChild(child);
2271
blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage));
2273
LayoutUnit startOff = startOffsetForLine(blockOffset, false, region, offsetFromLogicalTopOfFirstPage, logicalHeightForChild(child));
2275
if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
2276
if (childMarginStart < 0)
2277
startOff += childMarginStart;
2278
newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
2279
} else if (startOff != startPosition)
2280
newPosition = startOff + childMarginStart;
2282
return newPosition - oldPosition;
2285
void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
2287
LayoutUnit startPosition = borderStart() + paddingStart();
2288
if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
2289
startPosition -= verticalScrollbarWidth();
2290
LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
2292
// Add in our start margin.
2293
LayoutUnit childMarginStart = marginStartForChild(child);
2294
LayoutUnit newPosition = startPosition + childMarginStart;
2296
// Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
2297
// to shift over as necessary to dodge any floats that might get in the way.
2298
if (child->avoidsFloats() && containsFloats() && !inRenderFlowThread())
2299
newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
2301
setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
2304
void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
2306
if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
2307
// Update our max pos/neg bottom margins, since we collapsed our bottom margins
2308
// with our children.
2309
setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
2311
if (!marginInfo.marginAfterQuirk())
2312
setMarginAfterQuirk(false);
2314
if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
2315
// We have no bottom margin and our last child has a quirky margin.
2316
// We will pick up this quirky margin and pass it through.
2317
// This deals with the <td><div><p> case.
2318
setMarginAfterQuirk(true);
2322
void RenderBlock::handleAfterSideOfBlock(LayoutUnit beforeSide, LayoutUnit afterSide, MarginInfo& marginInfo)
2324
marginInfo.setAtAfterSideOfBlock(true);
2326
// If we can't collapse with children then go ahead and add in the bottom margin.
2327
// Don't do this for ordinary anonymous blocks as only the enclosing box should add in
2329
if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
2330
&& (!isAnonymousBlock() || isAnonymousColumnsBlock() || isAnonymousColumnSpanBlock())
2331
&& (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
2332
setLogicalHeight(logicalHeight() + marginInfo.margin());
2334
// Now add in our bottom border/padding.
2335
setLogicalHeight(logicalHeight() + afterSide);
2337
// Negative margins can cause our height to shrink below our minimal height (border/padding).
2338
// If this happens, ensure that the computed height is increased to the minimal height.
2339
setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
2341
// Update our bottom collapsed margin info.
2342
setCollapsedBottomMargin(marginInfo);
2345
void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
2347
if (isHorizontalWritingMode()) {
2348
if (applyDelta == ApplyLayoutDelta)
2349
view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
2350
child->setX(logicalLeft);
2352
if (applyDelta == ApplyLayoutDelta)
2353
view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
2354
child->setY(logicalLeft);
2358
void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
2360
if (isHorizontalWritingMode()) {
2361
if (applyDelta == ApplyLayoutDelta)
2362
view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
2363
child->setY(logicalTop);
2365
if (applyDelta == ApplyLayoutDelta)
2366
view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
2367
child->setX(logicalTop);
2371
void RenderBlock::layoutBlockChildren(bool relayoutChildren, LayoutUnit& maxFloatLogicalBottom)
2373
if (gPercentHeightDescendantsMap) {
2374
if (TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this)) {
2375
TrackedRendererListHashSet::iterator end = descendants->end();
2376
for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
2377
RenderBox* box = *it;
2378
while (box != this) {
2379
if (box->normalChildNeedsLayout())
2381
box->setChildNeedsLayout(true, MarkOnlyThis);
2382
box = box->containingBlock();
2391
LayoutUnit beforeEdge = borderBefore() + paddingBefore();
2392
LayoutUnit afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
2394
setLogicalHeight(beforeEdge);
2396
// Lay out our hypothetical grid line as though it occurs at the top of the block.
2397
if (view()->layoutState()->lineGrid() == this)
2398
layoutLineGridBox();
2400
// The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
2401
MarginInfo marginInfo(this, beforeEdge, afterEdge);
2403
// Fieldsets need to find their legend and position it inside the border of the object.
2404
// The legend then gets skipped during normal layout. The same is true for ruby text.
2405
// It doesn't get included in the normal layout process but is instead skipped.
2406
RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
2408
LayoutUnit previousFloatLogicalBottom = 0;
2409
maxFloatLogicalBottom = 0;
2411
RenderBox* next = firstChildBox();
2414
RenderBox* child = next;
2415
next = child->nextSiblingBox();
2417
if (childToExclude == child)
2418
continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
2420
// Make sure we layout children if they need it.
2421
// FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
2422
// an auto value. Add a method to determine this, so that we can avoid the relayout.
2423
if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
2424
child->setChildNeedsLayout(true, MarkOnlyThis);
2426
// If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2427
if (relayoutChildren && child->needsPreferredWidthsRecalculation())
2428
child->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
2430
// Handle the four types of special elements first. These include positioned content, floating content, compacts and
2431
// run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
2432
if (handleSpecialChild(child, marginInfo))
2435
// Lay out the child.
2436
layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
2439
// Now do the handling of the bottom of the block, adding in our bottom border/padding and
2440
// determining the correct collapsed bottom margin information.
2441
handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
2444
void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, LayoutUnit& previousFloatLogicalBottom, LayoutUnit& maxFloatLogicalBottom)
2446
LayoutUnit oldPosMarginBefore = maxPositiveMarginBefore();
2447
LayoutUnit oldNegMarginBefore = maxNegativeMarginBefore();
2449
// The child is a normal flow object. Compute the margins we will use for collapsing now.
2450
child->computeAndSetBlockDirectionMargins(this);
2452
// Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
2453
RenderStyle* childStyle = child->style();
2454
if (childStyle->marginBeforeCollapse() == MSEPARATE) {
2455
marginInfo.setAtBeforeSideOfBlock(false);
2456
marginInfo.clearMargin();
2459
// Try to guess our correct logical top position. In most cases this guess will
2460
// be correct. Only if we're wrong (when we compute the real logical top position)
2461
// will we have to potentially relayout.
2462
LayoutUnit estimateWithoutPagination;
2463
LayoutUnit logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo, estimateWithoutPagination);
2465
// Cache our old rect so that we can dirty the proper repaint rects if the child moves.
2466
LayoutRect oldRect = child->frameRect();
2467
LayoutUnit oldLogicalTop = logicalTopForChild(child);
2469
#if !ASSERT_DISABLED
2470
LayoutSize oldLayoutDelta = view()->layoutDelta();
2472
// Go ahead and position the child as though it didn't collapse with the top.
2473
setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
2475
RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
2476
bool markDescendantsWithFloats = false;
2477
if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
2478
markDescendantsWithFloats = true;
2479
else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
2480
// If an element might be affected by the presence of floats, then always mark it for
2482
LayoutUnit fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
2483
if (fb > logicalTopEstimate)
2484
markDescendantsWithFloats = true;
2487
if (childRenderBlock) {
2488
if (markDescendantsWithFloats)
2489
childRenderBlock->markAllDescendantsWithFloatsForLayout();
2490
if (!child->isWritingModeRoot())
2491
previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
2494
if (!child->needsLayout())
2495
child->markForPaginationRelayoutIfNeeded();
2497
bool childHadLayout = child->everHadLayout();
2498
bool childNeededLayout = child->needsLayout();
2499
if (childNeededLayout)
2502
// Cache if we are at the top of the block right now.
2503
bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2505
// Now determine the correct ypos based off examination of collapsing margin
2507
LayoutUnit logicalTopBeforeClear = collapseMargins(child, marginInfo);
2509
// Now check for clear.
2510
LayoutUnit logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2512
bool paginated = view()->layoutState()->isPaginated();
2514
logicalTopAfterClear = adjustBlockChildForPagination(logicalTopAfterClear, estimateWithoutPagination, child,
2515
atBeforeSideOfBlock && logicalTopBeforeClear == logicalTopAfterClear);
2517
setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2519
// Now we have a final top position. See if it really does end up being different from our estimate.
2520
// clearFloatsIfNeeded can also mark the child as needing a layout even though we didn't move. This happens
2521
// when collapseMargins dynamically adds overhanging floats because of a child with negative margins.
2522
if (logicalTopAfterClear != logicalTopEstimate || child->needsLayout()) {
2523
if (child->shrinkToAvoidFloats()) {
2524
// The child's width depends on the line width.
2525
// When the child shifts to clear an item, its width can
2526
// change (because it has more available line width).
2527
// So go ahead and mark the item as dirty.
2528
child->setChildNeedsLayout(true, MarkOnlyThis);
2531
if (childRenderBlock) {
2532
if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2533
childRenderBlock->markAllDescendantsWithFloatsForLayout();
2534
if (!child->needsLayout())
2535
child->markForPaginationRelayoutIfNeeded();
2538
// Our guess was wrong. Make the child lay itself out again.
2539
child->layoutIfNeeded();
2542
// We are no longer at the top of the block if we encounter a non-empty child.
2543
// This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2544
if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2545
marginInfo.setAtBeforeSideOfBlock(false);
2547
// Now place the child in the correct left position
2548
determineLogicalLeftPositionForChild(child);
2550
// Update our height now that the child has been placed in the correct position.
2551
setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2552
if (childStyle->marginAfterCollapse() == MSEPARATE) {
2553
setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2554
marginInfo.clearMargin();
2556
// If the child has overhanging floats that intrude into following siblings (or possibly out
2557
// of this block), then the parent gets notified of the floats now.
2558
if (childRenderBlock && childRenderBlock->containsFloats())
2559
maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), !childNeededLayout));
2561
LayoutSize childOffset = child->location() - oldRect.location();
2562
if (childOffset.width() || childOffset.height()) {
2563
view()->addLayoutDelta(childOffset);
2565
// If the child moved, we have to repaint it as well as any floating/positioned
2566
// descendants. An exception is if we need a layout. In this case, we know we're going to
2567
// repaint ourselves (and the child) anyway.
2568
if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2569
child->repaintDuringLayoutIfMoved(oldRect);
2572
if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2574
child->repaintOverhangingFloats(true);
2578
// Check for an after page/column break.
2579
LayoutUnit newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2580
if (newHeight != height())
2581
setLogicalHeight(newHeight);
2584
ASSERT(view()->layoutDeltaMatches(oldLayoutDelta));
2587
void RenderBlock::simplifiedNormalFlowLayout()
2589
if (childrenInline()) {
2590
ListHashSet<RootInlineBox*> lineBoxes;
2591
for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
2592
RenderObject* o = walker.current();
2593
if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
2594
o->layoutIfNeeded();
2595
if (toRenderBox(o)->inlineBoxWrapper()) {
2596
RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2599
} else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline()))
2600
o->setNeedsLayout(false);
2603
// FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2604
GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2605
for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2606
RootInlineBox* box = *it;
2607
box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2610
for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2611
if (!box->isOutOfFlowPositioned())
2612
box->layoutIfNeeded();
2617
bool RenderBlock::simplifiedLayout()
2619
if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2622
LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2624
if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2627
// Lay out positioned descendants or objects that just need to recompute overflow.
2628
if (needsSimplifiedNormalFlowLayout())
2629
simplifiedNormalFlowLayout();
2631
// Lay out our positioned objects if our positioned child bit is set.
2632
if (posChildNeedsLayout())
2633
layoutPositionedObjects(false);
2635
// Recompute our overflow information.
2636
// FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2637
// updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2638
// For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2639
// lowestPosition on every relayout so it's not a regression.
2641
computeOverflow(clientLogicalBottom(), true);
2645
updateLayerTransform();
2647
updateScrollInfoAfterLayout();
2649
setNeedsLayout(false);
2653
void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2655
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2656
if (!positionedDescendants)
2660
view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2663
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2664
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2666
// When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2667
// non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2668
// objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2669
// positioned explicitly) this should not incur a performance penalty.
2670
if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
2671
r->setChildNeedsLayout(true, MarkOnlyThis);
2673
// If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
2674
if (relayoutChildren && r->needsPreferredWidthsRecalculation())
2675
r->setPreferredLogicalWidthsDirty(true, MarkOnlyThis);
2677
if (!r->needsLayout())
2678
r->markForPaginationRelayoutIfNeeded();
2680
// 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
2681
// and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2682
if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2683
r->setNeedsLayout(false);
2685
// If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
2686
// If it's wrong we'll lay out again.
2687
LayoutUnit oldLogicalTop = 0;
2688
bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
2689
if (needsBlockDirectionLocationSetBeforeLayout) {
2690
if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
2691
r->updateLogicalHeight();
2693
r->updateLogicalWidth();
2694
oldLogicalTop = logicalTopForChild(r);
2697
r->layoutIfNeeded();
2699
// Lay out again if our estimate was wrong.
2700
if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop) {
2701
r->setChildNeedsLayout(true, MarkOnlyThis);
2702
r->layoutIfNeeded();
2707
view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2710
void RenderBlock::markPositionedObjectsForLayout()
2712
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2713
if (positionedDescendants) {
2715
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2716
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2718
r->setChildNeedsLayout(true);
2723
void RenderBlock::markForPaginationRelayoutIfNeeded()
2725
ASSERT(!needsLayout());
2729
if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
2730
setChildNeedsLayout(true, MarkOnlyThis);
2733
void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2735
// Repaint any overhanging floats (if we know we're the one to paint them).
2736
// Otherwise, bail out.
2737
if (!hasOverhangingFloats())
2740
// FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2741
// in this block. Better yet would be to push extra state for the containers of other floats.
2742
LayoutStateDisabler layoutStateDisabler(view());
2743
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2744
FloatingObjectSetIterator end = floatingObjectSet.end();
2745
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2746
FloatingObject* r = *it;
2747
// Only repaint the object if it is overhanging, is not in its own layer, and
2748
// is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2749
// condition is replaced with being a descendant of us.
2750
if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->shouldPaint()) && !r->m_renderer->hasSelfPaintingLayer()) {
2751
r->m_renderer->repaint();
2752
r->m_renderer->repaintOverhangingFloats();
2757
void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2759
LayoutPoint adjustedPaintOffset = paintOffset + location();
2761
PaintPhase phase = paintInfo.phase;
2763
// Check if we need to do anything at all.
2764
// FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2765
// paints the root's background.
2767
LayoutRect overflowBox = overflowRectForPaintRejection();
2768
flipForWritingMode(overflowBox);
2769
overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2770
overflowBox.moveBy(adjustedPaintOffset);
2771
if (!overflowBox.intersects(paintInfo.rect))
2775
bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset);
2776
paintObject(paintInfo, adjustedPaintOffset);
2778
popContentsClip(paintInfo, phase, adjustedPaintOffset);
2780
// Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2781
// z-index. We paint after we painted the background/border, so that the scrollbars will
2782
// sit above the background/border.
2783
if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2784
layer()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect);
2787
void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2789
if (paintInfo.context->paintingDisabled())
2792
const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2793
bool ruleTransparent = style()->columnRuleIsTransparent();
2794
EBorderStyle ruleStyle = style()->columnRuleStyle();
2795
LayoutUnit ruleThickness = style()->columnRuleWidth();
2796
LayoutUnit colGap = columnGap();
2797
bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleThickness <= colGap;
2801
ColumnInfo* colInfo = columnInfo();
2802
unsigned colCount = columnCount(colInfo);
2804
bool antialias = shouldAntialiasLines(paintInfo.context);
2806
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
2807
bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
2808
LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
2809
LayoutUnit ruleAdd = logicalLeftOffsetForContent();
2810
LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
2811
LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
2812
BoxSide boxSide = isHorizontalWritingMode()
2813
? leftToRight ? BSLeft : BSRight
2814
: leftToRight ? BSTop : BSBottom;
2816
for (unsigned i = 0; i < colCount; i++) {
2817
// Move to the next position.
2819
ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2820
currLogicalLeftOffset += inlineDirectionSize + colGap;
2822
ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2823
currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2826
// Now paint the column rule.
2827
if (i < colCount - 1) {
2828
LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2829
LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2830
LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2831
LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2832
IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
2833
drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2836
ruleLogicalLeft = currLogicalLeftOffset;
2839
bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
2840
LayoutUnit ruleLeft = isHorizontalWritingMode()
2841
? borderLeft() + paddingLeft()
2842
: colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
2843
LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2844
LayoutUnit ruleTop = isHorizontalWritingMode()
2845
? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
2846
: borderStart() + paddingStart();
2847
LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2848
LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2851
if (isHorizontalWritingMode())
2852
ruleRect.setY(height() - ruleRect.maxY());
2854
ruleRect.setX(width() - ruleRect.maxX());
2857
ruleRect.moveBy(paintOffset);
2859
BoxSide boxSide = isHorizontalWritingMode()
2860
? topToBottom ? BSTop : BSBottom
2861
: topToBottom ? BSLeft : BSRight;
2863
LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2864
if (!isHorizontalWritingMode())
2865
step = step.transposedSize();
2867
for (unsigned i = 1; i < colCount; i++) {
2868
ruleRect.move(step);
2869
IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
2870
drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2875
void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2877
// We need to do multiple passes, breaking up our child painting into strips.
2878
GraphicsContext* context = paintInfo.context;
2879
ColumnInfo* colInfo = columnInfo();
2880
unsigned colCount = columnCount(colInfo);
2883
LayoutUnit currLogicalTopOffset = 0;
2884
LayoutUnit colGap = columnGap();
2885
for (unsigned i = 0; i < colCount; i++) {
2886
// For each rect, we clip to the rect, and then we adjust our coords.
2887
LayoutRect colRect = columnRectAt(colInfo, i);
2888
flipForWritingMode(colRect);
2889
LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2890
LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2891
if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2892
if (isHorizontalWritingMode())
2893
offset.expand(0, colRect.y() - borderTop() - paddingTop());
2895
offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2897
colRect.moveBy(paintOffset);
2898
PaintInfo info(paintInfo);
2899
info.rect.intersect(pixelSnappedIntRect(colRect));
2901
if (!info.rect.isEmpty()) {
2902
GraphicsContextStateSaver stateSaver(*context);
2903
LayoutRect clipRect(colRect);
2905
if (i < colCount - 1) {
2906
if (isHorizontalWritingMode())
2907
clipRect.expand(colGap / 2, 0);
2909
clipRect.expand(0, colGap / 2);
2911
// Each strip pushes a clip, since column boxes are specified as being
2912
// like overflow:hidden.
2913
// FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2914
// are clipped according to the 'overflow' property.
2915
context->clip(pixelSnappedIntRect(clipRect));
2917
// Adjust our x and y when painting.
2918
LayoutPoint adjustedPaintOffset = paintOffset + offset;
2920
paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2922
paintContents(info, adjustedPaintOffset);
2925
LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2926
if (style()->isFlippedBlocksWritingMode())
2927
currLogicalTopOffset += blockDelta;
2929
currLogicalTopOffset -= blockDelta;
2933
void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2935
// Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2936
// It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2937
// will do a full repaint().
2938
if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2941
if (childrenInline())
2942
m_lineBoxes.paint(this, paintInfo, paintOffset);
2944
PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2945
newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2947
// We don't paint our own background, but we do let the kids paint their backgrounds.
2948
PaintInfo paintInfoForChild(paintInfo);
2949
paintInfoForChild.phase = newPhase;
2950
paintInfoForChild.updatePaintingRootForChildren(this);
2952
// FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2953
// NSViews. Do not add any more code for this.
2954
bool usePrintRect = !view()->printRect().isEmpty();
2955
paintChildren(paintInfo, paintOffset, paintInfoForChild, usePrintRect);
2959
void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2961
for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2962
if (!paintChild(child, paintInfo, paintOffset, paintInfoForChild, usePrintRect))
2967
bool RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset, PaintInfo& paintInfoForChild, bool usePrintRect)
2969
// Check for page-break-before: always, and if it's set, break and bail.
2970
bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2971
LayoutUnit absoluteChildY = paintOffset.y() + child->y();
2972
if (checkBeforeAlways
2973
&& absoluteChildY > paintInfo.rect.y()
2974
&& absoluteChildY < paintInfo.rect.maxY()) {
2975
view()->setBestTruncatedAt(absoluteChildY, this, true);
2979
RenderView* renderView = view();
2980
if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2981
// Paginate block-level replaced elements.
2982
if (absoluteChildY + child->height() > renderView->printRect().maxY()) {
2983
if (absoluteChildY < renderView->truncatedAt())
2984
renderView->setBestTruncatedAt(absoluteChildY, child);
2985
// If we were able to truncate, don't paint.
2986
if (absoluteChildY >= renderView->truncatedAt())
2991
LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2992
if (!child->hasSelfPaintingLayer() && !child->isFloating())
2993
child->paint(paintInfoForChild, childPoint);
2995
// Check for page-break-after: always, and if it's set, break and bail.
2996
bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2997
if (checkAfterAlways
2998
&& (absoluteChildY + child->height()) > paintInfo.rect.y()
2999
&& (absoluteChildY + child->height()) < paintInfo.rect.maxY()) {
3000
view()->setBestTruncatedAt(absoluteChildY + child->height() + max<LayoutUnit>(0, child->collapsedMarginAfter()), this, true);
3007
void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
3009
// Paint the caret if the FrameSelection says so or if caret browsing is enabled
3010
bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
3011
RenderObject* caretPainter;
3012
bool isContentEditable;
3013
if (type == CursorCaret) {
3014
caretPainter = frame()->selection()->caretRenderer();
3015
isContentEditable = frame()->selection()->rendererIsEditable();
3017
caretPainter = frame()->page()->dragCaretController()->caretRenderer();
3018
isContentEditable = frame()->page()->dragCaretController()->isContentEditable();
3021
if (caretPainter == this && (isContentEditable || caretBrowsing)) {
3022
if (type == CursorCaret)
3023
frame()->selection()->paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
3025
frame()->page()->dragCaretController()->paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
3029
void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3031
PaintPhase paintPhase = paintInfo.phase;
3033
// 1. paint background, borders etc
3034
if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
3035
if (hasBoxDecorations())
3036
paintBoxDecorations(paintInfo, paintOffset);
3038
paintColumnRules(paintInfo, paintOffset);
3041
if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
3042
paintMask(paintInfo, paintOffset);
3046
// We're done. We don't bother painting any children.
3047
if (paintPhase == PaintPhaseBlockBackground)
3050
// Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
3051
LayoutPoint scrolledOffset = paintOffset;
3052
if (hasOverflowClip())
3053
scrolledOffset.move(-scrolledContentOffset());
3055
// 2. paint contents
3056
if (paintPhase != PaintPhaseSelfOutline) {
3058
paintColumnContents(paintInfo, scrolledOffset);
3060
paintContents(paintInfo, scrolledOffset);
3063
// 3. paint selection
3064
// FIXME: Make this work with multi column layouts. For now don't fill gaps.
3065
bool isPrinting = document()->printing();
3066
if (!isPrinting && !hasColumns())
3067
paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
3070
if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
3072
paintColumnContents(paintInfo, scrolledOffset, true);
3074
paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
3077
// 5. paint outline.
3078
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
3079
paintOutline(paintInfo.context, LayoutRect(paintOffset, size()));
3081
// 6. paint continuation outlines.
3082
if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
3083
RenderInline* inlineCont = inlineElementContinuation();
3084
// FIXME: For now, do not add continuations for outline painting by our containing block if we are a relative positioned
3085
// anonymous block (i.e. have our own layer). This is because a block depends on renderers in its continuation table being
3086
// in the same layer.
3087
if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE && !hasLayer()) {
3088
RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
3089
RenderBlock* cb = containingBlock();
3091
bool inlineEnclosedInSelfPaintingLayer = false;
3092
for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
3093
if (box->hasSelfPaintingLayer()) {
3094
inlineEnclosedInSelfPaintingLayer = true;
3099
if (!inlineEnclosedInSelfPaintingLayer)
3100
cb->addContinuationWithOutline(inlineRenderer);
3101
else if (!inlineRenderer->firstLineBox())
3102
inlineRenderer->paintOutline(paintInfo.context, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
3104
paintContinuationOutlines(paintInfo, paintOffset);
3108
// If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
3109
// then paint the caret.
3110
if (paintPhase == PaintPhaseForeground) {
3111
paintCaret(paintInfo, paintOffset, CursorCaret);
3112
paintCaret(paintInfo, paintOffset, DragCaret);
3116
LayoutPoint RenderBlock::flipFloatForWritingModeForChild(const FloatingObject* child, const LayoutPoint& point) const
3118
if (!style()->isFlippedBlocksWritingMode())
3121
// This is similar to RenderBox::flipForWritingModeForChild. We have to subtract out our left/top offsets twice, since
3122
// it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
3124
if (isHorizontalWritingMode())
3125
return LayoutPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
3126
return LayoutPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
3129
void RenderBlock::paintFloats(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool preservePhase)
3131
if (!m_floatingObjects)
3134
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3135
FloatingObjectSetIterator end = floatingObjectSet.end();
3136
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3137
FloatingObject* r = *it;
3138
// Only paint the object if our m_shouldPaint flag is set.
3139
if (r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()) {
3140
PaintInfo currentPaintInfo(paintInfo);
3141
currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
3142
LayoutPoint childPoint = flipFloatForWritingModeForChild(r, LayoutPoint(paintOffset.x() + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), paintOffset.y() + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
3143
r->m_renderer->paint(currentPaintInfo, childPoint);
3144
if (!preservePhase) {
3145
currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
3146
r->m_renderer->paint(currentPaintInfo, childPoint);
3147
currentPaintInfo.phase = PaintPhaseFloat;
3148
r->m_renderer->paint(currentPaintInfo, childPoint);
3149
currentPaintInfo.phase = PaintPhaseForeground;
3150
r->m_renderer->paint(currentPaintInfo, childPoint);
3151
currentPaintInfo.phase = PaintPhaseOutline;
3152
r->m_renderer->paint(currentPaintInfo, childPoint);
3158
RenderInline* RenderBlock::inlineElementContinuation() const
3160
RenderBoxModelObject* continuation = this->continuation();
3161
return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
3164
RenderBlock* RenderBlock::blockElementContinuation() const
3166
RenderBoxModelObject* currentContinuation = continuation();
3167
if (!currentContinuation || currentContinuation->isInline())
3169
RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
3170
if (nextContinuation->isAnonymousBlock())
3171
return nextContinuation->blockElementContinuation();
3172
return nextContinuation;
3175
static ContinuationOutlineTableMap* continuationOutlineTable()
3177
DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
3181
void RenderBlock::addContinuationWithOutline(RenderInline* flow)
3183
// We can't make this work if the inline is in a layer. We'll just rely on the broken
3185
ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
3187
ContinuationOutlineTableMap* table = continuationOutlineTable();
3188
ListHashSet<RenderInline*>* continuations = table->get(this);
3189
if (!continuations) {
3190
continuations = new ListHashSet<RenderInline*>;
3191
table->set(this, continuations);
3194
continuations->add(flow);
3197
bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
3199
ContinuationOutlineTableMap* table = continuationOutlineTable();
3200
if (table->isEmpty())
3203
ListHashSet<RenderInline*>* continuations = table->get(this);
3207
return continuations->contains(flow);
3210
void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
3212
ContinuationOutlineTableMap* table = continuationOutlineTable();
3213
if (table->isEmpty())
3216
ListHashSet<RenderInline*>* continuations = table->get(this);
3220
LayoutPoint accumulatedPaintOffset = paintOffset;
3221
// Paint each continuation outline.
3222
ListHashSet<RenderInline*>::iterator end = continuations->end();
3223
for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
3224
// Need to add in the coordinates of the intervening blocks.
3225
RenderInline* flow = *it;
3226
RenderBlock* block = flow->containingBlock();
3227
for ( ; block && block != this; block = block->containingBlock())
3228
accumulatedPaintOffset.moveBy(block->location());
3230
flow->paintOutline(info.context, accumulatedPaintOffset);
3234
delete continuations;
3235
table->remove(this);
3238
bool RenderBlock::shouldPaintSelectionGaps() const
3240
return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
3243
bool RenderBlock::isSelectionRoot() const
3248
// FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
3252
if (isBody() || isRoot() || hasOverflowClip()
3253
|| isPositioned() || isFloating()
3254
|| isTableCell() || isInlineBlockOrInlineTable()
3255
|| hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()
3256
|| isRenderFlowThread())
3259
if (view() && view()->selectionStart()) {
3260
Node* startElement = view()->selectionStart()->node();
3261
if (startElement && startElement->rootEditableElement() == node())
3268
GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer)
3270
ASSERT(!needsLayout());
3272
if (!shouldPaintSelectionGaps())
3275
// FIXME: this is broken with transforms
3276
TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
3277
mapLocalToContainer(repaintContainer, transformState);
3278
LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
3280
if (hasOverflowClip())
3281
offsetFromRepaintContainer -= scrolledContentOffset();
3283
LayoutUnit lastTop = 0;
3284
LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
3285
LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
3287
return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
3290
void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
3292
if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
3293
LayoutUnit lastTop = 0;
3294
LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
3295
LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
3296
GraphicsContextStateSaver stateSaver(*paintInfo.context);
3298
LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
3299
if (!gapRectsBounds.isEmpty()) {
3300
if (RenderLayer* layer = enclosingLayer()) {
3301
gapRectsBounds.moveBy(-paintOffset);
3303
LayoutRect localBounds(gapRectsBounds);
3304
flipForWritingMode(localBounds);
3305
gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
3306
if (layer->renderer()->hasOverflowClip())
3307
gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
3309
layer->addBlockSelectionGapsBounds(gapRectsBounds);
3315
static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects)
3317
if (!positionedObjects)
3320
TrackedRendererListHashSet::const_iterator end = positionedObjects->end();
3321
for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
3323
paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
3327
static LayoutUnit blockDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
3329
return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
3332
static LayoutUnit inlineDirectionOffset(RenderBlock* rootBlock, const LayoutSize& offsetFromRootBlock)
3334
return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
3337
LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
3340
if (isHorizontalWritingMode())
3341
result = logicalRect;
3343
result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
3344
flipForWritingMode(result);
3345
result.moveBy(rootBlockPhysicalPosition);
3349
GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3350
LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3352
// IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
3353
// Clip out floating and positioned objects when painting selection gaps.
3355
// Note that we don't clip out overflow for positioned objects. We just stick to the border box.
3356
LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
3357
rootBlock->flipForWritingMode(flippedBlockRect);
3358
flippedBlockRect.moveBy(rootBlockPhysicalPosition);
3359
clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects());
3360
if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
3361
for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
3362
clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes.
3363
if (m_floatingObjects) {
3364
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3365
FloatingObjectSetIterator end = floatingObjectSet.end();
3366
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3367
FloatingObject* r = *it;
3368
LayoutRect floatBox(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
3369
offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
3370
r->m_renderer->width(), r->m_renderer->height());
3371
rootBlock->flipForWritingMode(floatBox);
3372
floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
3373
paintInfo->context->clipOut(pixelSnappedIntRect(floatBox));
3378
// 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
3381
if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
3384
if (hasColumns() || hasTransform() || style()->columnSpan()) {
3385
// FIXME: We should learn how to gap fill multiple columns and transforms eventually.
3386
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3387
lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3388
lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3392
if (childrenInline())
3393
result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3395
result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
3397
// Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
3398
if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
3399
result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3400
logicalHeight(), paintInfo));
3404
GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3405
LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3409
bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
3411
if (!firstLineBox()) {
3412
if (containsStart) {
3413
// Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
3415
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
3416
lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
3417
lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
3422
RootInlineBox* lastSelectedLine = 0;
3423
RootInlineBox* curr;
3424
for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
3426
// Now paint the gaps for the lines.
3427
for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
3428
LayoutUnit selTop = curr->selectionTopAdjustedForPrecedingBlock();
3429
LayoutUnit selHeight = curr->selectionHeightAdjustedForPrecedingBlock();
3431
if (!containsStart && !lastSelectedLine &&
3432
selectionState() != SelectionStart && selectionState() != SelectionBoth)
3433
result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3434
selTop, paintInfo));
3436
LayoutRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
3437
logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : offsetFromRootBlock.transposedSize());
3438
LayoutRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
3439
if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
3440
|| (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
3441
result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
3443
lastSelectedLine = curr;
3446
if (containsStart && !lastSelectedLine)
3447
// VisibleSelection must start just after our last line.
3448
lastSelectedLine = lastRootBox();
3450
if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
3451
// Go ahead and update our lastY to be the bottom of the last selected line.
3452
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
3453
lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3454
lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
3459
GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3460
LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
3464
// Go ahead and jump right to the first block child that contains some selected objects.
3466
for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
3468
for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
3469
SelectionState childState = curr->selectionState();
3470
if (childState == SelectionBoth || childState == SelectionEnd)
3471
sawSelectionEnd = true;
3473
if (curr->isFloatingOrOutOfFlowPositioned())
3474
continue; // We must be a normal flow object in order to even be considered.
3476
if (curr->isInFlowPositioned() && curr->hasLayer()) {
3477
// If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
3478
// Just disregard it completely.
3479
LayoutSize relOffset = curr->layer()->offsetForInFlowPosition();
3480
if (relOffset.width() || relOffset.height())
3484
bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
3485
bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
3486
if (fillBlockGaps) {
3487
// We need to fill the vertical gap above this object.
3488
if (childState == SelectionEnd || childState == SelectionInside)
3489
// Fill the gap above the object.
3490
result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
3491
curr->logicalTop(), paintInfo));
3493
// 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*
3494
// our object. We know this if the selection did not end inside our object.
3495
if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
3496
childState = SelectionNone;
3498
// Fill side gaps on this object based off its state.
3499
bool leftGap, rightGap;
3500
getSelectionGapInfo(childState, leftGap, rightGap);
3503
result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3505
result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
3507
// Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
3508
// they can without bumping into floating or positioned objects. Ideally they will go right up
3509
// to the border of the root selection block.
3510
lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
3511
lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
3512
lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
3513
} else if (childState != SelectionNone)
3514
// We must be a block that has some selected object inside it. Go ahead and recur.
3515
result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
3516
lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
3521
LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3522
LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
3524
LayoutUnit logicalTop = lastLogicalTop;
3525
LayoutUnit logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
3526
if (logicalHeight <= 0)
3527
return LayoutRect();
3529
// Get the selection offsets for the bottom of the gap
3530
LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3531
LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3532
LayoutUnit logicalWidth = logicalRight - logicalLeft;
3533
if (logicalWidth <= 0)
3534
return LayoutRect();
3536
LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3538
paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor(), style()->colorSpace());
3542
LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3543
RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3545
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3546
LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
3547
LayoutUnit rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3548
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3549
if (rootBlockLogicalWidth <= 0)
3550
return LayoutRect();
3552
LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3554
paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3558
LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
3559
RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
3561
LayoutUnit rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3562
LayoutUnit rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3563
LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
3564
LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3565
if (rootBlockLogicalWidth <= 0)
3566
return LayoutRect();
3568
LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3570
paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3574
void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3576
bool ltr = style()->isLeftToRightDirection();
3577
leftGap = (state == RenderObject::SelectionInside) ||
3578
(state == RenderObject::SelectionEnd && ltr) ||
3579
(state == RenderObject::SelectionStart && !ltr);
3580
rightGap = (state == RenderObject::SelectionInside) ||
3581
(state == RenderObject::SelectionStart && ltr) ||
3582
(state == RenderObject::SelectionEnd && !ltr);
3585
LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3587
LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
3588
if (logicalLeft == logicalLeftOffsetForContent()) {
3589
if (rootBlock != this)
3590
// The border can potentially be further extended by our containingBlock().
3591
return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3594
RenderBlock* cb = this;
3595
while (cb != rootBlock) {
3596
logicalLeft += cb->logicalLeft();
3597
cb = cb->containingBlock();
3603
LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
3605
LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
3606
if (logicalRight == logicalRightOffsetForContent()) {
3607
if (rootBlock != this)
3608
// The border can potentially be further extended by our containingBlock().
3609
return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3610
return logicalRight;
3612
RenderBlock* cb = this;
3613
while (cb != rootBlock) {
3614
logicalRight += cb->logicalLeft();
3615
cb = cb->containingBlock();
3618
return logicalRight;
3621
RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
3623
if (isSelectionRoot())
3626
const RenderObject* object = this;
3627
RenderObject* sibling;
3629
sibling = object->previousSibling();
3630
while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
3631
sibling = sibling->previousSibling();
3633
offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
3634
object = object->parent();
3635
} while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
3640
RenderBlock* beforeBlock = toRenderBlock(sibling);
3642
offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3644
RenderObject* child = beforeBlock->lastChild();
3645
while (child && child->isRenderBlock()) {
3646
beforeBlock = toRenderBlock(child);
3647
offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
3648
child = beforeBlock->lastChild();
3653
void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
3655
if (!descendantsMap) {
3656
descendantsMap = new TrackedDescendantsMap;
3657
containerMap = new TrackedContainerMap;
3660
TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
3661
if (!descendantSet) {
3662
descendantSet = new TrackedRendererListHashSet;
3663
descendantsMap->set(this, descendantSet);
3665
bool added = descendantSet->add(descendant).isNewEntry;
3667
ASSERT(containerMap->get(descendant));
3668
ASSERT(containerMap->get(descendant)->contains(this));
3672
HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
3673
if (!containerSet) {
3674
containerSet = new HashSet<RenderBlock*>;
3675
containerMap->set(descendant, containerSet);
3677
ASSERT(!containerSet->contains(this));
3678
containerSet->add(this);
3681
void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
3683
if (!descendantsMap)
3686
HashSet<RenderBlock*>* containerSet = containerMap->take(descendant);
3690
HashSet<RenderBlock*>::iterator end = containerSet->end();
3691
for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3692
RenderBlock* container = *it;
3694
// FIXME: Disabling this assert temporarily until we fix the layout
3695
// bugs associated with positioned objects not properly cleared from
3696
// their ancestor chain before being moved. See webkit bug 93766.
3697
// ASSERT(descendant->isDescendantOf(container));
3699
TrackedRendererListHashSet* descendantSet = descendantsMap->get(container);
3700
ASSERT(descendantSet);
3703
ASSERT(descendantSet->contains(descendant));
3704
descendantSet->remove(descendant);
3705
if (descendantSet->isEmpty()) {
3706
descendantsMap->remove(container);
3707
delete descendantSet;
3711
delete containerSet;
3714
TrackedRendererListHashSet* RenderBlock::positionedObjects() const
3716
if (gPositionedDescendantsMap)
3717
return gPositionedDescendantsMap->get(this);
3721
void RenderBlock::insertPositionedObject(RenderBox* o)
3723
ASSERT(!isAnonymousBlock());
3725
if (o->isRenderFlowThread())
3728
insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
3731
void RenderBlock::removePositionedObject(RenderBox* o)
3733
removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
3736
void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState)
3738
TrackedRendererListHashSet* positionedDescendants = positionedObjects();
3739
if (!positionedDescendants)
3744
TrackedRendererListHashSet::iterator end = positionedDescendants->end();
3746
Vector<RenderBox*, 16> deadObjects;
3748
for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
3750
if (!o || r->isDescendantOf(o)) {
3751
if (containingBlockState == NewContainingBlock)
3752
r->setChildNeedsLayout(true, MarkOnlyThis);
3754
// It is parent blocks job to add positioned child to positioned objects list of its containing block
3755
// Parent layout needs to be invalidated to ensure this happens.
3756
RenderObject* p = r->parent();
3757
while (p && !p->isRenderBlock())
3760
p->setChildNeedsLayout(true);
3762
deadObjects.append(r);
3766
for (unsigned i = 0; i < deadObjects.size(); i++)
3767
removePositionedObject(deadObjects.at(i));
3770
void RenderBlock::removeFloatingObjects()
3772
if (!m_floatingObjects)
3775
deleteAllValues(m_floatingObjects->set());
3776
m_floatingObjects->clear();
3779
RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3781
ASSERT(o->isFloating());
3783
// Create the list of special objects if we don't aleady have one
3784
if (!m_floatingObjects)
3785
m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
3787
// Don't insert the object again if it's already in the list
3788
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3789
FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3790
if (it != floatingObjectSet.end())
3794
// Create the special object entry & append it to the list
3796
FloatingObject* newObj = new FloatingObject(o->style()->floating());
3798
// Our location is irrelevant if we're unsplittable or no pagination is in effect.
3799
// Just go ahead and lay out the float.
3800
bool isChildRenderBlock = o->isRenderBlock();
3801
if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
3802
o->setChildNeedsLayout(true, MarkOnlyThis);
3804
bool needsBlockDirectionLocationSetBeforeLayout = isChildRenderBlock && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
3805
if (!needsBlockDirectionLocationSetBeforeLayout || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3806
o->layoutIfNeeded();
3808
o->updateLogicalWidth();
3809
o->computeAndSetBlockDirectionMargins(this);
3811
setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
3813
newObj->setShouldPaint(!o->hasSelfPaintingLayer()); // If a layer exists, the float will paint itself. Otherwise someone else will.
3814
newObj->setIsDescendant(true);
3815
newObj->m_renderer = o;
3817
m_floatingObjects->add(newObj);
3822
void RenderBlock::removeFloatingObject(RenderBox* o)
3824
if (m_floatingObjects) {
3825
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3826
FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3827
if (it != floatingObjectSet.end()) {
3828
FloatingObject* r = *it;
3829
if (childrenInline()) {
3830
LayoutUnit logicalTop = logicalTopForFloat(r);
3831
LayoutUnit logicalBottom = logicalBottomForFloat(r);
3833
// Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3834
if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == LayoutUnit::max())
3835
logicalBottom = LayoutUnit::max();
3837
// Special-case zero- and less-than-zero-height floats: those don't touch
3838
// the line that they're on, but it still needs to be dirtied. This is
3839
// accomplished by pretending they have a height of 1.
3840
logicalBottom = max(logicalBottom, logicalTop + 1);
3842
if (r->m_originatingLine) {
3843
if (!selfNeedsLayout()) {
3844
ASSERT(r->m_originatingLine->renderer() == this);
3845
r->m_originatingLine->markDirty();
3847
#if !ASSERT_DISABLED
3848
r->m_originatingLine = 0;
3851
markLinesDirtyInBlockRange(0, logicalBottom);
3853
m_floatingObjects->remove(r);
3854
ASSERT(!r->m_originatingLine);
3860
void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3862
if (!m_floatingObjects)
3865
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3866
FloatingObject* curr = floatingObjectSet.last();
3867
while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
3868
m_floatingObjects->remove(curr);
3869
ASSERT(!curr->m_originatingLine);
3871
if (floatingObjectSet.isEmpty())
3873
curr = floatingObjectSet.last();
3877
LayoutPoint RenderBlock::computeLogicalLocationForFloat(const FloatingObject* floatingObject, LayoutUnit logicalTopOffset) const
3879
RenderBox* childBox = floatingObject->renderer();
3880
LayoutUnit logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3881
LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3882
LayoutUnit floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset); // The width we look for.
3884
LayoutUnit floatLogicalLeft;
3886
if (childBox->style()->floating() == LeftFloat) {
3887
LayoutUnit heightRemainingLeft = 1;
3888
LayoutUnit heightRemainingRight = 1;
3889
floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3890
// FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
3891
while (logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight) - floatLogicalLeft + LayoutUnit::epsilon() < floatLogicalWidth) {
3892
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3893
floatLogicalLeft = logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft);
3894
if (inRenderFlowThread()) {
3895
// Have to re-evaluate all of our offsets, since they may have changed.
3896
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3897
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3898
floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3901
floatLogicalLeft = max(logicalLeftOffset - borderAndPaddingLogicalLeft(), floatLogicalLeft);
3903
LayoutUnit heightRemainingLeft = 1;
3904
LayoutUnit heightRemainingRight = 1;
3905
floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3906
// FIXME: LayoutUnit::epsilon is probably only necessary here due to lost precision elsewhere https://bugs.webkit.org/show_bug.cgi?id=94000
3907
while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTopOffset, logicalLeftOffset, false, &heightRemainingLeft) + LayoutUnit::epsilon() < floatLogicalWidth) {
3908
logicalTopOffset += min(heightRemainingLeft, heightRemainingRight);
3909
floatLogicalLeft = logicalRightOffsetForLine(logicalTopOffset, logicalRightOffset, false, &heightRemainingRight);
3910
if (inRenderFlowThread()) {
3911
// Have to re-evaluate all of our offsets, since they may have changed.
3912
logicalRightOffset = logicalRightOffsetForContent(logicalTopOffset); // Constant part of right offset.
3913
logicalLeftOffset = logicalLeftOffsetForContent(logicalTopOffset); // Constant part of left offset.
3914
floatLogicalWidth = min(logicalWidthForFloat(floatingObject), logicalRightOffset - logicalLeftOffset);
3917
floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
3918
// |floatLogicalWidth| was capped to the available line width.
3919
// See fast/block/float/clamped-right-float.html.
3922
return LayoutPoint(floatLogicalLeft, logicalTopOffset);
3925
bool RenderBlock::positionNewFloats()
3927
if (!m_floatingObjects)
3930
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3931
if (floatingObjectSet.isEmpty())
3934
// If all floats have already been positioned, then we have no work to do.
3935
if (floatingObjectSet.last()->isPlaced())
3938
// Move backwards through our floating object list until we find a float that has
3939
// already been positioned. Then we'll be able to move forward, positioning all of
3940
// the new floats that need it.
3941
FloatingObjectSetIterator it = floatingObjectSet.end();
3942
--it; // Go to last item.
3943
FloatingObjectSetIterator begin = floatingObjectSet.begin();
3944
FloatingObject* lastPlacedFloatingObject = 0;
3945
while (it != begin) {
3947
if ((*it)->isPlaced()) {
3948
lastPlacedFloatingObject = *it;
3954
LayoutUnit logicalTop = logicalHeight();
3956
// The float cannot start above the top position of the last positioned float.
3957
if (lastPlacedFloatingObject)
3958
logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
3960
FloatingObjectSetIterator end = floatingObjectSet.end();
3961
// Now walk through the set of unpositioned floats and place them.
3962
for (; it != end; ++it) {
3963
FloatingObject* floatingObject = *it;
3964
// The containing block is responsible for positioning floats, so if we have floats in our
3965
// list that come from somewhere else, do not attempt to position them.
3966
if (floatingObject->renderer()->containingBlock() != this)
3969
RenderBox* childBox = floatingObject->renderer();
3970
LayoutUnit childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3972
LayoutRect oldRect = childBox->frameRect();
3974
if (childBox->style()->clear() & CLEFT)
3975
logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3976
if (childBox->style()->clear() & CRIGHT)
3977
logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3979
LayoutPoint floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, logicalTop);
3981
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
3982
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
3983
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
3985
LayoutState* layoutState = view()->layoutState();
3986
bool isPaginated = layoutState->isPaginated();
3987
if (isPaginated && !childBox->needsLayout())
3988
childBox->markForPaginationRelayoutIfNeeded();
3990
childBox->layoutIfNeeded();
3993
// If we are unsplittable and don't fit, then we need to move down.
3994
// We include our margins as part of the unsplittable area.
3995
LayoutUnit newLogicalTop = adjustForUnsplittableChild(childBox, floatLogicalLocation.y(), true);
3997
// See if we have a pagination strut that is making us move down further.
3998
// Note that an unsplittable child can't also have a pagination strut, so this is
3999
// exclusive with the case above.
4000
RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
4001
if (childBlock && childBlock->paginationStrut()) {
4002
newLogicalTop += childBlock->paginationStrut();
4003
childBlock->setPaginationStrut(0);
4006
if (newLogicalTop != floatLogicalLocation.y()) {
4007
floatingObject->m_paginationStrut = newLogicalTop - floatLogicalLocation.y();
4009
floatLogicalLocation = computeLogicalLocationForFloat(floatingObject, newLogicalTop);
4010
setLogicalLeftForFloat(floatingObject, floatLogicalLocation.x());
4011
setLogicalLeftForChild(childBox, floatLogicalLocation.x() + childLogicalLeftMargin);
4012
setLogicalTopForChild(childBox, floatLogicalLocation.y() + marginBeforeForChild(childBox));
4015
childBlock->setChildNeedsLayout(true, MarkOnlyThis);
4016
childBox->layoutIfNeeded();
4020
setLogicalTopForFloat(floatingObject, floatLogicalLocation.y());
4021
setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
4023
m_floatingObjects->addPlacedObject(floatingObject);
4025
// If the child moved, we have to repaint it.
4026
if (childBox->checkForRepaintDuringLayout())
4027
childBox->repaintDuringLayoutIfMoved(oldRect);
4032
void RenderBlock::newLine(EClear clear)
4034
positionNewFloats();
4036
LayoutUnit newY = 0;
4040
newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
4043
newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
4046
newY = lowestFloatLogicalBottom();
4050
if (height() < newY)
4051
setLogicalHeight(newY);
4054
void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
4056
insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
4059
void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
4061
removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
4064
TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const
4066
return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
4069
bool RenderBlock::hasPercentHeightContainerMap()
4071
return gPercentHeightContainerMap;
4074
bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
4076
// We don't null check gPercentHeightContainerMap since the caller
4077
// already ensures this and we need to call this function on every
4078
// descendant in clearPercentHeightDescendantsFrom().
4079
ASSERT(gPercentHeightContainerMap);
4080
return gPercentHeightContainerMap->contains(descendant);
4083
void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
4085
// We query the map directly, rather than looking at style's
4086
// logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
4087
// can change with writing mode/directional changes.
4088
if (!hasPercentHeightContainerMap())
4091
if (!hasPercentHeightDescendant(descendant))
4094
removePercentHeightDescendant(descendant);
4097
void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
4099
ASSERT(gPercentHeightContainerMap);
4100
for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
4104
RenderBox* box = toRenderBox(curr);
4105
if (!hasPercentHeightDescendant(box))
4108
removePercentHeightDescendant(box);
4112
static bool rangesIntersect(int floatTop, int floatBottom, int objectTop, int objectBottom)
4114
if (objectTop >= floatBottom || objectBottom < floatTop)
4117
// The top of the object overlaps the float
4118
if (objectTop >= floatTop)
4121
// The object encloses the float
4122
if (objectTop < floatTop && objectBottom > floatBottom)
4125
// The bottom of the object overlaps the float
4126
if (objectBottom > objectTop && objectBottom > floatTop && objectBottom <= floatBottom)
4132
template <RenderBlock::FloatingObject::Type FloatTypeValue>
4133
inline void RenderBlock::FloatIntervalSearchAdapter<FloatTypeValue>::collectIfNeeded(const IntervalType& interval) const
4135
const FloatingObject* r = interval.data();
4136
if (r->type() != FloatTypeValue || !rangesIntersect(interval.low(), interval.high(), m_lowValue, m_highValue))
4139
// All the objects returned from the tree should be already placed.
4140
ASSERT(r->isPlaced() && rangesIntersect(m_renderer->pixelSnappedLogicalTopForFloat(r), m_renderer->pixelSnappedLogicalBottomForFloat(r), m_lowValue, m_highValue));
4142
if (FloatTypeValue == FloatingObject::FloatLeft
4143
&& m_renderer->logicalRightForFloat(r) > m_offset) {
4144
m_offset = m_renderer->logicalRightForFloat(r);
4145
if (m_heightRemaining)
4146
*m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
4149
if (FloatTypeValue == FloatingObject::FloatRight
4150
&& m_renderer->logicalLeftForFloat(r) < m_offset) {
4151
m_offset = m_renderer->logicalLeftForFloat(r);
4152
if (m_heightRemaining)
4153
*m_heightRemaining = m_renderer->logicalBottomForFloat(r) - m_lowValue;
4157
LayoutUnit RenderBlock::textIndentOffset() const
4160
RenderView* renderView = 0;
4161
if (style()->textIndent().isPercent())
4162
cw = containingBlock()->availableLogicalWidth();
4163
else if (style()->textIndent().isViewportPercentage())
4164
renderView = view();
4165
return minimumValueForLength(style()->textIndent(), cw, renderView);
4168
LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
4170
LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
4171
if (!inRenderFlowThread())
4172
return logicalLeftOffset;
4173
LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
4174
return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
4177
LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region, LayoutUnit offsetFromLogicalTopOfFirstPage) const
4179
LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
4180
logicalRightOffset += availableLogicalWidth();
4181
if (!inRenderFlowThread())
4182
return logicalRightOffset;
4183
LayoutRect boxRect = borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage);
4184
return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
4187
LayoutUnit RenderBlock::logicalLeftOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
4189
LayoutUnit left = fixedOffset;
4190
if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
4191
if (heightRemaining)
4192
*heightRemaining = 1;
4194
FloatIntervalSearchAdapter<FloatingObject::FloatLeft> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), left, heightRemaining);
4195
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
4198
if (applyTextIndent && style()->isLeftToRightDirection())
4199
left += textIndentOffset();
4201
if (style()->lineAlign() == LineAlignNone)
4204
// Push in our left offset so that it is aligned with the character grid.
4205
LayoutState* layoutState = view()->layoutState();
4209
RenderBlock* lineGrid = layoutState->lineGrid();
4210
if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
4213
// FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
4214
float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
4218
LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
4219
LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
4221
// Push in to the nearest character width (truncated so that we pixel snap left).
4222
// FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
4223
// any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
4224
// FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
4225
// FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
4226
// FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
4227
// FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
4228
// (https://bugs.webkit.org/show_bug.cgi?id=79944)
4229
float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
4234
LayoutUnit RenderBlock::logicalRightOffsetForLine(LayoutUnit logicalTop, LayoutUnit fixedOffset, bool applyTextIndent, LayoutUnit* heightRemaining, LayoutUnit logicalHeight) const
4236
LayoutUnit right = fixedOffset;
4237
if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
4238
if (heightRemaining)
4239
*heightRemaining = 1;
4241
LayoutUnit rightFloatOffset = fixedOffset;
4242
FloatIntervalSearchAdapter<FloatingObject::FloatRight> adapter(this, roundToInt(logicalTop), roundToInt(logicalTop + logicalHeight), rightFloatOffset, heightRemaining);
4243
m_floatingObjects->placedFloatsTree().allOverlapsWithAdapter(adapter);
4244
right = min(right, rightFloatOffset);
4247
if (applyTextIndent && !style()->isLeftToRightDirection())
4248
right -= textIndentOffset();
4250
if (style()->lineAlign() == LineAlignNone)
4253
// Push in our right offset so that it is aligned with the character grid.
4254
LayoutState* layoutState = view()->layoutState();
4258
RenderBlock* lineGrid = layoutState->lineGrid();
4259
if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
4262
// FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
4263
float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
4267
LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
4268
LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
4270
// Push in to the nearest character width (truncated so that we pixel snap right).
4271
// FIXME: Should be patched when subpixel layout lands, since this calculation doesn't have to pixel snap
4272
// any more (https://bugs.webkit.org/show_bug.cgi?id=79946).
4273
// FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
4274
// FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
4275
// FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
4276
// FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
4277
// (https://bugs.webkit.org/show_bug.cgi?id=79944)
4278
float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
4279
right -= ceilf(remainder);
4283
LayoutUnit RenderBlock::nextFloatLogicalBottomBelow(LayoutUnit logicalHeight) const
4285
if (!m_floatingObjects)
4286
return logicalHeight;
4288
LayoutUnit bottom = LayoutUnit::max();
4289
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4290
FloatingObjectSetIterator end = floatingObjectSet.end();
4291
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4292
FloatingObject* r = *it;
4293
LayoutUnit floatBottom = logicalBottomForFloat(r);
4294
if (floatBottom > logicalHeight)
4295
bottom = min(floatBottom, bottom);
4298
return bottom == LayoutUnit::max() ? LayoutUnit() : bottom;
4301
LayoutUnit RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
4303
if (!m_floatingObjects)
4305
LayoutUnit lowestFloatBottom = 0;
4306
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4307
FloatingObjectSetIterator end = floatingObjectSet.end();
4308
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4309
FloatingObject* r = *it;
4310
if (r->isPlaced() && r->type() & floatType)
4311
lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
4313
return lowestFloatBottom;
4316
void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
4318
if (logicalTop >= logicalBottom)
4321
RootInlineBox* lowestDirtyLine = lastRootBox();
4322
RootInlineBox* afterLowest = lowestDirtyLine;
4323
while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
4324
afterLowest = lowestDirtyLine;
4325
lowestDirtyLine = lowestDirtyLine->prevRootBox();
4328
while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
4329
afterLowest->markDirty();
4330
afterLowest = afterLowest->prevRootBox();
4334
void RenderBlock::clearFloats()
4336
if (m_floatingObjects)
4337
m_floatingObjects->setHorizontalWritingMode(isHorizontalWritingMode());
4339
HashSet<RenderBox*> oldIntrudingFloatSet;
4340
if (!childrenInline() && m_floatingObjects) {
4341
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4342
FloatingObjectSetIterator end = floatingObjectSet.end();
4343
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4344
FloatingObject* floatingObject = *it;
4345
if (!floatingObject->isDescendant())
4346
oldIntrudingFloatSet.add(floatingObject->m_renderer);
4350
// Inline blocks are covered by the isReplaced() check in the avoidFloats method.
4351
if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrOutOfFlowPositioned() || isTableCell()) {
4352
if (m_floatingObjects) {
4353
deleteAllValues(m_floatingObjects->set());
4354
m_floatingObjects->clear();
4356
if (!oldIntrudingFloatSet.isEmpty())
4357
markAllDescendantsWithFloatsForLayout();
4361
typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
4362
RendererToFloatInfoMap floatMap;
4364
if (m_floatingObjects) {
4365
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4366
if (childrenInline()) {
4367
FloatingObjectSetIterator end = floatingObjectSet.end();
4368
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4369
FloatingObject* f = *it;
4370
floatMap.add(f->m_renderer, f);
4373
deleteAllValues(floatingObjectSet);
4374
m_floatingObjects->clear();
4377
// We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
4378
// floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
4379
// See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
4380
if (!parent() || !parent()->isRenderBlock())
4383
// Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
4384
// out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
4386
RenderBlock* parentBlock = toRenderBlock(parent());
4387
bool parentHasFloats = false;
4388
RenderObject* prev = previousSibling();
4389
while (prev && (prev->isFloatingOrOutOfFlowPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
4390
if (prev->isFloating())
4391
parentHasFloats = true;
4392
prev = prev->previousSibling();
4395
// First add in floats from the parent.
4396
LayoutUnit logicalTopOffset = logicalTop();
4397
if (parentHasFloats)
4398
addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
4400
LayoutUnit logicalLeftOffset = 0;
4402
logicalTopOffset -= toRenderBox(prev)->logicalTop();
4405
logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
4408
// Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
4409
RenderBlock* block = toRenderBlock(prev);
4410
if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
4411
addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
4413
if (childrenInline()) {
4414
LayoutUnit changeLogicalTop = LayoutUnit::max();
4415
LayoutUnit changeLogicalBottom = LayoutUnit::min();
4416
if (m_floatingObjects) {
4417
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4418
FloatingObjectSetIterator end = floatingObjectSet.end();
4419
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4420
FloatingObject* f = *it;
4421
FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
4422
LayoutUnit logicalBottom = logicalBottomForFloat(f);
4423
if (oldFloatingObject) {
4424
LayoutUnit oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
4425
if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
4426
changeLogicalTop = 0;
4427
changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
4429
if (logicalBottom != oldLogicalBottom) {
4430
changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
4431
changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
4433
LayoutUnit logicalTop = logicalTopForFloat(f);
4434
LayoutUnit oldLogicalTop = logicalTopForFloat(oldFloatingObject);
4435
if (logicalTop != oldLogicalTop) {
4436
changeLogicalTop = min(changeLogicalTop, min(logicalTop, oldLogicalTop));
4437
changeLogicalBottom = max(changeLogicalBottom, max(logicalTop, oldLogicalTop));
4441
floatMap.remove(f->m_renderer);
4442
if (oldFloatingObject->m_originatingLine && !selfNeedsLayout()) {
4443
ASSERT(oldFloatingObject->m_originatingLine->renderer() == this);
4444
oldFloatingObject->m_originatingLine->markDirty();
4446
delete oldFloatingObject;
4448
changeLogicalTop = 0;
4449
changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
4454
RendererToFloatInfoMap::iterator end = floatMap.end();
4455
for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
4456
FloatingObject* floatingObject = (*it).value;
4457
if (!floatingObject->isDescendant()) {
4458
changeLogicalTop = 0;
4459
changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
4462
deleteAllValues(floatMap);
4464
markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
4465
} else if (!oldIntrudingFloatSet.isEmpty()) {
4466
// If there are previously intruding floats that no longer intrude, then children with floats
4467
// should also get layout because they might need their floating object lists cleared.
4468
if (m_floatingObjects->set().size() < oldIntrudingFloatSet.size())
4469
markAllDescendantsWithFloatsForLayout();
4471
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4472
FloatingObjectSetIterator end = floatingObjectSet.end();
4473
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end && !oldIntrudingFloatSet.isEmpty(); ++it)
4474
oldIntrudingFloatSet.remove((*it)->m_renderer);
4475
if (!oldIntrudingFloatSet.isEmpty())
4476
markAllDescendantsWithFloatsForLayout();
4481
LayoutUnit RenderBlock::addOverhangingFloats(RenderBlock* child, bool makeChildPaintOtherFloats)
4483
// Prevent floats from being added to the canvas by the root element, e.g., <html>.
4484
if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
4487
LayoutUnit childLogicalTop = child->logicalTop();
4488
LayoutUnit childLogicalLeft = child->logicalLeft();
4489
LayoutUnit lowestFloatLogicalBottom = 0;
4491
// Floats that will remain the child's responsibility to paint should factor into its
4493
FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end();
4494
for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
4495
FloatingObject* r = *childIt;
4496
LayoutUnit logicalBottomForFloat = min(this->logicalBottomForFloat(r), LayoutUnit::max() - childLogicalTop);
4497
LayoutUnit logicalBottom = childLogicalTop + logicalBottomForFloat;
4498
lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
4500
if (logicalBottom > logicalHeight()) {
4501
// If the object is not in the list, we add it now.
4502
if (!containsFloat(r->m_renderer)) {
4503
LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(-childLogicalLeft, -childLogicalTop) : LayoutSize(-childLogicalTop, -childLogicalLeft);
4504
FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size()));
4505
floatingObj->m_renderer = r->m_renderer;
4507
// The nearest enclosing layer always paints the float (so that zindex and stacking
4508
// behaves properly). We always want to propagate the desire to paint the float as
4509
// far out as we can, to the outermost block that overlaps the float, stopping only
4510
// if we hit a self-painting layer boundary.
4511
if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer())
4512
r->setShouldPaint(false);
4514
floatingObj->setShouldPaint(false);
4516
floatingObj->setIsDescendant(true);
4518
// We create the floating object list lazily.
4519
if (!m_floatingObjects)
4520
m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
4522
m_floatingObjects->add(floatingObj);
4525
if (makeChildPaintOtherFloats && !r->shouldPaint() && !r->m_renderer->hasSelfPaintingLayer()
4526
&& r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
4527
// The float is not overhanging from this block, so if it is a descendant of the child, the child should
4528
// paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
4530
// If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
4532
r->setShouldPaint(true);
4535
// 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
4537
if (r->isDescendant())
4538
child->addOverflowFromChild(r->m_renderer, LayoutSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
4541
return lowestFloatLogicalBottom;
4544
bool RenderBlock::hasOverhangingFloat(RenderBox* renderer)
4546
if (!m_floatingObjects || hasColumns() || !parent())
4549
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4550
FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer);
4551
if (it == floatingObjectSet.end())
4554
return logicalBottomForFloat(*it) > logicalHeight();
4557
void RenderBlock::addIntrudingFloats(RenderBlock* prev, LayoutUnit logicalLeftOffset, LayoutUnit logicalTopOffset)
4559
ASSERT(!avoidsFloats());
4561
// If the parent or previous sibling doesn't have any floats to add, don't bother.
4562
if (!prev->m_floatingObjects)
4565
logicalLeftOffset += marginLogicalLeft();
4567
const FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
4568
FloatingObjectSetIterator prevEnd = prevSet.end();
4569
for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
4570
FloatingObject* r = *prevIt;
4571
if (logicalBottomForFloat(r) > logicalTopOffset) {
4572
if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) {
4573
LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, logicalTopOffset) : LayoutSize(logicalTopOffset, logicalLeftOffset);
4574
FloatingObject* floatingObj = new FloatingObject(r->type(), LayoutRect(r->frameRect().location() - offset, r->frameRect().size()));
4576
// Applying the child's margin makes no sense in the case where the child was passed in.
4577
// since this margin was added already through the modification of the |logicalLeftOffset| variable
4578
// above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
4579
// into account. Only apply this code if prev is the parent, since otherwise the left margin
4580
// will get applied twice.
4581
if (prev != parent()) {
4582
if (isHorizontalWritingMode())
4583
floatingObj->setX(floatingObj->x() + prev->marginLeft());
4585
floatingObj->setY(floatingObj->y() + prev->marginTop());
4588
floatingObj->setShouldPaint(false); // We are not in the direct inheritance chain for this float. We will never paint it.
4589
floatingObj->m_renderer = r->m_renderer;
4591
// We create the floating object list lazily.
4592
if (!m_floatingObjects)
4593
m_floatingObjects = adoptPtr(new FloatingObjects(this, isHorizontalWritingMode()));
4594
m_floatingObjects->add(floatingObj);
4600
bool RenderBlock::avoidsFloats() const
4602
// Floats can't intrude into our box if we have a non-auto column count or width.
4603
return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
4606
bool RenderBlock::containsFloat(RenderBox* renderer) const
4608
return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer);
4611
void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
4613
if (!everHadLayout())
4616
MarkingBehavior markParents = inLayout ? MarkOnlyThis : MarkContainingBlockChain;
4617
setChildNeedsLayout(true, markParents);
4620
removeFloatingObject(floatToRemove);
4622
// Iterate over our children and mark them as needed.
4623
if (!childrenInline()) {
4624
for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4625
if ((!floatToRemove && child->isFloatingOrOutOfFlowPositioned()) || !child->isRenderBlock())
4627
RenderBlock* childBlock = toRenderBlock(child);
4628
if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
4629
childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
4634
void RenderBlock::markSiblingsWithFloatsForLayout(RenderBox* floatToRemove)
4636
if (!m_floatingObjects)
4639
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4640
FloatingObjectSetIterator end = floatingObjectSet.end();
4642
for (RenderObject* next = nextSibling(); next; next = next->nextSibling()) {
4643
if (!next->isRenderBlock() || next->isFloatingOrOutOfFlowPositioned() || toRenderBlock(next)->avoidsFloats())
4646
RenderBlock* nextBlock = toRenderBlock(next);
4647
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
4648
RenderBox* floatingBox = (*it)->renderer();
4649
if (floatToRemove && floatingBox != floatToRemove)
4651
if (nextBlock->containsFloat(floatingBox))
4652
nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox);
4657
LayoutUnit RenderBlock::getClearDelta(RenderBox* child, LayoutUnit logicalTop)
4659
// There is no need to compute clearance if we have no floats.
4660
if (!containsFloats())
4663
// At least one float is present. We need to perform the clearance computation.
4664
bool clearSet = child->style()->clear() != CNONE;
4665
LayoutUnit logicalBottom = 0;
4666
switch (child->style()->clear()) {
4670
logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
4673
logicalBottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
4676
logicalBottom = lowestFloatLogicalBottom();
4680
// 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).
4681
LayoutUnit result = clearSet ? max<LayoutUnit>(0, logicalBottom - logicalTop) : LayoutUnit();
4682
if (!result && child->avoidsFloats()) {
4683
LayoutUnit newLogicalTop = logicalTop;
4685
LayoutUnit availableLogicalWidthAtNewLogicalTopOffset = availableLogicalWidthForLine(newLogicalTop, false, logicalHeightForChild(child));
4686
if (availableLogicalWidthAtNewLogicalTopOffset == availableLogicalWidthForContent(newLogicalTop))
4687
return newLogicalTop - logicalTop;
4689
RenderRegion* region = regionAtBlockOffset(logicalTopForChild(child));
4690
LayoutRect borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
4691
LayoutUnit childLogicalWidthAtOldLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
4693
// FIXME: None of this is right for perpendicular writing-mode children.
4694
LayoutUnit childOldLogicalWidth = child->logicalWidth();
4695
LayoutUnit childOldMarginLeft = child->marginLeft();
4696
LayoutUnit childOldMarginRight = child->marginRight();
4697
LayoutUnit childOldLogicalTop = child->logicalTop();
4699
child->setLogicalTop(newLogicalTop);
4700
child->updateLogicalWidth();
4701
region = regionAtBlockOffset(logicalTopForChild(child));
4702
borderBox = child->borderBoxRectInRegion(region, offsetFromLogicalTopOfFirstPage() + logicalTopForChild(child), DoNotCacheRenderBoxRegionInfo);
4703
LayoutUnit childLogicalWidthAtNewLogicalTopOffset = isHorizontalWritingMode() ? borderBox.width() : borderBox.height();
4705
child->setLogicalTop(childOldLogicalTop);
4706
child->setLogicalWidth(childOldLogicalWidth);
4707
child->setMarginLeft(childOldMarginLeft);
4708
child->setMarginRight(childOldMarginRight);
4710
if (childLogicalWidthAtNewLogicalTopOffset <= availableLogicalWidthAtNewLogicalTopOffset) {
4711
// Even though we may not be moving, if the logical width did shrink because of the presence of new floats, then
4712
// we need to force a relayout as though we shifted. This happens because of the dynamic addition of overhanging floats
4713
// from previous siblings when negative margins exist on a child (see the addOverhangingFloats call at the end of collapseMargins).
4714
if (childLogicalWidthAtOldLogicalTopOffset != childLogicalWidthAtNewLogicalTopOffset)
4715
child->setChildNeedsLayout(true, MarkOnlyThis);
4716
return newLogicalTop - logicalTop;
4719
newLogicalTop = nextFloatLogicalBottomBelow(newLogicalTop);
4720
ASSERT(newLogicalTop >= logicalTop);
4721
if (newLogicalTop < logicalTop)
4724
ASSERT_NOT_REACHED();
4729
bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
4731
if (!scrollsOverflow())
4734
return layer()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset)));
4737
Node* RenderBlock::nodeForHitTest() const
4739
// If we are in the margins of block elements that are part of a
4740
// continuation we're actually still inside the enclosing element
4741
// that was split. Use the appropriate inner node.
4742
return isAnonymousBlockContinuation() ? continuation()->node() : node();
4745
bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4747
LayoutPoint adjustedLocation(accumulatedOffset + location());
4748
LayoutSize localOffset = toLayoutSize(adjustedLocation);
4750
if (!isRenderView()) {
4751
// Check if we need to do anything at all.
4752
LayoutRect overflowBox = visualOverflowRect();
4753
flipForWritingMode(overflowBox);
4754
overflowBox.moveBy(adjustedLocation);
4755
if (!locationInContainer.intersects(overflowBox))
4759
if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
4760
updateHitTestResult(result, locationInContainer.point() - localOffset);
4761
// FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
4762
if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer))
4766
// If we have clipping, then we can't have any spillout.
4767
bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
4768
bool useClip = (hasControlClip() || useOverflowClip);
4769
bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize)));
4770
if (checkChildren) {
4771
// Hit test descendants first.
4772
LayoutSize scrolledOffset(localOffset);
4773
if (hasOverflowClip())
4774
scrolledOffset -= scrolledContentOffset();
4776
// Hit test contents if we don't have columns.
4777
if (!hasColumns()) {
4778
if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4779
updateHitTestResult(result, locationInContainer.point() - localOffset);
4782
if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
4784
} else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
4785
updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
4790
// Now hit test our background
4791
if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
4792
LayoutRect boundsRect(adjustedLocation, size());
4793
if (visibleToHitTesting() && locationInContainer.intersects(boundsRect)) {
4794
updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
4795
if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect))
4803
bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset)
4805
if (!m_floatingObjects)
4808
LayoutPoint adjustedLocation = accumulatedOffset;
4809
if (isRenderView()) {
4810
adjustedLocation += toLayoutSize(toRenderView(this)->frameView()->scrollPosition());
4813
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4814
FloatingObjectSetIterator begin = floatingObjectSet.begin();
4815
for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) {
4817
FloatingObject* floatingObject = *it;
4818
if (floatingObject->shouldPaint() && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
4819
LayoutUnit xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x();
4820
LayoutUnit yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y();
4821
LayoutPoint childPoint = flipFloatForWritingModeForChild(floatingObject, adjustedLocation + LayoutSize(xOffset, yOffset));
4822
if (floatingObject->m_renderer->hitTest(request, result, locationInContainer, childPoint)) {
4823
updateHitTestResult(result, locationInContainer.point() - toLayoutSize(childPoint));
4832
class ColumnRectIterator {
4833
WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
4835
ColumnRectIterator(const RenderBlock& block)
4837
, m_colInfo(block.columnInfo())
4838
, m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
4839
, m_isHorizontal(block.isHorizontalWritingMode())
4840
, m_logicalLeft(block.logicalLeftOffsetForContent())
4842
int colCount = m_colInfo->columnCount();
4843
m_colIndex = colCount - 1;
4844
m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
4855
LayoutRect columnRect() const { return m_colRect; }
4856
bool hasMore() const { return m_colIndex >= 0; }
4858
void adjust(LayoutSize& offset) const
4860
LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
4861
offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
4862
if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
4864
offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
4866
offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
4876
m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
4877
m_block.flipForWritingMode(m_colRect);
4878
m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
4881
const RenderBlock& m_block;
4882
const ColumnInfo* const m_colInfo;
4883
const int m_direction;
4884
const bool m_isHorizontal;
4885
const LayoutUnit m_logicalLeft;
4887
LayoutUnit m_currLogicalTopOffset;
4888
LayoutRect m_colRect;
4891
bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4893
// We need to do multiple passes, breaking up our hit testing into strips.
4897
for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
4898
LayoutRect hitRect = locationInContainer.boundingBox();
4899
LayoutRect colRect = it.columnRect();
4900
colRect.moveBy(accumulatedOffset);
4901
if (locationInContainer.intersects(colRect)) {
4902
// The point is inside this column.
4903
// Adjust accumulatedOffset to change where we hit test.
4906
LayoutPoint finalLocation = accumulatedOffset + offset;
4907
if (!result.isRectBasedTest() || colRect.contains(hitRect))
4908
return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation));
4910
hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction);
4917
void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const
4919
for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
4920
LayoutRect colRect = it.columnRect();
4921
if (colRect.contains(locationInContainer)) {
4928
bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
4930
if (childrenInline() && !isTable()) {
4931
// We have to hit-test our line boxes.
4932
if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction))
4935
// Hit test our children.
4936
HitTestAction childHitTest = hitTestAction;
4937
if (hitTestAction == HitTestChildBlockBackgrounds)
4938
childHitTest = HitTestChildBlockBackground;
4939
for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
4940
LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
4941
if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest))
4949
Position RenderBlock::positionForBox(InlineBox *box, bool start) const
4954
if (!box->renderer()->node())
4955
return createLegacyEditingPosition(node(), start ? caretMinOffset() : caretMaxOffset());
4957
if (!box->isInlineTextBox())
4958
return createLegacyEditingPosition(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
4960
InlineTextBox* textBox = toInlineTextBox(box);
4961
return createLegacyEditingPosition(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
4964
static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
4966
ASSERT(!ancestor || ancestor->node());
4967
ASSERT(child && child->node());
4968
return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
4969
|| ancestor->node()->rendererIsEditable() == child->node()->rendererIsEditable();
4972
// FIXME: This function should go on RenderObject as an instance method. Then
4973
// all cases in which positionForPoint recurs could call this instead to
4974
// prevent crossing editable boundaries. This would require many tests.
4975
static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
4977
LayoutPoint childLocation = child->location();
4978
if (child->isInFlowPositioned())
4979
childLocation += child->offsetForInFlowPosition();
4981
// FIXME: This is wrong if the child's writing-mode is different from the parent's.
4982
LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
4984
// If this is an anonymous renderer, we just recur normally
4985
Node* childNode = child->node();
4987
return child->positionForPoint(pointInChildCoordinates);
4989
// Otherwise, first make sure that the editability of the parent and child agree.
4990
// If they don't agree, then we return a visible position just before or after the child
4991
RenderObject* ancestor = parent;
4992
while (ancestor && !ancestor->node())
4993
ancestor = ancestor->parent();
4995
// If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
4996
if (isEditingBoundary(ancestor, child))
4997
return child->positionForPoint(pointInChildCoordinates);
4999
// Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
5000
LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
5001
LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
5002
if (logicalLeft < childMiddle)
5003
return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
5004
return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
5007
VisiblePosition RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
5009
ASSERT(childrenInline());
5011
if (!firstRootBox())
5012
return createVisiblePosition(0, DOWNSTREAM);
5014
bool linesAreFlipped = style()->isFlippedLinesWritingMode();
5015
bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
5017
// look for the closest line box in the root box which is at the passed-in y coordinate
5018
InlineBox* closestBox = 0;
5019
RootInlineBox* firstRootBoxWithChildren = 0;
5020
RootInlineBox* lastRootBoxWithChildren = 0;
5021
for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
5022
if (!root->firstLeafChild())
5024
if (!firstRootBoxWithChildren)
5025
firstRootBoxWithChildren = root;
5027
if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
5028
|| (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
5031
lastRootBoxWithChildren = root;
5033
// check if this root line box is located at this y coordinate
5034
if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
5035
if (linesAreFlipped) {
5036
RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
5037
while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
5038
nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
5040
if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
5041
|| (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
5044
closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
5050
bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
5052
if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
5053
// y coordinate is below last root line box, pretend we hit it
5054
closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
5058
if (moveCaretToBoundary) {
5059
LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
5060
if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
5061
|| (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
5062
InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
5063
if (box->isLineBreak()) {
5064
if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
5067
// y coordinate is above first root line box, so return the start of the first
5068
return VisiblePosition(positionForBox(box, true), DOWNSTREAM);
5072
// pass the box a top position that is inside it
5073
LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine());
5074
if (!isHorizontalWritingMode())
5075
point = point.transposedPoint();
5076
if (closestBox->renderer()->isReplaced())
5077
return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
5078
return closestBox->renderer()->positionForPoint(point);
5081
if (lastRootBoxWithChildren) {
5082
// We hit this case for Mac behavior when the Y coordinate is below the last box.
5083
ASSERT(moveCaretToBoundary);
5084
InlineBox* logicallyLastBox;
5085
if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
5086
return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
5089
// Can't reach this. We have a root line box, but it has no kids.
5090
// FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
5091
// seems to hit this code path.
5092
return createVisiblePosition(0, DOWNSTREAM);
5095
static inline bool isChildHitTestCandidate(RenderBox* box)
5097
return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned();
5100
VisiblePosition RenderBlock::positionForPoint(const LayoutPoint& point)
5103
return RenderBox::positionForPoint(point);
5106
// FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
5107
LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
5108
LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
5110
if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0))
5111
return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
5112
if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth()))
5113
return createVisiblePosition(caretMaxOffset(), DOWNSTREAM);
5116
LayoutPoint pointInContents = point;
5117
offsetForContents(pointInContents);
5118
LayoutPoint pointInLogicalContents(pointInContents);
5119
if (!isHorizontalWritingMode())
5120
pointInLogicalContents = pointInLogicalContents.transposedPoint();
5122
if (childrenInline())
5123
return positionForPointWithInlineChildren(pointInLogicalContents);
5125
RenderBox* lastCandidateBox = lastChildBox();
5126
while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
5127
lastCandidateBox = lastCandidateBox->previousSiblingBox();
5129
bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
5130
if (lastCandidateBox) {
5131
if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox)
5132
|| (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox)))
5133
return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
5135
for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
5136
if (!isChildHitTestCandidate(childBox))
5138
LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox);
5139
// We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
5140
if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
5141
|| (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
5142
return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
5146
// We only get here if there are no hit test candidate children below the click.
5147
return RenderBox::positionForPoint(point);
5150
void RenderBlock::offsetForContents(LayoutPoint& offset) const
5152
offset = flipForWritingMode(offset);
5154
if (hasOverflowClip())
5155
offset += scrolledContentOffset();
5158
adjustPointToColumnContents(offset);
5160
offset = flipForWritingMode(offset);
5163
LayoutUnit RenderBlock::availableLogicalWidth() const
5165
// If we have multiple columns, then the available logical width is reduced to our column width.
5167
return desiredColumnWidth();
5168
return RenderBox::availableLogicalWidth();
5171
int RenderBlock::columnGap() const
5173
if (style()->hasNormalColumnGap())
5174
return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
5175
return static_cast<int>(style()->columnGap());
5178
void RenderBlock::calcColumnWidth()
5180
if (document()->regionBasedColumnsEnabled())
5183
// Calculate our column width and column count.
5184
// FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
5185
unsigned desiredColumnCount = 1;
5186
LayoutUnit desiredColumnWidth = contentLogicalWidth();
5188
// For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
5189
if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
5190
setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
5194
LayoutUnit availWidth = desiredColumnWidth;
5195
LayoutUnit colGap = columnGap();
5196
LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
5197
int colCount = max<int>(1, style()->columnCount());
5199
if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
5200
desiredColumnCount = colCount;
5201
desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
5202
} else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
5203
desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
5204
desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
5206
desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
5207
desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
5209
setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
5212
bool RenderBlock::requiresColumns(int desiredColumnCount) const
5214
// If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
5215
// in the RenderView instead.
5216
bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody());
5219
&& (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated)
5220
&& !firstChild()->isAnonymousColumnsBlock()
5221
&& !firstChild()->isAnonymousColumnSpanBlock();
5224
void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
5226
bool destroyColumns = !requiresColumns(count);
5227
if (destroyColumns) {
5229
delete gColumnInfoMap->take(this);
5230
setHasColumns(false);
5235
info = gColumnInfoMap->get(this);
5237
if (!gColumnInfoMap)
5238
gColumnInfoMap = new ColumnInfoMap;
5239
info = new ColumnInfo;
5240
gColumnInfoMap->add(this, info);
5241
setHasColumns(true);
5243
info->setDesiredColumnCount(count);
5244
info->setDesiredColumnWidth(width);
5245
info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
5246
info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
5250
void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style)
5255
ColumnInfo* info = gColumnInfoMap->get(this);
5257
bool needsLayout = false;
5258
ColumnInfo::Axis oldAxis = info->progressionAxis();
5259
ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis;
5260
if (oldAxis != newAxis) {
5261
info->setProgressionAxis(newAxis);
5265
bool oldProgressionIsReversed = info->progressionIsReversed();
5266
bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression;
5267
if (oldProgressionIsReversed != newProgressionIsReversed) {
5268
info->setProgressionIsReversed(newProgressionIsReversed);
5273
setNeedsLayoutAndPrefWidthsRecalc();
5276
LayoutUnit RenderBlock::desiredColumnWidth() const
5279
return contentLogicalWidth();
5280
return gColumnInfoMap->get(this)->desiredColumnWidth();
5283
unsigned RenderBlock::desiredColumnCount() const
5287
return gColumnInfoMap->get(this)->desiredColumnCount();
5290
ColumnInfo* RenderBlock::columnInfo() const
5294
return gColumnInfoMap->get(this);
5297
unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
5299
ASSERT(hasColumns());
5300
ASSERT(gColumnInfoMap->get(this) == colInfo);
5301
return colInfo->columnCount();
5304
LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
5306
ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
5308
// Compute the appropriate rect based off our information.
5309
LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
5310
LayoutUnit colLogicalHeight = colInfo->columnHeight();
5311
LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
5312
LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
5313
int colGap = columnGap();
5314
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5315
if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
5316
colLogicalLeft += index * (colLogicalWidth + colGap);
5318
colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
5320
if (!colInfo->progressionIsReversed())
5321
colLogicalTop += index * (colLogicalHeight + colGap);
5323
colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap);
5326
if (isHorizontalWritingMode())
5327
return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
5328
return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
5331
bool RenderBlock::relayoutForPagination(bool hasSpecifiedPageLogicalHeight, LayoutUnit pageLogicalHeight, LayoutStateMaintainer& statePusher)
5336
OwnPtr<RenderOverflow> savedOverflow = m_overflow.release();
5337
if (childrenInline())
5338
addOverflowFromInlineChildren();
5340
addOverflowFromBlockChildren();
5341
LayoutUnit layoutOverflowLogicalBottom = (isHorizontalWritingMode() ? layoutOverflowRect().maxY() : layoutOverflowRect().maxX()) - borderBefore() - paddingBefore();
5343
// FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
5344
// the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
5345
ColumnInfo* colInfo = columnInfo();
5346
if (!hasSpecifiedPageLogicalHeight) {
5347
LayoutUnit columnHeight = pageLogicalHeight;
5348
int minColumnCount = colInfo->forcedBreaks() + 1;
5349
int desiredColumnCount = colInfo->desiredColumnCount();
5350
if (minColumnCount >= desiredColumnCount) {
5351
// The forced page breaks are in control of the balancing. Just set the column height to the
5352
// maximum page break distance.
5353
if (!pageLogicalHeight) {
5354
LayoutUnit distanceBetweenBreaks = max<LayoutUnit>(colInfo->maximumDistanceBetweenForcedBreaks(),
5355
view()->layoutState()->pageLogicalOffset(this, borderBefore() + paddingBefore() + layoutOverflowLogicalBottom) - colInfo->forcedBreakOffset());
5356
columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
5358
} else if (layoutOverflowLogicalBottom > boundedMultiply(pageLogicalHeight, desiredColumnCount)) {
5359
// Now that we know the intrinsic height of the columns, we have to rebalance them.
5360
columnHeight = max<LayoutUnit>(colInfo->minimumColumnHeight(), ceilf((float)layoutOverflowLogicalBottom / desiredColumnCount));
5363
if (columnHeight && columnHeight != pageLogicalHeight) {
5365
setEverHadLayout(true);
5366
layoutBlock(false, columnHeight);
5371
if (pageLogicalHeight)
5372
colInfo->setColumnCountAndHeight(ceilf((float)layoutOverflowLogicalBottom / pageLogicalHeight), pageLogicalHeight);
5374
if (columnCount(colInfo)) {
5375
setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
5378
m_overflow = savedOverflow.release();
5383
void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
5385
// Just bail if we have no columns.
5389
ColumnInfo* colInfo = columnInfo();
5390
if (!columnCount(colInfo))
5393
// Determine which columns we intersect.
5394
LayoutUnit colGap = columnGap();
5395
LayoutUnit halfColGap = colGap / 2;
5396
LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
5397
LayoutUnit logicalOffset = 0;
5398
for (unsigned i = 0; i < colInfo->columnCount(); i++) {
5399
// Add in half the column gap to the left and right of the rect.
5400
LayoutRect colRect = columnRectAt(colInfo, i);
5401
flipForWritingMode(colRect);
5402
if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
5403
LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
5404
if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
5405
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5406
// FIXME: The clamping that follows is not completely right for right-to-left
5408
// Clamp everything above the column to its top left.
5409
if (point.y() < gapAndColumnRect.y())
5410
point = gapAndColumnRect.location();
5411
// Clamp everything below the column to the next column's top left. If there is
5412
// no next column, this still maps to just after this column.
5413
else if (point.y() >= gapAndColumnRect.maxY()) {
5414
point = gapAndColumnRect.location();
5415
point.move(0, gapAndColumnRect.height());
5418
if (point.x() < colRect.x())
5419
point.setX(colRect.x());
5420
else if (point.x() >= colRect.maxX())
5421
point.setX(colRect.maxX() - 1);
5424
// We're inside the column. Translate the x and y into our column coordinate space.
5425
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5426
point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset));
5428
point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
5432
// Move to the next position.
5433
logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
5435
LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
5436
if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
5437
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5438
// FIXME: The clamping that follows is not completely right for right-to-left
5440
// Clamp everything above the column to its top left.
5441
if (point.x() < gapAndColumnRect.x())
5442
point = gapAndColumnRect.location();
5443
// Clamp everything below the column to the next column's top left. If there is
5444
// no next column, this still maps to just after this column.
5445
else if (point.x() >= gapAndColumnRect.maxX()) {
5446
point = gapAndColumnRect.location();
5447
point.move(gapAndColumnRect.width(), 0);
5450
if (point.y() < colRect.y())
5451
point.setY(colRect.y());
5452
else if (point.y() >= colRect.maxY())
5453
point.setY(colRect.maxY() - 1);
5456
// We're inside the column. Translate the x and y into our column coordinate space.
5457
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5458
point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y());
5460
point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
5464
// Move to the next position.
5465
logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
5470
void RenderBlock::adjustRectForColumns(LayoutRect& r) const
5472
// Just bail if we have no columns.
5476
ColumnInfo* colInfo = columnInfo();
5478
// Determine which columns we intersect.
5479
unsigned colCount = columnCount(colInfo);
5483
// Begin with a result rect that is empty.
5486
bool isHorizontal = isHorizontalWritingMode();
5487
LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
5488
LayoutUnit colHeight = colInfo->columnHeight();
5492
LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
5493
LayoutUnit endOffset = min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight);
5495
// FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
5496
unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
5497
unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
5499
if (startColumn == endColumn) {
5500
// The rect is fully contained within one column. Adjust for our offsets
5501
// and repaint only that portion.
5502
LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
5503
LayoutRect colRect = columnRectAt(colInfo, startColumn);
5504
LayoutRect repaintRect = r;
5506
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
5508
repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
5510
repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
5513
repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
5515
repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
5517
repaintRect.intersect(colRect);
5518
result.unite(repaintRect);
5520
// We span multiple columns. We can just unite the start and end column to get the final
5522
result.unite(columnRectAt(colInfo, startColumn));
5523
result.unite(columnRectAt(colInfo, endColumn));
5529
LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
5531
ASSERT(hasColumns());
5532
if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
5534
ColumnInfo* colInfo = columnInfo();
5535
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
5536
LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
5537
if (isHorizontalWritingMode())
5538
return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
5539
return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
5542
void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
5544
ASSERT(hasColumns());
5545
if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
5548
ColumnInfo* colInfo = columnInfo();
5549
LayoutUnit columnLogicalHeight = colInfo->columnHeight();
5550
LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
5552
if (isHorizontalWritingMode())
5553
rect.setY(expandedLogicalHeight - rect.maxY());
5555
rect.setX(expandedLogicalHeight - rect.maxX());
5558
void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
5563
ColumnInfo* colInfo = columnInfo();
5565
LayoutUnit logicalLeft = logicalLeftOffsetForContent();
5566
unsigned colCount = columnCount(colInfo);
5567
LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
5568
LayoutUnit colLogicalHeight = colInfo->columnHeight();
5570
for (unsigned i = 0; i < colCount; ++i) {
5571
// Compute the edges for a given column in the block progression direction.
5572
LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
5573
if (!isHorizontalWritingMode())
5574
sliceRect = sliceRect.transposedRect();
5576
LayoutUnit logicalOffset = i * colLogicalHeight;
5578
// Now we're in the same coordinate space as the point. See if it is inside the rectangle.
5579
if (isHorizontalWritingMode()) {
5580
if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
5581
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5582
offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
5584
offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
5588
if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
5589
if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
5590
offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
5592
offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
5599
void RenderBlock::computePreferredLogicalWidths()
5601
ASSERT(preferredLogicalWidthsDirty());
5603
updateFirstLetter();
5605
RenderStyle* styleToUse = style();
5606
if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
5607
&& style()->marqueeBehavior() != MALTERNATE && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
5608
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
5610
m_minPreferredLogicalWidth = 0;
5611
m_maxPreferredLogicalWidth = 0;
5613
if (childrenInline())
5614
computeInlinePreferredLogicalWidths();
5616
computeBlockPreferredLogicalWidths();
5618
m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
5620
if (!styleToUse->autoWrap() && childrenInline()) {
5621
m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
5623
// A horizontal marquee with inline children has no minimum width.
5624
if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
5625
m_minPreferredLogicalWidth = 0;
5628
int scrollbarWidth = 0;
5629
// FIXME: This should only be done for horizontal writing mode.
5630
// For vertical writing mode, this should check overflowX and use the horizontalScrollbarHeight.
5631
if (hasOverflowClip() && styleToUse->overflowY() == OSCROLL) {
5632
layer()->setHasVerticalScrollbar(true);
5633
scrollbarWidth = verticalScrollbarWidth();
5634
m_maxPreferredLogicalWidth += scrollbarWidth;
5637
if (isTableCell()) {
5638
Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
5639
if (w.isFixed() && w.value() > 0) {
5640
m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(w.value()));
5645
m_minPreferredLogicalWidth += scrollbarWidth;
5648
if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
5649
m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
5650
m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
5653
if (styleToUse->logicalMaxWidth().isFixed()) {
5654
m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
5655
m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
5658
// Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents.
5659
if (isTableCell()) {
5660
m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil();
5661
m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil();
5664
LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
5665
m_minPreferredLogicalWidth += borderAndPadding;
5666
m_maxPreferredLogicalWidth += borderAndPadding;
5668
setPreferredLogicalWidthsDirty(false);
5671
struct InlineMinMaxIterator {
5672
/* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
5673
inline min/max width calculations. Note the following about the way it walks:
5674
(1) Positioned content is skipped (since it does not contribute to min/max width of a block)
5675
(2) We do not drill into the children of floats or replaced elements, since you can't break
5676
in the middle of such an element.
5677
(3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
5678
distinct borders/margin/padding that contribute to the min/max width.
5680
RenderObject* parent;
5681
RenderObject* current;
5684
InlineMinMaxIterator(RenderObject* p, bool end = false)
5685
:parent(p), current(p), endOfInline(end) {}
5687
RenderObject* next();
5690
RenderObject* InlineMinMaxIterator::next()
5692
RenderObject* result = 0;
5693
bool oldEndOfInline = endOfInline;
5694
endOfInline = false;
5695
while (current || current == parent) {
5696
if (!oldEndOfInline &&
5697
(current == parent ||
5698
(!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
5699
result = current->firstChild();
5701
// We hit the end of our inline. (It was empty, e.g., <span></span>.)
5702
if (!oldEndOfInline && current->isRenderInline()) {
5708
while (current && current != parent) {
5709
result = current->nextSibling();
5711
current = current->parent();
5712
if (current && current != parent && current->isRenderInline()) {
5723
if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
5730
// Update our position.
5735
static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
5737
if (cssUnit.type() != Auto)
5738
return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
5742
static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
5744
RenderStyle* childStyle = child->style();
5746
return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
5747
getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
5749
return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
5750
getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
5751
child->borderStart();
5754
static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
5755
RenderObject* trailingSpaceChild)
5757
if (trailingSpaceChild && trailingSpaceChild->isText()) {
5758
// Collapse away the trailing space at the end of a block.
5759
RenderText* t = toRenderText(trailingSpaceChild);
5760
const UChar space = ' ';
5761
const Font& font = t->style()->font(); // FIXME: This ignores first-line.
5762
float spaceWidth = font.width(RenderBlock::constructTextRun(t, font, &space, 1, t->style()));
5763
inlineMax -= spaceWidth + font.wordSpacing();
5764
if (inlineMin > inlineMax)
5765
inlineMin = inlineMax;
5769
static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
5771
LayoutUnit snappedResult = ceiledLayoutUnit(result);
5772
preferredWidth = max(snappedResult, preferredWidth);
5775
// With sub-pixel enabled: When converting between floating point and LayoutUnits
5776
// we risk losing precision with each conversion. When this occurs while
5777
// accumulating our preferred widths, we can wind up with a line width that's
5778
// larger than our maxPreferredWidth due to pure float accumulation.
5780
// With sub-pixel disabled: values from Lengths or the render tree aren't subject
5781
// to the same loss of precision, as they're always truncated and stored as
5782
// integers. We mirror that behavior here to prevent over-allocating our preferred
5784
static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
5786
#if ENABLE(SUBPIXEL_LAYOUT)
5787
return ceiledLayoutUnit(value);
5789
return static_cast<int>(value);
5794
void RenderBlock::computeInlinePreferredLogicalWidths()
5796
float inlineMax = 0;
5797
float inlineMin = 0;
5799
RenderStyle* styleToUse = style();
5800
RenderBlock* containingBlock = this->containingBlock();
5801
LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
5803
// If we are at the start of a line, we want to ignore all white-space.
5804
// Also strip spaces if we previously had text that ended in a trailing space.
5805
bool stripFrontSpaces = true;
5806
RenderObject* trailingSpaceChild = 0;
5808
// Firefox and Opera will allow a table cell to grow to fit an image inside it under
5809
// very specific cirucumstances (in order to match common WinIE renderings).
5810
// Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
5811
bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
5813
bool autoWrap, oldAutoWrap;
5814
autoWrap = oldAutoWrap = styleToUse->autoWrap();
5816
InlineMinMaxIterator childIterator(this);
5817
bool addedTextIndent = false; // Only gets added in once.
5818
LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view());
5819
RenderObject* prevFloat = 0;
5820
bool isPrevChildInlineFlow = false;
5821
bool shouldBreakLineAfterText = false;
5822
while (RenderObject* child = childIterator.next()) {
5823
autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
5824
child->style()->autoWrap();
5826
if (!child->isBR()) {
5827
// Step One: determine whether or not we need to go ahead and
5828
// terminate our current line. Each discrete chunk can become
5829
// the new min-width, if it is the widest chunk seen so far, and
5830
// it can also become the max-width.
5832
// Children fall into three categories:
5833
// (1) An inline flow object. These objects always have a min/max of 0,
5834
// and are included in the iteration solely so that their margins can
5837
// (2) An inline non-text non-flow object, e.g., an inline replaced element.
5838
// These objects can always be on a line by themselves, so in this situation
5839
// we need to go ahead and break the current line, and then add in our own
5840
// margins and min/max width on its own line, and then terminate the line.
5842
// (3) A text object. Text runs can have breakable characters at the start,
5843
// the middle or the end. They may also lose whitespace off the front if
5844
// we're already ignoring whitespace. In order to compute accurate min-width
5845
// information, we need three pieces of information.
5846
// (a) the min-width of the first non-breakable run. Should be 0 if the text string
5847
// starts with whitespace.
5848
// (b) the min-width of the last non-breakable run. Should be 0 if the text string
5849
// ends with whitespace.
5850
// (c) the min/max width of the string (trimmed for whitespace).
5852
// If the text string starts with whitespace, then we need to go ahead and
5853
// terminate our current line (unless we're already in a whitespace stripping
5856
// If the text string has a breakable character in the middle, but didn't start
5857
// with whitespace, then we add the width of the first non-breakable run and
5858
// then end the current line. We then need to use the intermediate min/max width
5859
// values (if any of them are larger than our current min/max). We then look at
5860
// the width of the last non-breakable run and use that to start a new line
5861
// (unless we end in whitespace).
5862
RenderStyle* childStyle = child->style();
5866
if (!child->isText()) {
5867
// Case (1) and (2). Inline replaced and inline flow elements.
5868
if (child->isRenderInline()) {
5869
// Add in padding/border/margin from the appropriate side of
5871
float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
5875
inlineMin += childMin;
5876
inlineMax += childMax;
5878
child->setPreferredLogicalWidthsDirty(false);
5880
// Inline replaced elts add in their margins to their min/max values.
5881
LayoutUnit margins = 0;
5882
Length startMargin = childStyle->marginStart();
5883
Length endMargin = childStyle->marginEnd();
5884
if (startMargin.isFixed())
5885
margins += adjustFloatForSubPixelLayout(startMargin.value());
5886
if (endMargin.isFixed())
5887
margins += adjustFloatForSubPixelLayout(endMargin.value());
5888
childMin += margins.ceilToFloat();
5889
childMax += margins.ceilToFloat();
5893
if (!child->isRenderInline() && !child->isText()) {
5894
// Case (2). Inline replaced elements and floats.
5895
// Go ahead and terminate the current line as far as
5896
// minwidth is concerned.
5897
childMin += child->minPreferredLogicalWidth().ceilToFloat();
5898
childMax += child->maxPreferredLogicalWidth().ceilToFloat();
5900
bool clearPreviousFloat;
5901
if (child->isFloating()) {
5902
clearPreviousFloat = (prevFloat
5903
&& ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
5904
|| (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
5907
clearPreviousFloat = false;
5909
bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
5910
if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
5911
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5915
// If we're supposed to clear the previous float, then terminate maxwidth as well.
5916
if (clearPreviousFloat) {
5917
updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5921
// Add in text-indent. This is added in only once.
5923
if (!addedTextIndent) {
5925
childMin += ti.ceilToFloat();
5926
childMax += ti.ceilToFloat();
5929
textIndent = adjustFloatForSubPixelLayout(childMin);
5931
addedTextIndent = true;
5934
// Add our width to the max.
5935
inlineMax += max<float>(0, childMax);
5937
if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
5938
if (child->isFloating())
5939
updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5941
inlineMin += childMin;
5943
// Now check our line.
5944
updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
5946
// Now start a new line.
5950
if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
5951
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5955
// We are no longer stripping whitespace at the start of
5957
if (!child->isFloating()) {
5958
stripFrontSpaces = false;
5959
trailingSpaceChild = 0;
5961
} else if (child->isText()) {
5963
RenderText* t = toRenderText(child);
5965
if (t->isWordBreak()) {
5966
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5971
if (t->style()->hasTextCombine() && t->isCombineText())
5972
toRenderCombineText(t)->combineText();
5974
// Determine if we have a breakable character. Pass in
5975
// whether or not we should ignore any spaces at the front
5976
// of the string. If those are going to be stripped out,
5977
// then they shouldn't be considered in the breakable char
5979
bool hasBreakableChar, hasBreak;
5980
float beginMin, endMin;
5981
bool beginWS, endWS;
5982
float beginMax, endMax;
5983
t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
5984
hasBreakableChar, hasBreak, beginMax, endMax,
5985
childMin, childMax, stripFrontSpaces);
5987
// This text object will not be rendered, but it may still provide a breaking opportunity.
5988
if (!hasBreak && childMax == 0) {
5989
if (autoWrap && (beginWS || endWS)) {
5990
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5996
if (stripFrontSpaces)
5997
trailingSpaceChild = child;
5999
trailingSpaceChild = 0;
6001
// Add in text-indent. This is added in only once.
6003
if (!addedTextIndent) {
6004
ti = textIndent.ceilToFloat();
6012
textIndent = childMin;
6014
addedTextIndent = true;
6017
// If we have no breakable characters at all,
6018
// then this is the easy case. We add ourselves to the current
6019
// min and max and continue.
6020
if (!hasBreakableChar) {
6021
inlineMin += childMin;
6023
// We have a breakable character. Now we need to know if
6024
// we start and end with whitespace.
6026
// Go ahead and end the current line.
6027
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6029
inlineMin += beginMin;
6030
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6034
inlineMin = childMin;
6037
// We end in whitespace, which means we can go ahead
6038
// and end our current line.
6039
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6041
shouldBreakLineAfterText = false;
6043
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6045
shouldBreakLineAfterText = true;
6050
inlineMax += beginMax;
6051
updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
6052
updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
6054
addedTextIndent = true;
6056
inlineMax += max<float>(0, childMax);
6059
// Ignore spaces after a list marker.
6060
if (child->isListMarker())
6061
stripFrontSpaces = true;
6063
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6064
updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
6065
inlineMin = inlineMax = 0;
6066
stripFrontSpaces = true;
6067
trailingSpaceChild = 0;
6068
addedTextIndent = true;
6071
if (!child->isText() && child->isRenderInline())
6072
isPrevChildInlineFlow = true;
6074
isPrevChildInlineFlow = false;
6076
oldAutoWrap = autoWrap;
6079
if (styleToUse->collapseWhiteSpace())
6080
stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
6082
updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
6083
updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
6086
void RenderBlock::computeBlockPreferredLogicalWidths()
6088
RenderStyle* styleToUse = style();
6089
bool nowrap = styleToUse->whiteSpace() == NOWRAP;
6091
RenderObject* child = firstChild();
6092
RenderBlock* containingBlock = this->containingBlock();
6093
LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
6095
// Positioned children don't affect the min/max width
6096
if (child->isOutOfFlowPositioned()) {
6097
child = child->nextSibling();
6101
RenderStyle* childStyle = child->style();
6102
if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
6103
LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
6104
if (childStyle->clear() & CLEFT) {
6105
m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
6108
if (childStyle->clear() & CRIGHT) {
6109
m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
6110
floatRightWidth = 0;
6114
// A margin basically has three types: fixed, percentage, and auto (variable).
6115
// Auto and percentage margins simply become 0 when computing min/max width.
6116
// Fixed margins can be added in as is.
6117
Length startMarginLength = childStyle->marginStartUsing(styleToUse);
6118
Length endMarginLength = childStyle->marginEndUsing(styleToUse);
6119
LayoutUnit margin = 0;
6120
LayoutUnit marginStart = 0;
6121
LayoutUnit marginEnd = 0;
6122
if (startMarginLength.isFixed())
6123
marginStart += startMarginLength.value();
6124
if (endMarginLength.isFixed())
6125
marginEnd += endMarginLength.value();
6126
margin = marginStart + marginEnd;
6128
LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
6129
if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
6130
RenderBox* childBox = toRenderBox(child);
6131
LogicalExtentComputedValues computedValues;
6132
childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
6133
childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
6135
childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
6136
childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
6139
LayoutUnit w = childMinPreferredLogicalWidth + margin;
6140
m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
6142
// IE ignores tables for calculation of nowrap. Makes some sense.
6143
if (nowrap && !child->isTable())
6144
m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
6146
w = childMaxPreferredLogicalWidth + margin;
6148
if (!child->isFloating()) {
6149
if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
6150
// Determine a left and right max value based off whether or not the floats can fit in the
6151
// margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
6152
// is smaller than the float width.
6153
bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection();
6154
LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
6155
LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
6156
LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
6157
LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
6158
w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
6159
w = max(w, floatLeftWidth + floatRightWidth);
6162
m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
6163
floatLeftWidth = floatRightWidth = 0;
6166
if (child->isFloating()) {
6167
if (styleToUse->floating() == LeftFloat)
6168
floatLeftWidth += w;
6170
floatRightWidth += w;
6172
m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
6174
child = child->nextSibling();
6177
// Always make sure these values are non-negative.
6178
m_minPreferredLogicalWidth = max<LayoutUnit>(0, m_minPreferredLogicalWidth);
6179
m_maxPreferredLogicalWidth = max<LayoutUnit>(0, m_maxPreferredLogicalWidth);
6181
m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
6184
bool RenderBlock::hasLineIfEmpty() const
6189
if (node()->isRootEditableElement())
6192
if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
6198
LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
6200
// Inline blocks are replaced elements. Otherwise, just pass off to
6201
// the base class. If we're being queried as though we're the root line
6202
// box, then the fact that we're an inline-block is irrelevant, and we behave
6203
// just like a block.
6204
if (isReplaced() && linePositionMode == PositionOnContainingLine)
6205
return RenderBox::lineHeight(firstLine, direction, linePositionMode);
6207
if (firstLine && document()->styleSheetCollection()->usesFirstLineRules()) {
6208
RenderStyle* s = style(firstLine);
6210
return s->computedLineHeight(view());
6213
if (m_lineHeight == -1)
6214
m_lineHeight = style()->computedLineHeight(view());
6216
return m_lineHeight;
6219
int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
6221
// Inline blocks are replaced elements. Otherwise, just pass off to
6222
// the base class. If we're being queried as though we're the root line
6223
// box, then the fact that we're an inline-block is irrelevant, and we behave
6224
// just like a block.
6225
if (isReplaced() && linePositionMode == PositionOnContainingLine) {
6226
// For "leaf" theme objects, let the theme decide what the baseline position is.
6227
// FIXME: Might be better to have a custom CSS property instead, so that if the theme
6228
// is turned off, checkboxes/radios will still have decent baselines.
6229
// FIXME: Need to patch form controls to deal with vertical lines.
6230
if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
6231
return theme()->baselinePosition(this);
6233
// CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
6234
// the normal flow. We make an exception for marquees, since their baselines are meaningless
6235
// (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
6236
// We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
6237
// vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
6238
// of our content box.
6239
bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)
6240
: (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun());
6242
int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction);
6244
LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
6245
if (baselinePos != -1 && baselinePos <= bottomOfContent)
6246
return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
6248
return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
6251
const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
6252
return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
6255
int RenderBlock::firstLineBoxBaseline() const
6257
if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
6260
if (childrenInline()) {
6262
return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
6267
for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
6268
if (!curr->isFloatingOrOutOfFlowPositioned()) {
6269
int result = curr->firstLineBoxBaseline();
6271
return curr->logicalTop() + result; // Translate to our coordinate space.
6279
int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const
6281
return lastLineBoxBaseline(direction);
6284
int RenderBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const
6286
if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
6289
if (childrenInline()) {
6290
if (!firstLineBox() && hasLineIfEmpty()) {
6291
const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
6292
return fontMetrics.ascent()
6293
+ (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
6294
+ (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
6297
return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
6300
bool haveNormalFlowChild = false;
6301
for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
6302
if (!curr->isFloatingOrOutOfFlowPositioned()) {
6303
haveNormalFlowChild = true;
6304
int result = curr->inlineBlockBaseline(lineDirection);
6306
return curr->logicalTop() + result; // Translate to our coordinate space.
6309
if (!haveNormalFlowChild && hasLineIfEmpty()) {
6310
const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
6311
return fontMetrics.ascent()
6312
+ (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
6313
+ (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
6320
bool RenderBlock::containsNonZeroBidiLevel() const
6322
for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
6323
for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
6324
if (box->bidiLevel())
6331
RenderBlock* RenderBlock::firstLineBlock() const
6333
RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
6334
bool hasPseudo = false;
6336
hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
6339
RenderObject* parentBlock = firstLineBlock->parent();
6340
if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
6341
!parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
6343
ASSERT(parentBlock->isRenderBlock());
6344
firstLineBlock = toRenderBlock(parentBlock);
6350
return firstLineBlock;
6353
static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
6355
RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
6356
// Force inline display (except for floating first-letters).
6357
pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
6358
// CSS2 says first-letter can't be positioned.
6359
pseudoStyle->setPosition(StaticPosition);
6363
// CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
6364
// "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
6365
// "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
6366
static inline bool isPunctuationForFirstLetter(UChar c)
6368
CharCategory charCategory = category(c);
6369
return charCategory == Punctuation_Open
6370
|| charCategory == Punctuation_Close
6371
|| charCategory == Punctuation_InitialQuote
6372
|| charCategory == Punctuation_FinalQuote
6373
|| charCategory == Punctuation_Other;
6376
static inline bool shouldSkipForFirstLetter(UChar c)
6378
return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
6381
static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
6383
RenderObject* firstLetterBlock = start;
6385
bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
6386
&& firstLetterBlock->canHaveGeneratedChildren();
6387
if (canHaveFirstLetterRenderer)
6388
return firstLetterBlock;
6390
RenderObject* parentBlock = firstLetterBlock->parent();
6391
if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
6392
!parentBlock->isBlockFlow())
6394
firstLetterBlock = parentBlock;
6400
void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild)
6402
RenderObject* firstLetter = currentChild->parent();
6403
RenderObject* firstLetterContainer = firstLetter->parent();
6404
RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
6405
ASSERT(firstLetter->isFloating() || firstLetter->isInline());
6407
if (Node::diff(firstLetter->style(), pseudoStyle, document()) == Node::Detach) {
6408
// The first-letter renderer needs to be replaced. Create a new renderer of the right type.
6409
RenderObject* newFirstLetter;
6410
if (pseudoStyle->display() == INLINE)
6411
newFirstLetter = new (renderArena()) RenderInline(document());
6413
newFirstLetter = new (renderArena()) RenderBlock(document());
6414
newFirstLetter->setStyle(pseudoStyle);
6416
// Move the first letter into the new renderer.
6417
LayoutStateDisabler layoutStateDisabler(view());
6418
while (RenderObject* child = firstLetter->firstChild()) {
6419
if (child->isText())
6420
toRenderText(child)->removeAndDestroyTextBoxes();
6421
firstLetter->removeChild(child);
6422
newFirstLetter->addChild(child, 0);
6425
RenderTextFragment* remainingText = 0;
6426
RenderObject* nextSibling = firstLetter->nextSibling();
6427
RenderObject* remainingTextObject = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText();
6428
if (remainingTextObject && remainingTextObject->isText() && toRenderText(remainingTextObject)->isTextFragment())
6429
remainingText = toRenderTextFragment(remainingTextObject);
6430
if (remainingText) {
6431
ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
6432
// Replace the old renderer with the new one.
6433
remainingText->setFirstLetter(newFirstLetter);
6434
toRenderBoxModelObject(newFirstLetter)->setFirstLetterRemainingText(remainingText);
6436
// To prevent removal of single anonymous block in RenderBlock::removeChild and causing
6437
// |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
6438
firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter);
6439
firstLetter->destroy();
6440
firstLetter = newFirstLetter;
6441
firstLetterContainer->addChild(firstLetter, nextSibling);
6443
firstLetter->setStyle(pseudoStyle);
6445
for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
6446
if (genChild->isText())
6447
genChild->setStyle(pseudoStyle);
6451
void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild)
6453
RenderObject* firstLetterContainer = currentChild->parent();
6454
RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
6455
RenderObject* firstLetter = 0;
6456
if (pseudoStyle->display() == INLINE)
6457
firstLetter = new (renderArena()) RenderInline(document());
6459
firstLetter = new (renderArena()) RenderBlock(document());
6460
firstLetter->setStyle(pseudoStyle);
6461
firstLetterContainer->addChild(firstLetter, currentChild);
6463
RenderText* textObj = toRenderText(currentChild);
6465
// The original string is going to be either a generated content string or a DOM node's
6466
// string. We want the original string before it got transformed in case first-letter has
6467
// no text-transform or a different text-transform applied to it.
6468
RefPtr<StringImpl> oldText = textObj->originalText();
6471
if (oldText && oldText->length() > 0) {
6472
unsigned length = 0;
6474
// Account for leading spaces and punctuation.
6475
while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length]))
6478
// Account for first letter.
6481
// Keep looking for whitespace and allowed punctuation, but avoid
6482
// accumulating just whitespace into the :first-letter.
6483
for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) {
6484
UChar c = (*oldText)[scanLength];
6486
if (!shouldSkipForFirstLetter(c))
6489
if (isPunctuationForFirstLetter(c))
6490
length = scanLength + 1;
6493
// Construct a text fragment for the text after the first letter.
6494
// This text fragment might be empty.
6495
RenderTextFragment* remainingText =
6496
new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
6497
remainingText->setStyle(textObj->style());
6498
if (remainingText->node())
6499
remainingText->node()->setRenderer(remainingText);
6501
firstLetterContainer->addChild(remainingText, textObj);
6502
firstLetterContainer->removeChild(textObj);
6503
remainingText->setFirstLetter(firstLetter);
6504
toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText);
6506
// construct text fragment for the first letter
6507
RenderTextFragment* letter =
6508
new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
6509
letter->setStyle(pseudoStyle);
6510
firstLetter->addChild(letter);
6516
void RenderBlock::updateFirstLetter()
6518
if (!document()->styleSheetCollection()->usesFirstLetterRules())
6521
if (style()->styleType() == FIRST_LETTER)
6524
// FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
6525
// an efficient way to check for that situation though before implementing anything.
6526
RenderObject* firstLetterBlock = findFirstLetterBlock(this);
6527
if (!firstLetterBlock)
6530
// Drill into inlines looking for our first text child.
6531
RenderObject* currChild = firstLetterBlock->firstChild();
6533
if (currChild->isText())
6535
if (currChild->isListMarker())
6536
currChild = currChild->nextSibling();
6537
else if (currChild->isFloatingOrOutOfFlowPositioned()) {
6538
if (currChild->style()->styleType() == FIRST_LETTER) {
6539
currChild = currChild->firstChild();
6542
currChild = currChild->nextSibling();
6543
} else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
6545
else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren()) {
6546
// We found a lower-level node with first-letter, which supersedes the higher-level style
6547
firstLetterBlock = currChild;
6548
currChild = currChild->firstChild();
6550
currChild = currChild->firstChild();
6556
// If the child already has style, then it has already been created, so we just want
6558
if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
6559
updateFirstLetterStyle(firstLetterBlock, currChild);
6563
if (!currChild->isText() || currChild->isBR())
6566
// Our layout state is not valid for the repaints we are going to trigger by
6567
// adding and removing children of firstLetterContainer.
6568
LayoutStateDisabler layoutStateDisabler(view());
6570
createFirstLetterRenderer(firstLetterBlock, currChild);
6573
// Helper methods for obtaining the last line, computing line counts and heights for line counts
6574
// (crawling into blocks).
6575
static bool shouldCheckLines(RenderObject* obj)
6577
return !obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn()
6578
&& obj->isBlockFlow() && obj->style()->height().isAuto()
6579
&& (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
6582
static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
6584
if (block->style()->visibility() == VISIBLE) {
6585
if (block->childrenInline()) {
6586
for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
6592
for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
6593
if (shouldCheckLines(obj)) {
6594
RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
6604
static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
6606
if (block->style()->visibility() == VISIBLE) {
6607
if (block->childrenInline()) {
6608
for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
6610
return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
6614
RenderBox* normalFlowChildWithoutLines = 0;
6615
for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
6616
if (shouldCheckLines(obj)) {
6617
int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
6619
return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
6620
} else if (!obj->isFloatingOrOutOfFlowPositioned() && !obj->isRunIn())
6621
normalFlowChildWithoutLines = obj;
6623
if (normalFlowChildWithoutLines && l == 0)
6624
return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
6631
RootInlineBox* RenderBlock::lineAtIndex(int i)
6634
return getLineAtIndex(this, i, count);
6637
int RenderBlock::lineCount()
6640
if (style()->visibility() == VISIBLE) {
6641
if (childrenInline())
6642
for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
6645
for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
6646
if (shouldCheckLines(obj))
6647
count += toRenderBlock(obj)->lineCount();
6652
int RenderBlock::heightForLineCount(int l)
6655
return getHeightForLineCount(this, l, true, count);
6658
void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
6660
// We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
6661
// for either overflow or translations via relative positioning.
6662
if (style()->visibility() == VISIBLE) {
6663
if (childrenInline()) {
6664
for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
6665
if (box->firstChild())
6666
left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
6667
if (box->lastChild())
6668
right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
6672
for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
6673
if (!obj->isFloatingOrOutOfFlowPositioned()) {
6674
if (obj->isBlockFlow() && !obj->hasOverflowClip())
6675
toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
6676
else if (obj->style()->visibility() == VISIBLE) {
6677
// We are a replaced element or some kind of non-block-flow object.
6678
left = min(left, x + obj->x());
6679
right = max(right, x + obj->x() + obj->width());
6685
if (m_floatingObjects) {
6686
const FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
6687
FloatingObjectSetIterator end = floatingObjectSet.end();
6688
for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
6689
FloatingObject* r = *it;
6690
// Only examine the object if our m_shouldPaint flag is set.
6691
if (r->shouldPaint()) {
6692
LayoutUnit floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x();
6693
LayoutUnit floatRight = floatLeft + r->m_renderer->width();
6694
left = min(left, floatLeft);
6695
right = max(right, floatRight);
6702
void RenderBlock::borderFitAdjust(LayoutRect& rect) const
6704
if (style()->borderFit() == BorderFitBorder)
6707
// Walk any normal flow lines to snugly fit.
6708
LayoutUnit left = LayoutUnit::max();
6709
LayoutUnit right = LayoutUnit::min();
6710
LayoutUnit oldWidth = rect.width();
6711
adjustForBorderFit(0, left, right);
6712
if (left != LayoutUnit::max()) {
6713
left = min(left, oldWidth - (borderRight() + paddingRight()));
6715
left -= (borderLeft() + paddingLeft());
6718
rect.expand(-left, 0);
6721
if (right != LayoutUnit::min()) {
6722
right = max(right, borderLeft() + paddingLeft());
6724
right += (borderRight() + paddingRight());
6725
if (right < oldWidth)
6726
rect.expand(-(oldWidth - right), 0);
6730
void RenderBlock::clearTruncation()
6732
if (style()->visibility() == VISIBLE) {
6733
if (childrenInline() && hasMarkupTruncation()) {
6734
setHasMarkupTruncation(false);
6735
for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
6736
box->clearTruncation();
6738
for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
6739
if (shouldCheckLines(obj))
6740
toRenderBlock(obj)->clearTruncation();
6746
void RenderBlock::setMaxMarginBeforeValues(LayoutUnit pos, LayoutUnit neg)
6749
if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
6751
m_rareData = adoptPtr(new RenderBlockRareData(this));
6753
m_rareData->m_margins.setPositiveMarginBefore(pos);
6754
m_rareData->m_margins.setNegativeMarginBefore(neg);
6757
void RenderBlock::setMaxMarginAfterValues(LayoutUnit pos, LayoutUnit neg)
6760
if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
6762
m_rareData = adoptPtr(new RenderBlockRareData(this));
6764
m_rareData->m_margins.setPositiveMarginAfter(pos);
6765
m_rareData->m_margins.setNegativeMarginAfter(neg);
6768
void RenderBlock::setPaginationStrut(LayoutUnit strut)
6773
m_rareData = adoptPtr(new RenderBlockRareData(this));
6775
m_rareData->m_paginationStrut = strut;
6778
void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
6783
m_rareData = adoptPtr(new RenderBlockRareData(this));
6785
m_rareData->m_pageLogicalOffset = logicalOffset;
6788
void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
6790
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
6791
// inline boxes above and below us (thus getting merged with them to form a single irregular
6793
if (isAnonymousBlockContinuation()) {
6794
// FIXME: This is wrong for block-flows that are horizontal.
6795
// https://bugs.webkit.org/show_bug.cgi?id=46781
6796
rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
6797
width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
6798
continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
6799
inlineElementContinuation()->containingBlock()->location()));
6801
rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
6804
void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
6806
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
6807
// inline boxes above and below us (thus getting merged with them to form a single irregular
6809
if (isAnonymousBlockContinuation()) {
6810
// FIXME: This is wrong for block-flows that are horizontal.
6811
// https://bugs.webkit.org/show_bug.cgi?id=46781
6812
FloatRect localRect(0, -collapsedMarginBefore(),
6813
width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
6814
quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
6815
continuation()->absoluteQuads(quads, wasFixed);
6817
quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
6820
LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
6822
LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
6823
if (isAnonymousBlockContinuation())
6824
r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
6828
RenderObject* RenderBlock::hoverAncestor() const
6830
return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
6833
void RenderBlock::updateDragState(bool dragOn)
6835
RenderBox::updateDragState(dragOn);
6837
continuation()->updateDragState(dragOn);
6840
RenderStyle* RenderBlock::outlineStyleForRepaint() const
6842
return isAnonymousBlockContinuation() ? continuation()->style() : style();
6845
void RenderBlock::childBecameNonInline(RenderObject*)
6847
makeChildrenNonInline();
6848
if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
6849
toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
6850
// |this| may be dead here
6853
void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
6855
if (result.innerNode())
6858
if (Node* n = nodeForHitTest()) {
6859
result.setInnerNode(n);
6860
if (!result.innerNonSharedNode())
6861
result.setInnerNonSharedNode(n);
6862
result.setLocalPoint(point);
6866
LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
6868
// Do the normal calculation in most cases.
6870
return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
6872
LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
6874
if (extraWidthToEndOfLine) {
6875
if (isRenderBlock()) {
6876
*extraWidthToEndOfLine = width() - caretRect.maxX();
6878
// FIXME: This code looks wrong.
6879
// myRight and containerRight are set up, but then clobbered.
6880
// So *extraWidthToEndOfLine will always be 0 here.
6882
LayoutUnit myRight = caretRect.maxX();
6883
// FIXME: why call localToAbsoluteForContent() twice here, too?
6884
FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
6886
LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
6887
FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
6889
*extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
6896
void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset)
6898
// For blocks inside inlines, we go ahead and include margins so that we run right up to the
6899
// inline boxes above and below us (thus getting merged with them to form a single irregular
6901
if (inlineElementContinuation()) {
6902
// FIXME: This check really isn't accurate.
6903
bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
6904
// FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
6905
// FIXME: This is wrong for block-flows that are horizontal.
6906
// https://bugs.webkit.org/show_bug.cgi?id=46781
6907
bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
6908
float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit();
6909
float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit();
6910
LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
6911
if (!rect.isEmpty())
6912
rects.append(pixelSnappedIntRect(rect));
6913
} else if (width() && height())
6914
rects.append(pixelSnappedIntRect(additionalOffset, size()));
6916
if (!hasOverflowClip() && !hasControlClip()) {
6917
for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
6918
LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
6919
LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
6920
LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
6921
if (!rect.isEmpty())
6922
rects.append(pixelSnappedIntRect(rect));
6925
for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
6926
if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
6927
RenderBox* box = toRenderBox(curr);
6929
// FIXME: This doesn't work correctly with transforms.
6931
pos = curr->localToAbsolute();
6933
pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
6934
box->addFocusRingRects(rects, flooredLayoutPoint(pos));
6939
if (inlineElementContinuation())
6940
inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()));
6943
RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
6945
if (isAnonymousColumnsBlock())
6946
return createAnonymousColumnsWithParentRenderer(parent);
6947
if (isAnonymousColumnSpanBlock())
6948
return createAnonymousColumnSpanWithParentRenderer(parent);
6949
return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
6952
bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6954
ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
6956
if (!inRenderFlowThread())
6957
return true; // Printing and multi-column both make new pages to accommodate content.
6959
// See if we're in the last region.
6960
LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
6961
RenderRegion* region = enclosingRenderFlowThread()->regionAtBlockOffset(pageOffset, this);
6964
if (region->isLastRegion())
6965
return region->isRenderRegionSet() || region->style()->regionOverflow() == BreakRegionOverflow
6966
|| (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
6970
LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
6972
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
6973
if (!pageLogicalHeight)
6974
return logicalOffset;
6976
// The logicalOffset is in our coordinate space. We can add in our pushed offset.
6977
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
6978
if (pageBoundaryRule == ExcludePageBoundary)
6979
return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
6980
return logicalOffset + remainingLogicalHeight;
6983
static bool inNormalFlow(RenderBox* child)
6985
RenderBlock* curr = child->containingBlock();
6986
RenderView* renderView = child->view();
6987
while (curr && curr != renderView) {
6988
if (curr->hasColumns() || curr->isRenderFlowThread())
6990
if (curr->isFloatingOrOutOfFlowPositioned())
6992
curr = curr->containingBlock();
6997
ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
6999
return ColumnInfo::Column;
7002
LayoutUnit RenderBlock::applyBeforeBreak(RenderBox* child, LayoutUnit logicalOffset)
7004
// FIXME: Add page break checking here when we support printing.
7005
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
7006
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
7007
bool checkRegionBreaks = inRenderFlowThread();
7008
bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS)
7009
|| (checkRegionBreaks && child->style()->regionBreakBefore() == PBALWAYS);
7010
if (checkBeforeAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
7011
if (checkColumnBreaks)
7012
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
7013
if (checkRegionBreaks) {
7014
LayoutUnit offsetBreakAdjustment = 0;
7015
if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset, child, true, &offsetBreakAdjustment))
7016
return logicalOffset + offsetBreakAdjustment;
7018
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
7020
return logicalOffset;
7023
LayoutUnit RenderBlock::applyAfterBreak(RenderBox* child, LayoutUnit logicalOffset, MarginInfo& marginInfo)
7025
// FIXME: Add page break checking here when we support printing.
7026
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
7027
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
7028
bool checkRegionBreaks = inRenderFlowThread();
7029
bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS)
7030
|| (checkRegionBreaks && child->style()->regionBreakAfter() == PBALWAYS);
7031
if (checkAfterAlways && inNormalFlow(child) && hasNextPage(logicalOffset, IncludePageBoundary)) {
7032
marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
7033
if (checkColumnBreaks)
7034
view()->layoutState()->addForcedColumnBreak(child, logicalOffset);
7035
if (checkRegionBreaks) {
7036
LayoutUnit marginOffset = marginInfo.canCollapseWithMarginBefore() ? LayoutUnit() : marginInfo.margin();
7037
LayoutUnit offsetBreakAdjustment = 0;
7038
if (enclosingRenderFlowThread()->addForcedRegionBreak(offsetFromLogicalTopOfFirstPage() + logicalOffset + marginOffset, child, false, &offsetBreakAdjustment))
7039
return logicalOffset + offsetBreakAdjustment;
7041
return nextPageLogicalTop(logicalOffset, IncludePageBoundary);
7043
return logicalOffset;
7046
LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
7048
RenderView* renderView = view();
7049
LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
7050
LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
7052
LayoutUnit cumulativeOffset = offset + blockLogicalTop;
7053
if (!inRenderFlowThread()) {
7054
LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
7055
if (!pageLogicalHeight)
7057
return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
7059
return enclosingRenderFlowThread()->pageLogicalTopForOffset(cumulativeOffset);
7062
LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
7064
RenderView* renderView = view();
7065
if (!inRenderFlowThread())
7066
return renderView->layoutState()->m_pageLogicalHeight;
7067
return enclosingRenderFlowThread()->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
7070
LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
7072
RenderView* renderView = view();
7073
offset += offsetFromLogicalTopOfFirstPage();
7075
if (!inRenderFlowThread()) {
7076
LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
7077
LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
7078
if (pageBoundaryRule == IncludePageBoundary) {
7079
// If includeBoundaryPoint is true the line exactly on the top edge of a
7080
// column will act as being part of the previous column.
7081
remainingHeight = intMod(remainingHeight, pageLogicalHeight);
7083
return remainingHeight;
7086
return enclosingRenderFlowThread()->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
7089
LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
7091
bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
7092
bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
7093
bool checkRegionBreaks = inRenderFlowThread();
7094
bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
7095
|| (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
7096
|| (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
7097
if (!isUnsplittable)
7098
return logicalOffset;
7099
LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
7100
LayoutState* layoutState = view()->layoutState();
7101
if (layoutState->m_columnInfo)
7102
layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
7103
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
7104
bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
7105
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
7106
|| !hasNextPage(logicalOffset))
7107
return logicalOffset;
7108
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
7109
if (remainingLogicalHeight < childLogicalHeight) {
7110
if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
7111
return logicalOffset;
7112
return logicalOffset + remainingLogicalHeight;
7114
return logicalOffset;
7117
bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
7119
bool checkRegion = false;
7120
for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
7121
pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
7122
if (minimumLogicalHeight <= pageLogicalHeight)
7124
if (!hasNextPage(logicalOffset + adjustment))
7126
adjustment += pageLogicalHeight;
7129
return !checkRegion;
7132
void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta)
7134
// FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
7135
// put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
7136
// the line on the top of the next page will appear too far down relative to the same kind of line at the top
7137
// of the first column.
7139
// The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
7140
// simply spills out above the top of the column. This effect would match what happens at the top of the first column.
7141
// We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
7142
// for overflow to occur), and then cache visible overflow for each column rect.
7144
// Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
7145
// content that paints in a previous column (and content that paints in the following column).
7147
// For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
7148
// at least make positive leading work in typical cases.
7150
// FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
7151
// Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
7152
// line and all following lines.
7153
LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
7154
LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
7155
LayoutUnit lineHeight = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY()) - logicalOffset;
7156
RenderView* renderView = view();
7157
LayoutState* layoutState = renderView->layoutState();
7158
if (layoutState->m_columnInfo)
7159
layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
7160
logicalOffset += delta;
7161
lineBox->setPaginationStrut(0);
7162
lineBox->setIsFirstAfterPageBreak(false);
7163
LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
7164
bool hasUniformPageLogicalHeight = !inRenderFlowThread() || enclosingRenderFlowThread()->regionsHaveUniformLogicalHeight();
7165
// If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
7166
// still going to add a strut, so that the visible overflow fits on a single page.
7167
if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
7168
|| !hasNextPage(logicalOffset))
7170
LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
7171
if (remainingLogicalHeight < lineHeight) {
7172
// If we have a non-uniform page height, then we have to shift further possibly.
7173
if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
7175
if (lineHeight > pageLogicalHeight) {
7176
// Split the top margin in order to avoid splitting the visible part of the line.
7177
remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
7179
LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
7180
LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
7181
if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset && !isOutOfFlowPositioned() && !isTableCell())
7182
setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
7184
delta += remainingLogicalHeight;
7185
lineBox->setPaginationStrut(remainingLogicalHeight);
7186
lineBox->setIsFirstAfterPageBreak(true);
7188
} else if (remainingLogicalHeight == pageLogicalHeight && lineBox != firstRootBox())
7189
lineBox->setIsFirstAfterPageBreak(true);
7192
LayoutUnit RenderBlock::adjustBlockChildForPagination(LayoutUnit logicalTopAfterClear, LayoutUnit estimateWithoutPagination, RenderBox* child, bool atBeforeSideOfBlock)
7194
RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
7196
if (estimateWithoutPagination != logicalTopAfterClear) {
7197
// Our guess prior to pagination movement was wrong. Before we attempt to paginate, let's try again at the new
7199
setLogicalHeight(logicalTopAfterClear);
7200
setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
7202
if (child->shrinkToAvoidFloats()) {
7203
// The child's width depends on the line width.
7204
// When the child shifts to clear an item, its width can
7205
// change (because it has more available line width).
7206
// So go ahead and mark the item as dirty.
7207
child->setChildNeedsLayout(true, MarkOnlyThis);
7210
if (childRenderBlock) {
7211
if (!child->avoidsFloats() && childRenderBlock->containsFloats())
7212
childRenderBlock->markAllDescendantsWithFloatsForLayout();
7213
if (!child->needsLayout())
7214
child->markForPaginationRelayoutIfNeeded();
7217
// Our guess was wrong. Make the child lay itself out again.
7218
child->layoutIfNeeded();
7221
LayoutUnit oldTop = logicalTopAfterClear;
7223
// If the object has a page or column break value of "before", then we should shift to the top of the next page.
7224
LayoutUnit result = applyBeforeBreak(child, logicalTopAfterClear);
7226
// For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
7227
LayoutUnit logicalTopBeforeUnsplittableAdjustment = result;
7228
LayoutUnit logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, result);
7230
LayoutUnit paginationStrut = 0;
7231
LayoutUnit unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
7232
if (unsplittableAdjustmentDelta)
7233
paginationStrut = unsplittableAdjustmentDelta;
7234
else if (childRenderBlock && childRenderBlock->paginationStrut())
7235
paginationStrut = childRenderBlock->paginationStrut();
7237
if (paginationStrut) {
7238
// We are willing to propagate out to our parent block as long as we were at the top of the block prior
7239
// to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
7240
if (atBeforeSideOfBlock && oldTop == result && !isOutOfFlowPositioned() && !isTableCell()) {
7241
// FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
7242
// have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
7243
// and pushes to the next page anyway, so not too concerned about it.
7244
setPaginationStrut(result + paginationStrut);
7245
if (childRenderBlock)
7246
childRenderBlock->setPaginationStrut(0);
7248
result += paginationStrut;
7251
// Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
7252
setLogicalHeight(logicalHeight() + (result - oldTop));
7254
// Return the final adjusted logical top.
7258
bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta) const
7260
if (!inRenderFlowThread())
7263
RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
7264
// Just bail if we still don't have a region.
7265
if (!rootBox->hasContainingRegion() && !currentRegion)
7267
// Just bail if the region didn't change.
7268
if (rootBox->hasContainingRegion() && rootBox->containingRegion() == currentRegion)
7270
return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion, offsetFromLogicalTopOfFirstPage());
7273
LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
7275
LayoutState* layoutState = view()->layoutState();
7276
if (layoutState && !layoutState->isPaginated())
7279
// FIXME: Sanity check that the renderer in the layout state is ours, since otherwise the computation will be off.
7280
// Right now this assert gets hit inside computeLogicalHeight for percentage margins, since they're computed using
7281
// widths which can vary in each region. Until we patch that, we can't have this assert.
7282
// ASSERT(layoutState->m_renderer == this);
7284
LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
7285
return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
7287
// FIXME: Right now, this assert is hit outside layout, from logicalLeftSelectionOffset in selectionGapRectsForRepaint (called from FrameSelection::selectAll).
7288
// ASSERT(inRenderFlowThread());
7290
// FIXME: This is a slower path that doesn't use layout state and relies on getting your logical top inside the enclosing flow thread. It doesn't
7291
// work with columns or pages currently, but it should once they have been switched over to using flow threads.
7292
if (!inRenderFlowThread())
7295
const RenderBlock* currentBlock = this;
7296
LayoutRect blockRect(0, 0, width(), height());
7298
while (currentBlock && !currentBlock->isRenderFlowThread()) {
7299
RenderBlock* containerBlock = currentBlock->containingBlock();
7300
ASSERT(containerBlock);
7301
if (!containerBlock)
7303
LayoutPoint currentBlockLocation = currentBlock->location();
7305
if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
7306
// We have to put the block rect in container coordinates
7307
// and we have to take into account both the container and current block flipping modes
7308
if (containerBlock->style()->isFlippedBlocksWritingMode()) {
7309
if (containerBlock->isHorizontalWritingMode())
7310
blockRect.setY(currentBlock->height() - blockRect.maxY());
7312
blockRect.setX(currentBlock->width() - blockRect.maxX());
7314
currentBlock->flipForWritingMode(blockRect);
7316
blockRect.moveBy(currentBlockLocation);
7317
currentBlock = containerBlock;
7319
return currentBlock->isHorizontalWritingMode() ? blockRect.y() : blockRect.x();
7322
RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
7324
if (!inRenderFlowThread())
7327
RenderFlowThread* flowThread = enclosingRenderFlowThread();
7328
if (!flowThread || !flowThread->hasValidRegionInfo())
7331
return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
7334
void RenderBlock::setStaticInlinePositionForChild(RenderBox* child, LayoutUnit blockOffset, LayoutUnit inlinePosition)
7336
if (inRenderFlowThread()) {
7337
// Shift the inline position to exclude the region offset.
7338
inlinePosition += startOffsetForContent() - startOffsetForContent(blockOffset);
7340
child->layer()->setStaticInlinePosition(inlinePosition);
7343
bool RenderBlock::logicalWidthChangedInRegions() const
7345
if (!inRenderFlowThread())
7348
RenderFlowThread* flowThread = enclosingRenderFlowThread();
7349
if (!flowThread || !flowThread->hasValidRegionInfo())
7352
return flowThread->logicalWidthChangedInRegions(this, offsetFromLogicalTopOfFirstPage());
7355
RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
7357
ASSERT(region && inRenderFlowThread());
7359
// We need to clamp to the block, since we want any lines or blocks that overflow out of the
7360
// logical top or logical bottom of the block to size as though the border box in the first and
7361
// last regions extended infinitely. Otherwise the lines are going to size according to the regions
7362
// they overflow into, which makes no sense when this block doesn't exist in |region| at all.
7363
RenderRegion* startRegion;
7364
RenderRegion* endRegion;
7365
enclosingRenderFlowThread()->getRegionRangeForBox(this, startRegion, endRegion);
7367
if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
7369
if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
7375
LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
7377
// If the child has the same directionality as we do, then we can just return its
7378
// collapsed margin.
7379
if (!child->isWritingModeRoot())
7380
return child->collapsedMarginBefore();
7382
// The child has a different directionality. If the child is parallel, then it's just
7383
// flipped relative to us. We can use the collapsed margin for the opposite edge.
7384
if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
7385
return child->collapsedMarginAfter();
7387
// The child is perpendicular to us, which means its margins don't collapse but are on the
7388
// "logical left/right" sides of the child box. We can just return the raw margin in this case.
7389
return marginBeforeForChild(child);
7392
LayoutUnit RenderBlock::collapsedMarginAfterForChild(const RenderBox* child) const
7394
// If the child has the same directionality as we do, then we can just return its
7395
// collapsed margin.
7396
if (!child->isWritingModeRoot())
7397
return child->collapsedMarginAfter();
7399
// The child has a different directionality. If the child is parallel, then it's just
7400
// flipped relative to us. We can use the collapsed margin for the opposite edge.
7401
if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
7402
return child->collapsedMarginBefore();
7404
// The child is perpendicular to us, which means its margins don't collapse but are on the
7405
// "logical left/right" side of the child box. We can just return the raw margin in this case.
7406
return marginAfterForChild(child);
7409
RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child) const
7411
LayoutUnit childBeforePositive = 0;
7412
LayoutUnit childBeforeNegative = 0;
7413
LayoutUnit childAfterPositive = 0;
7414
LayoutUnit childAfterNegative = 0;
7416
LayoutUnit beforeMargin = 0;
7417
LayoutUnit afterMargin = 0;
7419
RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
7421
// If the child has the same directionality as we do, then we can just return its
7422
// margins in the same direction.
7423
if (!child->isWritingModeRoot()) {
7424
if (childRenderBlock) {
7425
childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
7426
childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
7427
childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
7428
childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
7430
beforeMargin = child->marginBefore();
7431
afterMargin = child->marginAfter();
7433
} else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
7434
// The child has a different directionality. If the child is parallel, then it's just
7435
// flipped relative to us. We can use the margins for the opposite edges.
7436
if (childRenderBlock) {
7437
childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
7438
childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
7439
childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
7440
childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
7442
beforeMargin = child->marginAfter();
7443
afterMargin = child->marginBefore();
7446
// The child is perpendicular to us, which means its margins don't collapse but are on the
7447
// "logical left/right" sides of the child box. We can just return the raw margin in this case.
7448
beforeMargin = marginBeforeForChild(child);
7449
afterMargin = marginAfterForChild(child);
7452
// Resolve uncollapsing margins into their positive/negative buckets.
7454
if (beforeMargin > 0)
7455
childBeforePositive = beforeMargin;
7457
childBeforeNegative = -beforeMargin;
7460
if (afterMargin > 0)
7461
childAfterPositive = afterMargin;
7463
childAfterNegative = -afterMargin;
7466
return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
7469
const char* RenderBlock::renderName() const
7472
return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
7475
return "RenderBlock (floating)";
7476
if (isOutOfFlowPositioned())
7477
return "RenderBlock (positioned)";
7478
if (isAnonymousColumnsBlock())
7479
return "RenderBlock (anonymous multi-column)";
7480
if (isAnonymousColumnSpanBlock())
7481
return "RenderBlock (anonymous multi-column span)";
7482
if (isAnonymousBlock())
7483
return "RenderBlock (anonymous)";
7484
else if (isAnonymous())
7485
return "RenderBlock (generated)";
7486
if (isRelPositioned())
7487
return "RenderBlock (relative positioned)";
7488
if (isStickyPositioned())
7489
return "RenderBlock (sticky positioned)";
7491
return "RenderBlock (run-in)";
7492
return "RenderBlock";
7495
inline void RenderBlock::FloatingObjects::clear()
7498
m_placedFloatsTree.clear();
7499
m_leftObjectsCount = 0;
7500
m_rightObjectsCount = 0;
7503
inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
7505
if (type == FloatingObject::FloatLeft)
7506
m_leftObjectsCount++;
7508
m_rightObjectsCount++;
7511
inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
7513
if (type == FloatingObject::FloatLeft)
7514
m_leftObjectsCount--;
7516
m_rightObjectsCount--;
7519
inline RenderBlock::FloatingObjectInterval RenderBlock::FloatingObjects::intervalForFloatingObject(FloatingObject* floatingObject)
7521
if (m_horizontalWritingMode)
7522
return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxY(), floatingObject);
7523
return RenderBlock::FloatingObjectInterval(floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject);
7526
void RenderBlock::FloatingObjects::addPlacedObject(FloatingObject* floatingObject)
7528
ASSERT(!floatingObject->isInPlacedTree());
7530
floatingObject->setIsPlaced(true);
7531
if (m_placedFloatsTree.isInitialized())
7532
m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
7535
floatingObject->setIsInPlacedTree(true);
7539
void RenderBlock::FloatingObjects::removePlacedObject(FloatingObject* floatingObject)
7541
ASSERT(floatingObject->isPlaced() && floatingObject->isInPlacedTree());
7543
if (m_placedFloatsTree.isInitialized()) {
7544
bool removed = m_placedFloatsTree.remove(intervalForFloatingObject(floatingObject));
7545
ASSERT_UNUSED(removed, removed);
7548
floatingObject->setIsPlaced(false);
7550
floatingObject->setIsInPlacedTree(false);
7554
inline void RenderBlock::FloatingObjects::add(FloatingObject* floatingObject)
7556
increaseObjectsCount(floatingObject->type());
7557
m_set.add(floatingObject);
7558
if (floatingObject->isPlaced())
7559
addPlacedObject(floatingObject);
7562
inline void RenderBlock::FloatingObjects::remove(FloatingObject* floatingObject)
7564
decreaseObjectsCount(floatingObject->type());
7565
m_set.remove(floatingObject);
7566
ASSERT(floatingObject->isPlaced() || !floatingObject->isInPlacedTree());
7567
if (floatingObject->isPlaced())
7568
removePlacedObject(floatingObject);
7571
void RenderBlock::FloatingObjects::computePlacedFloatsTree()
7573
ASSERT(!m_placedFloatsTree.isInitialized());
7574
if (m_set.isEmpty())
7576
m_placedFloatsTree.initIfNeeded(m_renderer->view()->intervalArena());
7577
FloatingObjectSetIterator it = m_set.begin();
7578
FloatingObjectSetIterator end = m_set.end();
7579
for (; it != end; ++it) {
7580
FloatingObject* floatingObject = *it;
7581
if (floatingObject->isPlaced())
7582
m_placedFloatsTree.add(intervalForFloatingObject(floatingObject));
7586
template <typename CharacterType>
7587
static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion)
7591
TextDirection textDirection = LTR;
7592
bool directionalOverride = style->rtlOrdering() == VisualOrder;
7594
TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride);
7595
if (textRunNeedsRenderingContext(font))
7596
run.setRenderingContext(SVGTextRunRenderingContext::create(context));
7601
template <typename CharacterType>
7602
static inline TextRun constructTextRunInternal(RenderObject* context, const Font& font, const CharacterType* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
7606
TextDirection textDirection = LTR;
7607
bool directionalOverride = style->rtlOrdering() == VisualOrder;
7608
if (flags != DefaultTextRunFlags) {
7609
if (flags & RespectDirection)
7610
textDirection = style->direction();
7611
if (flags & RespectDirectionOverride)
7612
directionalOverride |= isOverride(style->unicodeBidi());
7614
TextRun run(characters, length, 0, 0, expansion, textDirection, directionalOverride);
7615
if (textRunNeedsRenderingContext(font))
7616
run.setRenderingContext(SVGTextRunRenderingContext::create(context));
7621
#if ENABLE(8BIT_TEXTRUN)
7622
TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const LChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion)
7624
return constructTextRunInternal(context, font, characters, length, style, expansion);
7628
TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const UChar* characters, int length, RenderStyle* style, TextRun::ExpansionBehavior expansion)
7630
return constructTextRunInternal(context, font, characters, length, style, expansion);
7633
TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, RenderStyle* style, TextRun::ExpansionBehavior expansion)
7635
#if ENABLE(8BIT_TEXTRUN)
7637
return constructTextRunInternal(context, font, text->characters8(), text->textLength(), style, expansion);
7638
return constructTextRunInternal(context, font, text->characters16(), text->textLength(), style, expansion);
7640
return constructTextRunInternal(context, font, text->characters(), text->textLength(), style, expansion);
7644
TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const RenderText* text, unsigned offset, unsigned length, RenderStyle* style, TextRun::ExpansionBehavior expansion)
7646
ASSERT(offset + length <= text->textLength());
7647
#if ENABLE(8BIT_TEXTRUN)
7649
return constructTextRunInternal(context, font, text->characters8() + offset, length, style, expansion);
7650
return constructTextRunInternal(context, font, text->characters16() + offset, length, style, expansion);
7652
return constructTextRunInternal(context, font, text->characters() + offset, length, style, expansion);
7656
TextRun RenderBlock::constructTextRun(RenderObject* context, const Font& font, const String& string, RenderStyle* style, TextRun::ExpansionBehavior expansion, TextRunFlags flags)
7658
unsigned length = string.length();
7660
#if ENABLE(8BIT_TEXTRUN)
7661
if (length && string.is8Bit())
7662
return constructTextRunInternal(context, font, string.characters8(), length, style, expansion, flags);
7663
return constructTextRunInternal(context, font, string.characters(), length, style, expansion, flags);
7665
return constructTextRunInternal(context, font, string.characters(), length, style, expansion, flags);
7669
RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
7671
// FIXME: Do we need to cover the new flex box here ?
7672
// FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
7673
EDisplay newDisplay;
7674
RenderBlock* newBox = 0;
7675
if (display == BOX || display == INLINE_BOX) {
7676
newBox = new (parent->renderArena()) RenderDeprecatedFlexibleBox(parent->document() /* anonymous box */);
7679
newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7683
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay);
7684
newBox->setStyle(newStyle.release());
7688
RenderBlock* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent)
7690
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
7691
newStyle->inheritColumnPropertiesFrom(parent->style());
7693
RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7694
newBox->setStyle(newStyle.release());
7698
RenderBlock* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent)
7700
RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
7701
newStyle->setColumnSpan(ColumnSpanAll);
7703
RenderBlock* newBox = new (parent->renderArena()) RenderBlock(parent->document() /* anonymous box */);
7704
newBox->setStyle(newStyle.release());
7709
void RenderBlock::checkPositionedObjectsNeedLayout()
7711
if (!gPositionedDescendantsMap)
7714
if (TrackedRendererListHashSet* positionedDescendantSet = positionedObjects()) {
7715
TrackedRendererListHashSet::const_iterator end = positionedDescendantSet->end();
7716
for (TrackedRendererListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) {
7717
RenderBox* currBox = *it;
7718
ASSERT(!currBox->needsLayout());
7723
void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
7726
for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
7727
root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
7730
// These helpers are only used by the PODIntervalTree for debugging purposes.
7731
String ValueToString<int>::string(const int value)
7733
return String::number(value);
7736
String ValueToString<RenderBlock::FloatingObject*>::string(const RenderBlock::FloatingObject* floatingObject)
7738
return String::format("%p (%dx%d %dx%d)", floatingObject, floatingObject->frameRect().pixelSnappedX(), floatingObject->frameRect().pixelSnappedY(), floatingObject->frameRect().pixelSnappedMaxX(), floatingObject->frameRect().pixelSnappedMaxY());
7743
} // namespace WebCore