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