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