• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2007 David Smith (catfish.man@gmail.com)
5  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public License
18  * along with this library; see the file COPYING.LIB.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22 
23 #include "config.h"
24 #include "RenderBlock.h"
25 
26 #include "Document.h"
27 #include "Element.h"
28 #include "FloatQuad.h"
29 #include "Frame.h"
30 #include "FrameView.h"
31 #include "GraphicsContext.h"
32 #include "HTMLFormElement.h"
33 #include "HTMLNames.h"
34 #include "HitTestResult.h"
35 #include "InlineTextBox.h"
36 #include "RenderFlexibleBox.h"
37 #include "RenderImage.h"
38 #include "RenderInline.h"
39 #include "RenderMarquee.h"
40 #include "RenderReplica.h"
41 #include "RenderTableCell.h"
42 #include "RenderTextFragment.h"
43 #include "RenderTheme.h"
44 #include "RenderView.h"
45 #include "SelectionController.h"
46 #include "Settings.h"
47 #include "TransformState.h"
48 #include <wtf/StdLibExtras.h>
49 
50 #ifdef ANDROID_LAYOUT
51 #include "Settings.h"
52 #endif
53 
54 using namespace std;
55 using namespace WTF;
56 using namespace Unicode;
57 
58 namespace WebCore {
59 
60 // Number of pixels to allow as a fudge factor when clicking above or below a line.
61 // clicking up to verticalLineClickFudgeFactor pixels above a line will correspond to the closest point on the line.
62 static const int verticalLineClickFudgeFactor = 3;
63 
64 using namespace HTMLNames;
65 
66 struct ColumnInfo : public Noncopyable {
ColumnInfoWebCore::ColumnInfo67     ColumnInfo()
68         : m_desiredColumnWidth(0)
69         , m_desiredColumnCount(1)
70         { }
71     int m_desiredColumnWidth;
72     unsigned m_desiredColumnCount;
73     Vector<IntRect> m_columnRects;
74 };
75 
76 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
77 static ColumnInfoMap* gColumnInfoMap = 0;
78 
79 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
80 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
81 
82 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
83 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
84 
85 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
86 
87 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
88 static int gDelayUpdateScrollInfo = 0;
89 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
90 
91 // Our MarginInfo state used when laying out block children.
MarginInfo(RenderBlock * block,int top,int bottom)92 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int top, int bottom)
93 {
94     // Whether or not we can collapse our own margins with our children.  We don't do this
95     // if we had any border/padding (obviously), if we're the root or HTML elements, or if
96     // we're positioned, floating, a table cell.
97     m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned() &&
98         !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable();
99 
100     m_canCollapseTopWithChildren = m_canCollapseWithChildren && (top == 0) && block->style()->marginTopCollapse() != MSEPARATE;
101 
102     // If any height other than auto is specified in CSS, then we don't collapse our bottom
103     // margins with our children's margins.  To do otherwise would be to risk odd visual
104     // effects when the children overflow out of the parent block and yet still collapse
105     // with it.  We also don't collapse if we have any bottom border/padding.
106     m_canCollapseBottomWithChildren = m_canCollapseWithChildren && (bottom == 0) &&
107         (block->style()->height().isAuto() && block->style()->height().value() == 0) && block->style()->marginBottomCollapse() != MSEPARATE;
108 
109     m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginTopCollapse() == MDISCARD ||
110         block->style()->marginBottomCollapse() == MDISCARD;
111 
112     m_atTopOfBlock = true;
113     m_atBottomOfBlock = false;
114 
115     m_posMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(true) : 0;
116     m_negMargin = m_canCollapseTopWithChildren ? block->maxTopMargin(false) : 0;
117 
118     m_topQuirk = m_bottomQuirk = m_determinedTopQuirk = false;
119 }
120 
121 // -------------------------------------------------------------------------------------------------------
122 
RenderBlock(Node * node)123 RenderBlock::RenderBlock(Node* node)
124       : RenderBox(node)
125       , m_floatingObjects(0)
126       , m_positionedObjects(0)
127       , m_inlineContinuation(0)
128       , m_maxMargin(0)
129       , m_lineHeight(-1)
130 {
131     setChildrenInline(true);
132 }
133 
~RenderBlock()134 RenderBlock::~RenderBlock()
135 {
136     delete m_floatingObjects;
137     delete m_positionedObjects;
138     delete m_maxMargin;
139 
140     if (hasColumns())
141         delete gColumnInfoMap->take(this);
142 
143     if (gPercentHeightDescendantsMap) {
144         if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
145             HashSet<RenderBox*>::iterator end = descendantSet->end();
146             for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
147                 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
148                 ASSERT(containerSet);
149                 if (!containerSet)
150                     continue;
151                 ASSERT(containerSet->contains(this));
152                 containerSet->remove(this);
153                 if (containerSet->isEmpty()) {
154                     gPercentHeightContainerMap->remove(*descendant);
155                     delete containerSet;
156                 }
157             }
158             delete descendantSet;
159         }
160     }
161 }
162 
destroy()163 void RenderBlock::destroy()
164 {
165     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
166     // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
167     children()->destroyLeftoverChildren();
168 
169     // Destroy our continuation before anything other than anonymous children.
170     // The reason we don't destroy it before anonymous children is that they may
171     // have continuations of their own that are anonymous children of our continuation.
172     if (m_inlineContinuation) {
173         m_inlineContinuation->destroy();
174         m_inlineContinuation = 0;
175     }
176 
177     if (!documentBeingDestroyed()) {
178         if (firstLineBox()) {
179             // We can't wait for RenderBox::destroy to clear the selection,
180             // because by then we will have nuked the line boxes.
181             // FIXME: The SelectionController should be responsible for this when it
182             // is notified of DOM mutations.
183             if (isSelectionBorder())
184                 view()->clearSelection();
185 
186             // If we are an anonymous block, then our line boxes might have children
187             // that will outlast this block. In the non-anonymous block case those
188             // children will be destroyed by the time we return from this function.
189             if (isAnonymousBlock()) {
190                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextFlowBox()) {
191                     while (InlineBox* childBox = box->firstChild())
192                         childBox->remove();
193                 }
194             }
195         } else if (isInline() && parent())
196             parent()->dirtyLinesFromChangedChild(this);
197     }
198 
199     m_lineBoxes.deleteLineBoxes(renderArena());
200 
201     RenderBox::destroy();
202 }
203 
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)204 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
205 {
206     setReplaced(newStyle->isDisplayReplacedType());
207 
208     if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) {
209         if (newStyle->position() == StaticPosition)
210             // Clear our positioned objects list. Our absolutely positioned descendants will be
211             // inserted into our containing block's positioned objects list during layout.
212             removePositionedObjects(0);
213         else if (style()->position() == StaticPosition) {
214             // Remove our absolutely positioned descendants from their current containing block.
215             // They will be inserted into our positioned objects list during layout.
216             RenderObject* cb = parent();
217             while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
218                 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
219                     cb = cb->containingBlock();
220                     break;
221                 }
222                 cb = cb->parent();
223             }
224 
225             if (cb->isRenderBlock())
226                 toRenderBlock(cb)->removePositionedObjects(this);
227         }
228     }
229 
230     RenderBox::styleWillChange(diff, newStyle);
231 }
232 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)233 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
234 {
235     RenderBox::styleDidChange(diff, oldStyle);
236 
237     // FIXME: We could save this call when the change only affected non-inherited properties
238     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
239         if (child->isAnonymousBlock()) {
240             RefPtr<RenderStyle> newStyle = RenderStyle::create();
241             newStyle->inheritFrom(style());
242             newStyle->setDisplay(BLOCK);
243             child->setStyle(newStyle.release());
244         }
245     }
246 
247     m_lineHeight = -1;
248 
249     // Update pseudos for :before and :after now.
250     if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
251         updateBeforeAfterContent(BEFORE);
252         updateBeforeAfterContent(AFTER);
253     }
254     updateFirstLetter();
255 }
256 
updateBeforeAfterContent(PseudoId pseudoId)257 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
258 {
259     // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
260     if (parent() && parent()->createsAnonymousWrapper())
261         return;
262     return children()->updateBeforeAfterContent(this, pseudoId);
263 }
264 
addChild(RenderObject * newChild,RenderObject * beforeChild)265 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
266 {
267     // Make sure we don't append things after :after-generated content if we have it.
268     if (!beforeChild && isAfterContent(lastChild()))
269         beforeChild = lastChild();
270 
271     bool madeBoxesNonInline = false;
272 
273     // If the requested beforeChild is not one of our children, then this is because
274     // there is an anonymous container within this object that contains the beforeChild.
275     if (beforeChild && beforeChild->parent() != this) {
276         RenderObject* anonymousChild = beforeChild->parent();
277         ASSERT(anonymousChild);
278 
279         while (anonymousChild->parent() != this)
280             anonymousChild = anonymousChild->parent();
281 
282         ASSERT(anonymousChild->isAnonymous());
283 
284         if (anonymousChild->isAnonymousBlock()) {
285             // Insert the child into the anonymous block box instead of here.
286             if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
287                 beforeChild->parent()->addChild(newChild, beforeChild);
288             else
289                 addChild(newChild, beforeChild->parent());
290             return;
291         }
292 
293         ASSERT(anonymousChild->isTable());
294         if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
295                 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
296                 || newChild->isTableSection()
297                 || newChild->isTableRow()
298                 || newChild->isTableCell()) {
299             // Insert into the anonymous table.
300             anonymousChild->addChild(newChild, beforeChild);
301             return;
302         }
303 
304         // Go on to insert before the anonymous table.
305         beforeChild = anonymousChild;
306     }
307 
308     // A block has to either have all of its children inline, or all of its children as blocks.
309     // So, if our children are currently inline and a block child has to be inserted, we move all our
310     // inline children into anonymous block boxes.
311     if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
312         // This is a block with inline content. Wrap the inline content in anonymous blocks.
313         makeChildrenNonInline(beforeChild);
314         madeBoxesNonInline = true;
315 
316         if (beforeChild && beforeChild->parent() != this) {
317             beforeChild = beforeChild->parent();
318             ASSERT(beforeChild->isAnonymousBlock());
319             ASSERT(beforeChild->parent() == this);
320         }
321     } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
322         // If we're inserting an inline child but all of our children are blocks, then we have to make sure
323         // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
324         // a new one is created and inserted into our list of children in the appropriate position.
325         RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
326 
327         if (afterChild && afterChild->isAnonymousBlock()) {
328             afterChild->addChild(newChild);
329             return;
330         }
331 
332         if (newChild->isInline()) {
333             // No suitable existing anonymous box - create a new one.
334             RenderBlock* newBox = createAnonymousBlock();
335             RenderBox::addChild(newBox, beforeChild);
336             newBox->addChild(newChild);
337             return;
338         }
339     }
340 
341     RenderBox::addChild(newChild, beforeChild);
342 
343     if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
344         toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
345     // this object may be dead here
346 }
347 
getInlineRun(RenderObject * start,RenderObject * boundary,RenderObject * & inlineRunStart,RenderObject * & inlineRunEnd)348 static void getInlineRun(RenderObject* start, RenderObject* boundary,
349                          RenderObject*& inlineRunStart,
350                          RenderObject*& inlineRunEnd)
351 {
352     // Beginning at |start| we find the largest contiguous run of inlines that
353     // we can.  We denote the run with start and end points, |inlineRunStart|
354     // and |inlineRunEnd|.  Note that these two values may be the same if
355     // we encounter only one inline.
356     //
357     // We skip any non-inlines we encounter as long as we haven't found any
358     // inlines yet.
359     //
360     // |boundary| indicates a non-inclusive boundary point.  Regardless of whether |boundary|
361     // is inline or not, we will not include it in a run with inlines before it.  It's as though we encountered
362     // a non-inline.
363 
364     // Start by skipping as many non-inlines as we can.
365     RenderObject * curr = start;
366     bool sawInline;
367     do {
368         while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
369             curr = curr->nextSibling();
370 
371         inlineRunStart = inlineRunEnd = curr;
372 
373         if (!curr)
374             return; // No more inline children to be found.
375 
376         sawInline = curr->isInline();
377 
378         curr = curr->nextSibling();
379         while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
380             inlineRunEnd = curr;
381             if (curr->isInline())
382                 sawInline = true;
383             curr = curr->nextSibling();
384         }
385     } while (!sawInline);
386 }
387 
deleteLineBoxTree()388 void RenderBlock::deleteLineBoxTree()
389 {
390     m_lineBoxes.deleteLineBoxTree(renderArena());
391 }
392 
createRootInlineBox()393 RootInlineBox* RenderBlock::createRootInlineBox()
394 {
395     return new (renderArena()) RootInlineBox(this);
396 }
397 
createAndAppendRootInlineBox()398 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
399 {
400     RootInlineBox* rootBox = createRootInlineBox();
401     m_lineBoxes.appendLineBox(rootBox);
402     return rootBox;
403 }
404 
moveChildTo(RenderObject * to,RenderObjectChildList * toChildList,RenderObject * child)405 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* child)
406 {
407     ASSERT(this == child->parent());
408     toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false);
409 }
410 
moveChildTo(RenderObject * to,RenderObjectChildList * toChildList,RenderObject * beforeChild,RenderObject * child)411 void RenderBlock::moveChildTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild, RenderObject* child)
412 {
413     ASSERT(this == child->parent());
414     ASSERT(!beforeChild || to == beforeChild->parent());
415     toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
416 }
417 
moveAllChildrenTo(RenderObject * to,RenderObjectChildList * toChildList)418 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList)
419 {
420     RenderObject* nextChild = children()->firstChild();
421     while (nextChild) {
422         RenderObject* child = nextChild;
423         nextChild = child->nextSibling();
424         toChildList->appendChildNode(to, children()->removeChildNode(this, child, false), false);
425     }
426 }
427 
moveAllChildrenTo(RenderObject * to,RenderObjectChildList * toChildList,RenderObject * beforeChild)428 void RenderBlock::moveAllChildrenTo(RenderObject* to, RenderObjectChildList* toChildList, RenderObject* beforeChild)
429 {
430     ASSERT(!beforeChild || to == beforeChild->parent());
431     if (!beforeChild) {
432         moveAllChildrenTo(to, toChildList);
433         return;
434     }
435     RenderObject* nextChild = children()->firstChild();
436     while (nextChild) {
437         RenderObject* child = nextChild;
438         nextChild = child->nextSibling();
439         toChildList->insertChildNode(to, children()->removeChildNode(this, child, false), beforeChild, false);
440     }
441 }
442 
makeChildrenNonInline(RenderObject * insertionPoint)443 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
444 {
445     // makeChildrenNonInline takes a block whose children are *all* inline and it
446     // makes sure that inline children are coalesced under anonymous
447     // blocks.  If |insertionPoint| is defined, then it represents the insertion point for
448     // the new block child that is causing us to have to wrap all the inlines.  This
449     // means that we cannot coalesce inlines before |insertionPoint| with inlines following
450     // |insertionPoint|, because the new child is going to be inserted in between the inlines,
451     // splitting them.
452     ASSERT(isInlineBlockOrInlineTable() || !isInline());
453     ASSERT(!insertionPoint || insertionPoint->parent() == this);
454 
455     setChildrenInline(false);
456 
457     RenderObject *child = firstChild();
458     if (!child)
459         return;
460 
461     deleteLineBoxTree();
462 
463     while (child) {
464         RenderObject *inlineRunStart, *inlineRunEnd;
465         getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
466 
467         if (!inlineRunStart)
468             break;
469 
470         child = inlineRunEnd->nextSibling();
471 
472         RenderBlock* block = createAnonymousBlock();
473         children()->insertChildNode(this, block, inlineRunStart);
474         RenderObject* o = inlineRunStart;
475         while (o != inlineRunEnd) {
476             RenderObject* no = o;
477             o = no->nextSibling();
478 
479             moveChildTo(block, block->children(), no);
480         }
481         moveChildTo(block, block->children(), inlineRunEnd);
482     }
483 
484 #ifndef NDEBUG
485     for (RenderObject *c = firstChild(); c; c = c->nextSibling())
486         ASSERT(!c->isInline());
487 #endif
488 
489     repaint();
490 }
491 
removeLeftoverAnonymousBlock(RenderBlock * child)492 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
493 {
494     ASSERT(child->isAnonymousBlock());
495     ASSERT(!child->childrenInline());
496 
497     if (child->inlineContinuation())
498         return;
499 
500     RenderObject* firstAnChild = child->m_children.firstChild();
501     RenderObject* lastAnChild = child->m_children.lastChild();
502     if (firstAnChild) {
503         RenderObject* o = firstAnChild;
504         while (o) {
505             o->setParent(this);
506             o = o->nextSibling();
507         }
508         firstAnChild->setPreviousSibling(child->previousSibling());
509         lastAnChild->setNextSibling(child->nextSibling());
510         if (child->previousSibling())
511             child->previousSibling()->setNextSibling(firstAnChild);
512         if (child->nextSibling())
513             child->nextSibling()->setPreviousSibling(lastAnChild);
514     } else {
515         if (child->previousSibling())
516             child->previousSibling()->setNextSibling(child->nextSibling());
517         if (child->nextSibling())
518             child->nextSibling()->setPreviousSibling(child->previousSibling());
519     }
520     if (child == m_children.firstChild())
521         m_children.setFirstChild(firstAnChild);
522     if (child == m_children.lastChild())
523         m_children.setLastChild(lastAnChild);
524     child->setParent(0);
525     child->setPreviousSibling(0);
526     child->setNextSibling(0);
527 
528     child->children()->setFirstChild(0);
529     child->m_next = 0;
530 
531     child->destroy();
532 }
533 
removeChild(RenderObject * oldChild)534 void RenderBlock::removeChild(RenderObject* oldChild)
535 {
536     // If this child is a block, and if our previous and next siblings are
537     // both anonymous blocks with inline content, then we can go ahead and
538     // fold the inline content back together.
539     RenderObject* prev = oldChild->previousSibling();
540     RenderObject* next = oldChild->nextSibling();
541     bool canDeleteAnonymousBlocks = !documentBeingDestroyed() && !isInline() && !oldChild->isInline() &&
542                                     (!oldChild->isRenderBlock() || !toRenderBlock(oldChild)->inlineContinuation()) &&
543                                     (!prev || (prev->isAnonymousBlock() && prev->childrenInline())) &&
544                                     (!prev || (!prev->firstChild() || !prev->firstChild()->isInline() || !prev->firstChild()->isRunIn())) &&
545                                     (!next || (next->isAnonymousBlock() && next->childrenInline()));
546     if (canDeleteAnonymousBlocks && prev && next) {
547         // Take all the children out of the |next| block and put them in
548         // the |prev| block.
549         prev->setNeedsLayoutAndPrefWidthsRecalc();
550         RenderBlock* nextBlock = toRenderBlock(next);
551         RenderBlock* prevBlock = toRenderBlock(prev);
552         nextBlock->moveAllChildrenTo(prevBlock, prevBlock->children());
553         // Delete the now-empty block's lines and nuke it.
554         nextBlock->deleteLineBoxTree();
555         nextBlock->destroy();
556     }
557 
558     RenderBox::removeChild(oldChild);
559 
560     RenderObject* child = prev ? prev : next;
561     if (canDeleteAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
562         // The removal has knocked us down to containing only a single anonymous
563         // box.  We can go ahead and pull the content right back up into our
564         // box.
565         setNeedsLayoutAndPrefWidthsRecalc();
566         RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, false));
567         setChildrenInline(true);
568         anonBlock->moveAllChildrenTo(this, children());
569         // Delete the now-empty block's lines and nuke it.
570         anonBlock->deleteLineBoxTree();
571         anonBlock->destroy();
572     }
573 
574     // If this was our last child be sure to clear out our line boxes.
575     if (childrenInline() && !firstChild())
576         lineBoxes()->deleteLineBoxes(renderArena());
577 }
578 
isSelfCollapsingBlock() const579 bool RenderBlock::isSelfCollapsingBlock() const
580 {
581     // We are not self-collapsing if we
582     // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
583     // (b) are a table,
584     // (c) have border/padding,
585     // (d) have a min-height
586     // (e) have specified that one of our margins can't collapse using a CSS extension
587     if (height() > 0 ||
588         isTable() || (borderBottom() + paddingBottom() + borderTop() + paddingTop()) != 0 ||
589         style()->minHeight().isPositive() ||
590         style()->marginTopCollapse() == MSEPARATE || style()->marginBottomCollapse() == MSEPARATE)
591         return false;
592 
593     bool hasAutoHeight = style()->height().isAuto();
594     if (style()->height().isPercent() && !style()->htmlHacks()) {
595         hasAutoHeight = true;
596         for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
597             if (cb->style()->height().isFixed() || cb->isTableCell())
598                 hasAutoHeight = false;
599         }
600     }
601 
602     // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
603     // on whether we have content that is all self-collapsing or not.
604     if (hasAutoHeight || ((style()->height().isFixed() || style()->height().isPercent()) && style()->height().isZero())) {
605         // If the block has inline children, see if we generated any line boxes.  If we have any
606         // line boxes, then we can't be self-collapsing, since we have content.
607         if (childrenInline())
608             return !firstLineBox();
609 
610         // Whether or not we collapse is dependent on whether all our normal flow children
611         // are also self-collapsing.
612         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
613             if (child->isFloatingOrPositioned())
614                 continue;
615             if (!child->isSelfCollapsingBlock())
616                 return false;
617         }
618         return true;
619     }
620     return false;
621 }
622 
startDelayUpdateScrollInfo()623 void RenderBlock::startDelayUpdateScrollInfo()
624 {
625     if (gDelayUpdateScrollInfo == 0) {
626         ASSERT(!gDelayedUpdateScrollInfoSet);
627         gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
628     }
629     ASSERT(gDelayedUpdateScrollInfoSet);
630     ++gDelayUpdateScrollInfo;
631 }
632 
finishDelayUpdateScrollInfo()633 void RenderBlock::finishDelayUpdateScrollInfo()
634 {
635     --gDelayUpdateScrollInfo;
636     ASSERT(gDelayUpdateScrollInfo >= 0);
637     if (gDelayUpdateScrollInfo == 0) {
638         ASSERT(gDelayedUpdateScrollInfoSet);
639 
640         OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet);
641         gDelayedUpdateScrollInfoSet = 0;
642 
643         for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
644             RenderBlock* block = *it;
645             if (block->hasOverflowClip()) {
646                 block->layer()->updateScrollInfoAfterLayout();
647             }
648         }
649     }
650 }
651 
updateScrollInfoAfterLayout()652 void RenderBlock::updateScrollInfoAfterLayout()
653 {
654     if (hasOverflowClip()) {
655         if (gDelayUpdateScrollInfo)
656             gDelayedUpdateScrollInfoSet->add(this);
657         else
658             layer()->updateScrollInfoAfterLayout();
659     }
660 }
661 
layout()662 void RenderBlock::layout()
663 {
664     // Update our first letter info now.
665     updateFirstLetter();
666 
667     // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
668     // layoutBlock().
669     layoutBlock(false);
670 
671     // It's safe to check for control clip here, since controls can never be table cells.
672     // If we have a lightweight clip, there can never be any overflow from children.
673     if (hasControlClip() && m_overflow)
674         clearLayoutOverflow();
675 }
676 
layoutBlock(bool relayoutChildren)677 void RenderBlock::layoutBlock(bool relayoutChildren)
678 {
679     ASSERT(needsLayout());
680 
681     if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
682         return;                                      // cause us to come in here.  Just bail.
683 
684     if (!relayoutChildren && layoutOnlyPositionedObjects())
685         return;
686 
687     LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
688     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
689 
690     int oldWidth = width();
691     int oldColumnWidth = desiredColumnWidth();
692 
693 #ifdef ANDROID_LAYOUT
694     int oldVisibleWidth = m_visibleWidth;
695 #endif
696 
697     calcWidth();
698     calcColumnWidth();
699 
700     m_overflow.clear();
701 
702     if (oldWidth != width() || oldColumnWidth != desiredColumnWidth())
703         relayoutChildren = true;
704 
705 #ifdef ANDROID_LAYOUT
706     const Settings* settings = document()->settings();
707     ASSERT(settings);
708     if (oldVisibleWidth != m_visibleWidth
709             && settings->layoutAlgorithm() == Settings::kLayoutFitColumnToScreen)
710         relayoutChildren = true;
711 #endif
712 
713     clearFloats();
714 
715     int previousHeight = height();
716     setHeight(0);
717 
718     // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
719     // our current maximal positive and negative margins.  These values are used when we
720     // are collapsed with adjacent blocks, so for example, if you have block A and B
721     // collapsing together, then you'd take the maximal positive margin from both A and B
722     // and subtract it from the maximal negative margin from both A and B to get the
723     // true collapsed margin.  This algorithm is recursive, so when we finish layout()
724     // our block knows its current maximal positive/negative values.
725     //
726     // Start out by setting our margin values to our current margins.  Table cells have
727     // no margins, so we don't fill in the values for table cells.
728     bool isCell = isTableCell();
729     if (!isCell) {
730         initMaxMarginValues();
731 
732         setTopMarginQuirk(style()->marginTop().quirk());
733         setBottomMarginQuirk(style()->marginBottom().quirk());
734 
735         Node* n = node();
736         if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
737             // See if this form is malformed (i.e., unclosed). If so, don't give the form
738             // a bottom margin.
739             setMaxBottomMargins(0, 0);
740         }
741     }
742 
743     // For overflow:scroll blocks, ensure we have both scrollbars in place always.
744     if (scrollsOverflow()) {
745         if (style()->overflowX() == OSCROLL)
746             layer()->setHasHorizontalScrollbar(true);
747         if (style()->overflowY() == OSCROLL)
748             layer()->setHasVerticalScrollbar(true);
749     }
750 
751     int repaintTop = 0;
752     int repaintBottom = 0;
753     int maxFloatBottom = 0;
754     if (childrenInline())
755         layoutInlineChildren(relayoutChildren, repaintTop, repaintBottom);
756     else
757         layoutBlockChildren(relayoutChildren, maxFloatBottom);
758 
759     // Expand our intrinsic height to encompass floats.
760     int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
761     if (floatBottom() > (height() - toAdd) && expandsToEncloseOverhangingFloats())
762         setHeight(floatBottom() + toAdd);
763 
764     // Now lay out our columns within this intrinsic height, since they can slightly affect the intrinsic height as
765     // we adjust for clean column breaks.
766     int singleColumnBottom = layoutColumns();
767 
768     // Calculate our new height.
769     int oldHeight = height();
770     calcHeight();
771     if (oldHeight != height()) {
772         if (oldHeight > height() && maxFloatBottom > height() && !childrenInline()) {
773             // One of our children's floats may have become an overhanging float for us. We need to look for it.
774             for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
775                 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
776                     RenderBlock* block = toRenderBlock(child);
777                     if (block->floatBottom() + block->y() > height())
778                         addOverhangingFloats(block, -block->x(), -block->y(), false);
779                 }
780             }
781         }
782 
783         // We have to rebalance columns to the new height.
784         layoutColumns(singleColumnBottom);
785     }
786 
787     if (previousHeight != height())
788         relayoutChildren = true;
789 
790     // It's weird that we're treating float information as normal flow overflow, but we do this because floatRect() isn't
791     // able to be propagated up the render tree yet.  Overflow information is however.  This check is designed to catch anyone
792     // who wasn't going to propagate float information up to the parent and yet could potentially be painted by its ancestor.
793     if (isRoot() || expandsToEncloseOverhangingFloats())
794         addOverflowFromFloats();
795 
796     // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
797     if (!hasColumns()) {
798         if (childrenInline())
799             addOverflowFromInlineChildren();
800         else
801             addOverflowFromBlockChildren();
802     }
803 
804     // Add visual overflow from box-shadow and reflections.
805     addShadowOverflow();
806 
807     layoutPositionedObjects(relayoutChildren || isRoot());
808 
809     positionListMarker();
810 
811     statePusher.pop();
812 
813     // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
814     // we overflow or not.
815     updateScrollInfoAfterLayout();
816 
817     // Repaint with our new bounds if they are different from our old bounds.
818     bool didFullRepaint = repainter.repaintAfterLayout();
819     if (!didFullRepaint && repaintTop != repaintBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
820         int repaintLeft = min(leftVisualOverflow(), leftLayoutOverflow());
821         int repaintRight = max(rightVisualOverflow(), rightLayoutOverflow());
822         IntRect repaintRect(repaintLeft, repaintTop, repaintRight - repaintLeft, repaintBottom - repaintTop);
823 
824         // FIXME: Deal with multiple column repainting.  We have to split the repaint
825         // rect up into multiple rects if it spans columns.
826 
827         repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
828 
829         if (hasOverflowClip()) {
830             // Adjust repaint rect for scroll offset
831             int x = repaintRect.x();
832             int y = repaintRect.y();
833             layer()->subtractScrolledContentOffset(x, y);
834             repaintRect.setX(x);
835             repaintRect.setY(y);
836 
837             // Don't allow this rect to spill out of our overflow box.
838             repaintRect.intersect(IntRect(0, 0, width(), height()));
839         }
840 
841         // Make sure the rect is still non-empty after intersecting for overflow above
842         if (!repaintRect.isEmpty()) {
843             repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
844             if (hasReflection())
845                 repaintRectangle(reflectedRect(repaintRect));
846         }
847     }
848     setNeedsLayout(false);
849 }
850 
addOverflowFromBlockChildren()851 void RenderBlock::addOverflowFromBlockChildren()
852 {
853     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
854         if (!child->isFloatingOrPositioned())
855             addOverflowFromChild(child);
856     }
857 }
858 
addOverflowFromFloats()859 void RenderBlock::addOverflowFromFloats()
860 {
861     IntRect result;
862     if (!m_floatingObjects)
863         return;
864     FloatingObject* r;
865     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
866     for (; (r = it.current()); ++it) {
867         if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
868             addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
869     }
870     return;
871 }
872 
expandsToEncloseOverhangingFloats() const873 bool RenderBlock::expandsToEncloseOverhangingFloats() const
874 {
875     return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox()) || hasColumns() || isTableCell() || isFieldset();
876 }
877 
adjustPositionedBlock(RenderBox * child,const MarginInfo & marginInfo)878 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
879 {
880     if (child->style()->hasStaticX()) {
881         if (style()->direction() == LTR)
882             child->layer()->setStaticX(borderLeft() + paddingLeft());
883         else
884             child->layer()->setStaticX(borderRight() + paddingRight());
885     }
886 
887     if (child->style()->hasStaticY()) {
888         int y = height();
889         if (!marginInfo.canCollapseWithTop()) {
890             child->calcVerticalMargins();
891             int marginTop = child->marginTop();
892             int collapsedTopPos = marginInfo.posMargin();
893             int collapsedTopNeg = marginInfo.negMargin();
894             if (marginTop > 0) {
895                 if (marginTop > collapsedTopPos)
896                     collapsedTopPos = marginTop;
897             } else {
898                 if (-marginTop > collapsedTopNeg)
899                     collapsedTopNeg = -marginTop;
900             }
901             y += (collapsedTopPos - collapsedTopNeg) - marginTop;
902         }
903         RenderLayer* childLayer = child->layer();
904         if (childLayer->staticY() != y) {
905             child->layer()->setStaticY(y);
906             child->setChildNeedsLayout(true, false);
907         }
908     }
909 }
910 
adjustFloatingBlock(const MarginInfo & marginInfo)911 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
912 {
913     // The float should be positioned taking into account the bottom margin
914     // of the previous flow.  We add that margin into the height, get the
915     // float positioned properly, and then subtract the margin out of the
916     // height again.  In the case of self-collapsing blocks, we always just
917     // use the top margins, since the self-collapsing block collapsed its
918     // own bottom margin into its top margin.
919     //
920     // Note also that the previous flow may collapse its margin into the top of
921     // our block.  If this is the case, then we do not add the margin in to our
922     // height when computing the position of the float.   This condition can be tested
923     // for by simply calling canCollapseWithTop.  See
924     // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
925     // an example of this scenario.
926     int marginOffset = marginInfo.canCollapseWithTop() ? 0 : marginInfo.margin();
927     setHeight(height() + marginOffset);
928     positionNewFloats();
929     setHeight(height() - marginOffset);
930 }
931 
handleSpecialChild(RenderBox * child,const MarginInfo & marginInfo)932 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
933 {
934     // Handle in the given order
935     return handlePositionedChild(child, marginInfo)
936         || handleFloatingChild(child, marginInfo)
937         || handleRunInChild(child);
938 }
939 
940 
handlePositionedChild(RenderBox * child,const MarginInfo & marginInfo)941 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
942 {
943     if (child->isPositioned()) {
944         child->containingBlock()->insertPositionedObject(child);
945         adjustPositionedBlock(child, marginInfo);
946         return true;
947     }
948     return false;
949 }
950 
handleFloatingChild(RenderBox * child,const MarginInfo & marginInfo)951 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
952 {
953     if (child->isFloating()) {
954         insertFloatingObject(child);
955         adjustFloatingBlock(marginInfo);
956         return true;
957     }
958     return false;
959 }
960 
handleRunInChild(RenderBox * child)961 bool RenderBlock::handleRunInChild(RenderBox* child)
962 {
963     // See if we have a run-in element with inline children.  If the
964     // children aren't inline, then just treat the run-in as a normal
965     // block.
966     if (!child->isRunIn() || !child->childrenInline())
967         return false;
968     // FIXME: We don't handle non-block elements with run-in for now.
969     if (!child->isRenderBlock())
970         return false;
971 
972     // Get the next non-positioned/non-floating RenderBlock.
973     RenderBlock* blockRunIn = toRenderBlock(child);
974     RenderObject* curr = blockRunIn->nextSibling();
975     while (curr && curr->isFloatingOrPositioned())
976         curr = curr->nextSibling();
977 
978     if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous())
979         return false;
980 
981     RenderBlock* currBlock = toRenderBlock(curr);
982 
983     // Remove the old child.
984     children()->removeChildNode(this, blockRunIn);
985 
986     // Create an inline.
987     Node* runInNode = blockRunIn->node();
988     RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
989     inlineRunIn->setStyle(blockRunIn->style());
990 
991     bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER;
992 
993     // Move the nodes from the old child to the new child, but skip any :before/:after content.  It has already
994     // been regenerated by the new inline.
995     for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild; runInChild = runInChild->nextSibling()) {
996         if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) {
997             blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
998             inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
999         }
1000     }
1001 
1002     // Now insert the new child under |currBlock|.
1003     currBlock->children()->insertChildNode(currBlock, inlineRunIn, currBlock->firstChild());
1004 
1005     // If the run-in had an element, we need to set the new renderer.
1006     if (runInNode)
1007         runInNode->setRenderer(inlineRunIn);
1008 
1009     // Destroy the block run-in, which includes deleting its line box tree.
1010     blockRunIn->deleteLineBoxTree();
1011     blockRunIn->destroy();
1012 
1013     // The block acts like an inline, so just null out its
1014     // position.
1015 
1016     return true;
1017 }
1018 
collapseMargins(RenderBox * child,MarginInfo & marginInfo)1019 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1020 {
1021     // Get our max pos and neg top margins.
1022     int posTop = child->maxTopMargin(true);
1023     int negTop = child->maxTopMargin(false);
1024 
1025     // For self-collapsing blocks, collapse our bottom margins into our
1026     // top to get new posTop and negTop values.
1027     if (child->isSelfCollapsingBlock()) {
1028         posTop = max(posTop, child->maxBottomMargin(true));
1029         negTop = max(negTop, child->maxBottomMargin(false));
1030     }
1031 
1032     // See if the top margin is quirky. We only care if this child has
1033     // margins that will collapse with us.
1034     bool topQuirk = child->isTopMarginQuirk() || style()->marginTopCollapse() == MDISCARD;
1035 
1036     if (marginInfo.canCollapseWithTop()) {
1037         // This child is collapsing with the top of the
1038         // block.  If it has larger margin values, then we need to update
1039         // our own maximal values.
1040         if (!style()->htmlHacks() || !marginInfo.quirkContainer() || !topQuirk)
1041             setMaxTopMargins(max(posTop, maxTopPosMargin()), max(negTop, maxTopNegMargin()));
1042 
1043         // The minute any of the margins involved isn't a quirk, don't
1044         // collapse it away, even if the margin is smaller (www.webreference.com
1045         // has an example of this, a <dt> with 0.8em author-specified inside
1046         // a <dl> inside a <td>.
1047         if (!marginInfo.determinedTopQuirk() && !topQuirk && (posTop-negTop)) {
1048             setTopMarginQuirk(false);
1049             marginInfo.setDeterminedTopQuirk(true);
1050         }
1051 
1052         if (!marginInfo.determinedTopQuirk() && topQuirk && marginTop() == 0)
1053             // We have no top margin and our top child has a quirky margin.
1054             // We will pick up this quirky margin and pass it through.
1055             // This deals with the <td><div><p> case.
1056             // Don't do this for a block that split two inlines though.  You do
1057             // still apply margins in this case.
1058             setTopMarginQuirk(true);
1059     }
1060 
1061     if (marginInfo.quirkContainer() && marginInfo.atTopOfBlock() && (posTop - negTop))
1062         marginInfo.setTopQuirk(topQuirk);
1063 
1064     int ypos = height();
1065     if (child->isSelfCollapsingBlock()) {
1066         // This child has no height.  We need to compute our
1067         // position before we collapse the child's margins together,
1068         // so that we can get an accurate position for the zero-height block.
1069         int collapsedTopPos = max(marginInfo.posMargin(), child->maxTopMargin(true));
1070         int collapsedTopNeg = max(marginInfo.negMargin(), child->maxTopMargin(false));
1071         marginInfo.setMargin(collapsedTopPos, collapsedTopNeg);
1072 
1073         // Now collapse the child's margins together, which means examining our
1074         // bottom margin values as well.
1075         marginInfo.setPosMarginIfLarger(child->maxBottomMargin(true));
1076         marginInfo.setNegMarginIfLarger(child->maxBottomMargin(false));
1077 
1078         if (!marginInfo.canCollapseWithTop())
1079             // We need to make sure that the position of the self-collapsing block
1080             // is correct, since it could have overflowing content
1081             // that needs to be positioned correctly (e.g., a block that
1082             // had a specified height of 0 but that actually had subcontent).
1083             ypos = height() + collapsedTopPos - collapsedTopNeg;
1084     }
1085     else {
1086         if (child->style()->marginTopCollapse() == MSEPARATE) {
1087             setHeight(height() + marginInfo.margin() + child->marginTop());
1088             ypos = height();
1089         }
1090         else if (!marginInfo.atTopOfBlock() ||
1091             (!marginInfo.canCollapseTopWithChildren()
1092              && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.topQuirk()))) {
1093             // We're collapsing with a previous sibling's margins and not
1094             // with the top of the block.
1095             setHeight(height() + max(marginInfo.posMargin(), posTop) - max(marginInfo.negMargin(), negTop));
1096             ypos = height();
1097         }
1098 
1099         marginInfo.setPosMargin(child->maxBottomMargin(true));
1100         marginInfo.setNegMargin(child->maxBottomMargin(false));
1101 
1102         if (marginInfo.margin())
1103             marginInfo.setBottomQuirk(child->isBottomMarginQuirk() || style()->marginBottomCollapse() == MDISCARD);
1104     }
1105 
1106     return ypos;
1107 }
1108 
clearFloatsIfNeeded(RenderBox * child,MarginInfo & marginInfo,int oldTopPosMargin,int oldTopNegMargin,int yPos)1109 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
1110 {
1111     int heightIncrease = getClearDelta(child, yPos);
1112     if (!heightIncrease)
1113         return yPos;
1114 
1115     if (child->isSelfCollapsingBlock()) {
1116         // For self-collapsing blocks that clear, they can still collapse their
1117         // margins with following siblings.  Reset the current margins to represent
1118         // the self-collapsing block's margins only.
1119         // CSS2.1 states:
1120         // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1121         // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1122         // self-collapsing block's bottom margin.
1123         bool atBottomOfBlock = true;
1124         for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1125             if (!curr->isFloatingOrPositioned())
1126                 atBottomOfBlock = false;
1127         }
1128         if (atBottomOfBlock) {
1129             marginInfo.setPosMargin(child->maxBottomMargin(true));
1130             marginInfo.setNegMargin(child->maxBottomMargin(false));
1131         } else {
1132             marginInfo.setPosMargin(max(child->maxTopMargin(true), child->maxBottomMargin(true)));
1133             marginInfo.setNegMargin(max(child->maxTopMargin(false), child->maxBottomMargin(false)));
1134         }
1135 
1136         // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1137         // of the parent block).
1138         setHeight(child->y() - max(0, marginInfo.margin()));
1139     } else
1140         // Increase our height by the amount we had to clear.
1141         setHeight(height() + heightIncrease);
1142 
1143     if (marginInfo.canCollapseWithTop()) {
1144         // We can no longer collapse with the top of the block since a clear
1145         // occurred.  The empty blocks collapse into the cleared block.
1146         // FIXME: This isn't quite correct.  Need clarification for what to do
1147         // if the height the cleared block is offset by is smaller than the
1148         // margins involved.
1149         setMaxTopMargins(oldTopPosMargin, oldTopNegMargin);
1150         marginInfo.setAtTopOfBlock(false);
1151     }
1152 
1153     return yPos + heightIncrease;
1154 }
1155 
estimateVerticalPosition(RenderBox * child,const MarginInfo & marginInfo)1156 int RenderBlock::estimateVerticalPosition(RenderBox* child, const MarginInfo& marginInfo)
1157 {
1158     // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1159     // relayout if there are intruding floats.
1160     int yPosEstimate = height();
1161     if (!marginInfo.canCollapseWithTop()) {
1162         int childMarginTop = child->selfNeedsLayout() ? child->marginTop() : child->collapsedMarginTop();
1163         yPosEstimate += max(marginInfo.margin(), childMarginTop);
1164     }
1165     yPosEstimate += getClearDelta(child, yPosEstimate);
1166     return yPosEstimate;
1167 }
1168 
determineHorizontalPosition(RenderBox * child)1169 void RenderBlock::determineHorizontalPosition(RenderBox* child)
1170 {
1171     if (style()->direction() == LTR) {
1172         int xPos = borderLeft() + paddingLeft();
1173 
1174         // Add in our left margin.
1175         int chPos = xPos + child->marginLeft();
1176 
1177         // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
1178         // to shift over as necessary to dodge any floats that might get in the way.
1179         if (child->avoidsFloats()) {
1180             int leftOff = leftOffset(height(), false);
1181             if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginLeft().type() != Auto) {
1182                 if (child->marginLeft() < 0)
1183                     leftOff += child->marginLeft();
1184                 chPos = max(chPos, leftOff); // Let the float sit in the child's margin if it can fit.
1185             }
1186             else if (leftOff != xPos) {
1187                 // The object is shifting right. The object might be centered, so we need to
1188                 // recalculate our horizontal margins. Note that the containing block content
1189                 // width computation will take into account the delta between |leftOff| and |xPos|
1190                 // so that we can just pass the content width in directly to the |calcHorizontalMargins|
1191                 // function.
1192                 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
1193                 chPos = leftOff + child->marginLeft();
1194             }
1195         }
1196         view()->addLayoutDelta(IntSize(child->x() - chPos, 0));
1197         child->setLocation(chPos, child->y());
1198     } else {
1199         int xPos = width() - borderRight() - paddingRight() - verticalScrollbarWidth();
1200         int chPos = xPos - (child->width() + child->marginRight());
1201         if (child->avoidsFloats()) {
1202             int rightOff = rightOffset(height(), false);
1203             if (style()->textAlign() != WEBKIT_CENTER && child->style()->marginRight().type() != Auto) {
1204                 if (child->marginRight() < 0)
1205                     rightOff -= child->marginRight();
1206                 chPos = min(chPos, rightOff - child->width()); // Let the float sit in the child's margin if it can fit.
1207             } else if (rightOff != xPos) {
1208                 // The object is shifting left. The object might be centered, so we need to
1209                 // recalculate our horizontal margins. Note that the containing block content
1210                 // width computation will take into account the delta between |rightOff| and |xPos|
1211                 // so that we can just pass the content width in directly to the |calcHorizontalMargins|
1212                 // function.
1213                 child->calcHorizontalMargins(child->style()->marginLeft(), child->style()->marginRight(), lineWidth(child->y(), false));
1214                 chPos = rightOff - child->marginRight() - child->width();
1215             }
1216         }
1217         view()->addLayoutDelta(IntSize(child->x() - chPos, 0));
1218         child->setLocation(chPos, child->y());
1219     }
1220 }
1221 
setCollapsedBottomMargin(const MarginInfo & marginInfo)1222 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1223 {
1224     if (marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()) {
1225         // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1226         // with our children.
1227         setMaxBottomMargins(max(maxBottomPosMargin(), marginInfo.posMargin()), max(maxBottomNegMargin(), marginInfo.negMargin()));
1228 
1229         if (!marginInfo.bottomQuirk())
1230             setBottomMarginQuirk(false);
1231 
1232         if (marginInfo.bottomQuirk() && marginBottom() == 0)
1233             // We have no bottom margin and our last child has a quirky margin.
1234             // We will pick up this quirky margin and pass it through.
1235             // This deals with the <td><div><p> case.
1236             setBottomMarginQuirk(true);
1237     }
1238 }
1239 
handleBottomOfBlock(int top,int bottom,MarginInfo & marginInfo)1240 void RenderBlock::handleBottomOfBlock(int top, int bottom, MarginInfo& marginInfo)
1241 {
1242     marginInfo.setAtBottomOfBlock(true);
1243 
1244     // If we can't collapse with children then go ahead and add in the bottom margin.
1245     if (!marginInfo.canCollapseWithBottom() && !marginInfo.canCollapseWithTop()
1246         && (!style()->htmlHacks() || !marginInfo.quirkContainer() || !marginInfo.bottomQuirk()))
1247         setHeight(height() + marginInfo.margin());
1248 
1249     // Now add in our bottom border/padding.
1250     setHeight(height() + bottom);
1251 
1252     // Negative margins can cause our height to shrink below our minimal height (border/padding).
1253     // If this happens, ensure that the computed height is increased to the minimal height.
1254     setHeight(max(height(), top + bottom));
1255 
1256     // Update our bottom collapsed margin info.
1257     setCollapsedBottomMargin(marginInfo);
1258 }
1259 
layoutBlockChildren(bool relayoutChildren,int & maxFloatBottom)1260 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatBottom)
1261 {
1262     if (gPercentHeightDescendantsMap) {
1263         if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
1264             HashSet<RenderBox*>::iterator end = descendants->end();
1265             for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
1266                 RenderBox* box = *it;
1267                 while (box != this) {
1268                     if (box->normalChildNeedsLayout())
1269                         break;
1270                     box->setChildNeedsLayout(true, false);
1271                     box = box->containingBlock();
1272                     ASSERT(box);
1273                     if (!box)
1274                         break;
1275                 }
1276             }
1277         }
1278     }
1279 
1280     int top = borderTop() + paddingTop();
1281     int bottom = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
1282 
1283     setHeight(top);
1284 
1285     // The margin struct caches all our current margin collapsing state.  The compact struct caches state when we encounter compacts,
1286     MarginInfo marginInfo(this, top, bottom);
1287 
1288     // Fieldsets need to find their legend and position it inside the border of the object.
1289     // The legend then gets skipped during normal layout.
1290     RenderObject* legend = layoutLegend(relayoutChildren);
1291 
1292     int previousFloatBottom = 0;
1293     maxFloatBottom = 0;
1294 
1295     RenderBox* next = firstChildBox();
1296 
1297     while (next) {
1298         RenderBox* child = next;
1299         next = child->nextSiblingBox();
1300 
1301         if (legend == child)
1302             continue; // Skip the legend, since it has already been positioned up in the fieldset's border.
1303 
1304         // Make sure we layout children if they need it.
1305         // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1306         // an auto value.  Add a method to determine this, so that we can avoid the relayout.
1307         if (relayoutChildren || ((child->style()->height().isPercent() || child->style()->minHeight().isPercent() || child->style()->maxHeight().isPercent()) && !isRenderView()))
1308             child->setChildNeedsLayout(true, false);
1309 
1310         // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
1311         if (relayoutChildren && (child->style()->paddingLeft().isPercent() || child->style()->paddingRight().isPercent()))
1312             child->setPrefWidthsDirty(true, false);
1313 
1314         // Handle the four types of special elements first.  These include positioned content, floating content, compacts and
1315         // run-ins.  When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
1316         if (handleSpecialChild(child, marginInfo))
1317             continue;
1318 
1319         // Lay out the child.
1320         layoutBlockChild(child, marginInfo, previousFloatBottom, maxFloatBottom);
1321     }
1322 
1323     // Now do the handling of the bottom of the block, adding in our bottom border/padding and
1324     // determining the correct collapsed bottom margin information.
1325     handleBottomOfBlock(top, bottom, marginInfo);
1326 }
1327 
layoutBlockChild(RenderBox * child,MarginInfo & marginInfo,int & previousFloatBottom,int & maxFloatBottom)1328 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatBottom, int& maxFloatBottom)
1329 {
1330     int oldTopPosMargin = maxTopPosMargin();
1331     int oldTopNegMargin = maxTopNegMargin();
1332 
1333     // The child is a normal flow object.  Compute its vertical margins now.
1334     child->calcVerticalMargins();
1335 
1336     // Do not allow a collapse if the margin top collapse style is set to SEPARATE.
1337     if (child->style()->marginTopCollapse() == MSEPARATE) {
1338         marginInfo.setAtTopOfBlock(false);
1339         marginInfo.clearMargin();
1340     }
1341 
1342     // Try to guess our correct y position.  In most cases this guess will
1343     // be correct.  Only if we're wrong (when we compute the real y position)
1344     // will we have to potentially relayout.
1345     int yPosEstimate = estimateVerticalPosition(child, marginInfo);
1346 
1347     // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
1348     IntRect oldRect(child->x(), child->y() , child->width(), child->height());
1349 #ifndef NDEBUG
1350     IntSize oldLayoutDelta = view()->layoutDelta();
1351 #endif
1352     // Go ahead and position the child as though it didn't collapse with the top.
1353     view()->addLayoutDelta(IntSize(0, child->y() - yPosEstimate));
1354     child->setLocation(child->x(), yPosEstimate);
1355 
1356     bool markDescendantsWithFloats = false;
1357     if (yPosEstimate != oldRect.y() && !child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
1358         markDescendantsWithFloats = true;
1359     else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
1360         // If an element might be affected by the presence of floats, then always mark it for
1361         // layout.
1362         int fb = max(previousFloatBottom, floatBottom());
1363         if (fb > yPosEstimate)
1364             markDescendantsWithFloats = true;
1365     }
1366 
1367     if (child->isRenderBlock()) {
1368         if (markDescendantsWithFloats)
1369             toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
1370 
1371         previousFloatBottom = max(previousFloatBottom, oldRect.y() + toRenderBlock(child)->floatBottom());
1372     }
1373 
1374     bool childHadLayout = child->m_everHadLayout;
1375     bool childNeededLayout = child->needsLayout();
1376     if (childNeededLayout)
1377         child->layout();
1378 
1379     // Now determine the correct ypos based off examination of collapsing margin
1380     // values.
1381     int yBeforeClear = collapseMargins(child, marginInfo);
1382 
1383     // Now check for clear.
1384     int yAfterClear = clearFloatsIfNeeded(child, marginInfo, oldTopPosMargin, oldTopNegMargin, yBeforeClear);
1385 
1386     view()->addLayoutDelta(IntSize(0, yPosEstimate - yAfterClear));
1387     child->setLocation(child->x(), yAfterClear);
1388 
1389     // Now we have a final y position.  See if it really does end up being different from our estimate.
1390     if (yAfterClear != yPosEstimate) {
1391         if (child->shrinkToAvoidFloats()) {
1392             // The child's width depends on the line width.
1393             // When the child shifts to clear an item, its width can
1394             // change (because it has more available line width).
1395             // So go ahead and mark the item as dirty.
1396             child->setChildNeedsLayout(true, false);
1397         }
1398         if (!child->avoidsFloats() && child->isBlockFlow() && toRenderBlock(child)->containsFloats())
1399             toRenderBlock(child)->markAllDescendantsWithFloatsForLayout();
1400         // Our guess was wrong. Make the child lay itself out again.
1401         child->layoutIfNeeded();
1402     }
1403 
1404     // We are no longer at the top of the block if we encounter a non-empty child.
1405     // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
1406     if (marginInfo.atTopOfBlock() && !child->isSelfCollapsingBlock())
1407         marginInfo.setAtTopOfBlock(false);
1408 
1409     // Now place the child in the correct horizontal position
1410     determineHorizontalPosition(child);
1411 
1412     // Update our height now that the child has been placed in the correct position.
1413     setHeight(height() + child->height());
1414     if (child->style()->marginBottomCollapse() == MSEPARATE) {
1415         setHeight(height() + child->marginBottom());
1416         marginInfo.clearMargin();
1417     }
1418     // If the child has overhanging floats that intrude into following siblings (or possibly out
1419     // of this block), then the parent gets notified of the floats now.
1420     if (child->isBlockFlow() && toRenderBlock(child)->containsFloats())
1421         maxFloatBottom = max(maxFloatBottom, addOverhangingFloats(toRenderBlock(child), -child->x(), -child->y(), !childNeededLayout));
1422 
1423     IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
1424     if (childOffset.width() || childOffset.height()) {
1425         view()->addLayoutDelta(childOffset);
1426 
1427         // If the child moved, we have to repaint it as well as any floating/positioned
1428         // descendants.  An exception is if we need a layout.  In this case, we know we're going to
1429         // repaint ourselves (and the child) anyway.
1430         if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
1431             child->repaintDuringLayoutIfMoved(oldRect);
1432     }
1433 
1434     if (!childHadLayout && child->checkForRepaintDuringLayout()) {
1435         child->repaint();
1436         child->repaintOverhangingFloats(true);
1437     }
1438 
1439     ASSERT(oldLayoutDelta == view()->layoutDelta());
1440 }
1441 
layoutOnlyPositionedObjects()1442 bool RenderBlock::layoutOnlyPositionedObjects()
1443 {
1444     if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
1445         return false;
1446 
1447     LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection());
1448 
1449     if (needsPositionedMovementLayout()) {
1450         tryLayoutDoingPositionedMovementOnly();
1451         if (needsLayout())
1452             return false;
1453     }
1454 
1455     // All we have to is lay out our positioned objects.
1456     layoutPositionedObjects(false);
1457 
1458     statePusher.pop();
1459 
1460     updateScrollInfoAfterLayout();
1461 
1462 #ifdef ANDROID_FIX
1463     // iframe flatten will call FrameView::layout() which calls performPostLayoutTasks,
1464     // which may make us need to layout again
1465     if (!posChildNeedsLayout() || normalChildNeedsLayout() || selfNeedsLayout())
1466         return false;
1467 #endif
1468 
1469     setNeedsLayout(false);
1470     return true;
1471 }
1472 
layoutPositionedObjects(bool relayoutChildren)1473 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
1474 {
1475     if (m_positionedObjects) {
1476         RenderBox* r;
1477         Iterator end = m_positionedObjects->end();
1478         for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1479             r = *it;
1480             // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
1481             // non-positioned block.  Rather than trying to detect all of these movement cases, we just always lay out positioned
1482             // objects that are positioned implicitly like this.  Such objects are rare, and so in typical DHTML menu usage (where everything is
1483             // positioned explicitly) this should not incur a performance penalty.
1484             if (relayoutChildren || (r->style()->hasStaticY() && r->parent() != this && r->parent()->isBlockFlow()))
1485                 r->setChildNeedsLayout(true, false);
1486 
1487             // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
1488             //if (relayoutChildren && (r->style()->paddingLeft().isPercent() || r->style()->paddingRight().isPercent()))
1489                 r->setPrefWidthsDirty(true, false);
1490 
1491             // 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
1492             // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
1493             if (r->needsPositionedMovementLayoutOnly())
1494                 r->tryLayoutDoingPositionedMovementOnly();
1495             r->layoutIfNeeded();
1496         }
1497     }
1498 }
1499 
markPositionedObjectsForLayout()1500 void RenderBlock::markPositionedObjectsForLayout()
1501 {
1502     if (m_positionedObjects) {
1503         RenderBox* r;
1504         Iterator end = m_positionedObjects->end();
1505         for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1506             r = *it;
1507             r->setChildNeedsLayout(true);
1508         }
1509     }
1510 }
1511 
repaintOverhangingFloats(bool paintAllDescendants)1512 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
1513 {
1514     // Repaint any overhanging floats (if we know we're the one to paint them).
1515     if (hasOverhangingFloats()) {
1516         // We think that we must be in a bad state if m_floatingObjects is nil at this point, so
1517         // we assert on Debug builds and nil-check Release builds.
1518         ASSERT(m_floatingObjects);
1519         if (!m_floatingObjects)
1520             return;
1521 
1522         FloatingObject* r;
1523         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
1524 
1525         // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
1526         // in this block. Better yet would be to push extra state for the containers of other floats.
1527         view()->disableLayoutState();
1528         for ( ; (r = it.current()); ++it) {
1529             // Only repaint the object if it is overhanging, is not in its own layer, and
1530             // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
1531             // condition is replaced with being a descendant of us.
1532             if (r->m_bottom > height() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
1533                 r->m_renderer->repaint();
1534                 r->m_renderer->repaintOverhangingFloats();
1535             }
1536         }
1537         view()->enableLayoutState();
1538     }
1539 }
1540 
paint(PaintInfo & paintInfo,int tx,int ty)1541 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
1542 {
1543     tx += x();
1544     ty += y();
1545 
1546     PaintPhase phase = paintInfo.phase;
1547 
1548     // Check if we need to do anything at all.
1549     // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
1550     // paints the root's background.
1551     if (!isRoot()) {
1552         IntRect overflowBox = visibleOverflowRect();
1553         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
1554         overflowBox.move(tx, ty);
1555         if (!overflowBox.intersects(paintInfo.rect))
1556             return;
1557     }
1558 
1559     bool pushedClip = pushContentsClip(paintInfo, tx, ty);
1560     paintObject(paintInfo, tx, ty);
1561     if (pushedClip)
1562         popContentsClip(paintInfo, phase, tx, ty);
1563 
1564     // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1565     // z-index.  We paint after we painted the background/border, so that the scrollbars will
1566     // sit above the background/border.
1567     if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && shouldPaintWithinRoot(paintInfo))
1568         layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect);
1569 }
1570 
paintColumnRules(PaintInfo & paintInfo,int tx,int ty)1571 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
1572 {
1573     const Color& ruleColor = style()->columnRuleColor();
1574     bool ruleTransparent = style()->columnRuleIsTransparent();
1575     EBorderStyle ruleStyle = style()->columnRuleStyle();
1576     int ruleWidth = style()->columnRuleWidth();
1577     int colGap = columnGap();
1578     bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
1579     if (!renderRule)
1580         return;
1581 
1582     // We need to do multiple passes, breaking up our child painting into strips.
1583     int currXOffset = 0;
1584     int ruleAdd = borderLeft() + paddingLeft();
1585     int ruleX = 0;
1586     Vector<IntRect>* colRects = columnRects();
1587     unsigned colCount = colRects->size();
1588     for (unsigned i = 0; i < colCount; i++) {
1589         // For each rect, we clip to the rect, and then we adjust our coords.
1590         IntRect colRect = colRects->at(i);
1591 
1592         // Move to the next position.
1593         if (style()->direction() == LTR) {
1594             ruleX += colRect.width() + colGap / 2;
1595             currXOffset += colRect.width() + colGap;
1596         } else {
1597             ruleX -= (colRect.width() + colGap / 2);
1598             currXOffset -= (colRect.width() + colGap);
1599         }
1600 
1601         // Now paint the column rule.
1602         if (i < colCount - 1) {
1603             int ruleStart = tx + ruleX - ruleWidth / 2 + ruleAdd;
1604             int ruleEnd = ruleStart + ruleWidth;
1605             int ruleTop = ty + borderTop() + paddingTop();
1606             int ruleBottom = ruleTop + contentHeight();
1607             drawLineForBoxSide(paintInfo.context, ruleStart, ruleTop, ruleEnd, ruleBottom,
1608                                style()->direction() == LTR ? BSLeft : BSRight, ruleColor, style()->color(), ruleStyle, 0, 0);
1609         }
1610 
1611         ruleX = currXOffset;
1612     }
1613 }
1614 
paintColumnContents(PaintInfo & paintInfo,int tx,int ty,bool paintingFloats)1615 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats)
1616 {
1617     // We need to do multiple passes, breaking up our child painting into strips.
1618     GraphicsContext* context = paintInfo.context;
1619     int currXOffset = 0;
1620     int currYOffset = 0;
1621     int colGap = columnGap();
1622     Vector<IntRect>* colRects = columnRects();
1623     unsigned colCount = colRects->size();
1624     for (unsigned i = 0; i < colCount; i++) {
1625         // For each rect, we clip to the rect, and then we adjust our coords.
1626         IntRect colRect = colRects->at(i);
1627         colRect.move(tx, ty);
1628         context->save();
1629 
1630         // Each strip pushes a clip, since column boxes are specified as being
1631         // like overflow:hidden.
1632         context->clip(colRect);
1633 
1634         // Adjust tx and ty to change where we paint.
1635         PaintInfo info(paintInfo);
1636         info.rect.intersect(colRect);
1637 
1638         // Adjust our x and y when painting.
1639         int finalX = tx + currXOffset;
1640         int finalY = ty + currYOffset;
1641         if (paintingFloats)
1642             paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
1643         else
1644             paintContents(info, finalX, finalY);
1645 
1646         // Move to the next position.
1647         if (style()->direction() == LTR)
1648             currXOffset += colRect.width() + colGap;
1649         else
1650             currXOffset -= (colRect.width() + colGap);
1651 
1652         currYOffset -= colRect.height();
1653 
1654         context->restore();
1655     }
1656 }
1657 
paintContents(PaintInfo & paintInfo,int tx,int ty)1658 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
1659 {
1660     // Avoid painting descendants of the root element when stylesheets haven't loaded.  This eliminates FOUC.
1661     // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
1662     // will do a full repaint().
1663     if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
1664         return;
1665 
1666     if (childrenInline())
1667         m_lineBoxes.paint(this, paintInfo, tx, ty);
1668     else
1669         paintChildren(paintInfo, tx, ty);
1670 }
1671 
paintChildren(PaintInfo & paintInfo,int tx,int ty)1672 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
1673 {
1674     PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
1675     newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
1676 
1677     // We don't paint our own background, but we do let the kids paint their backgrounds.
1678     PaintInfo info(paintInfo);
1679     info.phase = newPhase;
1680     info.paintingRoot = paintingRootForChildren(paintInfo);
1681     bool isPrinting = document()->printing();
1682 
1683     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1684         // Check for page-break-before: always, and if it's set, break and bail.
1685         if (isPrinting && !childrenInline() && child->style()->pageBreakBefore() == PBALWAYS &&
1686             inRootBlockContext() && (ty + child->y()) > paintInfo.rect.y() &&
1687             (ty + child->y()) < paintInfo.rect.bottom()) {
1688             view()->setBestTruncatedAt(ty + child->y(), this, true);
1689             return;
1690         }
1691 
1692         if (!child->hasSelfPaintingLayer() && !child->isFloating())
1693             child->paint(info, tx, ty);
1694 
1695         // Check for page-break-after: always, and if it's set, break and bail.
1696         if (isPrinting && !childrenInline() && child->style()->pageBreakAfter() == PBALWAYS &&
1697             inRootBlockContext() && (ty + child->y() + child->height()) > paintInfo.rect.y() &&
1698             (ty + child->y() + child->height()) < paintInfo.rect.bottom()) {
1699             view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginBottom()), this, true);
1700             return;
1701         }
1702     }
1703 }
1704 
paintCaret(PaintInfo & paintInfo,int tx,int ty,CaretType type)1705 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
1706 {
1707     SelectionController* selection = type == CursorCaret ? document()->frame()->selection() : document()->frame()->dragCaretController();
1708 
1709     // Paint the caret if the SelectionController says so or if caret browsing is enabled
1710     bool caretBrowsing = document()->frame()->settings() && document()->frame()->settings()->caretBrowsingEnabled();
1711     RenderObject* caretPainter = selection->caretRenderer();
1712     if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) {
1713         // Convert the painting offset into the local coordinate system of this renderer,
1714         // to match the localCaretRect computed by the SelectionController
1715         offsetForContents(tx, ty);
1716 
1717         if (type == CursorCaret)
1718             document()->frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
1719         else
1720             document()->frame()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
1721     }
1722 }
1723 
paintObject(PaintInfo & paintInfo,int tx,int ty)1724 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
1725 {
1726     PaintPhase paintPhase = paintInfo.phase;
1727 
1728     // 1. paint background, borders etc
1729     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
1730         if (hasBoxDecorations())
1731             paintBoxDecorations(paintInfo, tx, ty);
1732         if (hasColumns())
1733             paintColumnRules(paintInfo, tx, ty);
1734     }
1735 
1736     if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
1737         paintMask(paintInfo, tx, ty);
1738         return;
1739     }
1740 
1741     // We're done.  We don't bother painting any children.
1742     if (paintPhase == PaintPhaseBlockBackground)
1743         return;
1744 
1745     // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).s
1746     int scrolledX = tx;
1747     int scrolledY = ty;
1748     if (hasOverflowClip())
1749         layer()->subtractScrolledContentOffset(scrolledX, scrolledY);
1750 
1751     // 2. paint contents
1752     if (paintPhase != PaintPhaseSelfOutline) {
1753         if (hasColumns())
1754             paintColumnContents(paintInfo, scrolledX, scrolledY);
1755         else
1756             paintContents(paintInfo, scrolledX, scrolledY);
1757     }
1758 
1759     // 3. paint selection
1760     // FIXME: Make this work with multi column layouts.  For now don't fill gaps.
1761     bool isPrinting = document()->printing();
1762     if (!isPrinting && !hasColumns())
1763         paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
1764 
1765     // 4. paint floats.
1766     if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
1767         if (hasColumns())
1768             paintColumnContents(paintInfo, scrolledX, scrolledY, true);
1769         else
1770             paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
1771     }
1772 
1773     // 5. paint outline.
1774     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
1775         paintOutline(paintInfo.context, tx, ty, width(), height(), style());
1776 
1777     // 6. paint continuation outlines.
1778     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
1779         if (inlineContinuation() && inlineContinuation()->hasOutline() && inlineContinuation()->style()->visibility() == VISIBLE) {
1780             RenderInline* inlineRenderer = toRenderInline(inlineContinuation()->node()->renderer());
1781             RenderBlock* cb = containingBlock();
1782 
1783             bool inlineEnclosedInSelfPaintingLayer = false;
1784             for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
1785                 if (box->hasSelfPaintingLayer()) {
1786                     inlineEnclosedInSelfPaintingLayer = true;
1787                     break;
1788                 }
1789             }
1790 
1791             if (!inlineEnclosedInSelfPaintingLayer)
1792                 cb->addContinuationWithOutline(inlineRenderer);
1793             else if (!inlineRenderer->firstLineBox())
1794                 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(),
1795                                              ty - y() + inlineRenderer->containingBlock()->y());
1796         }
1797         paintContinuationOutlines(paintInfo, tx, ty);
1798     }
1799 
1800     // 7. paint caret.
1801     // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
1802     // then paint the caret.
1803     if (paintPhase == PaintPhaseForeground) {
1804         paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret);
1805         paintCaret(paintInfo, scrolledX, scrolledY, DragCaret);
1806     }
1807 }
1808 
paintFloats(PaintInfo & paintInfo,int tx,int ty,bool preservePhase)1809 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase)
1810 {
1811     if (!m_floatingObjects)
1812         return;
1813 
1814     FloatingObject* r;
1815     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
1816     for (; (r = it.current()); ++it) {
1817         // Only paint the object if our m_shouldPaint flag is set.
1818         if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
1819             PaintInfo currentPaintInfo(paintInfo);
1820             currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
1821             int currentTX = tx + r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft();
1822             int currentTY = ty + r->m_top - r->m_renderer->y() + r->m_renderer->marginTop();
1823             r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
1824             if (!preservePhase) {
1825                 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
1826                 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
1827                 currentPaintInfo.phase = PaintPhaseFloat;
1828                 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
1829                 currentPaintInfo.phase = PaintPhaseForeground;
1830                 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
1831                 currentPaintInfo.phase = PaintPhaseOutline;
1832                 r->m_renderer->paint(currentPaintInfo, currentTX, currentTY);
1833             }
1834         }
1835     }
1836 }
1837 
paintEllipsisBoxes(PaintInfo & paintInfo,int tx,int ty)1838 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty)
1839 {
1840     if (!shouldPaintWithinRoot(paintInfo) || !firstLineBox())
1841         return;
1842 
1843     if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
1844         // We can check the first box and last box and avoid painting if we don't
1845         // intersect.
1846         int yPos = ty + firstLineBox()->y();
1847         int h = lastLineBox()->y() + lastLineBox()->height() - firstLineBox()->y();
1848         if (yPos >= paintInfo.rect.bottom() || yPos + h <= paintInfo.rect.y())
1849             return;
1850 
1851         // See if our boxes intersect with the dirty rect.  If so, then we paint
1852         // them.  Note that boxes can easily overlap, so we can't make any assumptions
1853         // based off positions of our first line box or our last line box.
1854         for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
1855             yPos = ty + curr->y();
1856             h = curr->height();
1857             if (curr->ellipsisBox() && yPos < paintInfo.rect.bottom() && yPos + h > paintInfo.rect.y())
1858                 curr->paintEllipsisBox(paintInfo, tx, ty);
1859         }
1860     }
1861 }
1862 
continuationOutlineTable()1863 static ContinuationOutlineTableMap* continuationOutlineTable()
1864 {
1865     DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
1866     return &table;
1867 }
1868 
addContinuationWithOutline(RenderInline * flow)1869 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
1870 {
1871     // We can't make this work if the inline is in a layer.  We'll just rely on the broken
1872     // way of painting.
1873     ASSERT(!flow->layer() && !flow->isInlineContinuation());
1874 
1875     ContinuationOutlineTableMap* table = continuationOutlineTable();
1876     ListHashSet<RenderInline*>* continuations = table->get(this);
1877     if (!continuations) {
1878         continuations = new ListHashSet<RenderInline*>;
1879         table->set(this, continuations);
1880     }
1881 
1882     continuations->add(flow);
1883 }
1884 
paintContinuationOutlines(PaintInfo & info,int tx,int ty)1885 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
1886 {
1887     ContinuationOutlineTableMap* table = continuationOutlineTable();
1888     if (table->isEmpty())
1889         return;
1890 
1891     ListHashSet<RenderInline*>* continuations = table->get(this);
1892     if (!continuations)
1893         return;
1894 
1895     // Paint each continuation outline.
1896     ListHashSet<RenderInline*>::iterator end = continuations->end();
1897     for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
1898         // Need to add in the coordinates of the intervening blocks.
1899         RenderInline* flow = *it;
1900         RenderBlock* block = flow->containingBlock();
1901         for ( ; block && block != this; block = block->containingBlock()) {
1902             tx += block->x();
1903             ty += block->y();
1904         }
1905         ASSERT(block);
1906         flow->paintOutline(info.context, tx, ty);
1907     }
1908 
1909     // Delete
1910     delete continuations;
1911     table->remove(this);
1912 }
1913 
setSelectionState(SelectionState s)1914 void RenderBlock::setSelectionState(SelectionState s)
1915 {
1916     if (selectionState() == s)
1917         return;
1918 
1919     if (s == SelectionInside && selectionState() != SelectionNone)
1920         return;
1921 
1922     if ((s == SelectionStart && selectionState() == SelectionEnd) ||
1923         (s == SelectionEnd && selectionState() == SelectionStart))
1924         RenderBox::setSelectionState(SelectionBoth);
1925     else
1926         RenderBox::setSelectionState(s);
1927 
1928     RenderBlock* cb = containingBlock();
1929     if (cb && !cb->isRenderView())
1930         cb->setSelectionState(s);
1931 }
1932 
shouldPaintSelectionGaps() const1933 bool RenderBlock::shouldPaintSelectionGaps() const
1934 {
1935     return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
1936 }
1937 
isSelectionRoot() const1938 bool RenderBlock::isSelectionRoot() const
1939 {
1940     if (!node())
1941         return false;
1942 
1943     // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
1944     if (isTable())
1945         return false;
1946 
1947     if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
1948         isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
1949         hasReflection() || hasMask())
1950         return true;
1951 
1952     if (view() && view()->selectionStart()) {
1953         Node* startElement = view()->selectionStart()->node();
1954         if (startElement && startElement->rootEditableElement() == node())
1955             return true;
1956     }
1957 
1958     return false;
1959 }
1960 
selectionGapRectsForRepaint(RenderBoxModelObject * repaintContainer)1961 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
1962 {
1963     ASSERT(!needsLayout());
1964 
1965     if (!shouldPaintSelectionGaps())
1966         return GapRects();
1967 
1968     // FIXME: this is broken with transforms
1969     TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
1970     mapLocalToContainer(repaintContainer, false, false, transformState);
1971     FloatPoint offsetFromRepaintContainer = transformState.mappedPoint();
1972     int x = offsetFromRepaintContainer.x();
1973     int y = offsetFromRepaintContainer.y();
1974 
1975     if (hasOverflowClip())
1976         layer()->subtractScrolledContentOffset(x, y);
1977 
1978     int lastTop = 0;
1979     int lastLeft = leftSelectionOffset(this, lastTop);
1980     int lastRight = rightSelectionOffset(this, lastTop);
1981 
1982     return fillSelectionGaps(this, x, y, x, y, lastTop, lastLeft, lastRight);
1983 }
1984 
paintSelection(PaintInfo & paintInfo,int tx,int ty)1985 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
1986 {
1987     if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
1988         int lastTop = 0;
1989         int lastLeft = leftSelectionOffset(this, lastTop);
1990         int lastRight = rightSelectionOffset(this, lastTop);
1991         paintInfo.context->save();
1992         IntRect gapRectsBounds = fillSelectionGaps(this, tx, ty, tx, ty, lastTop, lastLeft, lastRight, &paintInfo);
1993         if (!gapRectsBounds.isEmpty()) {
1994             if (RenderLayer* layer = enclosingLayer()) {
1995                 gapRectsBounds.move(IntSize(-tx, -ty));
1996                 if (!hasLayer()) {
1997                     FloatRect localBounds(gapRectsBounds);
1998                     gapRectsBounds = localToContainerQuad(localBounds, layer->renderer()).enclosingBoundingBox();
1999                 }
2000                 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2001             }
2002         }
2003         paintInfo.context->restore();
2004     }
2005 }
2006 
2007 #ifndef BUILDING_ON_TIGER
clipOutPositionedObjects(const RenderObject::PaintInfo * paintInfo,int tx,int ty,ListHashSet<RenderBox * > * positionedObjects)2008 static void clipOutPositionedObjects(const RenderObject::PaintInfo* paintInfo, int tx, int ty, ListHashSet<RenderBox*>* positionedObjects)
2009 {
2010     if (!positionedObjects)
2011         return;
2012 
2013     ListHashSet<RenderBox*>::const_iterator end = positionedObjects->end();
2014     for (ListHashSet<RenderBox*>::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2015         RenderBox* r = *it;
2016         paintInfo->context->clipOut(IntRect(tx + r->x(), ty + r->y(), r->width(), r->height()));
2017     }
2018 }
2019 #endif
2020 
fillSelectionGaps(RenderBlock * rootBlock,int blockX,int blockY,int tx,int ty,int & lastTop,int & lastLeft,int & lastRight,const PaintInfo * paintInfo)2021 GapRects RenderBlock::fillSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
2022                                         int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
2023 {
2024 #ifndef BUILDING_ON_TIGER
2025     // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2026     // Clip out floating and positioned objects when painting selection gaps.
2027     if (paintInfo) {
2028         // Note that we don't clip out overflow for positioned objects.  We just stick to the border box.
2029         clipOutPositionedObjects(paintInfo, tx, ty, m_positionedObjects);
2030         if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2031             for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2032                 clipOutPositionedObjects(paintInfo, cb->x(), cb->y(), cb->m_positionedObjects);
2033         if (m_floatingObjects) {
2034             for (DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects); it.current(); ++it) {
2035                 FloatingObject* r = it.current();
2036                 paintInfo->context->clipOut(IntRect(tx + r->m_left + r->m_renderer->marginLeft(),
2037                                                     ty + r->m_top + r->m_renderer->marginTop(),
2038                                                     r->m_renderer->width(), r->m_renderer->height()));
2039             }
2040         }
2041     }
2042 #endif
2043 
2044     // 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
2045     // fixed).
2046     GapRects result;
2047     if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2048         return result;
2049 
2050     if (hasColumns() || hasTransform()) {
2051         // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2052         lastTop = (ty - blockY) + height();
2053         lastLeft = leftSelectionOffset(rootBlock, height());
2054         lastRight = rightSelectionOffset(rootBlock, height());
2055         return result;
2056     }
2057 
2058     if (childrenInline())
2059         result = fillInlineSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo);
2060     else
2061         result = fillBlockSelectionGaps(rootBlock, blockX, blockY, tx, ty, lastTop, lastLeft, lastRight, paintInfo);
2062 
2063     // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2064     if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2065         result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + height(),
2066                                                     rootBlock, blockX, blockY, paintInfo));
2067     return result;
2068 }
2069 
fillInlineSelectionGaps(RenderBlock * rootBlock,int blockX,int blockY,int tx,int ty,int & lastTop,int & lastLeft,int & lastRight,const PaintInfo * paintInfo)2070 GapRects RenderBlock::fillInlineSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
2071                                               int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
2072 {
2073     GapRects result;
2074 
2075     bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
2076 
2077     if (!firstLineBox()) {
2078         if (containsStart) {
2079             // Go ahead and update our lastY to be the bottom of the block.  <hr>s or empty blocks with height can trip this
2080             // case.
2081             lastTop = (ty - blockY) + height();
2082             lastLeft = leftSelectionOffset(rootBlock, height());
2083             lastRight = rightSelectionOffset(rootBlock, height());
2084         }
2085         return result;
2086     }
2087 
2088     RootInlineBox* lastSelectedLine = 0;
2089     RootInlineBox* curr;
2090     for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
2091 
2092     // Now paint the gaps for the lines.
2093     for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
2094         int selTop =  curr->selectionTop();
2095         int selHeight = curr->selectionHeight();
2096 
2097         if (!containsStart && !lastSelectedLine &&
2098             selectionState() != SelectionStart && selectionState() != SelectionBoth)
2099             result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight, ty + selTop,
2100                                                         rootBlock, blockX, blockY, paintInfo));
2101 
2102         if (!paintInfo || (ty + selTop < paintInfo->rect.bottom() && ty + selTop + selHeight > paintInfo->rect.y()))
2103             result.unite(curr->fillLineSelectionGap(selTop, selHeight, rootBlock, blockX, blockY, tx, ty, paintInfo));
2104 
2105         lastSelectedLine = curr;
2106     }
2107 
2108     if (containsStart && !lastSelectedLine)
2109         // VisibleSelection must start just after our last line.
2110         lastSelectedLine = lastRootBox();
2111 
2112     if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
2113         // Go ahead and update our lastY to be the bottom of the last selected line.
2114         lastTop = (ty - blockY) + lastSelectedLine->selectionBottom();
2115         lastLeft = leftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2116         lastRight = rightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2117     }
2118     return result;
2119 }
2120 
fillBlockSelectionGaps(RenderBlock * rootBlock,int blockX,int blockY,int tx,int ty,int & lastTop,int & lastLeft,int & lastRight,const PaintInfo * paintInfo)2121 GapRects RenderBlock::fillBlockSelectionGaps(RenderBlock* rootBlock, int blockX, int blockY, int tx, int ty,
2122                                              int& lastTop, int& lastLeft, int& lastRight, const PaintInfo* paintInfo)
2123 {
2124     GapRects result;
2125 
2126     // Go ahead and jump right to the first block child that contains some selected objects.
2127     RenderBox* curr;
2128     for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2129 
2130     for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2131         SelectionState childState = curr->selectionState();
2132         if (childState == SelectionBoth || childState == SelectionEnd)
2133             sawSelectionEnd = true;
2134 
2135         if (curr->isFloatingOrPositioned())
2136             continue; // We must be a normal flow object in order to even be considered.
2137 
2138         if (curr->isRelPositioned() && curr->hasLayer()) {
2139             // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2140             // Just disregard it completely.
2141             IntSize relOffset = curr->layer()->relativePositionOffset();
2142             if (relOffset.width() || relOffset.height())
2143                 continue;
2144         }
2145 
2146         bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2147         bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2148         if (fillBlockGaps) {
2149             // We need to fill the vertical gap above this object.
2150             if (childState == SelectionEnd || childState == SelectionInside)
2151                 // Fill the gap above the object.
2152                 result.uniteCenter(fillVerticalSelectionGap(lastTop, lastLeft, lastRight,
2153                                                             ty + curr->y(), rootBlock, blockX, blockY, paintInfo));
2154 
2155             // 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*
2156             // our object.  We know this if the selection did not end inside our object.
2157             if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2158                 childState = SelectionNone;
2159 
2160             // Fill side gaps on this object based off its state.
2161             bool leftGap, rightGap;
2162             getHorizontalSelectionGapInfo(childState, leftGap, rightGap);
2163 
2164             if (leftGap)
2165                 result.uniteLeft(fillLeftSelectionGap(this, curr->x(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo));
2166             if (rightGap)
2167                 result.uniteRight(fillRightSelectionGap(this, curr->x() + curr->width(), curr->y(), curr->height(), rootBlock, blockX, blockY, tx, ty, paintInfo));
2168 
2169             // Update lastTop to be just underneath the object.  lastLeft and lastRight extend as far as
2170             // they can without bumping into floating or positioned objects.  Ideally they will go right up
2171             // to the border of the root selection block.
2172             lastTop = (ty - blockY) + (curr->y() + curr->height());
2173             lastLeft = leftSelectionOffset(rootBlock, curr->y() + curr->height());
2174             lastRight = rightSelectionOffset(rootBlock, curr->y() + curr->height());
2175         } else if (childState != SelectionNone)
2176             // We must be a block that has some selected object inside it.  Go ahead and recur.
2177             result.unite(toRenderBlock(curr)->fillSelectionGaps(rootBlock, blockX, blockY, tx + curr->x(), ty + curr->y(),
2178                                                                             lastTop, lastLeft, lastRight, paintInfo));
2179     }
2180     return result;
2181 }
2182 
fillHorizontalSelectionGap(RenderObject * selObj,int xPos,int yPos,int width,int height,const PaintInfo * paintInfo)2183 IntRect RenderBlock::fillHorizontalSelectionGap(RenderObject* selObj, int xPos, int yPos, int width, int height, const PaintInfo* paintInfo)
2184 {
2185     if (width <= 0 || height <= 0)
2186         return IntRect();
2187     IntRect gapRect(xPos, yPos, width, height);
2188     if (paintInfo && selObj->style()->visibility() == VISIBLE)
2189         paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
2190     return gapRect;
2191 }
2192 
fillVerticalSelectionGap(int lastTop,int lastLeft,int lastRight,int bottomY,RenderBlock * rootBlock,int blockX,int blockY,const PaintInfo * paintInfo)2193 IntRect RenderBlock::fillVerticalSelectionGap(int lastTop, int lastLeft, int lastRight, int bottomY, RenderBlock* rootBlock,
2194                                               int blockX, int blockY, const PaintInfo* paintInfo)
2195 {
2196     int top = blockY + lastTop;
2197     int height = bottomY - top;
2198     if (height <= 0)
2199         return IntRect();
2200 
2201     // Get the selection offsets for the bottom of the gap
2202     int left = blockX + max(lastLeft, leftSelectionOffset(rootBlock, bottomY));
2203     int right = blockX + min(lastRight, rightSelectionOffset(rootBlock, bottomY));
2204     int width = right - left;
2205     if (width <= 0)
2206         return IntRect();
2207 
2208     IntRect gapRect(left, top, width, height);
2209     if (paintInfo)
2210         paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
2211     return gapRect;
2212 }
2213 
fillLeftSelectionGap(RenderObject * selObj,int xPos,int yPos,int height,RenderBlock * rootBlock,int blockX,int,int tx,int ty,const PaintInfo * paintInfo)2214 IntRect RenderBlock::fillLeftSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
2215                                           int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo)
2216 {
2217     int top = yPos + ty;
2218     int left = blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height));
2219     int right = min(xPos + tx, blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height)));
2220     int width = right - left;
2221     if (width <= 0)
2222         return IntRect();
2223 
2224     IntRect gapRect(left, top, width, height);
2225     if (paintInfo)
2226         paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
2227     return gapRect;
2228 }
2229 
fillRightSelectionGap(RenderObject * selObj,int xPos,int yPos,int height,RenderBlock * rootBlock,int blockX,int,int tx,int ty,const PaintInfo * paintInfo)2230 IntRect RenderBlock::fillRightSelectionGap(RenderObject* selObj, int xPos, int yPos, int height, RenderBlock* rootBlock,
2231                                            int blockX, int /*blockY*/, int tx, int ty, const PaintInfo* paintInfo)
2232 {
2233     int left = max(xPos + tx, blockX + max(leftSelectionOffset(rootBlock, yPos), leftSelectionOffset(rootBlock, yPos + height)));
2234     int top = yPos + ty;
2235     int right = blockX + min(rightSelectionOffset(rootBlock, yPos), rightSelectionOffset(rootBlock, yPos + height));
2236     int width = right - left;
2237     if (width <= 0)
2238         return IntRect();
2239 
2240     IntRect gapRect(left, top, width, height);
2241     if (paintInfo)
2242         paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
2243     return gapRect;
2244 }
2245 
getHorizontalSelectionGapInfo(SelectionState state,bool & leftGap,bool & rightGap)2246 void RenderBlock::getHorizontalSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
2247 {
2248     bool ltr = style()->direction() == LTR;
2249     leftGap = (state == RenderObject::SelectionInside) ||
2250               (state == RenderObject::SelectionEnd && ltr) ||
2251               (state == RenderObject::SelectionStart && !ltr);
2252     rightGap = (state == RenderObject::SelectionInside) ||
2253                (state == RenderObject::SelectionStart && ltr) ||
2254                (state == RenderObject::SelectionEnd && !ltr);
2255 }
2256 
leftSelectionOffset(RenderBlock * rootBlock,int yPos)2257 int RenderBlock::leftSelectionOffset(RenderBlock* rootBlock, int yPos)
2258 {
2259     int left = leftOffset(yPos, false);
2260     if (left == borderLeft() + paddingLeft()) {
2261         if (rootBlock != this)
2262             // The border can potentially be further extended by our containingBlock().
2263             return containingBlock()->leftSelectionOffset(rootBlock, yPos + y());
2264         return left;
2265     }
2266     else {
2267         RenderBlock* cb = this;
2268         while (cb != rootBlock) {
2269             left += cb->x();
2270             cb = cb->containingBlock();
2271         }
2272     }
2273 
2274     return left;
2275 }
2276 
rightSelectionOffset(RenderBlock * rootBlock,int yPos)2277 int RenderBlock::rightSelectionOffset(RenderBlock* rootBlock, int yPos)
2278 {
2279     int right = rightOffset(yPos, false);
2280     if (right == (contentWidth() + (borderLeft() + paddingLeft()))) {
2281         if (rootBlock != this)
2282             // The border can potentially be further extended by our containingBlock().
2283             return containingBlock()->rightSelectionOffset(rootBlock, yPos + y());
2284         return right;
2285     }
2286     else {
2287         RenderBlock* cb = this;
2288         while (cb != rootBlock) {
2289             right += cb->x();
2290             cb = cb->containingBlock();
2291         }
2292     }
2293     return right;
2294 }
2295 
insertPositionedObject(RenderBox * o)2296 void RenderBlock::insertPositionedObject(RenderBox* o)
2297 {
2298     // Create the list of special objects if we don't aleady have one
2299     if (!m_positionedObjects)
2300         m_positionedObjects = new ListHashSet<RenderBox*>;
2301 
2302     m_positionedObjects->add(o);
2303 }
2304 
removePositionedObject(RenderBox * o)2305 void RenderBlock::removePositionedObject(RenderBox* o)
2306 {
2307     if (m_positionedObjects)
2308         m_positionedObjects->remove(o);
2309 }
2310 
removePositionedObjects(RenderBlock * o)2311 void RenderBlock::removePositionedObjects(RenderBlock* o)
2312 {
2313     if (!m_positionedObjects)
2314         return;
2315 
2316     RenderBox* r;
2317 
2318     Iterator end = m_positionedObjects->end();
2319 
2320     Vector<RenderBox*, 16> deadObjects;
2321 
2322     for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2323         r = *it;
2324         if (!o || r->isDescendantOf(o)) {
2325             if (o)
2326                 r->setChildNeedsLayout(true, false);
2327 
2328             // It is parent blocks job to add positioned child to positioned objects list of its containing block
2329             // Parent layout needs to be invalidated to ensure this happens.
2330             RenderObject* p = r->parent();
2331             while (p && !p->isRenderBlock())
2332                 p = p->parent();
2333             if (p)
2334                 p->setChildNeedsLayout(true);
2335 
2336             deadObjects.append(r);
2337         }
2338     }
2339 
2340     for (unsigned i = 0; i < deadObjects.size(); i++)
2341         m_positionedObjects->remove(deadObjects.at(i));
2342 }
2343 
insertFloatingObject(RenderBox * o)2344 void RenderBlock::insertFloatingObject(RenderBox* o)
2345 {
2346     ASSERT(o->isFloating());
2347 
2348     // Create the list of special objects if we don't aleady have one
2349     if (!m_floatingObjects) {
2350         m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
2351         m_floatingObjects->setAutoDelete(true);
2352     } else {
2353         // Don't insert the object again if it's already in the list
2354         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2355         FloatingObject* f;
2356         while ( (f = it.current()) ) {
2357             if (f->m_renderer == o) return;
2358             ++it;
2359         }
2360     }
2361 
2362     // Create the special object entry & append it to the list
2363 
2364     o->layoutIfNeeded();
2365 
2366     FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
2367 
2368     newObj->m_top = -1;
2369     newObj->m_bottom = -1;
2370     newObj->m_width = o->width() + o->marginLeft() + o->marginRight();
2371     newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself.  Otherwise someone else will.
2372     newObj->m_isDescendant = true;
2373     newObj->m_renderer = o;
2374 
2375     m_floatingObjects->append(newObj);
2376 }
2377 
removeFloatingObject(RenderBox * o)2378 void RenderBlock::removeFloatingObject(RenderBox* o)
2379 {
2380     if (m_floatingObjects) {
2381         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2382         while (it.current()) {
2383             if (it.current()->m_renderer == o) {
2384                 if (childrenInline())
2385                     markLinesDirtyInVerticalRange(0, it.current()->m_bottom);
2386                 m_floatingObjects->removeRef(it.current());
2387             }
2388             ++it;
2389         }
2390     }
2391 }
2392 
positionNewFloats()2393 bool RenderBlock::positionNewFloats()
2394 {
2395     if (!m_floatingObjects)
2396         return false;
2397 
2398     FloatingObject* f = m_floatingObjects->last();
2399 
2400     // If all floats have already been positioned, then we have no work to do.
2401     if (!f || f->m_top != -1)
2402         return false;
2403 
2404     // Move backwards through our floating object list until we find a float that has
2405     // already been positioned.  Then we'll be able to move forward, positioning all of
2406     // the new floats that need it.
2407     FloatingObject* lastFloat = m_floatingObjects->getPrev();
2408     while (lastFloat && lastFloat->m_top == -1) {
2409         f = m_floatingObjects->prev();
2410         lastFloat = m_floatingObjects->getPrev();
2411     }
2412 
2413     int y = height();
2414 
2415     // The float cannot start above the y position of the last positioned float.
2416     if (lastFloat)
2417         y = max(lastFloat->m_top, y);
2418 
2419     // Now walk through the set of unpositioned floats and place them.
2420     while (f) {
2421         // The containing block is responsible for positioning floats, so if we have floats in our
2422         // list that come from somewhere else, do not attempt to position them.
2423         if (f->m_renderer->containingBlock() != this) {
2424             f = m_floatingObjects->next();
2425             continue;
2426         }
2427 
2428         RenderBox* o = f->m_renderer;
2429         int _height = o->height() + o->marginTop() + o->marginBottom();
2430 
2431         int ro = rightOffset(); // Constant part of right offset.
2432         int lo = leftOffset(); // Constat part of left offset.
2433         int fwidth = f->m_width; // The width we look for.
2434         if (ro - lo < fwidth)
2435             fwidth = ro - lo; // Never look for more than what will be available.
2436 
2437         IntRect oldRect(o->x(), o->y() , o->width(), o->height());
2438 
2439         if (o->style()->clear() & CLEFT)
2440             y = max(leftBottom(), y);
2441         if (o->style()->clear() & CRIGHT)
2442             y = max(rightBottom(), y);
2443 
2444         if (o->style()->floating() == FLEFT) {
2445             int heightRemainingLeft = 1;
2446             int heightRemainingRight = 1;
2447             int fx = leftRelOffset(y, lo, false, &heightRemainingLeft);
2448             while (rightRelOffset(y, ro, false, &heightRemainingRight)-fx < fwidth) {
2449                 y += min(heightRemainingLeft, heightRemainingRight);
2450                 fx = leftRelOffset(y, lo, false, &heightRemainingLeft);
2451             }
2452             fx = max(0, fx);
2453             f->m_left = fx;
2454             o->setLocation(fx + o->marginLeft(), y + o->marginTop());
2455         } else {
2456             int heightRemainingLeft = 1;
2457             int heightRemainingRight = 1;
2458             int fx = rightRelOffset(y, ro, false, &heightRemainingRight);
2459             while (fx - leftRelOffset(y, lo, false, &heightRemainingLeft) < fwidth) {
2460                 y += min(heightRemainingLeft, heightRemainingRight);
2461                 fx = rightRelOffset(y, ro, false, &heightRemainingRight);
2462             }
2463             f->m_left = fx - f->m_width;
2464             o->setLocation(fx - o->marginRight() - o->width(), y + o->marginTop());
2465         }
2466 
2467         f->m_top = y;
2468         f->m_bottom = f->m_top + _height;
2469 
2470         // If the child moved, we have to repaint it.
2471         if (o->checkForRepaintDuringLayout())
2472             o->repaintDuringLayoutIfMoved(oldRect);
2473 
2474         f = m_floatingObjects->next();
2475     }
2476     return true;
2477 }
2478 
newLine(EClear clear)2479 void RenderBlock::newLine(EClear clear)
2480 {
2481     positionNewFloats();
2482     // set y position
2483     int newY = 0;
2484     switch (clear)
2485     {
2486         case CLEFT:
2487             newY = leftBottom();
2488             break;
2489         case CRIGHT:
2490             newY = rightBottom();
2491             break;
2492         case CBOTH:
2493             newY = floatBottom();
2494         default:
2495             break;
2496     }
2497     if (height() < newY)
2498         setHeight(newY);
2499 }
2500 
addPercentHeightDescendant(RenderBox * descendant)2501 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
2502 {
2503     if (!gPercentHeightDescendantsMap) {
2504         gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
2505         gPercentHeightContainerMap = new PercentHeightContainerMap;
2506     }
2507 
2508     HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
2509     if (!descendantSet) {
2510         descendantSet = new HashSet<RenderBox*>;
2511         gPercentHeightDescendantsMap->set(this, descendantSet);
2512     }
2513     bool added = descendantSet->add(descendant).second;
2514     if (!added) {
2515         ASSERT(gPercentHeightContainerMap->get(descendant));
2516         ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
2517         return;
2518     }
2519 
2520     HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
2521     if (!containerSet) {
2522         containerSet = new HashSet<RenderBlock*>;
2523         gPercentHeightContainerMap->set(descendant, containerSet);
2524     }
2525     ASSERT(!containerSet->contains(this));
2526     containerSet->add(this);
2527 }
2528 
removePercentHeightDescendant(RenderBox * descendant)2529 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
2530 {
2531     if (!gPercentHeightContainerMap)
2532         return;
2533 
2534     HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
2535     if (!containerSet)
2536         return;
2537 
2538     HashSet<RenderBlock*>::iterator end = containerSet->end();
2539     for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
2540         RenderBlock* container = *it;
2541         HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
2542         ASSERT(descendantSet);
2543         if (!descendantSet)
2544             continue;
2545         ASSERT(descendantSet->contains(descendant));
2546         descendantSet->remove(descendant);
2547         if (descendantSet->isEmpty()) {
2548             gPercentHeightDescendantsMap->remove(container);
2549             delete descendantSet;
2550         }
2551     }
2552 
2553     delete containerSet;
2554 }
2555 
percentHeightDescendants() const2556 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
2557 {
2558     return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
2559 }
2560 
leftOffset() const2561 int RenderBlock::leftOffset() const
2562 {
2563     return borderLeft() + paddingLeft();
2564 }
2565 
leftRelOffset(int y,int fixedOffset,bool applyTextIndent,int * heightRemaining) const2566 int RenderBlock::leftRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
2567 {
2568     int left = fixedOffset;
2569     if (m_floatingObjects) {
2570         if ( heightRemaining ) *heightRemaining = 1;
2571         FloatingObject* r;
2572         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2573         for ( ; (r = it.current()); ++it )
2574         {
2575             if (r->m_top <= y && r->m_bottom > y &&
2576                 r->type() == FloatingObject::FloatLeft &&
2577                 r->m_left + r->m_width > left) {
2578                 left = r->m_left + r->m_width;
2579                 if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
2580             }
2581         }
2582     }
2583 
2584     if (applyTextIndent && style()->direction() == LTR) {
2585         int cw = 0;
2586         if (style()->textIndent().isPercent())
2587             cw = containingBlock()->availableWidth();
2588         left += style()->textIndent().calcMinValue(cw);
2589     }
2590 
2591     return left;
2592 }
2593 
rightOffset() const2594 int RenderBlock::rightOffset() const
2595 {
2596     return borderLeft() + paddingLeft() + availableWidth();
2597 }
2598 
rightRelOffset(int y,int fixedOffset,bool applyTextIndent,int * heightRemaining) const2599 int RenderBlock::rightRelOffset(int y, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
2600 {
2601     int right = fixedOffset;
2602 
2603     if (m_floatingObjects) {
2604         if (heightRemaining) *heightRemaining = 1;
2605         FloatingObject* r;
2606         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2607         for ( ; (r = it.current()); ++it )
2608         {
2609             if (r->m_top <= y && r->m_bottom > y &&
2610                 r->type() == FloatingObject::FloatRight &&
2611                 r->m_left < right) {
2612                 right = r->m_left;
2613                 if ( heightRemaining ) *heightRemaining = r->m_bottom - y;
2614             }
2615         }
2616     }
2617 
2618     if (applyTextIndent && style()->direction() == RTL) {
2619         int cw = 0;
2620         if (style()->textIndent().isPercent())
2621             cw = containingBlock()->availableWidth();
2622         right -= style()->textIndent().calcMinValue(cw);
2623     }
2624 
2625     return right;
2626 }
2627 
2628 int
lineWidth(int y,bool firstLine) const2629 RenderBlock::lineWidth(int y, bool firstLine) const
2630 {
2631     int result = rightOffset(y, firstLine) - leftOffset(y, firstLine);
2632     return (result < 0) ? 0 : result;
2633 }
2634 
nextFloatBottomBelow(int height) const2635 int RenderBlock::nextFloatBottomBelow(int height) const
2636 {
2637     if (!m_floatingObjects)
2638         return 0;
2639 
2640     int bottom = INT_MAX;
2641     FloatingObject* r;
2642     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2643     for ( ; (r = it.current()); ++it) {
2644         if (r->m_bottom > height)
2645             bottom = min(r->m_bottom, bottom);
2646     }
2647 
2648     return bottom == INT_MAX ? 0 : bottom;
2649 }
2650 
2651 int
floatBottom() const2652 RenderBlock::floatBottom() const
2653 {
2654     if (!m_floatingObjects) return 0;
2655     int bottom = 0;
2656     FloatingObject* r;
2657     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2658     for ( ; (r = it.current()); ++it )
2659         if (r->m_bottom>bottom)
2660             bottom = r->m_bottom;
2661     return bottom;
2662 }
2663 
floatRect() const2664 IntRect RenderBlock::floatRect() const
2665 {
2666     IntRect result;
2667     if (!m_floatingObjects || hasOverflowClip() || hasColumns())
2668         return result;
2669     FloatingObject* r;
2670     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2671     for (; (r = it.current()); ++it) {
2672         if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2673             IntRect childRect = r->m_renderer->visibleOverflowRect();
2674             childRect.move(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop());
2675             result.unite(childRect);
2676         }
2677     }
2678 
2679     return result;
2680 }
2681 
lowestPosition(bool includeOverflowInterior,bool includeSelf) const2682 int RenderBlock::lowestPosition(bool includeOverflowInterior, bool includeSelf) const
2683 {
2684     int bottom = includeSelf && width() > 0 ? height() : 0;
2685 
2686     if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
2687         return bottom;
2688 
2689     if (!firstChild() && (!width() || !height()))
2690         return bottom;
2691 
2692     if (!hasColumns()) {
2693         // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
2694         // For now, we have to descend into all the children, since we may have a huge abs div inside
2695         // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
2696         // the abs div.
2697         // See the last test case in https://bugs.webkit.org/show_bug.cgi?id=9314 for why this is a problem.
2698         // For inline children, we miss relative positioned boxes that might be buried inside <span>s.
2699         for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
2700             if (!c->isFloatingOrPositioned() && c->isBox()) {
2701                 RenderBox* childBox = toRenderBox(c);
2702                 bottom = max(bottom, childBox->y() + childBox->lowestPosition(false));
2703             }
2704         }
2705     }
2706 
2707     if (includeSelf && isRelPositioned())
2708         bottom += relativePositionOffsetY();
2709     if (!includeOverflowInterior && hasOverflowClip())
2710         return bottom;
2711 
2712     int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetY() : 0;
2713 
2714     if (includeSelf)
2715         bottom = max(bottom, bottomLayoutOverflow() + relativeOffset);
2716 
2717     if (m_positionedObjects) {
2718         RenderBox* r;
2719         Iterator end = m_positionedObjects->end();
2720         for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2721             r = *it;
2722             // Fixed positioned objects do not scroll and thus should not constitute
2723             // part of the lowest position.
2724             if (r->style()->position() != FixedPosition) {
2725                 // FIXME: Should work for overflow sections too.
2726                 // If a positioned object lies completely to the left of the root it will be unreachable via scrolling.
2727                 // Therefore we should not allow it to contribute to the lowest position.
2728                 if (!isRenderView() || r->x() + r->width() > 0 || r->x() + r->rightmostPosition(false) > 0) {
2729                     int lp = r->y() + r->lowestPosition(false);
2730                     bottom = max(bottom, lp + relativeOffset);
2731                 }
2732             }
2733         }
2734     }
2735 
2736     if (hasColumns()) {
2737         Vector<IntRect>* colRects = columnRects();
2738         for (unsigned i = 0; i < colRects->size(); i++)
2739             bottom = max(bottom, colRects->at(i).bottom() + relativeOffset);
2740         return bottom;
2741     }
2742 
2743     if (m_floatingObjects) {
2744         FloatingObject* r;
2745         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2746         for ( ; (r = it.current()); ++it ) {
2747             if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
2748                 int lp = r->m_top + r->m_renderer->marginTop() + r->m_renderer->lowestPosition(false);
2749                 bottom = max(bottom, lp + relativeOffset);
2750             }
2751         }
2752     }
2753 
2754     if (!includeSelf) {
2755         bottom = max(bottom, borderTop() + paddingTop() + paddingBottom() + relativeOffset);
2756         if (childrenInline()) {
2757             if (lastRootBox()) {
2758                 int childBottomEdge = lastRootBox()->selectionBottom();
2759                 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset);
2760             }
2761         } else {
2762             // Find the last normal flow child.
2763             RenderBox* currBox = lastChildBox();
2764             while (currBox && currBox->isFloatingOrPositioned())
2765                 currBox = currBox->previousSiblingBox();
2766             if (currBox) {
2767                 int childBottomEdge = currBox->y() + currBox->height() + currBox->collapsedMarginBottom();
2768                 bottom = max(bottom, childBottomEdge + paddingBottom() + relativeOffset);
2769             }
2770         }
2771     }
2772 
2773     return bottom;
2774 }
2775 
rightmostPosition(bool includeOverflowInterior,bool includeSelf) const2776 int RenderBlock::rightmostPosition(bool includeOverflowInterior, bool includeSelf) const
2777 {
2778     int right = includeSelf && height() > 0 ? width() : 0;
2779 
2780     if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
2781         return right;
2782 
2783     if (!firstChild() && (!width() || !height()))
2784         return right;
2785 
2786     if (!hasColumns()) {
2787         // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
2788         // For now, we have to descend into all the children, since we may have a huge abs div inside
2789         // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
2790         // the abs div.
2791         for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
2792             if (!c->isFloatingOrPositioned() && c->isBox()) {
2793                 RenderBox* childBox = toRenderBox(c);
2794                 right = max(right, childBox->x() + childBox->rightmostPosition(false));
2795             }
2796         }
2797     }
2798 
2799     if (includeSelf && isRelPositioned())
2800         right += relativePositionOffsetX();
2801 
2802     if (!includeOverflowInterior && hasOverflowClip())
2803         return right;
2804 
2805     int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
2806 
2807     if (includeSelf)
2808         right = max(right, rightLayoutOverflow() + relativeOffset);
2809 
2810     if (m_positionedObjects) {
2811         RenderBox* r;
2812         Iterator end = m_positionedObjects->end();
2813         for (Iterator it = m_positionedObjects->begin() ; it != end; ++it) {
2814             r = *it;
2815             // Fixed positioned objects do not scroll and thus should not constitute
2816             // part of the rightmost position.
2817             if (r->style()->position() != FixedPosition) {
2818                 // FIXME: Should work for overflow sections too.
2819                 // If a positioned object lies completely above the root it will be unreachable via scrolling.
2820                 // Therefore we should not allow it to contribute to the rightmost position.
2821                 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) {
2822                     int rp = r->x() + r->rightmostPosition(false);
2823                     right = max(right, rp + relativeOffset);
2824                 }
2825             }
2826         }
2827     }
2828 
2829     if (hasColumns()) {
2830         // This only matters for LTR
2831         if (style()->direction() == LTR)
2832             right = max(columnRects()->last().right() + relativeOffset, right);
2833         return right;
2834     }
2835 
2836     if (m_floatingObjects) {
2837         FloatingObject* r;
2838         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2839         for ( ; (r = it.current()); ++it ) {
2840             if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
2841                 int rp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->rightmostPosition(false);
2842                 right = max(right, rp + relativeOffset);
2843             }
2844         }
2845     }
2846 
2847     if (!includeSelf) {
2848         right = max(right, borderLeft() + paddingLeft() + paddingRight() + relativeOffset);
2849         if (childrenInline()) {
2850             for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox()) {
2851                 int childRightEdge = currBox->x() + currBox->width();
2852 
2853                 // If this node is a root editable element, then the rightmostPosition should account for a caret at the end.
2854                 // FIXME: Need to find another way to do this, since scrollbars could show when we don't want them to.
2855                 if (node() && node()->isContentEditable() && node() == node()->rootEditableElement() && style()->direction() == LTR && !paddingRight())
2856                     childRightEdge += 1;
2857                 right = max(right, childRightEdge + paddingRight() + relativeOffset);
2858             }
2859         } else {
2860             // Walk all normal flow children.
2861             for (RenderBox* currBox = firstChildBox(); currBox; currBox = currBox->nextSiblingBox()) {
2862                 if (currBox->isFloatingOrPositioned())
2863                     continue;
2864                 int childRightEdge = currBox->x() + currBox->width() + currBox->marginRight();
2865                 right = max(right, childRightEdge + paddingRight() + relativeOffset);
2866             }
2867         }
2868     }
2869 
2870     return right;
2871 }
2872 
leftmostPosition(bool includeOverflowInterior,bool includeSelf) const2873 int RenderBlock::leftmostPosition(bool includeOverflowInterior, bool includeSelf) const
2874 {
2875     int left = includeSelf && height() > 0 ? 0 : width();
2876 
2877     if (!includeOverflowInterior && (hasOverflowClip() || hasControlClip()))
2878         return left;
2879 
2880     if (!firstChild() && (!width() || !height()))
2881         return left;
2882 
2883     if (!hasColumns()) {
2884         // FIXME: Come up with a way to use the layer tree to avoid visiting all the kids.
2885         // For now, we have to descend into all the children, since we may have a huge abs div inside
2886         // a tiny rel div buried somewhere deep in our child tree.  In this case we have to get to
2887         // the abs div.
2888         for (RenderObject* c = firstChild(); c; c = c->nextSibling()) {
2889             if (!c->isFloatingOrPositioned() && c->isBox()) {
2890                 RenderBox* childBox = toRenderBox(c);
2891                 left = min(left, childBox->x() + childBox->leftmostPosition(false));
2892             }
2893         }
2894     }
2895 
2896     if (includeSelf && isRelPositioned())
2897         left += relativePositionOffsetX();
2898 
2899     if (!includeOverflowInterior && hasOverflowClip())
2900         return left;
2901 
2902     int relativeOffset = includeSelf && isRelPositioned() ? relativePositionOffsetX() : 0;
2903 
2904     if (includeSelf)
2905         left = min(left, leftLayoutOverflow() + relativeOffset);
2906 
2907     if (m_positionedObjects) {
2908         RenderBox* r;
2909         Iterator end = m_positionedObjects->end();
2910         for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2911             r = *it;
2912             // Fixed positioned objects do not scroll and thus should not constitute
2913             // part of the leftmost position.
2914             if (r->style()->position() != FixedPosition) {
2915                 // FIXME: Should work for overflow sections too.
2916                 // If a positioned object lies completely above the root it will be unreachable via scrolling.
2917                 // Therefore we should not allow it to contribute to the leftmost position.
2918                 if (!isRenderView() || r->y() + r->height() > 0 || r->y() + r->lowestPosition(false) > 0) {
2919                     int lp = r->x() + r->leftmostPosition(false);
2920                     left = min(left, lp + relativeOffset);
2921                 }
2922             }
2923         }
2924     }
2925 
2926     if (hasColumns()) {
2927         // This only matters for RTL
2928         if (style()->direction() == RTL)
2929             left = min(columnRects()->last().x() + relativeOffset, left);
2930         return left;
2931     }
2932 
2933     if (m_floatingObjects) {
2934         FloatingObject* r;
2935         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2936         for ( ; (r = it.current()); ++it ) {
2937             if (r->m_shouldPaint || r->m_renderer->hasSelfPaintingLayer()) {
2938                 int lp = r->m_left + r->m_renderer->marginLeft() + r->m_renderer->leftmostPosition(false);
2939                 left = min(left, lp + relativeOffset);
2940             }
2941         }
2942     }
2943 
2944     if (!includeSelf && firstLineBox()) {
2945         for (InlineRunBox* currBox = firstLineBox(); currBox; currBox = currBox->nextLineBox())
2946             left = min(left, (int)currBox->x() + relativeOffset);
2947     }
2948 
2949     return left;
2950 }
2951 
2952 int
leftBottom()2953 RenderBlock::leftBottom()
2954 {
2955     if (!m_floatingObjects) return 0;
2956     int bottom = 0;
2957     FloatingObject* r;
2958     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2959     for ( ; (r = it.current()); ++it )
2960         if (r->m_bottom > bottom && r->type() == FloatingObject::FloatLeft)
2961             bottom = r->m_bottom;
2962 
2963     return bottom;
2964 }
2965 
2966 int
rightBottom()2967 RenderBlock::rightBottom()
2968 {
2969     if (!m_floatingObjects) return 0;
2970     int bottom = 0;
2971     FloatingObject* r;
2972     DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
2973     for ( ; (r = it.current()); ++it )
2974         if (r->m_bottom>bottom && r->type() == FloatingObject::FloatRight)
2975             bottom = r->m_bottom;
2976 
2977     return bottom;
2978 }
2979 
markLinesDirtyInVerticalRange(int top,int bottom,RootInlineBox * highest)2980 void RenderBlock::markLinesDirtyInVerticalRange(int top, int bottom, RootInlineBox* highest)
2981 {
2982     if (top >= bottom)
2983         return;
2984 
2985     RootInlineBox* lowestDirtyLine = lastRootBox();
2986     RootInlineBox* afterLowest = lowestDirtyLine;
2987     while (lowestDirtyLine && lowestDirtyLine->blockHeight() >= bottom) {
2988         afterLowest = lowestDirtyLine;
2989         lowestDirtyLine = lowestDirtyLine->prevRootBox();
2990     }
2991 
2992     while (afterLowest && afterLowest != highest && afterLowest->blockHeight() >= top) {
2993         afterLowest->markDirty();
2994         afterLowest = afterLowest->prevRootBox();
2995     }
2996 }
2997 
clearFloats()2998 void RenderBlock::clearFloats()
2999 {
3000     // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
3001     if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) {
3002         if (m_floatingObjects)
3003             m_floatingObjects->clear();
3004         return;
3005     }
3006 
3007     typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
3008     RendererToFloatInfoMap floatMap;
3009 
3010     if (m_floatingObjects) {
3011         if (childrenInline()) {
3012             m_floatingObjects->first();
3013             while (FloatingObject* f = m_floatingObjects->take())
3014                 floatMap.add(f->m_renderer, f);
3015         } else
3016             m_floatingObjects->clear();
3017     }
3018 
3019     // Attempt to locate a previous sibling with overhanging floats.  We skip any elements that are
3020     // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
3021     // to avoid floats.
3022     bool parentHasFloats = false;
3023     RenderObject* prev = previousSibling();
3024     while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
3025         if (prev->isFloating())
3026             parentHasFloats = true;
3027          prev = prev->previousSibling();
3028     }
3029 
3030     // First add in floats from the parent.
3031     int offset = y();
3032     if (parentHasFloats) {
3033         RenderBlock* parentBlock = toRenderBlock(parent());
3034         addIntrudingFloats(parentBlock, parentBlock->borderLeft() + parentBlock->paddingLeft(), offset);
3035     }
3036 
3037     int xoffset = 0;
3038     if (prev)
3039         offset -= toRenderBox(prev)->y();
3040     else if (parent()->isBox()) {
3041         prev = parent();
3042         xoffset += toRenderBox(prev)->borderLeft() + toRenderBox(prev)->paddingLeft();
3043     }
3044 
3045     // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
3046     if (!prev || !prev->isRenderBlock())
3047         return;
3048 
3049     RenderBlock* block = toRenderBlock(prev);
3050     if (block->m_floatingObjects && block->floatBottom() > offset)
3051         addIntrudingFloats(block, xoffset, offset);
3052 
3053     if (childrenInline()) {
3054         int changeTop = INT_MAX;
3055         int changeBottom = INT_MIN;
3056         if (m_floatingObjects) {
3057             for (FloatingObject* f = m_floatingObjects->first(); f; f = m_floatingObjects->next()) {
3058                 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
3059                 if (oldFloatingObject) {
3060                     if (f->m_width != oldFloatingObject->m_width || f->m_left != oldFloatingObject->m_left) {
3061                         changeTop = 0;
3062                         changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
3063                     } else if (f->m_bottom != oldFloatingObject->m_bottom) {
3064                         changeTop = min(changeTop, min(f->m_bottom, oldFloatingObject->m_bottom));
3065                         changeBottom = max(changeBottom, max(f->m_bottom, oldFloatingObject->m_bottom));
3066                     }
3067 
3068                     floatMap.remove(f->m_renderer);
3069                     delete oldFloatingObject;
3070                 } else {
3071                     changeTop = 0;
3072                     changeBottom = max(changeBottom, f->m_bottom);
3073                 }
3074             }
3075         }
3076 
3077         RendererToFloatInfoMap::iterator end = floatMap.end();
3078         for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
3079             FloatingObject* floatingObject = (*it).second;
3080             if (!floatingObject->m_isDescendant) {
3081                 changeTop = 0;
3082                 changeBottom = max(changeBottom, floatingObject->m_bottom);
3083             }
3084         }
3085         deleteAllValues(floatMap);
3086 
3087         markLinesDirtyInVerticalRange(changeTop, changeBottom);
3088     }
3089 }
3090 
addOverhangingFloats(RenderBlock * child,int xoff,int yoff,bool makeChildPaintOtherFloats)3091 int RenderBlock::addOverhangingFloats(RenderBlock* child, int xoff, int yoff, bool makeChildPaintOtherFloats)
3092 {
3093     // Prevent floats from being added to the canvas by the root element, e.g., <html>.
3094     if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot())
3095         return 0;
3096 
3097     int lowestFloatBottom = 0;
3098 
3099     // Floats that will remain the child's responsibility to paint should factor into its
3100     // overflow.
3101     DeprecatedPtrListIterator<FloatingObject> it(*child->m_floatingObjects);
3102     for (FloatingObject* r; (r = it.current()); ++it) {
3103         int bottom = child->y() + r->m_bottom;
3104         lowestFloatBottom = max(lowestFloatBottom, bottom);
3105 
3106         if (bottom > height()) {
3107             // If the object is not in the list, we add it now.
3108             if (!containsFloat(r->m_renderer)) {
3109                 FloatingObject *floatingObj = new FloatingObject(r->type());
3110                 floatingObj->m_top = r->m_top - yoff;
3111                 floatingObj->m_bottom = r->m_bottom - yoff;
3112                 floatingObj->m_left = r->m_left - xoff;
3113                 floatingObj->m_width = r->m_width;
3114                 floatingObj->m_renderer = r->m_renderer;
3115 
3116                 // The nearest enclosing layer always paints the float (so that zindex and stacking
3117                 // behaves properly).  We always want to propagate the desire to paint the float as
3118                 // far out as we can, to the outermost block that overlaps the float, stopping only
3119                 // if we hit a self-painting layer boundary.
3120                 if (r->m_renderer->enclosingSelfPaintingLayer() == enclosingSelfPaintingLayer())
3121                     r->m_shouldPaint = false;
3122                 else
3123                     floatingObj->m_shouldPaint = false;
3124 
3125                 // We create the floating object list lazily.
3126                 if (!m_floatingObjects) {
3127                     m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
3128                     m_floatingObjects->setAutoDelete(true);
3129                 }
3130                 m_floatingObjects->append(floatingObj);
3131             }
3132         } else if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() &&
3133                    r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingLayer() == child->enclosingLayer())
3134             // The float is not overhanging from this block, so if it is a descendant of the child, the child should
3135             // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
3136             // layer.
3137             // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
3138             // it should paint.
3139             r->m_shouldPaint = true;
3140 
3141         if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer())
3142             child->addOverflowFromChild(r->m_renderer, IntSize(r->m_left + r->m_renderer->marginLeft(), r->m_top + r->m_renderer->marginTop()));
3143     }
3144     return lowestFloatBottom;
3145 }
3146 
addIntrudingFloats(RenderBlock * prev,int xoff,int yoff)3147 void RenderBlock::addIntrudingFloats(RenderBlock* prev, int xoff, int yoff)
3148 {
3149     // If the parent or previous sibling doesn't have any floats to add, don't bother.
3150     if (!prev->m_floatingObjects)
3151         return;
3152 
3153     DeprecatedPtrListIterator<FloatingObject> it(*prev->m_floatingObjects);
3154     for (FloatingObject *r; (r = it.current()); ++it) {
3155         if (r->m_bottom > yoff) {
3156             // The object may already be in our list. Check for it up front to avoid
3157             // creating duplicate entries.
3158             FloatingObject* f = 0;
3159             if (m_floatingObjects) {
3160                 DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
3161                 while ((f = it.current())) {
3162                     if (f->m_renderer == r->m_renderer) break;
3163                     ++it;
3164                 }
3165             }
3166             if (!f) {
3167                 FloatingObject *floatingObj = new FloatingObject(r->type());
3168                 floatingObj->m_top = r->m_top - yoff;
3169                 floatingObj->m_bottom = r->m_bottom - yoff;
3170                 floatingObj->m_left = r->m_left - xoff;
3171                 // Applying the child's margin makes no sense in the case where the child was passed in.
3172                 // since his own margin was added already through the subtraction of the |xoff| variable
3173                 // above.  |xoff| will equal -flow->marginLeft() in this case, so it's already been taken
3174                 // into account.  Only apply this code if |child| is false, since otherwise the left margin
3175                 // will get applied twice.
3176                 if (prev != parent())
3177                     floatingObj->m_left += prev->marginLeft();
3178                 floatingObj->m_left -= marginLeft();
3179                 floatingObj->m_shouldPaint = false;  // We are not in the direct inheritance chain for this float. We will never paint it.
3180                 floatingObj->m_width = r->m_width;
3181                 floatingObj->m_renderer = r->m_renderer;
3182 
3183                 // We create the floating object list lazily.
3184                 if (!m_floatingObjects) {
3185                     m_floatingObjects = new DeprecatedPtrList<FloatingObject>;
3186                     m_floatingObjects->setAutoDelete(true);
3187                 }
3188                 m_floatingObjects->append(floatingObj);
3189             }
3190         }
3191     }
3192 }
3193 
avoidsFloats() const3194 bool RenderBlock::avoidsFloats() const
3195 {
3196     // Floats can't intrude into our box if we have a non-auto column count or width.
3197     return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
3198 }
3199 
containsFloat(RenderObject * o)3200 bool RenderBlock::containsFloat(RenderObject* o)
3201 {
3202     if (m_floatingObjects) {
3203         DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
3204         while (it.current()) {
3205             if (it.current()->m_renderer == o)
3206                 return true;
3207             ++it;
3208         }
3209     }
3210     return false;
3211 }
3212 
markAllDescendantsWithFloatsForLayout(RenderBox * floatToRemove,bool inLayout)3213 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
3214 {
3215     setChildNeedsLayout(true, !inLayout);
3216 
3217     if (floatToRemove)
3218         removeFloatingObject(floatToRemove);
3219 
3220     // Iterate over our children and mark them as needed.
3221     if (!childrenInline()) {
3222         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
3223             if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock())
3224                 continue;
3225             RenderBlock* childBlock = toRenderBlock(child);
3226             if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
3227                 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
3228         }
3229     }
3230 }
3231 
getClearDelta(RenderBox * child,int yPos)3232 int RenderBlock::getClearDelta(RenderBox* child, int yPos)
3233 {
3234     // There is no need to compute clearance if we have no floats.
3235     if (!containsFloats())
3236         return 0;
3237 
3238     // At least one float is present.  We need to perform the clearance computation.
3239     bool clearSet = child->style()->clear() != CNONE;
3240     int bottom = 0;
3241     switch (child->style()->clear()) {
3242         case CNONE:
3243             break;
3244         case CLEFT:
3245             bottom = leftBottom();
3246             break;
3247         case CRIGHT:
3248             bottom = rightBottom();
3249             break;
3250         case CBOTH:
3251             bottom = floatBottom();
3252             break;
3253     }
3254 
3255     // 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).
3256     int result = clearSet ? max(0, bottom - yPos) : 0;
3257     if (!result && child->avoidsFloats()) {
3258         int availableWidth = this->availableWidth();
3259         if (child->minPrefWidth() > availableWidth)
3260             return 0;
3261 
3262         int y = yPos;
3263         while (true) {
3264             int widthAtY = lineWidth(y, false);
3265             if (widthAtY == availableWidth)
3266                 return y - yPos;
3267 
3268             int oldChildY = child->y();
3269             int oldChildWidth = child->width();
3270             child->setY(y);
3271             child->calcWidth();
3272             int childWidthAtY = child->width();
3273             child->setY(oldChildY);
3274             child->setWidth(oldChildWidth);
3275 
3276             if (childWidthAtY <= widthAtY)
3277                 return y - yPos;
3278 
3279             y = nextFloatBottomBelow(y);
3280             ASSERT(y >= yPos);
3281             if (y < yPos)
3282                 break;
3283         }
3284         ASSERT_NOT_REACHED();
3285     }
3286     return result;
3287 }
3288 
isPointInOverflowControl(HitTestResult & result,int _x,int _y,int _tx,int _ty)3289 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
3290 {
3291     if (!scrollsOverflow())
3292         return false;
3293 
3294     return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty));
3295 }
3296 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int _x,int _y,int _tx,int _ty,HitTestAction hitTestAction)3297 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
3298 {
3299     int tx = _tx + x();
3300     int ty = _ty + y();
3301 
3302     if (!isRenderView()) {
3303         // Check if we need to do anything at all.
3304         IntRect overflowBox = visibleOverflowRect();
3305         overflowBox.move(tx, ty);
3306         if (!overflowBox.contains(_x, _y))
3307             return false;
3308     }
3309 
3310     if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) {
3311         updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
3312         return true;
3313     }
3314 
3315     // If we have clipping, then we can't have any spillout.
3316     bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
3317     bool useClip = (hasControlClip() || useOverflowClip);
3318     bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).contains(_x, _y) : overflowClipRect(tx, ty).contains(_x, _y));
3319     if (checkChildren) {
3320         // Hit test descendants first.
3321         int scrolledX = tx;
3322         int scrolledY = ty;
3323         if (hasOverflowClip())
3324             layer()->subtractScrolledContentOffset(scrolledX, scrolledY);
3325 
3326         // Hit test contents if we don't have columns.
3327         if (!hasColumns() && hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
3328             return true;
3329 
3330         // Hit test our columns if we do have them.
3331         if (hasColumns() && hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction))
3332             return true;
3333 
3334         // Hit test floats.
3335         if (hitTestAction == HitTestFloat && m_floatingObjects) {
3336             if (isRenderView()) {
3337                 scrolledX += toRenderView(this)->frameView()->scrollX();
3338                 scrolledY += toRenderView(this)->frameView()->scrollY();
3339             }
3340 
3341             FloatingObject* o;
3342             DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
3343             for (it.toLast(); (o = it.current()); --it) {
3344                 if (o->m_shouldPaint && !o->m_renderer->hasSelfPaintingLayer()) {
3345                     int xoffset = scrolledX + o->m_left + o->m_renderer->marginLeft() - o->m_renderer->x();
3346                     int yoffset =  scrolledY + o->m_top + o->m_renderer->marginTop() - o->m_renderer->y();
3347                     if (o->m_renderer->hitTest(request, result, IntPoint(_x, _y), xoffset, yoffset)) {
3348                         updateHitTestResult(result, IntPoint(_x - xoffset, _y - yoffset));
3349                         return true;
3350                     }
3351                 }
3352             }
3353         }
3354     }
3355 
3356     // Now hit test our background
3357     if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
3358         IntRect boundsRect(tx, ty, width(), height());
3359         if (visibleToHitTesting() && boundsRect.contains(_x, _y)) {
3360             updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
3361             return true;
3362         }
3363     }
3364 
3365     return false;
3366 }
3367 
hitTestColumns(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)3368 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
3369 {
3370     // We need to do multiple passes, breaking up our hit testing into strips.
3371     // We can always go left to right, since column contents are clipped (meaning that there
3372     // can't be any overlap).
3373     int currXOffset = 0;
3374     int currYOffset = 0;
3375     int colGap = columnGap();
3376     Vector<IntRect>* colRects = columnRects();
3377     for (unsigned i = 0; i < colRects->size(); i++) {
3378         IntRect colRect = colRects->at(i);
3379         colRect.move(tx, ty);
3380 
3381         if (colRect.contains(x, y)) {
3382             // The point is inside this column.
3383             // Adjust tx and ty to change where we hit test.
3384 
3385             int finalX = tx + currXOffset;
3386             int finalY = ty + currYOffset;
3387             return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
3388         }
3389 
3390         // Move to the next position.
3391         if (style()->direction() == LTR)
3392             currXOffset += colRect.width() + colGap;
3393         else
3394             currXOffset -= (colRect.width() + colGap);
3395 
3396         currYOffset -= colRect.height();
3397     }
3398 
3399     return false;
3400 }
3401 
hitTestContents(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)3402 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
3403 {
3404     if (childrenInline() && !isTable()) {
3405         // We have to hit-test our line boxes.
3406         if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction)) {
3407             updateHitTestResult(result, IntPoint(x - tx, y - ty));
3408             return true;
3409         }
3410     } else {
3411         // Hit test our children.
3412         HitTestAction childHitTest = hitTestAction;
3413         if (hitTestAction == HitTestChildBlockBackgrounds)
3414             childHitTest = HitTestChildBlockBackground;
3415         for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
3416             if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, tx, ty, childHitTest)) {
3417                 updateHitTestResult(result, IntPoint(x - tx, y - ty));
3418                 return true;
3419             }
3420         }
3421     }
3422 
3423     return false;
3424 }
3425 
positionForBox(InlineBox * box,bool start) const3426 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
3427 {
3428     if (!box)
3429         return Position();
3430 
3431     if (!box->renderer()->node())
3432         return Position(node(), start ? caretMinOffset() : caretMaxOffset());
3433 
3434     if (!box->isInlineTextBox())
3435         return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
3436 
3437     InlineTextBox *textBox = static_cast<InlineTextBox *>(box);
3438     return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
3439 }
3440 
positionForRenderer(RenderObject * renderer,bool start) const3441 Position RenderBlock::positionForRenderer(RenderObject* renderer, bool start) const
3442 {
3443     if (!renderer)
3444         return Position(node(), 0);
3445 
3446     Node* n = renderer->node() ? renderer->node() : node();
3447     if (!n)
3448         return Position();
3449 
3450     ASSERT(renderer == n->renderer());
3451 
3452     int offset = start ? renderer->caretMinOffset() : renderer->caretMaxOffset();
3453 
3454     // FIXME: This was a runtime check that seemingly couldn't fail; changed it to an assertion for now.
3455     ASSERT(!n->isCharacterDataNode() || renderer->isText());
3456 
3457     return Position(n, offset);
3458 }
3459 
3460 // FIXME: This function should go on RenderObject as an instance method. Then
3461 // all cases in which positionForPoint recurs could call this instead to
3462 // prevent crossing editable boundaries. This would require many tests.
positionForPointRespectingEditingBoundaries(RenderBox * parent,RenderBox * child,const IntPoint & pointInParentCoordinates)3463 static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBox* parent, RenderBox* child, const IntPoint& pointInParentCoordinates)
3464 {
3465     IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location());
3466 
3467     // If this is an anonymous renderer, we just recur normally
3468     Node* childNode = child->node();
3469     if (!childNode)
3470         return child->positionForPoint(pointInChildCoordinates);
3471 
3472     // Otherwise, first make sure that the editability of the parent and child agree.
3473     // If they don't agree, then we return a visible position just before or after the child
3474     RenderObject* ancestor = parent;
3475     while (ancestor && !ancestor->node())
3476         ancestor = ancestor->parent();
3477 
3478     // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
3479     if (!ancestor || ancestor->node()->isContentEditable() == childNode->isContentEditable())
3480         return child->positionForPoint(pointInChildCoordinates);
3481 
3482     // Otherwise return before or after the child, depending on if the click was left or right of the child
3483     int childMidX = child->width() / 2;
3484     if (pointInChildCoordinates.x() < childMidX)
3485         return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
3486     return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
3487 }
3488 
positionForPointWithInlineChildren(const IntPoint & pointInContents)3489 VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInContents)
3490 {
3491     ASSERT(childrenInline());
3492 
3493     if (!firstRootBox())
3494         return createVisiblePosition(0, DOWNSTREAM);
3495 
3496     // look for the closest line box in the root box which is at the passed-in y coordinate
3497     InlineBox* closestBox = 0;
3498     RootInlineBox* firstRootBoxWithChildren = 0;
3499     RootInlineBox* lastRootBoxWithChildren = 0;
3500     for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
3501         if (!root->firstLeafChild())
3502             continue;
3503         if (!firstRootBoxWithChildren)
3504             firstRootBoxWithChildren = root;
3505         lastRootBoxWithChildren = root;
3506 
3507         // set the bottom based on whether there is a next root box
3508         // FIXME: This will consider nextRootBox even if it has no children, and maybe it shouldn't.
3509         int bottom;
3510         if (root->nextRootBox()) {
3511             // FIXME: We would prefer to make the break point halfway between the bottom
3512             // of the previous root box and the top of the next root box.
3513             bottom = root->nextRootBox()->lineTop();
3514         } else
3515             bottom = root->lineBottom() + verticalLineClickFudgeFactor;
3516 
3517         // check if this root line box is located at this y coordinate
3518         if (pointInContents.y() < bottom) {
3519             closestBox = root->closestLeafChildForXPos(pointInContents.x());
3520             if (closestBox)
3521                 break;
3522         }
3523     }
3524 
3525     Settings* settings = document()->settings();
3526     bool useWindowsBehavior = settings && settings->editingBehavior() == EditingWindowsBehavior;
3527 
3528     if (useWindowsBehavior && !closestBox && lastRootBoxWithChildren) {
3529         // y coordinate is below last root line box, pretend we hit it
3530         closestBox = lastRootBoxWithChildren->closestLeafChildForXPos(pointInContents.x());
3531     }
3532 
3533     if (closestBox) {
3534         if (!useWindowsBehavior && pointInContents.y() < firstRootBoxWithChildren->lineTop() - verticalLineClickFudgeFactor) {
3535             // y coordinate is above first root line box, so return the start of the first
3536             return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM);
3537         }
3538 
3539         // pass the box a y position that is inside it
3540         return closestBox->renderer()->positionForPoint(IntPoint(pointInContents.x(), closestBox->m_y));
3541     }
3542 
3543     if (lastRootBoxWithChildren) {
3544         // We hit this case for Mac behavior when the Y coordinate is below the last box.
3545         ASSERT(!useWindowsBehavior);
3546         return VisiblePosition(positionForBox(lastRootBoxWithChildren->lastLeafChild(), false), DOWNSTREAM);
3547     }
3548 
3549     // Can't reach this. We have a root line box, but it has no kids.
3550     // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3551     // seems to hit this code path.
3552     return createVisiblePosition(0, DOWNSTREAM);
3553 }
3554 
isChildHitTestCandidate(RenderBox * box)3555 static inline bool isChildHitTestCandidate(RenderBox* box)
3556 {
3557     return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned();
3558 }
3559 
positionForPoint(const IntPoint & point)3560 VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
3561 {
3562     if (isTable())
3563         return RenderBox::positionForPoint(point);
3564 
3565     if (isReplaced()) {
3566         if (point.y() < 0 || (point.y() < height() && point.x() < 0))
3567             return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
3568         if (point.y() >= height() || (point.y() >= 0 && point.x() >= width()))
3569             return createVisiblePosition(caretMaxOffset(), DOWNSTREAM);
3570     }
3571 
3572     int contentsX = point.x();
3573     int contentsY = point.y();
3574     offsetForContents(contentsX, contentsY);
3575     IntPoint pointInContents(contentsX, contentsY);
3576 
3577     if (childrenInline())
3578         return positionForPointWithInlineChildren(pointInContents);
3579 
3580     if (lastChildBox() && contentsY > lastChildBox()->y()) {
3581         for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) {
3582             if (isChildHitTestCandidate(childBox))
3583                 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
3584         }
3585     } else {
3586         for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
3587             // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
3588             if (isChildHitTestCandidate(childBox) && contentsY < childBox->frameRect().bottom())
3589                 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
3590         }
3591     }
3592 
3593     // We only get here if there are no hit test candidate children below the click.
3594     return RenderBox::positionForPoint(point);
3595 }
3596 
offsetForContents(int & tx,int & ty) const3597 void RenderBlock::offsetForContents(int& tx, int& ty) const
3598 {
3599     if (hasOverflowClip())
3600         layer()->addScrolledContentOffset(tx, ty);
3601 
3602     if (hasColumns()) {
3603         IntPoint contentsPoint(tx, ty);
3604         adjustPointToColumnContents(contentsPoint);
3605         tx = contentsPoint.x();
3606         ty = contentsPoint.y();
3607     }
3608 }
3609 
availableWidth() const3610 int RenderBlock::availableWidth() const
3611 {
3612     // If we have multiple columns, then the available width is reduced to our column width.
3613     if (hasColumns())
3614         return desiredColumnWidth();
3615     return contentWidth();
3616 }
3617 
columnGap() const3618 int RenderBlock::columnGap() const
3619 {
3620     if (style()->hasNormalColumnGap())
3621         return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
3622     return static_cast<int>(style()->columnGap());
3623 }
3624 
calcColumnWidth()3625 void RenderBlock::calcColumnWidth()
3626 {
3627     // Calculate our column width and column count.
3628     unsigned desiredColumnCount = 1;
3629     int desiredColumnWidth = contentWidth();
3630 
3631     // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
3632     if (document()->printing() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) {
3633         setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3634         return;
3635     }
3636 
3637     int availWidth = desiredColumnWidth;
3638     int colGap = columnGap();
3639     int colWidth = max(1, static_cast<int>(style()->columnWidth()));
3640     int colCount = max(1, static_cast<int>(style()->columnCount()));
3641 
3642     if (style()->hasAutoColumnWidth()) {
3643         if ((colCount - 1) * colGap < availWidth) {
3644             desiredColumnCount = colCount;
3645             desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
3646         } else if (colGap < availWidth) {
3647             desiredColumnCount = availWidth / colGap;
3648             if (desiredColumnCount < 1)
3649                 desiredColumnCount = 1;
3650             desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
3651         }
3652     } else if (style()->hasAutoColumnCount()) {
3653         if (colWidth < availWidth) {
3654             desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
3655             if (desiredColumnCount < 1)
3656                 desiredColumnCount = 1;
3657             desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
3658         }
3659     } else {
3660         // Both are set.
3661         if (colCount * colWidth + (colCount - 1) * colGap <= availWidth) {
3662             desiredColumnCount = colCount;
3663             desiredColumnWidth = colWidth;
3664         } else if (colWidth < availWidth) {
3665             desiredColumnCount = (availWidth + colGap) / (colWidth + colGap);
3666             if (desiredColumnCount < 1)
3667                 desiredColumnCount = 1;
3668             desiredColumnWidth = (availWidth - (desiredColumnCount - 1) * colGap) / desiredColumnCount;
3669         }
3670     }
3671     setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3672 }
3673 
setDesiredColumnCountAndWidth(int count,int width)3674 void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
3675 {
3676     if (count == 1 && style()->hasAutoColumnWidth()) {
3677         if (hasColumns()) {
3678             delete gColumnInfoMap->take(this);
3679             setHasColumns(false);
3680         }
3681     } else {
3682         ColumnInfo* info;
3683         if (hasColumns())
3684             info = gColumnInfoMap->get(this);
3685         else {
3686             if (!gColumnInfoMap)
3687                 gColumnInfoMap = new ColumnInfoMap;
3688             info = new ColumnInfo;
3689             gColumnInfoMap->add(this, info);
3690             setHasColumns(true);
3691         }
3692         info->m_desiredColumnCount = count;
3693         info->m_desiredColumnWidth = width;
3694     }
3695 }
3696 
desiredColumnWidth() const3697 int RenderBlock::desiredColumnWidth() const
3698 {
3699     if (!hasColumns())
3700         return contentWidth();
3701     return gColumnInfoMap->get(this)->m_desiredColumnWidth;
3702 }
3703 
desiredColumnCount() const3704 unsigned RenderBlock::desiredColumnCount() const
3705 {
3706     if (!hasColumns())
3707         return 1;
3708     return gColumnInfoMap->get(this)->m_desiredColumnCount;
3709 }
3710 
columnRects() const3711 Vector<IntRect>* RenderBlock::columnRects() const
3712 {
3713     if (!hasColumns())
3714         return 0;
3715     return &gColumnInfoMap->get(this)->m_columnRects;
3716 }
3717 
layoutColumns(int endOfContent,int requestedColumnHeight)3718 int RenderBlock::layoutColumns(int endOfContent, int requestedColumnHeight)
3719 {
3720     // Don't do anything if we have no columns
3721     if (!hasColumns())
3722         return -1;
3723 
3724     ColumnInfo* info = gColumnInfoMap->get(this);
3725     int desiredColumnWidth = info->m_desiredColumnWidth;
3726     int desiredColumnCount = info->m_desiredColumnCount;
3727     Vector<IntRect>* columnRects = &info->m_columnRects;
3728 
3729     bool computeIntrinsicHeight = (endOfContent == -1);
3730 
3731     // Fill the columns in to the available height.  Attempt to balance the height of the columns.
3732     // Add in half our line-height to help with best-guess initial balancing.
3733     int columnSlop = lineHeight(false) / 2;
3734     int remainingSlopSpace = columnSlop * desiredColumnCount;
3735     int availableHeight = contentHeight();
3736     int colHeight;
3737     if (computeIntrinsicHeight && requestedColumnHeight >= 0)
3738         colHeight = requestedColumnHeight;
3739     else if (computeIntrinsicHeight)
3740         colHeight = availableHeight / desiredColumnCount + columnSlop;
3741     else
3742         colHeight = availableHeight;
3743     int originalColHeight = colHeight;
3744 
3745     int colGap = columnGap();
3746 
3747     // Compute a collection of column rects.
3748     columnRects->clear();
3749 
3750     // Then we do a simulated "paint" into the column slices and allow the content to slightly adjust our individual column rects.
3751     // FIXME: We need to take into account layers that are affected by the columns as well here so that they can have an opportunity
3752     // to adjust column rects also.
3753     RenderView* v = view();
3754     int left = borderLeft() + paddingLeft();
3755     int top = borderTop() + paddingTop();
3756     int currX = style()->direction() == LTR ? borderLeft() + paddingLeft() : borderLeft() + paddingLeft() + contentWidth() - desiredColumnWidth;
3757     int currY = top;
3758     unsigned colCount = desiredColumnCount;
3759     int maxColBottom = borderTop() + paddingTop();
3760     int contentBottom = top + availableHeight;
3761     int minimumColumnHeight = -1;
3762     for (unsigned i = 0; i < colCount; i++) {
3763         // If we aren't constrained, then the last column can just get all the remaining space.
3764         if (computeIntrinsicHeight && i == colCount - 1)
3765             colHeight = availableHeight;
3766 
3767         // This represents the real column position.
3768         IntRect colRect(currX, top, desiredColumnWidth, colHeight);
3769 
3770         // For the simulated paint, we pretend like everything is in one long strip.
3771         IntRect pageRect(left, currY, desiredColumnWidth, colHeight);
3772         v->setPrintRect(pageRect);
3773         v->setTruncatedAt(currY + colHeight);
3774         GraphicsContext context((PlatformGraphicsContext*)0);
3775         RenderObject::PaintInfo paintInfo(&context, pageRect, PaintPhaseForeground, false, 0, 0);
3776 
3777         setHasColumns(false);
3778         paintObject(paintInfo, 0, 0);
3779         setHasColumns(true);
3780 
3781         if (computeIntrinsicHeight && v->minimumColumnHeight() > originalColHeight) {
3782             // The initial column height was too small to contain one line of text.
3783             minimumColumnHeight = max(minimumColumnHeight, v->minimumColumnHeight());
3784         }
3785 
3786         int adjustedBottom = v->bestTruncatedAt();
3787         if (adjustedBottom <= currY)
3788             adjustedBottom = currY + colHeight;
3789 
3790         colRect.setHeight(adjustedBottom - currY);
3791 
3792         // Add in the lost space to the subsequent columns.
3793         // FIXME: This will create a "staircase" effect if there are enough columns, but the effect should be pretty subtle.
3794         if (computeIntrinsicHeight) {
3795             int lostSpace = colHeight - colRect.height();
3796             if (lostSpace > remainingSlopSpace) {
3797                 // Redestribute the space among the remaining columns.
3798                 int spaceToRedistribute = lostSpace - remainingSlopSpace;
3799                 int remainingColumns = colCount - i + 1;
3800                 colHeight += spaceToRedistribute / remainingColumns;
3801             }
3802             remainingSlopSpace = max(0, remainingSlopSpace - lostSpace);
3803         }
3804 
3805         if (style()->direction() == LTR)
3806             currX += desiredColumnWidth + colGap;
3807         else
3808             currX -= (desiredColumnWidth + colGap);
3809 
3810         currY += colRect.height();
3811         availableHeight -= colRect.height();
3812 
3813         maxColBottom = max(colRect.bottom(), maxColBottom);
3814 
3815         columnRects->append(colRect);
3816 
3817         // Start adding in more columns as long as there's still content left.
3818         if (currY < endOfContent && i == colCount - 1 && (computeIntrinsicHeight || contentHeight()))
3819             colCount++;
3820     }
3821 
3822     if (minimumColumnHeight >= 0) {
3823         // If originalColHeight was too small, we need to try to layout again.
3824         return layoutColumns(endOfContent, minimumColumnHeight);
3825     }
3826 
3827     int overflowRight = max(width(), currX - colGap);
3828     int overflowLeft = min(0, currX + desiredColumnWidth + colGap);
3829     int overflowHeight = maxColBottom;
3830     int toAdd = borderBottom() + paddingBottom() + horizontalScrollbarHeight();
3831 
3832     if (computeIntrinsicHeight)
3833         setHeight(maxColBottom + toAdd);
3834 
3835     m_overflow.clear();
3836     addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
3837 
3838     v->setPrintRect(IntRect());
3839     v->setTruncatedAt(0);
3840 
3841     ASSERT(colCount == columnRects->size());
3842 
3843     return contentBottom;
3844 }
3845 
adjustPointToColumnContents(IntPoint & point) const3846 void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
3847 {
3848     // Just bail if we have no columns.
3849     if (!hasColumns())
3850         return;
3851 
3852     Vector<IntRect>* colRects = columnRects();
3853 
3854     // Determine which columns we intersect.
3855     int colGap = columnGap();
3856     int leftGap = colGap / 2;
3857     IntPoint columnPoint(colRects->at(0).location());
3858     int yOffset = 0;
3859     for (unsigned i = 0; i < colRects->size(); i++) {
3860         // Add in half the column gap to the left and right of the rect.
3861         IntRect colRect = colRects->at(i);
3862         IntRect gapAndColumnRect(colRect.x() - leftGap, colRect.y(), colRect.width() + colGap, colRect.height());
3863 
3864         if (gapAndColumnRect.contains(point)) {
3865             // We're inside the column.  Translate the x and y into our column coordinate space.
3866             point.move(columnPoint.x() - colRect.x(), yOffset);
3867             return;
3868         }
3869 
3870         // Move to the next position.
3871         yOffset += colRect.height();
3872     }
3873 }
3874 
adjustRectForColumns(IntRect & r) const3875 void RenderBlock::adjustRectForColumns(IntRect& r) const
3876 {
3877     // Just bail if we have no columns.
3878     if (!hasColumns())
3879         return;
3880 
3881     Vector<IntRect>* colRects = columnRects();
3882 
3883     // Begin with a result rect that is empty.
3884     IntRect result;
3885 
3886     // Determine which columns we intersect.
3887     int currXOffset = 0;
3888     int currYOffset = 0;
3889     int colGap = columnGap();
3890     for (unsigned i = 0; i < colRects->size(); i++) {
3891         IntRect colRect = colRects->at(i);
3892 
3893         IntRect repaintRect = r;
3894         repaintRect.move(currXOffset, currYOffset);
3895 
3896         repaintRect.intersect(colRect);
3897 
3898         result.unite(repaintRect);
3899 
3900         // Move to the next position.
3901         if (style()->direction() == LTR)
3902             currXOffset += colRect.width() + colGap;
3903         else
3904             currXOffset -= (colRect.width() + colGap);
3905 
3906         currYOffset -= colRect.height();
3907     }
3908 
3909     r = result;
3910 }
3911 
calcPrefWidths()3912 void RenderBlock::calcPrefWidths()
3913 {
3914     ASSERT(prefWidthsDirty());
3915 
3916     updateFirstLetter();
3917 
3918     if (!isTableCell() && style()->width().isFixed() && style()->width().value() > 0)
3919         m_minPrefWidth = m_maxPrefWidth = calcContentBoxWidth(style()->width().value());
3920     else {
3921         m_minPrefWidth = 0;
3922         m_maxPrefWidth = 0;
3923 
3924         if (childrenInline())
3925             calcInlinePrefWidths();
3926         else
3927             calcBlockPrefWidths();
3928 
3929         m_maxPrefWidth = max(m_minPrefWidth, m_maxPrefWidth);
3930 
3931         if (!style()->autoWrap() && childrenInline()) {
3932             m_minPrefWidth = m_maxPrefWidth;
3933 
3934             // A horizontal marquee with inline children has no minimum width.
3935             if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
3936                 m_minPrefWidth = 0;
3937         }
3938 
3939         if (isTableCell()) {
3940             Length w = toRenderTableCell(this)->styleOrColWidth();
3941             if (w.isFixed() && w.value() > 0)
3942                 m_maxPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(w.value()));
3943         }
3944     }
3945 
3946     if (style()->minWidth().isFixed() && style()->minWidth().value() > 0) {
3947         m_maxPrefWidth = max(m_maxPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
3948         m_minPrefWidth = max(m_minPrefWidth, calcContentBoxWidth(style()->minWidth().value()));
3949     }
3950 
3951     if (style()->maxWidth().isFixed() && style()->maxWidth().value() != undefinedLength) {
3952         m_maxPrefWidth = min(m_maxPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
3953         m_minPrefWidth = min(m_minPrefWidth, calcContentBoxWidth(style()->maxWidth().value()));
3954     }
3955 
3956     int toAdd = 0;
3957     toAdd = borderLeft() + borderRight() + paddingLeft() + paddingRight();
3958 
3959     if (hasOverflowClip() && style()->overflowY() == OSCROLL)
3960         toAdd += verticalScrollbarWidth();
3961 
3962     m_minPrefWidth += toAdd;
3963     m_maxPrefWidth += toAdd;
3964 
3965     setPrefWidthsDirty(false);
3966 }
3967 
3968 struct InlineMinMaxIterator {
3969 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3970    inline min/max width calculations.  Note the following about the way it walks:
3971    (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3972    (2) We do not drill into the children of floats or replaced elements, since you can't break
3973        in the middle of such an element.
3974    (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3975        distinct borders/margin/padding that contribute to the min/max width.
3976 */
3977     RenderObject* parent;
3978     RenderObject* current;
3979     bool endOfInline;
3980 
InlineMinMaxIteratorWebCore::InlineMinMaxIterator3981     InlineMinMaxIterator(RenderObject* p, bool end = false)
3982         :parent(p), current(p), endOfInline(end) {}
3983 
3984     RenderObject* next();
3985 };
3986 
next()3987 RenderObject* InlineMinMaxIterator::next()
3988 {
3989     RenderObject* result = 0;
3990     bool oldEndOfInline = endOfInline;
3991     endOfInline = false;
3992     while (current || current == parent) {
3993         if (!oldEndOfInline &&
3994             (current == parent ||
3995              (!current->isFloating() && !current->isReplaced() && !current->isPositioned())))
3996             result = current->firstChild();
3997         if (!result) {
3998             // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3999             if (!oldEndOfInline && current->isRenderInline()) {
4000                 result = current;
4001                 endOfInline = true;
4002                 break;
4003             }
4004 
4005             while (current && current != parent) {
4006                 result = current->nextSibling();
4007                 if (result) break;
4008                 current = current->parent();
4009                 if (current && current != parent && current->isRenderInline()) {
4010                     result = current;
4011                     endOfInline = true;
4012                     break;
4013                 }
4014             }
4015         }
4016 
4017         if (!result)
4018             break;
4019 
4020         if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4021              break;
4022 
4023         current = result;
4024         result = 0;
4025     }
4026 
4027     // Update our position.
4028     current = result;
4029     return current;
4030 }
4031 
getBPMWidth(int childValue,Length cssUnit)4032 static int getBPMWidth(int childValue, Length cssUnit)
4033 {
4034     if (cssUnit.type() != Auto)
4035         return (cssUnit.isFixed() ? cssUnit.value() : childValue);
4036     return 0;
4037 }
4038 
getBorderPaddingMargin(const RenderBoxModelObject * child,bool endOfInline)4039 static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
4040 {
4041     RenderStyle* cstyle = child->style();
4042     int result = 0;
4043     bool leftSide = (cstyle->direction() == LTR) ? !endOfInline : endOfInline;
4044     result += getBPMWidth((leftSide ? child->marginLeft() : child->marginRight()),
4045                           (leftSide ? cstyle->marginLeft() :
4046                                       cstyle->marginRight()));
4047     result += getBPMWidth((leftSide ? child->paddingLeft() : child->paddingRight()),
4048                           (leftSide ? cstyle->paddingLeft() :
4049                                       cstyle->paddingRight()));
4050     result += leftSide ? child->borderLeft() : child->borderRight();
4051     return result;
4052 }
4053 
stripTrailingSpace(int & inlineMax,int & inlineMin,RenderObject * trailingSpaceChild)4054 static inline void stripTrailingSpace(int& inlineMax, int& inlineMin,
4055                                       RenderObject* trailingSpaceChild)
4056 {
4057     if (trailingSpaceChild && trailingSpaceChild->isText()) {
4058         // Collapse away the trailing space at the end of a block.
4059         RenderText* t = toRenderText(trailingSpaceChild);
4060         const UChar space = ' ';
4061         const Font& font = t->style()->font(); // FIXME: This ignores first-line.
4062         int spaceWidth = font.width(TextRun(&space, 1));
4063         inlineMax -= spaceWidth + font.wordSpacing();
4064         if (inlineMin > inlineMax)
4065             inlineMin = inlineMax;
4066     }
4067 }
4068 
calcInlinePrefWidths()4069 void RenderBlock::calcInlinePrefWidths()
4070 {
4071     int inlineMax = 0;
4072     int inlineMin = 0;
4073 
4074     int cw = containingBlock()->contentWidth();
4075 
4076     // If we are at the start of a line, we want to ignore all white-space.
4077     // Also strip spaces if we previously had text that ended in a trailing space.
4078     bool stripFrontSpaces = true;
4079     RenderObject* trailingSpaceChild = 0;
4080 
4081     // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4082     // very specific cirucumstances (in order to match common WinIE renderings).
4083     // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4084     bool allowImagesToBreak = !style()->htmlHacks() || !isTableCell() || !style()->width().isIntrinsicOrAuto();
4085 
4086     bool autoWrap, oldAutoWrap;
4087     autoWrap = oldAutoWrap = style()->autoWrap();
4088 
4089     InlineMinMaxIterator childIterator(this);
4090     bool addedTextIndent = false; // Only gets added in once.
4091     RenderObject* prevFloat = 0;
4092     RenderObject* previousLeaf = 0;
4093     while (RenderObject* child = childIterator.next()) {
4094         autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
4095             child->style()->autoWrap();
4096 
4097         if (!child->isBR()) {
4098             // Step One: determine whether or not we need to go ahead and
4099             // terminate our current line.  Each discrete chunk can become
4100             // the new min-width, if it is the widest chunk seen so far, and
4101             // it can also become the max-width.
4102 
4103             // Children fall into three categories:
4104             // (1) An inline flow object.  These objects always have a min/max of 0,
4105             // and are included in the iteration solely so that their margins can
4106             // be added in.
4107             //
4108             // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4109             // These objects can always be on a line by themselves, so in this situation
4110             // we need to go ahead and break the current line, and then add in our own
4111             // margins and min/max width on its own line, and then terminate the line.
4112             //
4113             // (3) A text object.  Text runs can have breakable characters at the start,
4114             // the middle or the end.  They may also lose whitespace off the front if
4115             // we're already ignoring whitespace.  In order to compute accurate min-width
4116             // information, we need three pieces of information.
4117             // (a) the min-width of the first non-breakable run.  Should be 0 if the text string
4118             // starts with whitespace.
4119             // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4120             // ends with whitespace.
4121             // (c) the min/max width of the string (trimmed for whitespace).
4122             //
4123             // If the text string starts with whitespace, then we need to go ahead and
4124             // terminate our current line (unless we're already in a whitespace stripping
4125             // mode.
4126             //
4127             // If the text string has a breakable character in the middle, but didn't start
4128             // with whitespace, then we add the width of the first non-breakable run and
4129             // then end the current line.  We then need to use the intermediate min/max width
4130             // values (if any of them are larger than our current min/max).  We then look at
4131             // the width of the last non-breakable run and use that to start a new line
4132             // (unless we end in whitespace).
4133             RenderStyle* cstyle = child->style();
4134             int childMin = 0;
4135             int childMax = 0;
4136 
4137             if (!child->isText()) {
4138                 // Case (1) and (2).  Inline replaced and inline flow elements.
4139                 if (child->isRenderInline()) {
4140                     // Add in padding/border/margin from the appropriate side of
4141                     // the element.
4142                     int bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
4143                     childMin += bpm;
4144                     childMax += bpm;
4145 
4146                     inlineMin += childMin;
4147                     inlineMax += childMax;
4148 
4149                     child->setPrefWidthsDirty(false);
4150                 } else {
4151                     // Inline replaced elts add in their margins to their min/max values.
4152                     int margins = 0;
4153                     Length leftMargin = cstyle->marginLeft();
4154                     Length rightMargin = cstyle->marginRight();
4155                     if (leftMargin.isFixed())
4156                         margins += leftMargin.value();
4157                     if (rightMargin.isFixed())
4158                         margins += rightMargin.value();
4159                     childMin += margins;
4160                     childMax += margins;
4161                 }
4162             }
4163 
4164             if (!child->isRenderInline() && !child->isText()) {
4165                 // Case (2). Inline replaced elements and floats.
4166                 // Go ahead and terminate the current line as far as
4167                 // minwidth is concerned.
4168                 childMin += child->minPrefWidth();
4169                 childMax += child->maxPrefWidth();
4170 
4171                 bool clearPreviousFloat;
4172                 if (child->isFloating()) {
4173                     clearPreviousFloat = (prevFloat
4174                         && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT))
4175                             || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT))));
4176                     prevFloat = child;
4177                 } else
4178                     clearPreviousFloat = false;
4179 
4180                 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4181                 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) {
4182                     m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4183                     inlineMin = 0;
4184                 }
4185 
4186                 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4187                 if (clearPreviousFloat) {
4188                     m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
4189                     inlineMax = 0;
4190                 }
4191 
4192                 // Add in text-indent.  This is added in only once.
4193                 int ti = 0;
4194                 if (!addedTextIndent) {
4195                     addedTextIndent = true;
4196                     ti = style()->textIndent().calcMinValue(cw);
4197                     childMin+=ti;
4198                     childMax+=ti;
4199                 }
4200 
4201                 // Add our width to the max.
4202                 inlineMax += childMax;
4203 
4204                 if (!autoWrap || !canBreakReplacedElement) {
4205                     if (child->isFloating())
4206                         m_minPrefWidth = max(childMin, m_minPrefWidth);
4207                     else
4208                         inlineMin += childMin;
4209                 } else {
4210                     // Now check our line.
4211                     m_minPrefWidth = max(childMin, m_minPrefWidth);
4212 
4213                     // Now start a new line.
4214                     inlineMin = 0;
4215                 }
4216 
4217                 // We are no longer stripping whitespace at the start of
4218                 // a line.
4219                 if (!child->isFloating()) {
4220                     stripFrontSpaces = false;
4221                     trailingSpaceChild = 0;
4222                 }
4223             } else if (child->isText()) {
4224                 // Case (3). Text.
4225                 RenderText* t = toRenderText(child);
4226 
4227                 if (t->isWordBreak()) {
4228                     m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4229                     inlineMin = 0;
4230                     continue;
4231                 }
4232 
4233                 // Determine if we have a breakable character.  Pass in
4234                 // whether or not we should ignore any spaces at the front
4235                 // of the string.  If those are going to be stripped out,
4236                 // then they shouldn't be considered in the breakable char
4237                 // check.
4238                 bool hasBreakableChar, hasBreak;
4239                 int beginMin, endMin;
4240                 bool beginWS, endWS;
4241                 int beginMax, endMax;
4242                 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
4243                                      hasBreakableChar, hasBreak, beginMax, endMax,
4244                                      childMin, childMax, stripFrontSpaces);
4245 
4246                 // This text object will not be rendered, but it may still provide a breaking opportunity.
4247                 if (!hasBreak && childMax == 0) {
4248                     if (autoWrap && (beginWS || endWS)) {
4249                         m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4250                         inlineMin = 0;
4251                     }
4252                     continue;
4253                 }
4254 
4255                 if (stripFrontSpaces)
4256                     trailingSpaceChild = child;
4257                 else
4258                     trailingSpaceChild = 0;
4259 
4260                 // Add in text-indent.  This is added in only once.
4261                 int ti = 0;
4262                 if (!addedTextIndent) {
4263                     addedTextIndent = true;
4264                     ti = style()->textIndent().calcMinValue(cw);
4265                     childMin+=ti; beginMin += ti;
4266                     childMax+=ti; beginMax += ti;
4267                 }
4268 
4269                 // If we have no breakable characters at all,
4270                 // then this is the easy case. We add ourselves to the current
4271                 // min and max and continue.
4272                 if (!hasBreakableChar) {
4273                     inlineMin += childMin;
4274                 } else {
4275                     // We have a breakable character.  Now we need to know if
4276                     // we start and end with whitespace.
4277                     if (beginWS)
4278                         // Go ahead and end the current line.
4279                         m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4280                     else {
4281                         inlineMin += beginMin;
4282                         m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4283                         childMin -= ti;
4284                     }
4285 
4286                     inlineMin = childMin;
4287 
4288                     if (endWS) {
4289                         // We end in whitespace, which means we can go ahead
4290                         // and end our current line.
4291                         m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4292                         inlineMin = 0;
4293                     } else {
4294                         m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4295                         inlineMin = endMin;
4296                     }
4297                 }
4298 
4299                 if (hasBreak) {
4300                     inlineMax += beginMax;
4301                     m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
4302                     m_maxPrefWidth = max(childMax, m_maxPrefWidth);
4303                     inlineMax = endMax;
4304                 } else
4305                     inlineMax += childMax;
4306             }
4307 
4308             // Ignore spaces after a list marker.
4309             if (child->isListMarker())
4310                 stripFrontSpaces = true;
4311         } else {
4312             m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4313             m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
4314             inlineMin = inlineMax = 0;
4315             stripFrontSpaces = true;
4316             trailingSpaceChild = 0;
4317         }
4318 
4319         oldAutoWrap = autoWrap;
4320         if (!child->isRenderInline())
4321             previousLeaf = child;
4322     }
4323 
4324     if (style()->collapseWhiteSpace())
4325         stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4326 
4327     m_minPrefWidth = max(inlineMin, m_minPrefWidth);
4328     m_maxPrefWidth = max(inlineMax, m_maxPrefWidth);
4329 }
4330 
4331 // Use a very large value (in effect infinite).
4332 #define BLOCK_MAX_WIDTH 15000
4333 
calcBlockPrefWidths()4334 void RenderBlock::calcBlockPrefWidths()
4335 {
4336     bool nowrap = style()->whiteSpace() == NOWRAP;
4337 
4338     RenderObject *child = firstChild();
4339     int floatLeftWidth = 0, floatRightWidth = 0;
4340     while (child) {
4341         // Positioned children don't affect the min/max width
4342         if (child->isPositioned()) {
4343             child = child->nextSibling();
4344             continue;
4345         }
4346 
4347         if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
4348             int floatTotalWidth = floatLeftWidth + floatRightWidth;
4349             if (child->style()->clear() & CLEFT) {
4350                 m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth);
4351                 floatLeftWidth = 0;
4352             }
4353             if (child->style()->clear() & CRIGHT) {
4354                 m_maxPrefWidth = max(floatTotalWidth, m_maxPrefWidth);
4355                 floatRightWidth = 0;
4356             }
4357         }
4358 
4359         // A margin basically has three types: fixed, percentage, and auto (variable).
4360         // Auto and percentage margins simply become 0 when computing min/max width.
4361         // Fixed margins can be added in as is.
4362         Length ml = child->style()->marginLeft();
4363         Length mr = child->style()->marginRight();
4364         int margin = 0, marginLeft = 0, marginRight = 0;
4365         if (ml.isFixed())
4366             marginLeft += ml.value();
4367         if (mr.isFixed())
4368             marginRight += mr.value();
4369         margin = marginLeft + marginRight;
4370 
4371         int w = child->minPrefWidth() + margin;
4372         m_minPrefWidth = max(w, m_minPrefWidth);
4373 
4374         // IE ignores tables for calculation of nowrap. Makes some sense.
4375         if (nowrap && !child->isTable())
4376             m_maxPrefWidth = max(w, m_maxPrefWidth);
4377 
4378         w = child->maxPrefWidth() + margin;
4379 
4380         if (!child->isFloating()) {
4381             if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
4382                 // Determine a left and right max value based off whether or not the floats can fit in the
4383                 // margins of the object.  For negative margins, we will attempt to overlap the float if the negative margin
4384                 // is smaller than the float width.
4385                 int maxLeft = marginLeft > 0 ? max(floatLeftWidth, marginLeft) : floatLeftWidth + marginLeft;
4386                 int maxRight = marginRight > 0 ? max(floatRightWidth, marginRight) : floatRightWidth + marginRight;
4387                 w = child->maxPrefWidth() + maxLeft + maxRight;
4388                 w = max(w, floatLeftWidth + floatRightWidth);
4389             }
4390             else
4391                 m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth);
4392             floatLeftWidth = floatRightWidth = 0;
4393         }
4394 
4395         if (child->isFloating()) {
4396             if (style()->floating() == FLEFT)
4397                 floatLeftWidth += w;
4398             else
4399                 floatRightWidth += w;
4400         } else
4401             m_maxPrefWidth = max(w, m_maxPrefWidth);
4402 
4403         // A very specific WinIE quirk.
4404         // Example:
4405         /*
4406            <div style="position:absolute; width:100px; top:50px;">
4407               <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
4408                 <table style="width:100%"><tr><td></table>
4409               </div>
4410            </div>
4411         */
4412         // In the above example, the inner absolute positioned block should have a computed width
4413         // of 100px because of the table.
4414         // We can achieve this effect by making the maxwidth of blocks that contain tables
4415         // with percentage widths be infinite (as long as they are not inside a table cell).
4416         if (style()->htmlHacks() && child->style()->width().isPercent() &&
4417             !isTableCell() && child->isTable() && m_maxPrefWidth < BLOCK_MAX_WIDTH) {
4418             RenderBlock* cb = containingBlock();
4419             while (!cb->isRenderView() && !cb->isTableCell())
4420                 cb = cb->containingBlock();
4421             if (!cb->isTableCell())
4422                 m_maxPrefWidth = BLOCK_MAX_WIDTH;
4423         }
4424 
4425         child = child->nextSibling();
4426     }
4427 
4428     // Always make sure these values are non-negative.
4429     m_minPrefWidth = max(0, m_minPrefWidth);
4430     m_maxPrefWidth = max(0, m_maxPrefWidth);
4431 
4432     m_maxPrefWidth = max(floatLeftWidth + floatRightWidth, m_maxPrefWidth);
4433 }
4434 
hasLineIfEmpty() const4435 bool RenderBlock::hasLineIfEmpty() const
4436 {
4437     if (!node())
4438         return false;
4439 
4440     if (node()->isContentEditable() && node()->rootEditableElement() == node())
4441         return true;
4442 
4443     if (node()->isShadowNode() && (node()->shadowParentNode()->hasTagName(inputTag) || node()->shadowParentNode()->hasTagName(textareaTag)))
4444         return true;
4445 
4446     return false;
4447 }
4448 
lineHeight(bool firstLine,bool isRootLineBox) const4449 int RenderBlock::lineHeight(bool firstLine, bool isRootLineBox) const
4450 {
4451     // Inline blocks are replaced elements. Otherwise, just pass off to
4452     // the base class.  If we're being queried as though we're the root line
4453     // box, then the fact that we're an inline-block is irrelevant, and we behave
4454     // just like a block.
4455     if (isReplaced() && !isRootLineBox)
4456         return height() + marginTop() + marginBottom();
4457 
4458     if (firstLine && document()->usesFirstLineRules()) {
4459         RenderStyle* s = style(firstLine);
4460         if (s != style())
4461             return s->computedLineHeight();
4462     }
4463 
4464     if (m_lineHeight == -1)
4465         m_lineHeight = style()->computedLineHeight();
4466 
4467     return m_lineHeight;
4468 }
4469 
baselinePosition(bool b,bool isRootLineBox) const4470 int RenderBlock::baselinePosition(bool b, bool isRootLineBox) const
4471 {
4472     // Inline blocks are replaced elements. Otherwise, just pass off to
4473     // the base class.  If we're being queried as though we're the root line
4474     // box, then the fact that we're an inline-block is irrelevant, and we behave
4475     // just like a block.
4476     if (isReplaced() && !isRootLineBox) {
4477         // For "leaf" theme objects, let the theme decide what the baseline position is.
4478         // FIXME: Might be better to have a custom CSS property instead, so that if the theme
4479         // is turned off, checkboxes/radios will still have decent baselines.
4480         if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
4481             return theme()->baselinePosition(this);
4482 
4483         // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
4484         // the normal flow.  We make an exception for marquees, since their baselines are meaningless
4485         // (the content inside them moves).  This matches WinIE as well, which just bottom-aligns them.
4486         // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
4487         // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
4488         // of our content box.
4489         int baselinePos = (layer() && (layer()->marquee() || layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)) ? -1 : lastLineBoxBaseline();
4490         if (baselinePos != -1 && baselinePos <= borderTop() + paddingTop() + contentHeight())
4491             return marginTop() + baselinePos;
4492         return height() + marginTop() + marginBottom();
4493     }
4494     return RenderBox::baselinePosition(b, isRootLineBox);
4495 }
4496 
firstLineBoxBaseline() const4497 int RenderBlock::firstLineBoxBaseline() const
4498 {
4499     if (!isBlockFlow())
4500         return -1;
4501 
4502     if (childrenInline()) {
4503         if (firstLineBox())
4504             return firstLineBox()->y() + style(true)->font().ascent();
4505         else
4506             return -1;
4507     }
4508     else {
4509         for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
4510             if (!curr->isFloatingOrPositioned()) {
4511                 int result = curr->firstLineBoxBaseline();
4512                 if (result != -1)
4513                     return curr->y() + result; // Translate to our coordinate space.
4514             }
4515         }
4516     }
4517 
4518     return -1;
4519 }
4520 
lastLineBoxBaseline() const4521 int RenderBlock::lastLineBoxBaseline() const
4522 {
4523     if (!isBlockFlow())
4524         return -1;
4525 
4526     if (childrenInline()) {
4527         if (!firstLineBox() && hasLineIfEmpty())
4528             return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop();
4529         if (lastLineBox())
4530             return lastLineBox()->y() + style(lastLineBox() == firstLineBox())->font().ascent();
4531         return -1;
4532     }
4533     else {
4534         bool haveNormalFlowChild = false;
4535         for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
4536             if (!curr->isFloatingOrPositioned()) {
4537                 haveNormalFlowChild = true;
4538                 int result = curr->lastLineBoxBaseline();
4539                 if (result != -1)
4540                     return curr->y() + result; // Translate to our coordinate space.
4541             }
4542         }
4543         if (!haveNormalFlowChild && hasLineIfEmpty())
4544             return RenderBox::baselinePosition(true, true) + borderTop() + paddingTop();
4545     }
4546 
4547     return -1;
4548 }
4549 
containsNonZeroBidiLevel() const4550 bool RenderBlock::containsNonZeroBidiLevel() const
4551 {
4552     for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
4553         for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
4554             if (box->bidiLevel())
4555                 return true;
4556         }
4557     }
4558     return false;
4559 }
4560 
firstLineBlock() const4561 RenderBlock* RenderBlock::firstLineBlock() const
4562 {
4563     RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
4564     bool hasPseudo = false;
4565     while (true) {
4566         hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
4567         if (hasPseudo)
4568             break;
4569         RenderObject* parentBlock = firstLineBlock->parent();
4570         if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
4571             !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
4572             break;
4573         ASSERT(parentBlock->isRenderBlock());
4574         firstLineBlock = toRenderBlock(parentBlock);
4575     }
4576 
4577     if (!hasPseudo)
4578         return 0;
4579 
4580     return firstLineBlock;
4581 }
4582 
updateFirstLetter()4583 void RenderBlock::updateFirstLetter()
4584 {
4585     if (!document()->usesFirstLetterRules())
4586         return;
4587     // Don't recur
4588     if (style()->styleType() == FIRST_LETTER)
4589         return;
4590 
4591     // FIXME: We need to destroy the first-letter object if it is no longer the first child.  Need to find
4592     // an efficient way to check for that situation though before implementing anything.
4593     RenderObject* firstLetterBlock = this;
4594     bool hasPseudoStyle = false;
4595     while (true) {
4596         // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly
4597         // prevents form controls from honoring first-letter.
4598         hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
4599             && firstLetterBlock->canHaveChildren();
4600         if (hasPseudoStyle)
4601             break;
4602         RenderObject* parentBlock = firstLetterBlock->parent();
4603         if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
4604             !parentBlock->isBlockFlow())
4605             break;
4606         firstLetterBlock = parentBlock;
4607     }
4608 
4609     if (!hasPseudoStyle)
4610         return;
4611 
4612     // Drill into inlines looking for our first text child.
4613     RenderObject* currChild = firstLetterBlock->firstChild();
4614     while (currChild && currChild->needsLayout() && (!currChild->isReplaced() || currChild->isFloatingOrPositioned()) && !currChild->isText()) {
4615         if (currChild->isFloatingOrPositioned()) {
4616             if (currChild->style()->styleType() == FIRST_LETTER)
4617                 break;
4618             currChild = currChild->nextSibling();
4619         } else
4620             currChild = currChild->firstChild();
4621     }
4622 
4623     // Get list markers out of the way.
4624     while (currChild && currChild->isListMarker())
4625         currChild = currChild->nextSibling();
4626 
4627     if (!currChild)
4628         return;
4629 
4630     RenderObject* firstLetterContainer = currChild->parent();
4631 
4632     // If the child already has style, then it has already been created, so we just want
4633     // to update it.
4634     if (currChild->style()->styleType() == FIRST_LETTER) {
4635         RenderStyle* pseudo = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER,
4636                                                                      firstLetterContainer->firstLineStyle());
4637         currChild->setStyle(pseudo);
4638         for (RenderObject* genChild = currChild->firstChild(); genChild; genChild = genChild->nextSibling()) {
4639             if (genChild->isText())
4640                 genChild->setStyle(pseudo);
4641         }
4642         return;
4643     }
4644 
4645     // If the child does not already have style, we create it here.
4646     if (currChild->isText() && !currChild->isBR() && currChild->parent()->style()->styleType() != FIRST_LETTER) {
4647         // Our layout state is not valid for the repaints we are going to trigger by
4648         // adding and removing children of firstLetterContainer.
4649         view()->disableLayoutState();
4650 
4651         RenderText* textObj = toRenderText(currChild);
4652 
4653         // Create our pseudo style now that we have our firstLetterContainer determined.
4654         RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER,
4655                                                                           firstLetterContainer->firstLineStyle());
4656 
4657         // Force inline display (except for floating first-letters)
4658         pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
4659         pseudoStyle->setPosition(StaticPosition); // CSS2 says first-letter can't be positioned.
4660 
4661         RenderObject* firstLetter = 0;
4662         if (pseudoStyle->display() == INLINE)
4663             firstLetter = new (renderArena()) RenderInline(document());
4664         else
4665             firstLetter = new (renderArena()) RenderBlock(document());
4666         firstLetter->setStyle(pseudoStyle);
4667         firstLetterContainer->addChild(firstLetter, currChild);
4668 
4669         // The original string is going to be either a generated content string or a DOM node's
4670         // string.  We want the original string before it got transformed in case first-letter has
4671         // no text-transform or a different text-transform applied to it.
4672         RefPtr<StringImpl> oldText = textObj->originalText();
4673         ASSERT(oldText);
4674 
4675         if (oldText && oldText->length() > 0) {
4676             unsigned int length = 0;
4677 
4678             // account for leading spaces and punctuation
4679             while (length < oldText->length() && (isSpaceOrNewline((*oldText)[length]) || Unicode::isPunct((*oldText)[length])))
4680                 length++;
4681 
4682             // account for first letter
4683             length++;
4684 
4685             // construct text fragment for the text after the first letter
4686             // NOTE: this might empty
4687             RenderTextFragment* remainingText =
4688                 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
4689             remainingText->setStyle(textObj->style());
4690             if (remainingText->node())
4691                 remainingText->node()->setRenderer(remainingText);
4692 
4693             RenderObject* nextObj = textObj->nextSibling();
4694             firstLetterContainer->removeChild(textObj);
4695             firstLetterContainer->addChild(remainingText, nextObj);
4696             remainingText->setFirstLetter(firstLetter);
4697 
4698             // construct text fragment for the first letter
4699             RenderTextFragment* letter =
4700                 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
4701             RefPtr<RenderStyle> newStyle = RenderStyle::create();
4702             newStyle->inheritFrom(pseudoStyle);
4703             letter->setStyle(newStyle.release());
4704             firstLetter->addChild(letter);
4705 
4706             textObj->destroy();
4707         }
4708         view()->enableLayoutState();
4709     }
4710 }
4711 
inRootBlockContext() const4712 bool RenderBlock::inRootBlockContext() const
4713 {
4714     if (isTableCell() || isFloatingOrPositioned() || hasOverflowClip())
4715         return false;
4716 
4717     if (isRoot() || isRenderView())
4718         return true;
4719 
4720     return containingBlock()->inRootBlockContext();
4721 }
4722 
4723 // Helper methods for obtaining the last line, computing line counts and heights for line counts
4724 // (crawling into blocks).
shouldCheckLines(RenderObject * obj)4725 static bool shouldCheckLines(RenderObject* obj)
4726 {
4727     return !obj->isFloatingOrPositioned() && !obj->isRunIn() &&
4728             obj->isBlockFlow() && obj->style()->height().isAuto() &&
4729             (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
4730 }
4731 
getLineAtIndex(RenderBlock * block,int i,int & count)4732 static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
4733 {
4734     if (block->style()->visibility() == VISIBLE) {
4735         if (block->childrenInline()) {
4736             for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
4737                 if (count++ == i)
4738                     return box;
4739             }
4740         }
4741         else {
4742             for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
4743                 if (shouldCheckLines(obj)) {
4744                     RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
4745                     if (box)
4746                         return box;
4747                 }
4748             }
4749         }
4750     }
4751     return 0;
4752 }
4753 
getHeightForLineCount(RenderBlock * block,int l,bool includeBottom,int & count)4754 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
4755 {
4756     if (block->style()->visibility() == VISIBLE) {
4757         if (block->childrenInline()) {
4758             for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
4759                 if (++count == l)
4760                     return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
4761             }
4762         }
4763         else {
4764             RenderBox* normalFlowChildWithoutLines = 0;
4765             for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4766                 if (shouldCheckLines(obj)) {
4767                     int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
4768                     if (result != -1)
4769                         return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
4770                 }
4771                 else if (!obj->isFloatingOrPositioned() && !obj->isRunIn())
4772                     normalFlowChildWithoutLines = obj;
4773             }
4774             if (normalFlowChildWithoutLines && l == 0)
4775                 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
4776         }
4777     }
4778 
4779     return -1;
4780 }
4781 
lineAtIndex(int i)4782 RootInlineBox* RenderBlock::lineAtIndex(int i)
4783 {
4784     int count = 0;
4785     return getLineAtIndex(this, i, count);
4786 }
4787 
lineCount()4788 int RenderBlock::lineCount()
4789 {
4790     int count = 0;
4791     if (style()->visibility() == VISIBLE) {
4792         if (childrenInline())
4793             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4794                 count++;
4795         else
4796             for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
4797                 if (shouldCheckLines(obj))
4798                     count += toRenderBlock(obj)->lineCount();
4799     }
4800     return count;
4801 }
4802 
heightForLineCount(int l)4803 int RenderBlock::heightForLineCount(int l)
4804 {
4805     int count = 0;
4806     return getHeightForLineCount(this, l, true, count);
4807 }
4808 
adjustForBorderFit(int x,int & left,int & right) const4809 void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const
4810 {
4811     // We don't deal with relative positioning.  Our assumption is that you shrink to fit the lines without accounting
4812     // for either overflow or translations via relative positioning.
4813     if (style()->visibility() == VISIBLE) {
4814         if (childrenInline()) {
4815             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4816                 if (box->firstChild())
4817                     left = min(left, x + box->firstChild()->x());
4818                 if (box->lastChild())
4819                     right = max(right, x + box->lastChild()->x() + box->lastChild()->width());
4820             }
4821         }
4822         else {
4823             for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4824                 if (!obj->isFloatingOrPositioned()) {
4825                     if (obj->isBlockFlow() && !obj->hasOverflowClip())
4826                         toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
4827                     else if (obj->style()->visibility() == VISIBLE) {
4828                         // We are a replaced element or some kind of non-block-flow object.
4829                         left = min(left, x + obj->x());
4830                         right = max(right, x + obj->x() + obj->width());
4831                     }
4832                 }
4833             }
4834         }
4835 
4836         if (m_floatingObjects) {
4837             FloatingObject* r;
4838             DeprecatedPtrListIterator<FloatingObject> it(*m_floatingObjects);
4839             for (; (r = it.current()); ++it) {
4840                 // Only examine the object if our m_shouldPaint flag is set.
4841                 if (r->m_shouldPaint) {
4842                     int floatLeft = r->m_left - r->m_renderer->x() + r->m_renderer->marginLeft();
4843                     int floatRight = floatLeft + r->m_renderer->width();
4844                     left = min(left, floatLeft);
4845                     right = max(right, floatRight);
4846                 }
4847             }
4848         }
4849     }
4850 }
4851 
borderFitAdjust(int & x,int & w) const4852 void RenderBlock::borderFitAdjust(int& x, int& w) const
4853 {
4854     if (style()->borderFit() == BorderFitBorder)
4855         return;
4856 
4857     // Walk any normal flow lines to snugly fit.
4858     int left = INT_MAX;
4859     int right = INT_MIN;
4860     int oldWidth = w;
4861     adjustForBorderFit(0, left, right);
4862     if (left != INT_MAX) {
4863         left -= (borderLeft() + paddingLeft());
4864         if (left > 0) {
4865             x += left;
4866             w -= left;
4867         }
4868     }
4869     if (right != INT_MIN) {
4870         right += (borderRight() + paddingRight());
4871         if (right < oldWidth)
4872             w -= (oldWidth - right);
4873     }
4874 }
4875 
clearTruncation()4876 void RenderBlock::clearTruncation()
4877 {
4878     if (style()->visibility() == VISIBLE) {
4879         if (childrenInline() && hasMarkupTruncation()) {
4880             setHasMarkupTruncation(false);
4881             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4882                 box->clearTruncation();
4883         }
4884         else
4885             for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
4886                 if (shouldCheckLines(obj))
4887                     toRenderBlock(obj)->clearTruncation();
4888     }
4889 }
4890 
setMaxTopMargins(int pos,int neg)4891 void RenderBlock::setMaxTopMargins(int pos, int neg)
4892 {
4893     if (!m_maxMargin) {
4894         if (pos == MaxMargin::topPosDefault(this) && neg == MaxMargin::topNegDefault(this))
4895             return;
4896         m_maxMargin = new MaxMargin(this);
4897     }
4898     m_maxMargin->m_topPos = pos;
4899     m_maxMargin->m_topNeg = neg;
4900 }
4901 
setMaxBottomMargins(int pos,int neg)4902 void RenderBlock::setMaxBottomMargins(int pos, int neg)
4903 {
4904     if (!m_maxMargin) {
4905         if (pos == MaxMargin::bottomPosDefault(this) && neg == MaxMargin::bottomNegDefault(this))
4906             return;
4907         m_maxMargin = new MaxMargin(this);
4908     }
4909     m_maxMargin->m_bottomPos = pos;
4910     m_maxMargin->m_bottomNeg = neg;
4911 }
4912 
absoluteRects(Vector<IntRect> & rects,int tx,int ty)4913 void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
4914 {
4915     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
4916     // inline boxes above and below us (thus getting merged with them to form a single irregular
4917     // shape).
4918     if (inlineContinuation()) {
4919         rects.append(IntRect(tx, ty - collapsedMarginTop(),
4920                              width(), height() + collapsedMarginTop() + collapsedMarginBottom()));
4921         inlineContinuation()->absoluteRects(rects,
4922                                             tx - x() + inlineContinuation()->containingBlock()->x(),
4923                                             ty - y() + inlineContinuation()->containingBlock()->y());
4924     } else
4925         rects.append(IntRect(tx, ty, width(), height()));
4926 }
4927 
absoluteQuads(Vector<FloatQuad> & quads)4928 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads)
4929 {
4930     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
4931     // inline boxes above and below us (thus getting merged with them to form a single irregular
4932     // shape).
4933     if (inlineContinuation()) {
4934         FloatRect localRect(0, -collapsedMarginTop(),
4935                             width(), height() + collapsedMarginTop() + collapsedMarginBottom());
4936         quads.append(localToAbsoluteQuad(localRect));
4937         inlineContinuation()->absoluteQuads(quads);
4938     } else
4939         quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
4940 }
4941 
rectWithOutlineForRepaint(RenderBoxModelObject * repaintContainer,int outlineWidth)4942 IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
4943 {
4944     IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
4945     if (inlineContinuation())
4946         r.inflateY(collapsedMarginTop());
4947     return r;
4948 }
4949 
hoverAncestor() const4950 RenderObject* RenderBlock::hoverAncestor() const
4951 {
4952     return inlineContinuation() ? inlineContinuation() : RenderBox::hoverAncestor();
4953 }
4954 
updateDragState(bool dragOn)4955 void RenderBlock::updateDragState(bool dragOn)
4956 {
4957     RenderBox::updateDragState(dragOn);
4958     if (inlineContinuation())
4959         inlineContinuation()->updateDragState(dragOn);
4960 }
4961 
outlineStyleForRepaint() const4962 RenderStyle* RenderBlock::outlineStyleForRepaint() const
4963 {
4964     return inlineContinuation() ? inlineContinuation()->style() : style();
4965 }
4966 
childBecameNonInline(RenderObject *)4967 void RenderBlock::childBecameNonInline(RenderObject*)
4968 {
4969     makeChildrenNonInline();
4970     if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
4971         toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
4972     // |this| may be dead here
4973 }
4974 
updateHitTestResult(HitTestResult & result,const IntPoint & point)4975 void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point)
4976 {
4977     if (result.innerNode())
4978         return;
4979 
4980     Node* n = node();
4981     if (inlineContinuation())
4982         // We are in the margins of block elements that are part of a continuation.  In
4983         // this case we're actually still inside the enclosing inline element that was
4984         // split.  Go ahead and set our inner node accordingly.
4985         n = inlineContinuation()->node();
4986 
4987     if (n) {
4988         result.setInnerNode(n);
4989         if (!result.innerNonSharedNode())
4990             result.setInnerNonSharedNode(n);
4991         result.setLocalPoint(point);
4992     }
4993 }
4994 
localCaretRect(InlineBox * inlineBox,int caretOffset,int * extraWidthToEndOfLine)4995 IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
4996 {
4997     // Do the normal calculation in most cases.
4998     if (firstChild())
4999         return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
5000 
5001     // This is a special case:
5002     // The element is not an inline element, and it's empty. So we have to
5003     // calculate a fake position to indicate where objects are to be inserted.
5004 
5005     // FIXME: This does not take into account either :first-line or :first-letter
5006     // However, as soon as some content is entered, the line boxes will be
5007     // constructed and this kludge is not called any more. So only the caret size
5008     // of an empty :first-line'd block is wrong. I think we can live with that.
5009     RenderStyle* currentStyle = firstLineStyle();
5010     int height = lineHeight(true);
5011 
5012     enum CaretAlignment { alignLeft, alignRight, alignCenter };
5013 
5014     CaretAlignment alignment = alignLeft;
5015 
5016     switch (currentStyle->textAlign()) {
5017         case TAAUTO:
5018         case JUSTIFY:
5019             if (currentStyle->direction() == RTL)
5020                 alignment = alignRight;
5021             break;
5022         case LEFT:
5023         case WEBKIT_LEFT:
5024             break;
5025         case CENTER:
5026         case WEBKIT_CENTER:
5027             alignment = alignCenter;
5028             break;
5029         case RIGHT:
5030         case WEBKIT_RIGHT:
5031             alignment = alignRight;
5032             break;
5033     }
5034 
5035     int x = borderLeft() + paddingLeft();
5036     int w = width();
5037 
5038     switch (alignment) {
5039         case alignLeft:
5040             break;
5041         case alignCenter:
5042             x = (x + w - (borderRight() + paddingRight())) / 2;
5043             break;
5044         case alignRight:
5045             x = w - (borderRight() + paddingRight()) - caretWidth;
5046             break;
5047     }
5048 
5049     if (extraWidthToEndOfLine) {
5050         if (isRenderBlock()) {
5051             *extraWidthToEndOfLine = w - (x + caretWidth);
5052         } else {
5053             // FIXME: This code looks wrong.
5054             // myRight and containerRight are set up, but then clobbered.
5055             // So *extraWidthToEndOfLine will always be 0 here.
5056 
5057             int myRight = x + caretWidth;
5058             // FIXME: why call localToAbsoluteForContent() twice here, too?
5059             FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
5060 
5061             int containerRight = containingBlock()->x() + containingBlockWidthForContent();
5062             FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
5063 
5064             *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
5065         }
5066     }
5067 
5068     int y = paddingTop() + borderTop();
5069 
5070     return IntRect(x, y, caretWidth, height);
5071 }
5072 
addFocusRingRects(Vector<IntRect> & rects,int tx,int ty)5073 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
5074 {
5075     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5076     // inline boxes above and below us (thus getting merged with them to form a single irregular
5077     // shape).
5078     if (inlineContinuation()) {
5079         // FIXME: This check really isn't accurate.
5080         bool nextInlineHasLineBox = inlineContinuation()->firstLineBox();
5081         // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
5082         bool prevInlineHasLineBox = toRenderInline(inlineContinuation()->node()->renderer())->firstLineBox();
5083         int topMargin = prevInlineHasLineBox ? collapsedMarginTop() : 0;
5084         int bottomMargin = nextInlineHasLineBox ? collapsedMarginBottom() : 0;
5085         IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin);
5086         if (!rect.isEmpty())
5087             rects.append(rect);
5088     } else if (width() && height())
5089         rects.append(IntRect(tx, ty, width(), height()));
5090 
5091     if (!hasOverflowClip() && !hasControlClip()) {
5092         for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5093             int top = max(curr->lineTop(), curr->y());
5094             int bottom = min(curr->lineBottom(), curr->y() + curr->height());
5095             IntRect rect(tx + curr->x(), ty + top, curr->width(), bottom - top);
5096             if (!rect.isEmpty())
5097                 rects.append(rect);
5098         }
5099 
5100         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
5101             if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
5102                 RenderBox* box = toRenderBox(curr);
5103                 FloatPoint pos;
5104                 // FIXME: This doesn't work correctly with transforms.
5105                 if (box->layer())
5106                     pos = curr->localToAbsolute();
5107                 else
5108                     pos = FloatPoint(tx + box->x(), ty + box->y());
5109                 box->addFocusRingRects(rects, pos.x(), pos.y());
5110             }
5111         }
5112     }
5113 
5114     if (inlineContinuation())
5115         inlineContinuation()->addFocusRingRects(rects,
5116                                                 tx - x() + inlineContinuation()->containingBlock()->x(),
5117                                                 ty - y() + inlineContinuation()->containingBlock()->y());
5118 }
5119 
createAnonymousBlock(bool isFlexibleBox) const5120 RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const
5121 {
5122     RefPtr<RenderStyle> newStyle = RenderStyle::create();
5123     newStyle->inheritFrom(style());
5124 
5125     RenderBlock* newBox = 0;
5126     if (isFlexibleBox) {
5127         newStyle->setDisplay(BOX);
5128         newBox = new (renderArena()) RenderFlexibleBox(document() /* anonymous box */);
5129     } else {
5130         newStyle->setDisplay(BLOCK);
5131         newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
5132     }
5133 
5134     newBox->setStyle(newStyle.release());
5135     return newBox;
5136 }
5137 
renderName() const5138 const char* RenderBlock::renderName() const
5139 {
5140     if (isBody())
5141         return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
5142 
5143     if (isFloating())
5144         return "RenderBlock (floating)";
5145     if (isPositioned())
5146         return "RenderBlock (positioned)";
5147     if (isAnonymousBlock())
5148         return "RenderBlock (anonymous)";
5149     else if (isAnonymous())
5150         return "RenderBlock (generated)";
5151     if (isRelPositioned())
5152         return "RenderBlock (relative positioned)";
5153     if (isRunIn())
5154         return "RenderBlock (run-in)";
5155     return "RenderBlock";
5156 }
5157 
5158 } // namespace WebCore
5159