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