1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2007 David Smith (catfish.man@gmail.com)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
6 * Copyright (C) Research In Motion Limited 2010. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "config.h"
25 #include "RenderBlock.h"
26
27 #include "ColumnInfo.h"
28 #include "Document.h"
29 #include "Element.h"
30 #include "FloatQuad.h"
31 #include "Frame.h"
32 #include "FrameView.h"
33 #include "GraphicsContext.h"
34 #include "HTMLFormElement.h"
35 #include "HTMLNames.h"
36 #include "HitTestResult.h"
37 #include "InlineIterator.h"
38 #include "InlineTextBox.h"
39 #include "PaintInfo.h"
40 #include "RenderCombineText.h"
41 #include "RenderFlexibleBox.h"
42 #include "RenderImage.h"
43 #include "RenderInline.h"
44 #include "RenderLayer.h"
45 #include "RenderMarquee.h"
46 #include "RenderReplica.h"
47 #include "RenderTableCell.h"
48 #include "RenderTextFragment.h"
49 #include "RenderTheme.h"
50 #include "RenderView.h"
51 #include "SelectionController.h"
52 #include "Settings.h"
53 #include "TextRun.h"
54 #include "TransformState.h"
55 #include <wtf/StdLibExtras.h>
56
57 #ifdef ANDROID_LAYOUT
58 #include "Settings.h"
59 #endif
60
61 using namespace std;
62 using namespace WTF;
63 using namespace Unicode;
64
65 namespace WebCore {
66
67 using namespace HTMLNames;
68
69 typedef WTF::HashMap<const RenderBox*, ColumnInfo*> ColumnInfoMap;
70 static ColumnInfoMap* gColumnInfoMap = 0;
71
72 typedef WTF::HashMap<const RenderBlock*, HashSet<RenderBox*>*> PercentHeightDescendantsMap;
73 static PercentHeightDescendantsMap* gPercentHeightDescendantsMap = 0;
74
75 typedef WTF::HashMap<const RenderBox*, HashSet<RenderBlock*>*> PercentHeightContainerMap;
76 static PercentHeightContainerMap* gPercentHeightContainerMap = 0;
77
78 typedef WTF::HashMap<RenderBlock*, ListHashSet<RenderInline*>*> ContinuationOutlineTableMap;
79
80 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
81 static int gDelayUpdateScrollInfo = 0;
82 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
83
84 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
85
86 // Our MarginInfo state used when laying out block children.
MarginInfo(RenderBlock * block,int beforeBorderPadding,int afterBorderPadding)87 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, int beforeBorderPadding, int afterBorderPadding)
88 : m_atBeforeSideOfBlock(true)
89 , m_atAfterSideOfBlock(false)
90 , m_marginBeforeQuirk(false)
91 , m_marginAfterQuirk(false)
92 , m_determinedMarginBeforeQuirk(false)
93 {
94 // Whether or not we can collapse our own margins with our children. We don't do this
95 // if we had any border/padding (obviously), if we're the root or HTML elements, or if
96 // we're positioned, floating, a table cell.
97 m_canCollapseWithChildren = !block->isRenderView() && !block->isRoot() && !block->isPositioned()
98 && !block->isFloating() && !block->isTableCell() && !block->hasOverflowClip() && !block->isInlineBlockOrInlineTable()
99 && !block->isWritingModeRoot();
100
101 m_canCollapseMarginBeforeWithChildren = m_canCollapseWithChildren && (beforeBorderPadding == 0) && block->style()->marginBeforeCollapse() != MSEPARATE;
102
103 // If any height other than auto is specified in CSS, then we don't collapse our bottom
104 // margins with our children's margins. To do otherwise would be to risk odd visual
105 // effects when the children overflow out of the parent block and yet still collapse
106 // with it. We also don't collapse if we have any bottom border/padding.
107 m_canCollapseMarginAfterWithChildren = m_canCollapseWithChildren && (afterBorderPadding == 0) &&
108 (block->style()->logicalHeight().isAuto() && block->style()->logicalHeight().value() == 0) && block->style()->marginAfterCollapse() != MSEPARATE;
109
110 m_quirkContainer = block->isTableCell() || block->isBody() || block->style()->marginBeforeCollapse() == MDISCARD ||
111 block->style()->marginAfterCollapse() == MDISCARD;
112
113 m_positiveMargin = m_canCollapseMarginBeforeWithChildren ? block->maxPositiveMarginBefore() : 0;
114 m_negativeMargin = m_canCollapseMarginBeforeWithChildren ? block->maxNegativeMarginBefore() : 0;
115 }
116
117 // -------------------------------------------------------------------------------------------------------
118
RenderBlock(Node * node)119 RenderBlock::RenderBlock(Node* node)
120 : RenderBox(node)
121 , m_floatingObjects(0)
122 , m_positionedObjects(0)
123 , m_rareData(0)
124 , m_lineHeight(-1)
125 , m_beingDestroyed(false)
126 {
127 setChildrenInline(true);
128 }
129
~RenderBlock()130 RenderBlock::~RenderBlock()
131 {
132 if (m_floatingObjects)
133 deleteAllValues(m_floatingObjects->set());
134
135 if (hasColumns())
136 delete gColumnInfoMap->take(this);
137
138 if (gPercentHeightDescendantsMap) {
139 if (HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->take(this)) {
140 HashSet<RenderBox*>::iterator end = descendantSet->end();
141 for (HashSet<RenderBox*>::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
142 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(*descendant);
143 ASSERT(containerSet);
144 if (!containerSet)
145 continue;
146 ASSERT(containerSet->contains(this));
147 containerSet->remove(this);
148 if (containerSet->isEmpty()) {
149 gPercentHeightContainerMap->remove(*descendant);
150 delete containerSet;
151 }
152 }
153 delete descendantSet;
154 }
155 }
156 }
157
destroy()158 void RenderBlock::destroy()
159 {
160 // Mark as being destroyed to avoid trouble with merges in removeChild().
161 m_beingDestroyed = true;
162
163 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
164 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
165 children()->destroyLeftoverChildren();
166
167 // Destroy our continuation before anything other than anonymous children.
168 // The reason we don't destroy it before anonymous children is that they may
169 // have continuations of their own that are anonymous children of our continuation.
170 RenderBoxModelObject* continuation = this->continuation();
171 if (continuation) {
172 continuation->destroy();
173 setContinuation(0);
174 }
175
176 if (!documentBeingDestroyed()) {
177 if (firstLineBox()) {
178 // We can't wait for RenderBox::destroy to clear the selection,
179 // because by then we will have nuked the line boxes.
180 // FIXME: The SelectionController should be responsible for this when it
181 // is notified of DOM mutations.
182 if (isSelectionBorder())
183 view()->clearSelection();
184
185 // If we are an anonymous block, then our line boxes might have children
186 // that will outlast this block. In the non-anonymous block case those
187 // children will be destroyed by the time we return from this function.
188 if (isAnonymousBlock()) {
189 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
190 while (InlineBox* childBox = box->firstChild())
191 childBox->remove();
192 }
193 }
194 } else if (isInline() && parent())
195 parent()->dirtyLinesFromChangedChild(this);
196 }
197
198 m_lineBoxes.deleteLineBoxes(renderArena());
199
200 RenderBox::destroy();
201 }
202
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)203 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
204 {
205 s_canPropagateFloatIntoSibling = style() ? !isFloatingOrPositioned() && !avoidsFloats() : false;
206
207 setReplaced(newStyle->isDisplayInlineType());
208
209 if (style() && parent() && diff == StyleDifferenceLayout && style()->position() != newStyle->position()) {
210 if (newStyle->position() == StaticPosition)
211 // Clear our positioned objects list. Our absolutely positioned descendants will be
212 // inserted into our containing block's positioned objects list during layout.
213 removePositionedObjects(0);
214 else if (style()->position() == StaticPosition) {
215 // Remove our absolutely positioned descendants from their current containing block.
216 // They will be inserted into our positioned objects list during layout.
217 RenderObject* cb = parent();
218 while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
219 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
220 cb = cb->containingBlock();
221 break;
222 }
223 cb = cb->parent();
224 }
225
226 if (cb->isRenderBlock())
227 toRenderBlock(cb)->removePositionedObjects(this);
228 }
229
230 if (containsFloats() && !isFloating() && !isPositioned() && (newStyle->position() == AbsolutePosition || newStyle->position() == FixedPosition))
231 markAllDescendantsWithFloatsForLayout();
232 }
233
234 RenderBox::styleWillChange(diff, newStyle);
235 }
236
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)237 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
238 {
239 RenderBox::styleDidChange(diff, oldStyle);
240
241 if (!isAnonymousBlock()) {
242 // Ensure that all of our continuation blocks pick up the new style.
243 for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
244 RenderBoxModelObject* nextCont = currCont->continuation();
245 currCont->setContinuation(0);
246 currCont->setStyle(style());
247 currCont->setContinuation(nextCont);
248 }
249 }
250
251 // FIXME: We could save this call when the change only affected non-inherited properties
252 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
253 if (child->isAnonymousBlock()) {
254 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
255 if (style()->specifiesColumns()) {
256 if (child->style()->specifiesColumns())
257 newStyle->inheritColumnPropertiesFrom(style());
258 if (child->style()->columnSpan())
259 newStyle->setColumnSpan(true);
260 }
261 newStyle->setDisplay(BLOCK);
262 child->setStyle(newStyle.release());
263 }
264 }
265
266 m_lineHeight = -1;
267
268 // Update pseudos for :before and :after now.
269 if (!isAnonymous() && document()->usesBeforeAfterRules() && canHaveChildren()) {
270 updateBeforeAfterContent(BEFORE);
271 updateBeforeAfterContent(AFTER);
272 }
273
274 // After our style changed, if we lose our ability to propagate floats into next sibling
275 // blocks, then we need to find the top most parent containing that overhanging float and
276 // then mark its descendants with floats for layout and clear all floats from its next
277 // sibling blocks that exist in our floating objects list. See bug 56299 and 62875.
278 bool canPropagateFloatIntoSibling = !isFloatingOrPositioned() && !avoidsFloats();
279 if (diff == StyleDifferenceLayout && s_canPropagateFloatIntoSibling && !canPropagateFloatIntoSibling && hasOverhangingFloats()) {
280 RenderBlock* parentBlock = this;
281 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
282 FloatingObjectSetIterator end = floatingObjectSet.end();
283
284 for (RenderObject* curr = parent(); curr && !curr->isRenderView(); curr = curr->parent()) {
285 if (curr->isRenderBlock()) {
286 RenderBlock* currBlock = toRenderBlock(curr);
287
288 if (currBlock->hasOverhangingFloats()) {
289 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
290 RenderBox* renderer = (*it)->renderer();
291 if (currBlock->hasOverhangingFloat(renderer)) {
292 parentBlock = currBlock;
293 break;
294 }
295 }
296 }
297 }
298 }
299
300 parentBlock->markAllDescendantsWithFloatsForLayout();
301 parentBlock->markSiblingsWithFloatsForLayout();
302 }
303 }
304
updateBeforeAfterContent(PseudoId pseudoId)305 void RenderBlock::updateBeforeAfterContent(PseudoId pseudoId)
306 {
307 // If this is an anonymous wrapper, then the parent applies its own pseudo-element style to it.
308 if (parent() && parent()->createsAnonymousWrapper())
309 return;
310 return children()->updateBeforeAfterContent(this, pseudoId);
311 }
312
continuationBefore(RenderObject * beforeChild)313 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
314 {
315 if (beforeChild && beforeChild->parent() == this)
316 return this;
317
318 RenderBlock* curr = toRenderBlock(continuation());
319 RenderBlock* nextToLast = this;
320 RenderBlock* last = this;
321 while (curr) {
322 if (beforeChild && beforeChild->parent() == curr) {
323 if (curr->firstChild() == beforeChild)
324 return last;
325 return curr;
326 }
327
328 nextToLast = last;
329 last = curr;
330 curr = toRenderBlock(curr->continuation());
331 }
332
333 if (!beforeChild && !last->firstChild())
334 return nextToLast;
335 return last;
336 }
337
addChildToContinuation(RenderObject * newChild,RenderObject * beforeChild)338 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
339 {
340 RenderBlock* flow = continuationBefore(beforeChild);
341 ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
342 RenderBoxModelObject* beforeChildParent = 0;
343 if (beforeChild)
344 beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
345 else {
346 RenderBoxModelObject* cont = flow->continuation();
347 if (cont)
348 beforeChildParent = cont;
349 else
350 beforeChildParent = flow;
351 }
352
353 if (newChild->isFloatingOrPositioned())
354 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
355
356 // A continuation always consists of two potential candidates: a block or an anonymous
357 // column span box holding column span children.
358 bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
359 bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
360 bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
361
362 if (flow == beforeChildParent)
363 return flow->addChildIgnoringContinuation(newChild, beforeChild);
364
365 // The goal here is to match up if we can, so that we can coalesce and create the
366 // minimal # of continuations needed for the inline.
367 if (childIsNormal == bcpIsNormal)
368 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
369 if (flowIsNormal == childIsNormal)
370 return flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
371 return beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
372 }
373
374
addChildToAnonymousColumnBlocks(RenderObject * newChild,RenderObject * beforeChild)375 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
376 {
377 ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
378
379 // The goal is to locate a suitable box in which to place our child.
380 RenderBlock* beforeChildParent = toRenderBlock(beforeChild && beforeChild->parent()->isRenderBlock() ? beforeChild->parent() : lastChild());
381
382 // If the new child is floating or positioned it can just go in that block.
383 if (newChild->isFloatingOrPositioned())
384 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
385
386 // See if the child can be placed in the box.
387 bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
388 bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
389
390 if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans)
391 return beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
392
393 if (!beforeChild) {
394 // Create a new block of the correct type.
395 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
396 children()->appendChildNode(this, newBox);
397 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
398 return;
399 }
400
401 RenderObject* immediateChild = beforeChild;
402 bool isPreviousBlockViable = true;
403 while (immediateChild->parent() != this) {
404 if (isPreviousBlockViable)
405 isPreviousBlockViable = !immediateChild->previousSibling();
406 immediateChild = immediateChild->parent();
407 }
408 if (isPreviousBlockViable && immediateChild->previousSibling())
409 return toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
410
411 // Split our anonymous blocks.
412 RenderObject* newBeforeChild = splitAnonymousBlocksAroundChild(beforeChild);
413
414 // Create a new anonymous box of the appropriate type.
415 RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
416 children()->insertChildNode(this, newBox, newBeforeChild);
417 newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
418 return;
419 }
420
containingColumnsBlock(bool allowAnonymousColumnBlock)421 RenderBlock* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
422 {
423 for (RenderObject* curr = this; curr; curr = curr->parent()) {
424 if (!curr->isRenderBlock() || curr->isFloatingOrPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
425 || curr->isInlineBlockOrInlineTable())
426 return 0;
427
428 RenderBlock* currBlock = toRenderBlock(curr);
429 if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
430 return currBlock;
431
432 if (currBlock->isAnonymousColumnSpanBlock())
433 return 0;
434 }
435 return 0;
436 }
437
clone() const438 RenderBlock* RenderBlock::clone() const
439 {
440 RenderBlock* cloneBlock;
441 if (isAnonymousBlock())
442 cloneBlock = createAnonymousBlock();
443 else {
444 cloneBlock = new (renderArena()) RenderBlock(node());
445 cloneBlock->setStyle(style());
446 }
447 cloneBlock->setChildrenInline(childrenInline());
448 return cloneBlock;
449 }
450
splitBlocks(RenderBlock * fromBlock,RenderBlock * toBlock,RenderBlock * middleBlock,RenderObject * beforeChild,RenderBoxModelObject * oldCont)451 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
452 RenderBlock* middleBlock,
453 RenderObject* beforeChild, RenderBoxModelObject* oldCont)
454 {
455 // Create a clone of this inline.
456 RenderBlock* cloneBlock = clone();
457 if (!isAnonymousBlock())
458 cloneBlock->setContinuation(oldCont);
459
460 // Now take all of the children from beforeChild to the end and remove
461 // them from |this| and place them in the clone.
462 if (!beforeChild && isAfterContent(lastChild()))
463 beforeChild = lastChild();
464 moveChildrenTo(cloneBlock, beforeChild, 0);
465
466 // Hook |clone| up as the continuation of the middle block.
467 if (!cloneBlock->isAnonymousBlock())
468 middleBlock->setContinuation(cloneBlock);
469
470 // We have been reparented and are now under the fromBlock. We need
471 // to walk up our block parent chain until we hit the containing anonymous columns block.
472 // Once we hit the anonymous columns block we're done.
473 RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
474 RenderBoxModelObject* currChild = this;
475
476 while (curr && curr != fromBlock) {
477 ASSERT(curr->isRenderBlock());
478
479 RenderBlock* blockCurr = toRenderBlock(curr);
480
481 // Create a new clone.
482 RenderBlock* cloneChild = cloneBlock;
483 cloneBlock = blockCurr->clone();
484
485 // Insert our child clone as the first child.
486 cloneBlock->children()->appendChildNode(cloneBlock, cloneChild);
487
488 // Hook the clone up as a continuation of |curr|. Note we do encounter
489 // anonymous blocks possibly as we walk up the block chain. When we split an
490 // anonymous block, there's no need to do any continuation hookup, since we haven't
491 // actually split a real element.
492 if (!blockCurr->isAnonymousBlock()) {
493 oldCont = blockCurr->continuation();
494 blockCurr->setContinuation(cloneBlock);
495 cloneBlock->setContinuation(oldCont);
496 }
497
498 // Someone may have indirectly caused a <q> to split. When this happens, the :after content
499 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that the inline's :after
500 // content gets properly destroyed.
501 if (document()->usesBeforeAfterRules())
502 blockCurr->children()->updateBeforeAfterContent(blockCurr, AFTER);
503
504 // Now we need to take all of the children starting from the first child
505 // *after* currChild and append them all to the clone.
506 RenderObject* afterContent = isAfterContent(cloneBlock->lastChild()) ? cloneBlock->lastChild() : 0;
507 blockCurr->moveChildrenTo(cloneBlock, currChild->nextSibling(), 0, afterContent);
508
509 // Keep walking up the chain.
510 currChild = curr;
511 curr = toRenderBoxModelObject(curr->parent());
512 }
513
514 // Now we are at the columns block level. We need to put the clone into the toBlock.
515 toBlock->children()->appendChildNode(toBlock, cloneBlock);
516
517 // Now take all the children after currChild and remove them from the fromBlock
518 // and put them in the toBlock.
519 fromBlock->moveChildrenTo(toBlock, currChild->nextSibling(), 0);
520 }
521
splitFlow(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild,RenderBoxModelObject * oldCont)522 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
523 RenderObject* newChild, RenderBoxModelObject* oldCont)
524 {
525 RenderBlock* pre = 0;
526 RenderBlock* block = containingColumnsBlock();
527
528 // Delete our line boxes before we do the inline split into continuations.
529 block->deleteLineBoxTree();
530
531 bool madeNewBeforeBlock = false;
532 if (block->isAnonymousColumnsBlock()) {
533 // We can reuse this block and make it the preBlock of the next continuation.
534 pre = block;
535 pre->removePositionedObjects(0);
536 block = toRenderBlock(block->parent());
537 } else {
538 // No anonymous block available for use. Make one.
539 pre = block->createAnonymousColumnsBlock();
540 pre->setChildrenInline(false);
541 madeNewBeforeBlock = true;
542 }
543
544 RenderBlock* post = block->createAnonymousColumnsBlock();
545 post->setChildrenInline(false);
546
547 RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
548 if (madeNewBeforeBlock)
549 block->children()->insertChildNode(block, pre, boxFirst);
550 block->children()->insertChildNode(block, newBlockBox, boxFirst);
551 block->children()->insertChildNode(block, post, boxFirst);
552 block->setChildrenInline(false);
553
554 if (madeNewBeforeBlock)
555 block->moveChildrenTo(pre, boxFirst, 0);
556
557 splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
558
559 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
560 // time in makeChildrenNonInline by just setting this explicitly up front.
561 newBlockBox->setChildrenInline(false);
562
563 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
564 // connected, thus allowing newChild access to a renderArena should it need
565 // to wrap itself in additional boxes (e.g., table construction).
566 newBlockBox->addChild(newChild);
567
568 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
569 // get deleted properly. Because objects moves from the pre block into the post block, we want to
570 // make new line boxes instead of leaving the old line boxes around.
571 pre->setNeedsLayoutAndPrefWidthsRecalc();
572 block->setNeedsLayoutAndPrefWidthsRecalc();
573 post->setNeedsLayoutAndPrefWidthsRecalc();
574 }
575
splitAnonymousBlocksAroundChild(RenderObject * beforeChild)576 RenderObject* RenderBlock::splitAnonymousBlocksAroundChild(RenderObject* beforeChild)
577 {
578 while (beforeChild->parent() != this) {
579 RenderBlock* blockToSplit = toRenderBlock(beforeChild->parent());
580 if (blockToSplit->firstChild() != beforeChild) {
581 // We have to split the parentBlock into two blocks.
582 RenderBlock* post = createAnonymousBlockWithSameTypeAs(blockToSplit);
583 post->setChildrenInline(blockToSplit->childrenInline());
584 RenderBlock* parentBlock = toRenderBlock(blockToSplit->parent());
585 parentBlock->children()->insertChildNode(parentBlock, post, blockToSplit->nextSibling());
586 blockToSplit->moveChildrenTo(post, beforeChild, 0, blockToSplit->hasLayer());
587 post->setNeedsLayoutAndPrefWidthsRecalc();
588 blockToSplit->setNeedsLayoutAndPrefWidthsRecalc();
589 beforeChild = post;
590 } else
591 beforeChild = blockToSplit;
592 }
593 return beforeChild;
594 }
595
makeChildrenAnonymousColumnBlocks(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild)596 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlock* newBlockBox, RenderObject* newChild)
597 {
598 RenderBlock* pre = 0;
599 RenderBlock* post = 0;
600 RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|. Assign to a variable
601 // so that we don't have to patch all of the rest of the code later on.
602
603 // Delete the block's line boxes before we do the split.
604 block->deleteLineBoxTree();
605
606 if (beforeChild && beforeChild->parent() != this)
607 beforeChild = splitAnonymousBlocksAroundChild(beforeChild);
608
609 if (beforeChild != firstChild()) {
610 pre = block->createAnonymousColumnsBlock();
611 pre->setChildrenInline(block->childrenInline());
612 }
613
614 if (beforeChild) {
615 post = block->createAnonymousColumnsBlock();
616 post->setChildrenInline(block->childrenInline());
617 }
618
619 RenderObject* boxFirst = block->firstChild();
620 if (pre)
621 block->children()->insertChildNode(block, pre, boxFirst);
622 block->children()->insertChildNode(block, newBlockBox, boxFirst);
623 if (post)
624 block->children()->insertChildNode(block, post, boxFirst);
625 block->setChildrenInline(false);
626
627 // The pre/post blocks always have layers, so we know to always do a full insert/remove (so we pass true as the last argument).
628 block->moveChildrenTo(pre, boxFirst, beforeChild, true);
629 block->moveChildrenTo(post, beforeChild, 0, true);
630
631 // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
632 // time in makeChildrenNonInline by just setting this explicitly up front.
633 newBlockBox->setChildrenInline(false);
634
635 // We delayed adding the newChild until now so that the |newBlockBox| would be fully
636 // connected, thus allowing newChild access to a renderArena should it need
637 // to wrap itself in additional boxes (e.g., table construction).
638 newBlockBox->addChild(newChild);
639
640 // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
641 // get deleted properly. Because objects moved from the pre block into the post block, we want to
642 // make new line boxes instead of leaving the old line boxes around.
643 if (pre)
644 pre->setNeedsLayoutAndPrefWidthsRecalc();
645 block->setNeedsLayoutAndPrefWidthsRecalc();
646 if (post)
647 post->setNeedsLayoutAndPrefWidthsRecalc();
648 }
649
columnsBlockForSpanningElement(RenderObject * newChild)650 RenderBlock* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
651 {
652 // FIXME: This function is the gateway for the addition of column-span support. It will
653 // be added to in three stages:
654 // (1) Immediate children of a multi-column block can span.
655 // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
656 // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
657 // cross the streams and have to cope with both types of continuations mixed together).
658 // This function currently supports (1) and (2).
659 RenderBlock* columnsBlockAncestor = 0;
660 if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isFloatingOrPositioned()
661 && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
662 if (style()->specifiesColumns())
663 columnsBlockAncestor = this;
664 else if (parent() && parent()->isRenderBlock())
665 columnsBlockAncestor = toRenderBlock(parent())->containingColumnsBlock(false);
666 }
667 return columnsBlockAncestor;
668 }
669
addChildIgnoringAnonymousColumnBlocks(RenderObject * newChild,RenderObject * beforeChild)670 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
671 {
672 // Make sure we don't append things after :after-generated content if we have it.
673 if (!beforeChild) {
674 RenderObject* lastRenderer = lastChild();
675 if (isAfterContent(lastRenderer))
676 beforeChild = lastRenderer;
677 else if (lastRenderer && lastRenderer->isAnonymousBlock() && isAfterContent(lastRenderer->lastChild()))
678 beforeChild = lastRenderer->lastChild();
679 }
680
681 // If the requested beforeChild is not one of our children, then this is because
682 // there is an anonymous container within this object that contains the beforeChild.
683 if (beforeChild && beforeChild->parent() != this) {
684 RenderObject* anonymousChild = beforeChild->parent();
685 ASSERT(anonymousChild);
686
687 while (anonymousChild->parent() != this)
688 anonymousChild = anonymousChild->parent();
689
690 ASSERT(anonymousChild->isAnonymous());
691
692 if (anonymousChild->isAnonymousBlock()) {
693 // Insert the child into the anonymous block box instead of here.
694 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
695 beforeChild->parent()->addChild(newChild, beforeChild);
696 else
697 addChild(newChild, beforeChild->parent());
698 return;
699 }
700
701 ASSERT(anonymousChild->isTable());
702 if ((newChild->isTableCol() && newChild->style()->display() == TABLE_COLUMN_GROUP)
703 || (newChild->isRenderBlock() && newChild->style()->display() == TABLE_CAPTION)
704 || newChild->isTableSection()
705 || newChild->isTableRow()
706 || newChild->isTableCell()) {
707 // Insert into the anonymous table.
708 anonymousChild->addChild(newChild, beforeChild);
709 return;
710 }
711
712 // Go on to insert before the anonymous table.
713 beforeChild = anonymousChild;
714 }
715
716 // Check for a spanning element in columns.
717 RenderBlock* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
718 if (columnsBlockAncestor) {
719 // We are placing a column-span element inside a block.
720 RenderBlock* newBox = createAnonymousColumnSpanBlock();
721
722 if (columnsBlockAncestor != this) {
723 // We are nested inside a multi-column element and are being split by the span. We have to break up
724 // our block into continuations.
725 RenderBoxModelObject* oldContinuation = continuation();
726 setContinuation(newBox);
727
728 // Someone may have put a <p> inside a <q>, causing a split. When this happens, the :after content
729 // has to move into the inline continuation. Call updateBeforeAfterContent to ensure that our :after
730 // content gets properly destroyed.
731 bool isLastChild = (beforeChild == lastChild());
732 if (document()->usesBeforeAfterRules())
733 children()->updateBeforeAfterContent(this, AFTER);
734 if (isLastChild && beforeChild != lastChild())
735 beforeChild = 0; // We destroyed the last child, so now we need to update our insertion
736 // point to be 0. It's just a straight append now.
737
738 splitFlow(beforeChild, newBox, newChild, oldContinuation);
739 return;
740 }
741
742 // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
743 // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
744 // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
745 makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
746 return;
747 }
748
749 bool madeBoxesNonInline = false;
750
751 // A block has to either have all of its children inline, or all of its children as blocks.
752 // So, if our children are currently inline and a block child has to be inserted, we move all our
753 // inline children into anonymous block boxes.
754 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrPositioned()) {
755 // This is a block with inline content. Wrap the inline content in anonymous blocks.
756 makeChildrenNonInline(beforeChild);
757 madeBoxesNonInline = true;
758
759 if (beforeChild && beforeChild->parent() != this) {
760 beforeChild = beforeChild->parent();
761 ASSERT(beforeChild->isAnonymousBlock());
762 ASSERT(beforeChild->parent() == this);
763 }
764 } else if (!childrenInline() && (newChild->isFloatingOrPositioned() || newChild->isInline())) {
765 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
766 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
767 // a new one is created and inserted into our list of children in the appropriate position.
768 RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
769
770 if (afterChild && afterChild->isAnonymousBlock()) {
771 afterChild->addChild(newChild);
772 return;
773 }
774
775 if (newChild->isInline()) {
776 // No suitable existing anonymous box - create a new one.
777 RenderBlock* newBox = createAnonymousBlock();
778 RenderBox::addChild(newBox, beforeChild);
779 newBox->addChild(newChild);
780 return;
781 }
782 }
783
784 RenderBox::addChild(newChild, beforeChild);
785
786 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
787 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
788 // this object may be dead here
789 }
790
addChild(RenderObject * newChild,RenderObject * beforeChild)791 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
792 {
793 if (continuation() && !isAnonymousBlock())
794 return addChildToContinuation(newChild, beforeChild);
795 return addChildIgnoringContinuation(newChild, beforeChild);
796 }
797
addChildIgnoringContinuation(RenderObject * newChild,RenderObject * beforeChild)798 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
799 {
800 if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
801 return addChildToAnonymousColumnBlocks(newChild, beforeChild);
802 return addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
803 }
804
getInlineRun(RenderObject * start,RenderObject * boundary,RenderObject * & inlineRunStart,RenderObject * & inlineRunEnd)805 static void getInlineRun(RenderObject* start, RenderObject* boundary,
806 RenderObject*& inlineRunStart,
807 RenderObject*& inlineRunEnd)
808 {
809 // Beginning at |start| we find the largest contiguous run of inlines that
810 // we can. We denote the run with start and end points, |inlineRunStart|
811 // and |inlineRunEnd|. Note that these two values may be the same if
812 // we encounter only one inline.
813 //
814 // We skip any non-inlines we encounter as long as we haven't found any
815 // inlines yet.
816 //
817 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
818 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
819 // a non-inline.
820
821 // Start by skipping as many non-inlines as we can.
822 RenderObject * curr = start;
823 bool sawInline;
824 do {
825 while (curr && !(curr->isInline() || curr->isFloatingOrPositioned()))
826 curr = curr->nextSibling();
827
828 inlineRunStart = inlineRunEnd = curr;
829
830 if (!curr)
831 return; // No more inline children to be found.
832
833 sawInline = curr->isInline();
834
835 curr = curr->nextSibling();
836 while (curr && (curr->isInline() || curr->isFloatingOrPositioned()) && (curr != boundary)) {
837 inlineRunEnd = curr;
838 if (curr->isInline())
839 sawInline = true;
840 curr = curr->nextSibling();
841 }
842 } while (!sawInline);
843 }
844
deleteLineBoxTree()845 void RenderBlock::deleteLineBoxTree()
846 {
847 m_lineBoxes.deleteLineBoxTree(renderArena());
848 }
849
createRootInlineBox()850 RootInlineBox* RenderBlock::createRootInlineBox()
851 {
852 return new (renderArena()) RootInlineBox(this);
853 }
854
createAndAppendRootInlineBox()855 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
856 {
857 RootInlineBox* rootBox = createRootInlineBox();
858 m_lineBoxes.appendLineBox(rootBox);
859 return rootBox;
860 }
861
moveChildTo(RenderBlock * to,RenderObject * child,RenderObject * beforeChild,bool fullRemoveInsert)862 void RenderBlock::moveChildTo(RenderBlock* to, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
863 {
864 ASSERT(this == child->parent());
865 ASSERT(!beforeChild || to == beforeChild->parent());
866 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
867 }
868
moveChildrenTo(RenderBlock * to,RenderObject * startChild,RenderObject * endChild,RenderObject * beforeChild,bool fullRemoveInsert)869 void RenderBlock::moveChildrenTo(RenderBlock* to, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
870 {
871 ASSERT(!beforeChild || to == beforeChild->parent());
872 RenderObject* nextChild = startChild;
873 while (nextChild && nextChild != endChild) {
874 RenderObject* child = nextChild;
875 nextChild = child->nextSibling();
876 to->children()->insertChildNode(to, children()->removeChildNode(this, child, fullRemoveInsert), beforeChild, fullRemoveInsert);
877 if (child == endChild)
878 return;
879 }
880 }
881
makeChildrenNonInline(RenderObject * insertionPoint)882 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
883 {
884 // makeChildrenNonInline takes a block whose children are *all* inline and it
885 // makes sure that inline children are coalesced under anonymous
886 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
887 // the new block child that is causing us to have to wrap all the inlines. This
888 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
889 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
890 // splitting them.
891 ASSERT(isInlineBlockOrInlineTable() || !isInline());
892 ASSERT(!insertionPoint || insertionPoint->parent() == this);
893
894 setChildrenInline(false);
895
896 RenderObject *child = firstChild();
897 if (!child)
898 return;
899
900 deleteLineBoxTree();
901
902 while (child) {
903 RenderObject *inlineRunStart, *inlineRunEnd;
904 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
905
906 if (!inlineRunStart)
907 break;
908
909 child = inlineRunEnd->nextSibling();
910
911 RenderBlock* block = createAnonymousBlock();
912 children()->insertChildNode(this, block, inlineRunStart);
913 moveChildrenTo(block, inlineRunStart, child);
914 }
915
916 #ifndef NDEBUG
917 for (RenderObject *c = firstChild(); c; c = c->nextSibling())
918 ASSERT(!c->isInline());
919 #endif
920
921 repaint();
922 }
923
removeLeftoverAnonymousBlock(RenderBlock * child)924 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
925 {
926 ASSERT(child->isAnonymousBlock());
927 ASSERT(!child->childrenInline());
928
929 if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
930 return;
931
932 RenderObject* firstAnChild = child->m_children.firstChild();
933 RenderObject* lastAnChild = child->m_children.lastChild();
934 if (firstAnChild) {
935 RenderObject* o = firstAnChild;
936 while (o) {
937 o->setParent(this);
938 o = o->nextSibling();
939 }
940 firstAnChild->setPreviousSibling(child->previousSibling());
941 lastAnChild->setNextSibling(child->nextSibling());
942 if (child->previousSibling())
943 child->previousSibling()->setNextSibling(firstAnChild);
944 if (child->nextSibling())
945 child->nextSibling()->setPreviousSibling(lastAnChild);
946
947 if (child == m_children.firstChild())
948 m_children.setFirstChild(firstAnChild);
949 if (child == m_children.lastChild())
950 m_children.setLastChild(lastAnChild);
951 } else {
952 if (child == m_children.firstChild())
953 m_children.setFirstChild(child->nextSibling());
954 if (child == m_children.lastChild())
955 m_children.setLastChild(child->previousSibling());
956
957 if (child->previousSibling())
958 child->previousSibling()->setNextSibling(child->nextSibling());
959 if (child->nextSibling())
960 child->nextSibling()->setPreviousSibling(child->previousSibling());
961 }
962 child->setParent(0);
963 child->setPreviousSibling(0);
964 child->setNextSibling(0);
965
966 child->children()->setFirstChild(0);
967 child->m_next = 0;
968
969 child->destroy();
970 }
971
canMergeContiguousAnonymousBlocks(RenderObject * oldChild,RenderObject * prev,RenderObject * next)972 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
973 {
974 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
975 return false;
976
977 if (oldChild->parent() && oldChild->parent()->isDetails())
978 return false;
979
980 if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
981 || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
982 return false;
983
984 // FIXME: This check isn't required when inline run-ins can't be split into continuations.
985 if (prev && prev->firstChild() && prev->firstChild()->isInline() && prev->firstChild()->isRunIn())
986 return false;
987
988 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
989 || (next && (next->isRubyRun() || next->isRubyBase())))
990 return false;
991
992 if (!prev || !next)
993 return true;
994
995 // Make sure the types of the anonymous blocks match up.
996 return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
997 && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
998 }
999
removeChild(RenderObject * oldChild)1000 void RenderBlock::removeChild(RenderObject* oldChild)
1001 {
1002 // If this child is a block, and if our previous and next siblings are
1003 // both anonymous blocks with inline content, then we can go ahead and
1004 // fold the inline content back together.
1005 RenderObject* prev = oldChild->previousSibling();
1006 RenderObject* next = oldChild->nextSibling();
1007 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1008 if (canMergeAnonymousBlocks && prev && next) {
1009 prev->setNeedsLayoutAndPrefWidthsRecalc();
1010 RenderBlock* nextBlock = toRenderBlock(next);
1011 RenderBlock* prevBlock = toRenderBlock(prev);
1012
1013 if (prev->childrenInline() != next->childrenInline()) {
1014 RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1015 RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1016
1017 // Place the inline children block inside of the block children block instead of deleting it.
1018 // In order to reuse it, we have to reset it to just be a generic anonymous block. Make sure
1019 // to clear out inherited column properties by just making a new style, and to also clear the
1020 // column span flag if it is set.
1021 ASSERT(!inlineChildrenBlock->continuation());
1022 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
1023 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlock->hasLayer());
1024 inlineChildrenBlock->setStyle(newStyle);
1025
1026 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1027 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1028 inlineChildrenBlock->hasLayer() || blockChildrenBlock->hasLayer());
1029 next->setNeedsLayoutAndPrefWidthsRecalc();
1030
1031 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1032 // of "this". we null out prev or next so that is not used later in the function.
1033 if (inlineChildrenBlock == prevBlock)
1034 prev = 0;
1035 else
1036 next = 0;
1037 } else {
1038 // Take all the children out of the |next| block and put them in
1039 // the |prev| block.
1040 nextBlock->moveAllChildrenTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1041
1042 // Delete the now-empty block's lines and nuke it.
1043 nextBlock->deleteLineBoxTree();
1044 nextBlock->destroy();
1045 next = 0;
1046 }
1047 }
1048
1049 RenderBox::removeChild(oldChild);
1050
1051 RenderObject* child = prev ? prev : next;
1052 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && !isFlexibleBox()) {
1053 // The removal has knocked us down to containing only a single anonymous
1054 // box. We can go ahead and pull the content right back up into our
1055 // box.
1056 setNeedsLayoutAndPrefWidthsRecalc();
1057 setChildrenInline(child->childrenInline());
1058 RenderBlock* anonBlock = toRenderBlock(children()->removeChildNode(this, child, child->hasLayer()));
1059 anonBlock->moveAllChildrenTo(this, child->hasLayer());
1060 // Delete the now-empty block's lines and nuke it.
1061 anonBlock->deleteLineBoxTree();
1062 anonBlock->destroy();
1063 }
1064
1065 if (!firstChild() && !documentBeingDestroyed()) {
1066 // If this was our last child be sure to clear out our line boxes.
1067 if (childrenInline())
1068 lineBoxes()->deleteLineBoxes(renderArena());
1069 }
1070 }
1071
isSelfCollapsingBlock() const1072 bool RenderBlock::isSelfCollapsingBlock() const
1073 {
1074 // We are not self-collapsing if we
1075 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1076 // (b) are a table,
1077 // (c) have border/padding,
1078 // (d) have a min-height
1079 // (e) have specified that one of our margins can't collapse using a CSS extension
1080 if (logicalHeight() > 0
1081 || isTable() || borderAndPaddingLogicalHeight()
1082 || style()->logicalMinHeight().isPositive()
1083 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1084 return false;
1085
1086 Length logicalHeightLength = style()->logicalHeight();
1087 bool hasAutoHeight = logicalHeightLength.isAuto();
1088 if (logicalHeightLength.isPercent() && !document()->inQuirksMode()) {
1089 hasAutoHeight = true;
1090 for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1091 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1092 hasAutoHeight = false;
1093 }
1094 }
1095
1096 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1097 // on whether we have content that is all self-collapsing or not.
1098 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1099 // If the block has inline children, see if we generated any line boxes. If we have any
1100 // line boxes, then we can't be self-collapsing, since we have content.
1101 if (childrenInline())
1102 return !firstLineBox();
1103
1104 // Whether or not we collapse is dependent on whether all our normal flow children
1105 // are also self-collapsing.
1106 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1107 if (child->isFloatingOrPositioned())
1108 continue;
1109 if (!child->isSelfCollapsingBlock())
1110 return false;
1111 }
1112 return true;
1113 }
1114 return false;
1115 }
1116
startDelayUpdateScrollInfo()1117 void RenderBlock::startDelayUpdateScrollInfo()
1118 {
1119 if (gDelayUpdateScrollInfo == 0) {
1120 ASSERT(!gDelayedUpdateScrollInfoSet);
1121 gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1122 }
1123 ASSERT(gDelayedUpdateScrollInfoSet);
1124 ++gDelayUpdateScrollInfo;
1125 }
1126
finishDelayUpdateScrollInfo()1127 void RenderBlock::finishDelayUpdateScrollInfo()
1128 {
1129 --gDelayUpdateScrollInfo;
1130 ASSERT(gDelayUpdateScrollInfo >= 0);
1131 if (gDelayUpdateScrollInfo == 0) {
1132 ASSERT(gDelayedUpdateScrollInfoSet);
1133
1134 OwnPtr<DelayedUpdateScrollInfoSet> infoSet(gDelayedUpdateScrollInfoSet);
1135 gDelayedUpdateScrollInfoSet = 0;
1136
1137 for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1138 RenderBlock* block = *it;
1139 if (block->hasOverflowClip()) {
1140 block->layer()->updateScrollInfoAfterLayout();
1141 }
1142 }
1143 }
1144 }
1145
updateScrollInfoAfterLayout()1146 void RenderBlock::updateScrollInfoAfterLayout()
1147 {
1148 if (hasOverflowClip()) {
1149 if (gDelayUpdateScrollInfo)
1150 gDelayedUpdateScrollInfoSet->add(this);
1151 else
1152 layer()->updateScrollInfoAfterLayout();
1153 }
1154 }
1155
layout()1156 void RenderBlock::layout()
1157 {
1158 // Update our first letter info now.
1159 updateFirstLetter();
1160
1161 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
1162 // layoutBlock().
1163 layoutBlock(false);
1164
1165 // It's safe to check for control clip here, since controls can never be table cells.
1166 // If we have a lightweight clip, there can never be any overflow from children.
1167 if (hasControlClip() && m_overflow)
1168 clearLayoutOverflow();
1169 }
1170
layoutBlock(bool relayoutChildren,int pageLogicalHeight)1171 void RenderBlock::layoutBlock(bool relayoutChildren, int pageLogicalHeight)
1172 {
1173 ASSERT(needsLayout());
1174
1175 if (isInline() && !isInlineBlockOrInlineTable()) // Inline <form>s inside various table elements can
1176 return; // cause us to come in here. Just bail.
1177
1178 if (!relayoutChildren && simplifiedLayout())
1179 return;
1180
1181 LayoutRepainter repainter(*this, m_everHadLayout && checkForRepaintDuringLayout());
1182
1183 int oldWidth = logicalWidth();
1184 int oldColumnWidth = desiredColumnWidth();
1185
1186 computeLogicalWidth();
1187 calcColumnWidth();
1188
1189 m_overflow.clear();
1190
1191 if (oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth())
1192 relayoutChildren = true;
1193
1194 #ifdef ANDROID_LAYOUT
1195 checkAndSetRelayoutChildren(&relayoutChildren);
1196 #endif
1197
1198 clearFloats();
1199
1200 int previousHeight = logicalHeight();
1201 setLogicalHeight(0);
1202 bool hasSpecifiedPageLogicalHeight = false;
1203 bool pageLogicalHeightChanged = false;
1204 ColumnInfo* colInfo = columnInfo();
1205 if (hasColumns()) {
1206 if (!pageLogicalHeight) {
1207 // We need to go ahead and set our explicit page height if one exists, so that we can
1208 // avoid doing two layout passes.
1209 computeLogicalHeight();
1210 int columnHeight = contentLogicalHeight();
1211 if (columnHeight > 0) {
1212 pageLogicalHeight = columnHeight;
1213 hasSpecifiedPageLogicalHeight = true;
1214 }
1215 setLogicalHeight(0);
1216 }
1217 if (colInfo->columnHeight() != pageLogicalHeight && m_everHadLayout) {
1218 colInfo->setColumnHeight(pageLogicalHeight);
1219 pageLogicalHeightChanged = true;
1220 }
1221
1222 if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1223 colInfo->clearForcedBreaks();
1224 }
1225
1226 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode(), pageLogicalHeight, pageLogicalHeightChanged, colInfo);
1227
1228 // We use four values, maxTopPos, maxTopNeg, maxBottomPos, and maxBottomNeg, to track
1229 // our current maximal positive and negative margins. These values are used when we
1230 // are collapsed with adjacent blocks, so for example, if you have block A and B
1231 // collapsing together, then you'd take the maximal positive margin from both A and B
1232 // and subtract it from the maximal negative margin from both A and B to get the
1233 // true collapsed margin. This algorithm is recursive, so when we finish layout()
1234 // our block knows its current maximal positive/negative values.
1235 //
1236 // Start out by setting our margin values to our current margins. Table cells have
1237 // no margins, so we don't fill in the values for table cells.
1238 bool isCell = isTableCell();
1239 if (!isCell) {
1240 initMaxMarginValues();
1241
1242 setMarginBeforeQuirk(style()->marginBefore().quirk());
1243 setMarginAfterQuirk(style()->marginAfter().quirk());
1244
1245 Node* n = node();
1246 if (n && n->hasTagName(formTag) && static_cast<HTMLFormElement*>(n)->isMalformed()) {
1247 // See if this form is malformed (i.e., unclosed). If so, don't give the form
1248 // a bottom margin.
1249 setMaxMarginAfterValues(0, 0);
1250 }
1251
1252 setPaginationStrut(0);
1253 }
1254
1255 // For overflow:scroll blocks, ensure we have both scrollbars in place always.
1256 if (scrollsOverflow()) {
1257 if (style()->overflowX() == OSCROLL)
1258 layer()->setHasHorizontalScrollbar(true);
1259 if (style()->overflowY() == OSCROLL)
1260 layer()->setHasVerticalScrollbar(true);
1261 }
1262
1263 int repaintLogicalTop = 0;
1264 int repaintLogicalBottom = 0;
1265 int maxFloatLogicalBottom = 0;
1266 if (!firstChild() && !isAnonymousBlock())
1267 setChildrenInline(true);
1268 if (childrenInline())
1269 layoutInlineChildren(relayoutChildren, repaintLogicalTop, repaintLogicalBottom);
1270 else
1271 layoutBlockChildren(relayoutChildren, maxFloatLogicalBottom);
1272
1273 // Expand our intrinsic height to encompass floats.
1274 int toAdd = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1275 if (lowestFloatLogicalBottom() > (logicalHeight() - toAdd) && expandsToEncloseOverhangingFloats())
1276 setLogicalHeight(lowestFloatLogicalBottom() + toAdd);
1277
1278 if (layoutColumns(hasSpecifiedPageLogicalHeight, pageLogicalHeight, statePusher))
1279 return;
1280
1281 // Calculate our new height.
1282 int oldHeight = logicalHeight();
1283 int oldClientAfterEdge = clientLogicalBottom();
1284 computeLogicalHeight();
1285 int newHeight = logicalHeight();
1286 if (oldHeight != newHeight) {
1287 if (oldHeight > newHeight && maxFloatLogicalBottom > newHeight && !childrenInline()) {
1288 // One of our children's floats may have become an overhanging float for us. We need to look for it.
1289 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
1290 if (child->isBlockFlow() && !child->isFloatingOrPositioned()) {
1291 RenderBlock* block = toRenderBlock(child);
1292 if (block->lowestFloatLogicalBottom() + block->logicalTop() > newHeight)
1293 addOverhangingFloats(block, -block->logicalLeft(), -block->logicalTop(), false);
1294 }
1295 }
1296 }
1297 }
1298
1299 if (previousHeight != newHeight)
1300 relayoutChildren = true;
1301
1302 layoutPositionedObjects(relayoutChildren || isRoot());
1303
1304 // Add overflow from children (unless we're multi-column, since in that case all our child overflow is clipped anyway).
1305 computeOverflow(oldClientAfterEdge);
1306
1307 statePusher.pop();
1308
1309 if (view()->layoutState()->m_pageLogicalHeight)
1310 setPageLogicalOffset(view()->layoutState()->pageLogicalOffset(logicalTop()));
1311
1312 updateLayerTransform();
1313
1314 // Update our scroll information if we're overflow:auto/scroll/hidden now that we know if
1315 // we overflow or not.
1316 updateScrollInfoAfterLayout();
1317
1318 // Repaint with our new bounds if they are different from our old bounds.
1319 bool didFullRepaint = repainter.repaintAfterLayout();
1320 if (!didFullRepaint && repaintLogicalTop != repaintLogicalBottom && (style()->visibility() == VISIBLE || enclosingLayer()->hasVisibleContent())) {
1321 // FIXME: We could tighten up the left and right invalidation points if we let layoutInlineChildren fill them in based off the particular lines
1322 // it had to lay out. We wouldn't need the hasOverflowClip() hack in that case either.
1323 int repaintLogicalLeft = logicalLeftVisualOverflow();
1324 int repaintLogicalRight = logicalRightVisualOverflow();
1325 if (hasOverflowClip()) {
1326 // If we have clipped overflow, we should use layout overflow as well, since visual overflow from lines didn't propagate to our block's overflow.
1327 // Note the old code did this as well but even for overflow:visible. The addition of hasOverflowClip() at least tightens up the hack a bit.
1328 // layoutInlineChildren should be patched to compute the entire repaint rect.
1329 repaintLogicalLeft = min(repaintLogicalLeft, logicalLeftLayoutOverflow());
1330 repaintLogicalRight = max(repaintLogicalRight, logicalRightLayoutOverflow());
1331 }
1332
1333 IntRect repaintRect;
1334 if (isHorizontalWritingMode())
1335 repaintRect = IntRect(repaintLogicalLeft, repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop);
1336 else
1337 repaintRect = IntRect(repaintLogicalTop, repaintLogicalLeft, repaintLogicalBottom - repaintLogicalTop, repaintLogicalRight - repaintLogicalLeft);
1338
1339 // The repaint rect may be split across columns, in which case adjustRectForColumns() will return the union.
1340 adjustRectForColumns(repaintRect);
1341
1342 repaintRect.inflate(maximalOutlineSize(PaintPhaseOutline));
1343
1344 if (hasOverflowClip()) {
1345 // Adjust repaint rect for scroll offset
1346 repaintRect.move(-layer()->scrolledContentOffset());
1347
1348 // Don't allow this rect to spill out of our overflow box.
1349 repaintRect.intersect(IntRect(0, 0, width(), height()));
1350 }
1351
1352 // Make sure the rect is still non-empty after intersecting for overflow above
1353 if (!repaintRect.isEmpty()) {
1354 repaintRectangle(repaintRect); // We need to do a partial repaint of our content.
1355 if (hasReflection())
1356 repaintRectangle(reflectedRect(repaintRect));
1357 }
1358 }
1359 setNeedsLayout(false);
1360 }
1361
addOverflowFromChildren()1362 void RenderBlock::addOverflowFromChildren()
1363 {
1364 if (!hasColumns()) {
1365 if (childrenInline())
1366 addOverflowFromInlineChildren();
1367 else
1368 addOverflowFromBlockChildren();
1369 } else {
1370 ColumnInfo* colInfo = columnInfo();
1371 if (columnCount(colInfo)) {
1372 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1373 if (isHorizontalWritingMode()) {
1374 int overflowLeft = !style()->isLeftToRightDirection() ? min(0, lastRect.x()) : 0;
1375 int overflowRight = style()->isLeftToRightDirection() ? max(width(), lastRect.maxX()) : 0;
1376 int overflowHeight = borderBefore() + paddingBefore() + colInfo->columnHeight();
1377 addLayoutOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1378 if (!hasOverflowClip())
1379 addVisualOverflow(IntRect(overflowLeft, 0, overflowRight - overflowLeft, overflowHeight));
1380 } else {
1381 IntRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1382 int overflowTop = !style()->isLeftToRightDirection() ? min(0, lastRect.y()) : 0;
1383 int overflowBottom = style()->isLeftToRightDirection() ? max(height(), lastRect.maxY()) : 0;
1384 int overflowWidth = borderBefore() + paddingBefore() + colInfo->columnHeight();
1385 addLayoutOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1386 if (!hasOverflowClip())
1387 addVisualOverflow(IntRect(0, overflowTop, overflowWidth, overflowBottom - overflowTop));
1388 }
1389 }
1390 }
1391 }
1392
computeOverflow(int oldClientAfterEdge,bool recomputeFloats)1393 void RenderBlock::computeOverflow(int oldClientAfterEdge, bool recomputeFloats)
1394 {
1395 // Add overflow from children.
1396 addOverflowFromChildren();
1397
1398 if (!hasColumns() && (recomputeFloats || isRoot() || expandsToEncloseOverhangingFloats() || hasSelfPaintingLayer()))
1399 addOverflowFromFloats();
1400
1401 // Add in the overflow from positioned objects.
1402 addOverflowFromPositionedObjects();
1403
1404 if (hasOverflowClip()) {
1405 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1406 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1407 // be considered reachable.
1408 IntRect clientRect(clientBoxRect());
1409 IntRect rectToApply;
1410 if (isHorizontalWritingMode())
1411 rectToApply = IntRect(clientRect.x(), clientRect.y(), 1, max(0, oldClientAfterEdge - clientRect.y()));
1412 else
1413 rectToApply = IntRect(clientRect.x(), clientRect.y(), max(0, oldClientAfterEdge - clientRect.x()), 1);
1414 addLayoutOverflow(rectToApply);
1415 }
1416
1417 // Add visual overflow from box-shadow and reflections.
1418 addShadowOverflow();
1419 }
1420
addOverflowFromBlockChildren()1421 void RenderBlock::addOverflowFromBlockChildren()
1422 {
1423 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1424 if (!child->isFloatingOrPositioned())
1425 addOverflowFromChild(child);
1426 }
1427 }
1428
addOverflowFromFloats()1429 void RenderBlock::addOverflowFromFloats()
1430 {
1431 if (!m_floatingObjects)
1432 return;
1433
1434 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
1435 FloatingObjectSetIterator end = floatingObjectSet.end();
1436 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
1437 FloatingObject* r = *it;
1438 if (r->m_isDescendant)
1439 addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
1440 }
1441 return;
1442 }
1443
addOverflowFromPositionedObjects()1444 void RenderBlock::addOverflowFromPositionedObjects()
1445 {
1446 if (!m_positionedObjects)
1447 return;
1448
1449 RenderBox* positionedObject;
1450 Iterator end = m_positionedObjects->end();
1451 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
1452 positionedObject = *it;
1453
1454 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1455 if (positionedObject->style()->position() != FixedPosition)
1456 addOverflowFromChild(positionedObject);
1457 }
1458 }
1459
expandsToEncloseOverhangingFloats() const1460 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1461 {
1462 return isInlineBlockOrInlineTable() || isFloatingOrPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBox())
1463 || hasColumns() || isTableCell() || isFieldset() || isWritingModeRoot();
1464 }
1465
adjustPositionedBlock(RenderBox * child,const MarginInfo & marginInfo)1466 void RenderBlock::adjustPositionedBlock(RenderBox* child, const MarginInfo& marginInfo)
1467 {
1468 bool isHorizontal = isHorizontalWritingMode();
1469 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontal);
1470 RenderLayer* childLayer = child->layer();
1471
1472 childLayer->setStaticInlinePosition(borderAndPaddingStart());
1473
1474 int logicalTop = logicalHeight();
1475 if (!marginInfo.canCollapseWithMarginBefore()) {
1476 child->computeBlockDirectionMargins(this);
1477 int marginBefore = marginBeforeForChild(child);
1478 int collapsedBeforePos = marginInfo.positiveMargin();
1479 int collapsedBeforeNeg = marginInfo.negativeMargin();
1480 if (marginBefore > 0) {
1481 if (marginBefore > collapsedBeforePos)
1482 collapsedBeforePos = marginBefore;
1483 } else {
1484 if (-marginBefore > collapsedBeforeNeg)
1485 collapsedBeforeNeg = -marginBefore;
1486 }
1487 logicalTop += (collapsedBeforePos - collapsedBeforeNeg) - marginBefore;
1488 }
1489 if (childLayer->staticBlockPosition() != logicalTop) {
1490 childLayer->setStaticBlockPosition(logicalTop);
1491 if (hasStaticBlockPosition)
1492 child->setChildNeedsLayout(true, false);
1493 }
1494 }
1495
adjustFloatingBlock(const MarginInfo & marginInfo)1496 void RenderBlock::adjustFloatingBlock(const MarginInfo& marginInfo)
1497 {
1498 // The float should be positioned taking into account the bottom margin
1499 // of the previous flow. We add that margin into the height, get the
1500 // float positioned properly, and then subtract the margin out of the
1501 // height again. In the case of self-collapsing blocks, we always just
1502 // use the top margins, since the self-collapsing block collapsed its
1503 // own bottom margin into its top margin.
1504 //
1505 // Note also that the previous flow may collapse its margin into the top of
1506 // our block. If this is the case, then we do not add the margin in to our
1507 // height when computing the position of the float. This condition can be tested
1508 // for by simply calling canCollapseWithMarginBefore. See
1509 // http://www.hixie.ch/tests/adhoc/css/box/block/margin-collapse/046.html for
1510 // an example of this scenario.
1511 int marginOffset = marginInfo.canCollapseWithMarginBefore() ? 0 : marginInfo.margin();
1512 setLogicalHeight(logicalHeight() + marginOffset);
1513 positionNewFloats();
1514 setLogicalHeight(logicalHeight() - marginOffset);
1515 }
1516
handleSpecialChild(RenderBox * child,const MarginInfo & marginInfo)1517 bool RenderBlock::handleSpecialChild(RenderBox* child, const MarginInfo& marginInfo)
1518 {
1519 // Handle in the given order
1520 return handlePositionedChild(child, marginInfo)
1521 || handleFloatingChild(child, marginInfo)
1522 || handleRunInChild(child);
1523 }
1524
1525
handlePositionedChild(RenderBox * child,const MarginInfo & marginInfo)1526 bool RenderBlock::handlePositionedChild(RenderBox* child, const MarginInfo& marginInfo)
1527 {
1528 if (child->isPositioned()) {
1529 child->containingBlock()->insertPositionedObject(child);
1530 adjustPositionedBlock(child, marginInfo);
1531 return true;
1532 }
1533 return false;
1534 }
1535
handleFloatingChild(RenderBox * child,const MarginInfo & marginInfo)1536 bool RenderBlock::handleFloatingChild(RenderBox* child, const MarginInfo& marginInfo)
1537 {
1538 if (child->isFloating()) {
1539 insertFloatingObject(child);
1540 adjustFloatingBlock(marginInfo);
1541 return true;
1542 }
1543 return false;
1544 }
1545
handleRunInChild(RenderBox * child)1546 bool RenderBlock::handleRunInChild(RenderBox* child)
1547 {
1548 // See if we have a run-in element with inline children. If the
1549 // children aren't inline, then just treat the run-in as a normal
1550 // block.
1551 if (!child->isRunIn() || !child->childrenInline())
1552 return false;
1553 // FIXME: We don't handle non-block elements with run-in for now.
1554 if (!child->isRenderBlock())
1555 return false;
1556
1557 RenderBlock* blockRunIn = toRenderBlock(child);
1558 RenderObject* curr = blockRunIn->nextSibling();
1559 if (!curr || !curr->isRenderBlock() || !curr->childrenInline() || curr->isRunIn() || curr->isAnonymous() || curr->isFloatingOrPositioned())
1560 return false;
1561
1562 RenderBlock* currBlock = toRenderBlock(curr);
1563
1564 // Remove the old child.
1565 children()->removeChildNode(this, blockRunIn);
1566
1567 // Create an inline.
1568 Node* runInNode = blockRunIn->node();
1569 RenderInline* inlineRunIn = new (renderArena()) RenderInline(runInNode ? runInNode : document());
1570 inlineRunIn->setStyle(blockRunIn->style());
1571
1572 bool runInIsGenerated = child->style()->styleType() == BEFORE || child->style()->styleType() == AFTER;
1573
1574 // Move the nodes from the old child to the new child, but skip any :before/:after content. It has already
1575 // been regenerated by the new inline.
1576 for (RenderObject* runInChild = blockRunIn->firstChild(); runInChild;) {
1577 RenderObject* nextSibling = runInChild->nextSibling();
1578 if (runInIsGenerated || (runInChild->style()->styleType() != BEFORE && runInChild->style()->styleType() != AFTER)) {
1579 blockRunIn->children()->removeChildNode(blockRunIn, runInChild, false);
1580 inlineRunIn->addChild(runInChild); // Use addChild instead of appendChildNode since it handles correct placement of the children relative to :after-generated content.
1581 }
1582 runInChild = nextSibling;
1583 }
1584
1585 // Now insert the new child under |currBlock|. Use addChild instead of insertChildNode since it handles correct placement of the children, esp where we cannot insert
1586 // anything before the first child. e.g. details tag. See https://bugs.webkit.org/show_bug.cgi?id=58228.
1587 currBlock->addChild(inlineRunIn, currBlock->firstChild());
1588
1589 // If the run-in had an element, we need to set the new renderer.
1590 if (runInNode)
1591 runInNode->setRenderer(inlineRunIn);
1592
1593 // Destroy the block run-in, which includes deleting its line box tree.
1594 blockRunIn->deleteLineBoxTree();
1595 blockRunIn->destroy();
1596
1597 // The block acts like an inline, so just null out its
1598 // position.
1599
1600 return true;
1601 }
1602
collapseMargins(RenderBox * child,MarginInfo & marginInfo)1603 int RenderBlock::collapseMargins(RenderBox* child, MarginInfo& marginInfo)
1604 {
1605 // Get the four margin values for the child and cache them.
1606 const MarginValues childMargins = marginValuesForChild(child);
1607
1608 // Get our max pos and neg top margins.
1609 int posTop = childMargins.positiveMarginBefore();
1610 int negTop = childMargins.negativeMarginBefore();
1611
1612 // For self-collapsing blocks, collapse our bottom margins into our
1613 // top to get new posTop and negTop values.
1614 if (child->isSelfCollapsingBlock()) {
1615 posTop = max(posTop, childMargins.positiveMarginAfter());
1616 negTop = max(negTop, childMargins.negativeMarginAfter());
1617 }
1618
1619 // See if the top margin is quirky. We only care if this child has
1620 // margins that will collapse with us.
1621 bool topQuirk = child->isMarginBeforeQuirk() || style()->marginBeforeCollapse() == MDISCARD;
1622
1623 if (marginInfo.canCollapseWithMarginBefore()) {
1624 // This child is collapsing with the top of the
1625 // block. If it has larger margin values, then we need to update
1626 // our own maximal values.
1627 if (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !topQuirk)
1628 setMaxMarginBeforeValues(max(posTop, maxPositiveMarginBefore()), max(negTop, maxNegativeMarginBefore()));
1629
1630 // The minute any of the margins involved isn't a quirk, don't
1631 // collapse it away, even if the margin is smaller (www.webreference.com
1632 // has an example of this, a <dt> with 0.8em author-specified inside
1633 // a <dl> inside a <td>.
1634 if (!marginInfo.determinedMarginBeforeQuirk() && !topQuirk && (posTop - negTop)) {
1635 setMarginBeforeQuirk(false);
1636 marginInfo.setDeterminedMarginBeforeQuirk(true);
1637 }
1638
1639 if (!marginInfo.determinedMarginBeforeQuirk() && topQuirk && !marginBefore())
1640 // We have no top margin and our top child has a quirky margin.
1641 // We will pick up this quirky margin and pass it through.
1642 // This deals with the <td><div><p> case.
1643 // Don't do this for a block that split two inlines though. You do
1644 // still apply margins in this case.
1645 setMarginBeforeQuirk(true);
1646 }
1647
1648 if (marginInfo.quirkContainer() && marginInfo.atBeforeSideOfBlock() && (posTop - negTop))
1649 marginInfo.setMarginBeforeQuirk(topQuirk);
1650
1651 int beforeCollapseLogicalTop = logicalHeight();
1652 int logicalTop = beforeCollapseLogicalTop;
1653 if (child->isSelfCollapsingBlock()) {
1654 // This child has no height. We need to compute our
1655 // position before we collapse the child's margins together,
1656 // so that we can get an accurate position for the zero-height block.
1657 int collapsedBeforePos = max(marginInfo.positiveMargin(), childMargins.positiveMarginBefore());
1658 int collapsedBeforeNeg = max(marginInfo.negativeMargin(), childMargins.negativeMarginBefore());
1659 marginInfo.setMargin(collapsedBeforePos, collapsedBeforeNeg);
1660
1661 // Now collapse the child's margins together, which means examining our
1662 // bottom margin values as well.
1663 marginInfo.setPositiveMarginIfLarger(childMargins.positiveMarginAfter());
1664 marginInfo.setNegativeMarginIfLarger(childMargins.negativeMarginAfter());
1665
1666 if (!marginInfo.canCollapseWithMarginBefore())
1667 // We need to make sure that the position of the self-collapsing block
1668 // is correct, since it could have overflowing content
1669 // that needs to be positioned correctly (e.g., a block that
1670 // had a specified height of 0 but that actually had subcontent).
1671 logicalTop = logicalHeight() + collapsedBeforePos - collapsedBeforeNeg;
1672 }
1673 else {
1674 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1675 setLogicalHeight(logicalHeight() + marginInfo.margin() + marginBeforeForChild(child));
1676 logicalTop = logicalHeight();
1677 }
1678 else if (!marginInfo.atBeforeSideOfBlock() ||
1679 (!marginInfo.canCollapseMarginBeforeWithChildren()
1680 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginBeforeQuirk()))) {
1681 // We're collapsing with a previous sibling's margins and not
1682 // with the top of the block.
1683 setLogicalHeight(logicalHeight() + max(marginInfo.positiveMargin(), posTop) - max(marginInfo.negativeMargin(), negTop));
1684 logicalTop = logicalHeight();
1685 }
1686
1687 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1688 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1689
1690 if (marginInfo.margin())
1691 marginInfo.setMarginAfterQuirk(child->isMarginAfterQuirk() || style()->marginAfterCollapse() == MDISCARD);
1692 }
1693
1694 // If margins would pull us past the top of the next page, then we need to pull back and pretend like the margins
1695 // collapsed into the page edge.
1696 bool paginated = view()->layoutState()->isPaginated();
1697 if (paginated && logicalTop > beforeCollapseLogicalTop) {
1698 int oldLogicalTop = logicalTop;
1699 logicalTop = min(logicalTop, nextPageLogicalTop(beforeCollapseLogicalTop));
1700 setLogicalHeight(logicalHeight() + (logicalTop - oldLogicalTop));
1701 }
1702 return logicalTop;
1703 }
1704
clearFloatsIfNeeded(RenderBox * child,MarginInfo & marginInfo,int oldTopPosMargin,int oldTopNegMargin,int yPos)1705 int RenderBlock::clearFloatsIfNeeded(RenderBox* child, MarginInfo& marginInfo, int oldTopPosMargin, int oldTopNegMargin, int yPos)
1706 {
1707 int heightIncrease = getClearDelta(child, yPos);
1708 if (!heightIncrease)
1709 return yPos;
1710
1711 if (child->isSelfCollapsingBlock()) {
1712 // For self-collapsing blocks that clear, they can still collapse their
1713 // margins with following siblings. Reset the current margins to represent
1714 // the self-collapsing block's margins only.
1715 // CSS2.1 states:
1716 // "An element that has had clearance applied to it never collapses its top margin with its parent block's bottom margin.
1717 // Therefore if we are at the bottom of the block, let's go ahead and reset margins to only include the
1718 // self-collapsing block's bottom margin.
1719 bool atBottomOfBlock = true;
1720 for (RenderBox* curr = child->nextSiblingBox(); curr && atBottomOfBlock; curr = curr->nextSiblingBox()) {
1721 if (!curr->isFloatingOrPositioned())
1722 atBottomOfBlock = false;
1723 }
1724
1725 MarginValues childMargins = marginValuesForChild(child);
1726 if (atBottomOfBlock) {
1727 marginInfo.setPositiveMargin(childMargins.positiveMarginAfter());
1728 marginInfo.setNegativeMargin(childMargins.negativeMarginAfter());
1729 } else {
1730 marginInfo.setPositiveMargin(max(childMargins.positiveMarginBefore(), childMargins.positiveMarginAfter()));
1731 marginInfo.setNegativeMargin(max(childMargins.negativeMarginBefore(), childMargins.negativeMarginAfter()));
1732 }
1733
1734 // Adjust our height such that we are ready to be collapsed with subsequent siblings (or the bottom
1735 // of the parent block).
1736 setLogicalHeight(child->y() - max(0, marginInfo.margin()));
1737 } else
1738 // Increase our height by the amount we had to clear.
1739 setLogicalHeight(height() + heightIncrease);
1740
1741 if (marginInfo.canCollapseWithMarginBefore()) {
1742 // We can no longer collapse with the top of the block since a clear
1743 // occurred. The empty blocks collapse into the cleared block.
1744 // FIXME: This isn't quite correct. Need clarification for what to do
1745 // if the height the cleared block is offset by is smaller than the
1746 // margins involved.
1747 setMaxMarginBeforeValues(oldTopPosMargin, oldTopNegMargin);
1748 marginInfo.setAtBeforeSideOfBlock(false);
1749 }
1750
1751 return yPos + heightIncrease;
1752 }
1753
estimateLogicalTopPosition(RenderBox * child,const MarginInfo & marginInfo)1754 int RenderBlock::estimateLogicalTopPosition(RenderBox* child, const MarginInfo& marginInfo)
1755 {
1756 // FIXME: We need to eliminate the estimation of vertical position, because when it's wrong we sometimes trigger a pathological
1757 // relayout if there are intruding floats.
1758 int logicalTopEstimate = logicalHeight();
1759 if (!marginInfo.canCollapseWithMarginBefore()) {
1760 int childMarginBefore = child->selfNeedsLayout() ? marginBeforeForChild(child) : collapsedMarginBeforeForChild(child);
1761 logicalTopEstimate += max(marginInfo.margin(), childMarginBefore);
1762 }
1763
1764 bool paginated = view()->layoutState()->isPaginated();
1765
1766 // Adjust logicalTopEstimate down to the next page if the margins are so large that we don't fit on the current
1767 // page.
1768 if (paginated && logicalTopEstimate > logicalHeight())
1769 logicalTopEstimate = min(logicalTopEstimate, nextPageLogicalTop(logicalHeight()));
1770
1771 logicalTopEstimate += getClearDelta(child, logicalTopEstimate);
1772
1773 if (paginated) {
1774 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
1775 logicalTopEstimate = applyBeforeBreak(child, logicalTopEstimate);
1776
1777 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
1778 logicalTopEstimate = adjustForUnsplittableChild(child, logicalTopEstimate);
1779
1780 if (!child->selfNeedsLayout() && child->isRenderBlock())
1781 logicalTopEstimate += toRenderBlock(child)->paginationStrut();
1782 }
1783
1784 return logicalTopEstimate;
1785 }
1786
determineLogicalLeftPositionForChild(RenderBox * child)1787 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child)
1788 {
1789 int startPosition = borderStart() + paddingStart();
1790 int totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1791
1792 // Add in our start margin.
1793 int childMarginStart = marginStartForChild(child);
1794 int newPosition = startPosition + childMarginStart;
1795
1796 // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats. They need
1797 // to shift over as necessary to dodge any floats that might get in the way.
1798 if (child->avoidsFloats()) {
1799 int startOff = style()->isLeftToRightDirection() ? logicalLeftOffsetForLine(logicalHeight(), false) : totalAvailableLogicalWidth - logicalRightOffsetForLine(logicalHeight(), false);
1800 if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1801 if (childMarginStart < 0)
1802 startOff += childMarginStart;
1803 newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1804 } else if (startOff != startPosition) {
1805 // The object is shifting to the "end" side of the block. The object might be centered, so we need to
1806 // recalculate our inline direction margins. Note that the containing block content
1807 // width computation will take into account the delta between |startOff| and |startPosition|
1808 // so that we can just pass the content width in directly to the |computeMarginsInContainingBlockInlineDirection|
1809 // function.
1810 child->computeInlineDirectionMargins(this, availableLogicalWidthForLine(logicalTopForChild(child), false), logicalWidthForChild(child));
1811 newPosition = startOff + marginStartForChild(child);
1812 }
1813 }
1814
1815 setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), ApplyLayoutDelta);
1816 }
1817
setCollapsedBottomMargin(const MarginInfo & marginInfo)1818 void RenderBlock::setCollapsedBottomMargin(const MarginInfo& marginInfo)
1819 {
1820 if (marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()) {
1821 // Update our max pos/neg bottom margins, since we collapsed our bottom margins
1822 // with our children.
1823 setMaxMarginAfterValues(max(maxPositiveMarginAfter(), marginInfo.positiveMargin()), max(maxNegativeMarginAfter(), marginInfo.negativeMargin()));
1824
1825 if (!marginInfo.marginAfterQuirk())
1826 setMarginAfterQuirk(false);
1827
1828 if (marginInfo.marginAfterQuirk() && marginAfter() == 0)
1829 // We have no bottom margin and our last child has a quirky margin.
1830 // We will pick up this quirky margin and pass it through.
1831 // This deals with the <td><div><p> case.
1832 setMarginAfterQuirk(true);
1833 }
1834 }
1835
handleAfterSideOfBlock(int beforeSide,int afterSide,MarginInfo & marginInfo)1836 void RenderBlock::handleAfterSideOfBlock(int beforeSide, int afterSide, MarginInfo& marginInfo)
1837 {
1838 marginInfo.setAtAfterSideOfBlock(true);
1839
1840 // If we can't collapse with children then go ahead and add in the bottom margin.
1841 if (!marginInfo.canCollapseWithMarginAfter() && !marginInfo.canCollapseWithMarginBefore()
1842 && (!document()->inQuirksMode() || !marginInfo.quirkContainer() || !marginInfo.marginAfterQuirk()))
1843 setLogicalHeight(logicalHeight() + marginInfo.margin());
1844
1845 // Now add in our bottom border/padding.
1846 setLogicalHeight(logicalHeight() + afterSide);
1847
1848 // Negative margins can cause our height to shrink below our minimal height (border/padding).
1849 // If this happens, ensure that the computed height is increased to the minimal height.
1850 setLogicalHeight(max(logicalHeight(), beforeSide + afterSide));
1851
1852 // Update our bottom collapsed margin info.
1853 setCollapsedBottomMargin(marginInfo);
1854 }
1855
setLogicalLeftForChild(RenderBox * child,int logicalLeft,ApplyLayoutDeltaMode applyDelta)1856 void RenderBlock::setLogicalLeftForChild(RenderBox* child, int logicalLeft, ApplyLayoutDeltaMode applyDelta)
1857 {
1858 if (isHorizontalWritingMode()) {
1859 if (applyDelta == ApplyLayoutDelta)
1860 view()->addLayoutDelta(IntSize(child->x() - logicalLeft, 0));
1861 child->setX(logicalLeft);
1862 } else {
1863 if (applyDelta == ApplyLayoutDelta)
1864 view()->addLayoutDelta(IntSize(0, child->y() - logicalLeft));
1865 child->setY(logicalLeft);
1866 }
1867 }
1868
setLogicalTopForChild(RenderBox * child,int logicalTop,ApplyLayoutDeltaMode applyDelta)1869 void RenderBlock::setLogicalTopForChild(RenderBox* child, int logicalTop, ApplyLayoutDeltaMode applyDelta)
1870 {
1871 if (isHorizontalWritingMode()) {
1872 if (applyDelta == ApplyLayoutDelta)
1873 view()->addLayoutDelta(IntSize(0, child->y() - logicalTop));
1874 child->setY(logicalTop);
1875 } else {
1876 if (applyDelta == ApplyLayoutDelta)
1877 view()->addLayoutDelta(IntSize(child->x() - logicalTop, 0));
1878 child->setX(logicalTop);
1879 }
1880 }
1881
layoutBlockChildren(bool relayoutChildren,int & maxFloatLogicalBottom)1882 void RenderBlock::layoutBlockChildren(bool relayoutChildren, int& maxFloatLogicalBottom)
1883 {
1884 if (gPercentHeightDescendantsMap) {
1885 if (HashSet<RenderBox*>* descendants = gPercentHeightDescendantsMap->get(this)) {
1886 HashSet<RenderBox*>::iterator end = descendants->end();
1887 for (HashSet<RenderBox*>::iterator it = descendants->begin(); it != end; ++it) {
1888 RenderBox* box = *it;
1889 while (box != this) {
1890 if (box->normalChildNeedsLayout())
1891 break;
1892 box->setChildNeedsLayout(true, false);
1893 box = box->containingBlock();
1894 ASSERT(box);
1895 if (!box)
1896 break;
1897 }
1898 }
1899 }
1900 }
1901
1902 int beforeEdge = borderBefore() + paddingBefore();
1903 int afterEdge = borderAfter() + paddingAfter() + scrollbarLogicalHeight();
1904
1905 setLogicalHeight(beforeEdge);
1906
1907 // The margin struct caches all our current margin collapsing state. The compact struct caches state when we encounter compacts,
1908 MarginInfo marginInfo(this, beforeEdge, afterEdge);
1909
1910 // Fieldsets need to find their legend and position it inside the border of the object.
1911 // The legend then gets skipped during normal layout. The same is true for ruby text.
1912 // It doesn't get included in the normal layout process but is instead skipped.
1913 RenderObject* childToExclude = layoutSpecialExcludedChild(relayoutChildren);
1914
1915 int previousFloatLogicalBottom = 0;
1916 maxFloatLogicalBottom = 0;
1917
1918 RenderBox* next = firstChildBox();
1919
1920 while (next) {
1921 RenderBox* child = next;
1922 next = child->nextSiblingBox();
1923
1924 if (childToExclude == child)
1925 continue; // Skip this child, since it will be positioned by the specialized subclass (fieldsets and ruby runs).
1926
1927 // Make sure we layout children if they need it.
1928 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1929 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1930 if (relayoutChildren || ((child->style()->logicalHeight().isPercent() || child->style()->logicalMinHeight().isPercent() || child->style()->logicalMaxHeight().isPercent()) && !isRenderView()))
1931 child->setChildNeedsLayout(true, false);
1932
1933 // If relayoutChildren is set and the child has percentage padding, we also need to invalidate the child's pref widths.
1934 if (relayoutChildren && (child->style()->paddingStart().isPercent() || child->style()->paddingEnd().isPercent()))
1935 child->setPreferredLogicalWidthsDirty(true, false);
1936
1937 // Handle the four types of special elements first. These include positioned content, floating content, compacts and
1938 // run-ins. When we encounter these four types of objects, we don't actually lay them out as normal flow blocks.
1939 if (handleSpecialChild(child, marginInfo))
1940 continue;
1941
1942 // Lay out the child.
1943 layoutBlockChild(child, marginInfo, previousFloatLogicalBottom, maxFloatLogicalBottom);
1944 }
1945
1946 // Now do the handling of the bottom of the block, adding in our bottom border/padding and
1947 // determining the correct collapsed bottom margin information.
1948 handleAfterSideOfBlock(beforeEdge, afterEdge, marginInfo);
1949 }
1950
layoutBlockChild(RenderBox * child,MarginInfo & marginInfo,int & previousFloatLogicalBottom,int & maxFloatLogicalBottom)1951 void RenderBlock::layoutBlockChild(RenderBox* child, MarginInfo& marginInfo, int& previousFloatLogicalBottom, int& maxFloatLogicalBottom)
1952 {
1953 int oldPosMarginBefore = maxPositiveMarginBefore();
1954 int oldNegMarginBefore = maxNegativeMarginBefore();
1955
1956 // The child is a normal flow object. Compute the margins we will use for collapsing now.
1957 child->computeBlockDirectionMargins(this);
1958
1959 // Do not allow a collapse if the margin-before-collapse style is set to SEPARATE.
1960 if (child->style()->marginBeforeCollapse() == MSEPARATE) {
1961 marginInfo.setAtBeforeSideOfBlock(false);
1962 marginInfo.clearMargin();
1963 }
1964
1965 // Try to guess our correct logical top position. In most cases this guess will
1966 // be correct. Only if we're wrong (when we compute the real logical top position)
1967 // will we have to potentially relayout.
1968 int logicalTopEstimate = estimateLogicalTopPosition(child, marginInfo);
1969
1970 // Cache our old rect so that we can dirty the proper repaint rects if the child moves.
1971 IntRect oldRect(child->x(), child->y() , child->width(), child->height());
1972 int oldLogicalTop = logicalTopForChild(child);
1973
1974 #ifndef NDEBUG
1975 IntSize oldLayoutDelta = view()->layoutDelta();
1976 #endif
1977 // Go ahead and position the child as though it didn't collapse with the top.
1978 setLogicalTopForChild(child, logicalTopEstimate, ApplyLayoutDelta);
1979
1980 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
1981 bool markDescendantsWithFloats = false;
1982 if (logicalTopEstimate != oldLogicalTop && !child->avoidsFloats() && childRenderBlock && childRenderBlock->containsFloats())
1983 markDescendantsWithFloats = true;
1984 else if (!child->avoidsFloats() || child->shrinkToAvoidFloats()) {
1985 // If an element might be affected by the presence of floats, then always mark it for
1986 // layout.
1987 int fb = max(previousFloatLogicalBottom, lowestFloatLogicalBottom());
1988 if (fb > logicalTopEstimate)
1989 markDescendantsWithFloats = true;
1990 }
1991
1992 if (childRenderBlock) {
1993 if (markDescendantsWithFloats)
1994 childRenderBlock->markAllDescendantsWithFloatsForLayout();
1995 if (!child->isWritingModeRoot())
1996 previousFloatLogicalBottom = max(previousFloatLogicalBottom, oldLogicalTop + childRenderBlock->lowestFloatLogicalBottom());
1997 }
1998
1999 if (!child->needsLayout())
2000 child->markForPaginationRelayoutIfNeeded();
2001
2002 bool childHadLayout = child->m_everHadLayout;
2003 bool childNeededLayout = child->needsLayout();
2004 if (childNeededLayout)
2005 child->layout();
2006
2007 // Cache if we are at the top of the block right now.
2008 bool atBeforeSideOfBlock = marginInfo.atBeforeSideOfBlock();
2009
2010 // Now determine the correct ypos based off examination of collapsing margin
2011 // values.
2012 int logicalTopBeforeClear = collapseMargins(child, marginInfo);
2013
2014 // Now check for clear.
2015 int logicalTopAfterClear = clearFloatsIfNeeded(child, marginInfo, oldPosMarginBefore, oldNegMarginBefore, logicalTopBeforeClear);
2016
2017 bool paginated = view()->layoutState()->isPaginated();
2018 if (paginated) {
2019 int oldTop = logicalTopAfterClear;
2020
2021 // If the object has a page or column break value of "before", then we should shift to the top of the next page.
2022 logicalTopAfterClear = applyBeforeBreak(child, logicalTopAfterClear);
2023
2024 // For replaced elements and scrolled elements, we want to shift them to the next page if they don't fit on the current one.
2025 int logicalTopBeforeUnsplittableAdjustment = logicalTopAfterClear;
2026 int logicalTopAfterUnsplittableAdjustment = adjustForUnsplittableChild(child, logicalTopAfterClear);
2027
2028 int paginationStrut = 0;
2029 int unsplittableAdjustmentDelta = logicalTopAfterUnsplittableAdjustment - logicalTopBeforeUnsplittableAdjustment;
2030 if (unsplittableAdjustmentDelta)
2031 paginationStrut = unsplittableAdjustmentDelta;
2032 else if (childRenderBlock && childRenderBlock->paginationStrut())
2033 paginationStrut = childRenderBlock->paginationStrut();
2034
2035 if (paginationStrut) {
2036 // We are willing to propagate out to our parent block as long as we were at the top of the block prior
2037 // to collapsing our margins, and as long as we didn't clear or move as a result of other pagination.
2038 if (atBeforeSideOfBlock && oldTop == logicalTopBeforeClear && !isPositioned() && !isTableCell()) {
2039 // FIXME: Should really check if we're exceeding the page height before propagating the strut, but we don't
2040 // have all the information to do so (the strut only has the remaining amount to push). Gecko gets this wrong too
2041 // and pushes to the next page anyway, so not too concerned about it.
2042 setPaginationStrut(logicalTopAfterClear + paginationStrut);
2043 if (childRenderBlock)
2044 childRenderBlock->setPaginationStrut(0);
2045 } else
2046 logicalTopAfterClear += paginationStrut;
2047 }
2048
2049 // Similar to how we apply clearance. Go ahead and boost height() to be the place where we're going to position the child.
2050 setLogicalHeight(logicalHeight() + (logicalTopAfterClear - oldTop));
2051 }
2052
2053 setLogicalTopForChild(child, logicalTopAfterClear, ApplyLayoutDelta);
2054
2055 // Now we have a final top position. See if it really does end up being different from our estimate.
2056 if (logicalTopAfterClear != logicalTopEstimate) {
2057 if (child->shrinkToAvoidFloats()) {
2058 // The child's width depends on the line width.
2059 // When the child shifts to clear an item, its width can
2060 // change (because it has more available line width).
2061 // So go ahead and mark the item as dirty.
2062 child->setChildNeedsLayout(true, false);
2063 }
2064 if (childRenderBlock) {
2065 if (!child->avoidsFloats() && childRenderBlock->containsFloats())
2066 childRenderBlock->markAllDescendantsWithFloatsForLayout();
2067 if (!child->needsLayout())
2068 child->markForPaginationRelayoutIfNeeded();
2069 }
2070
2071 // Our guess was wrong. Make the child lay itself out again.
2072 child->layoutIfNeeded();
2073 }
2074
2075 // We are no longer at the top of the block if we encounter a non-empty child.
2076 // This has to be done after checking for clear, so that margins can be reset if a clear occurred.
2077 if (marginInfo.atBeforeSideOfBlock() && !child->isSelfCollapsingBlock())
2078 marginInfo.setAtBeforeSideOfBlock(false);
2079
2080 // Now place the child in the correct left position
2081 determineLogicalLeftPositionForChild(child);
2082
2083 // Update our height now that the child has been placed in the correct position.
2084 setLogicalHeight(logicalHeight() + logicalHeightForChild(child));
2085 if (child->style()->marginAfterCollapse() == MSEPARATE) {
2086 setLogicalHeight(logicalHeight() + marginAfterForChild(child));
2087 marginInfo.clearMargin();
2088 }
2089 // If the child has overhanging floats that intrude into following siblings (or possibly out
2090 // of this block), then the parent gets notified of the floats now.
2091 if (childRenderBlock && childRenderBlock->containsFloats())
2092 maxFloatLogicalBottom = max(maxFloatLogicalBottom, addOverhangingFloats(toRenderBlock(child), -child->logicalLeft(), -child->logicalTop(), !childNeededLayout));
2093
2094 IntSize childOffset(child->x() - oldRect.x(), child->y() - oldRect.y());
2095 if (childOffset.width() || childOffset.height()) {
2096 view()->addLayoutDelta(childOffset);
2097
2098 // If the child moved, we have to repaint it as well as any floating/positioned
2099 // descendants. An exception is if we need a layout. In this case, we know we're going to
2100 // repaint ourselves (and the child) anyway.
2101 if (childHadLayout && !selfNeedsLayout() && child->checkForRepaintDuringLayout())
2102 child->repaintDuringLayoutIfMoved(oldRect);
2103 }
2104
2105 if (!childHadLayout && child->checkForRepaintDuringLayout()) {
2106 child->repaint();
2107 child->repaintOverhangingFloats(true);
2108 }
2109
2110 if (paginated) {
2111 // Check for an after page/column break.
2112 int newHeight = applyAfterBreak(child, logicalHeight(), marginInfo);
2113 if (newHeight != height())
2114 setLogicalHeight(newHeight);
2115 }
2116
2117 ASSERT(oldLayoutDelta == view()->layoutDelta());
2118 }
2119
simplifiedNormalFlowLayout()2120 void RenderBlock::simplifiedNormalFlowLayout()
2121 {
2122 if (childrenInline()) {
2123 ListHashSet<RootInlineBox*> lineBoxes;
2124 bool endOfInline = false;
2125 RenderObject* o = bidiFirst(this, 0, false);
2126 while (o) {
2127 if (!o->isPositioned() && (o->isReplaced() || o->isFloating())) {
2128 o->layoutIfNeeded();
2129 if (toRenderBox(o)->inlineBoxWrapper()) {
2130 RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
2131 lineBoxes.add(box);
2132 }
2133 } else if (o->isText() || (o->isRenderInline() && !endOfInline))
2134 o->setNeedsLayout(false);
2135 o = bidiNext(this, o, 0, false, &endOfInline);
2136 }
2137
2138 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2139 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2140 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2141 RootInlineBox* box = *it;
2142 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2143 }
2144 } else {
2145 for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2146 if (!box->isPositioned())
2147 box->layoutIfNeeded();
2148 }
2149 }
2150 }
2151
simplifiedLayout()2152 bool RenderBlock::simplifiedLayout()
2153 {
2154 if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
2155 return false;
2156
2157 LayoutStateMaintainer statePusher(view(), this, IntSize(x(), y()), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
2158
2159 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
2160 return false;
2161
2162 // Lay out positioned descendants or objects that just need to recompute overflow.
2163 if (needsSimplifiedNormalFlowLayout())
2164 simplifiedNormalFlowLayout();
2165
2166 // Lay out our positioned objects if our positioned child bit is set.
2167 if (posChildNeedsLayout())
2168 layoutPositionedObjects(false);
2169
2170 // Recompute our overflow information.
2171 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
2172 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
2173 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
2174 // lowestPosition on every relayout so it's not a regression.
2175 m_overflow.clear();
2176 computeOverflow(clientLogicalBottom(), true);
2177
2178 statePusher.pop();
2179
2180 updateLayerTransform();
2181
2182 updateScrollInfoAfterLayout();
2183
2184 setNeedsLayout(false);
2185 return true;
2186 }
2187
layoutPositionedObjects(bool relayoutChildren)2188 void RenderBlock::layoutPositionedObjects(bool relayoutChildren)
2189 {
2190 if (!m_positionedObjects)
2191 return;
2192
2193 if (hasColumns())
2194 view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
2195
2196 RenderBox* r;
2197 Iterator end = m_positionedObjects->end();
2198 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2199 r = *it;
2200 // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
2201 // non-positioned block. Rather than trying to detect all of these movement cases, we just always lay out positioned
2202 // objects that are positioned implicitly like this. Such objects are rare, and so in typical DHTML menu usage (where everything is
2203 // positioned explicitly) this should not incur a performance penalty.
2204 if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this && r->parent()->isBlockFlow()))
2205 r->setChildNeedsLayout(true, false);
2206
2207 // If relayoutChildren is set and we have percentage padding, we also need to invalidate the child's pref widths.
2208 if (relayoutChildren && (r->style()->paddingStart().isPercent() || r->style()->paddingEnd().isPercent()))
2209 r->setPreferredLogicalWidthsDirty(true, false);
2210
2211 if (!r->needsLayout())
2212 r->markForPaginationRelayoutIfNeeded();
2213
2214 // 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
2215 // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
2216 if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
2217 r->setNeedsLayout(false);
2218 r->layoutIfNeeded();
2219 }
2220
2221 if (hasColumns())
2222 view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
2223 }
2224
markPositionedObjectsForLayout()2225 void RenderBlock::markPositionedObjectsForLayout()
2226 {
2227 if (m_positionedObjects) {
2228 RenderBox* r;
2229 Iterator end = m_positionedObjects->end();
2230 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
2231 r = *it;
2232 r->setChildNeedsLayout(true);
2233 }
2234 }
2235 }
2236
markForPaginationRelayoutIfNeeded()2237 void RenderBlock::markForPaginationRelayoutIfNeeded()
2238 {
2239 ASSERT(!needsLayout());
2240 if (needsLayout())
2241 return;
2242
2243 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(logicalTop()) != pageLogicalOffset()))
2244 setChildNeedsLayout(true, false);
2245 }
2246
repaintOverhangingFloats(bool paintAllDescendants)2247 void RenderBlock::repaintOverhangingFloats(bool paintAllDescendants)
2248 {
2249 // Repaint any overhanging floats (if we know we're the one to paint them).
2250 // Otherwise, bail out.
2251 if (!hasOverhangingFloats())
2252 return;
2253
2254 // FIXME: Avoid disabling LayoutState. At the very least, don't disable it for floats originating
2255 // in this block. Better yet would be to push extra state for the containers of other floats.
2256 view()->disableLayoutState();
2257 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2258 FloatingObjectSetIterator end = floatingObjectSet.end();
2259 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2260 FloatingObject* r = *it;
2261 // Only repaint the object if it is overhanging, is not in its own layer, and
2262 // is our responsibility to paint (m_shouldPaint is set). When paintAllDescendants is true, the latter
2263 // condition is replaced with being a descendant of us.
2264 if (logicalBottomForFloat(r) > logicalHeight() && ((paintAllDescendants && r->m_renderer->isDescendantOf(this)) || r->m_shouldPaint) && !r->m_renderer->hasSelfPaintingLayer()) {
2265 r->m_renderer->repaint();
2266 r->m_renderer->repaintOverhangingFloats();
2267 }
2268 }
2269 view()->enableLayoutState();
2270 }
2271
paint(PaintInfo & paintInfo,int tx,int ty)2272 void RenderBlock::paint(PaintInfo& paintInfo, int tx, int ty)
2273 {
2274 tx += x();
2275 ty += y();
2276
2277 PaintPhase phase = paintInfo.phase;
2278
2279 // Check if we need to do anything at all.
2280 // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
2281 // paints the root's background.
2282 if (!isRoot()) {
2283 IntRect overflowBox = visualOverflowRect();
2284 flipForWritingMode(overflowBox);
2285 overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
2286 overflowBox.move(tx, ty);
2287 if (!overflowBox.intersects(paintInfo.rect))
2288 return;
2289 }
2290
2291 bool pushedClip = pushContentsClip(paintInfo, tx, ty);
2292 paintObject(paintInfo, tx, ty);
2293 if (pushedClip)
2294 popContentsClip(paintInfo, phase, tx, ty);
2295
2296 // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
2297 // z-index. We paint after we painted the background/border, so that the scrollbars will
2298 // sit above the background/border.
2299 if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this))
2300 layer()->paintOverflowControls(paintInfo.context, tx, ty, paintInfo.rect);
2301 }
2302
paintColumnRules(PaintInfo & paintInfo,int tx,int ty)2303 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, int tx, int ty)
2304 {
2305 const Color& ruleColor = style()->visitedDependentColor(CSSPropertyWebkitColumnRuleColor);
2306 bool ruleTransparent = style()->columnRuleIsTransparent();
2307 EBorderStyle ruleStyle = style()->columnRuleStyle();
2308 int ruleWidth = style()->columnRuleWidth();
2309 int colGap = columnGap();
2310 bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent && ruleWidth <= colGap;
2311 if (!renderRule)
2312 return;
2313
2314 // We need to do multiple passes, breaking up our child painting into strips.
2315 ColumnInfo* colInfo = columnInfo();
2316 unsigned colCount = columnCount(colInfo);
2317 int currLogicalLeftOffset = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2318 int ruleAdd = logicalLeftOffsetForContent();
2319 int ruleLogicalLeft = style()->isLeftToRightDirection() ? 0 : contentLogicalWidth();
2320 for (unsigned i = 0; i < colCount; i++) {
2321 IntRect colRect = columnRectAt(colInfo, i);
2322
2323 int inlineDirectionSize = isHorizontalWritingMode() ? colRect.width() : colRect.height();
2324
2325 // Move to the next position.
2326 if (style()->isLeftToRightDirection()) {
2327 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
2328 currLogicalLeftOffset += inlineDirectionSize + colGap;
2329 } else {
2330 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
2331 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2332 }
2333
2334 // Now paint the column rule.
2335 if (i < colCount - 1) {
2336 int ruleLeft = isHorizontalWritingMode() ? tx + ruleLogicalLeft - ruleWidth / 2 + ruleAdd : tx + borderBefore() + paddingBefore();
2337 int ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleWidth : ruleLeft + contentWidth();
2338 int ruleTop = isHorizontalWritingMode() ? ty + borderTop() + paddingTop() : ty + ruleLogicalLeft - ruleWidth / 2 + ruleAdd;
2339 int ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleWidth;
2340 drawLineForBoxSide(paintInfo.context, ruleLeft, ruleTop, ruleRight, ruleBottom,
2341 style()->isLeftToRightDirection() ? BSLeft : BSRight, ruleColor, ruleStyle, 0, 0);
2342 }
2343
2344 ruleLogicalLeft = currLogicalLeftOffset;
2345 }
2346 }
2347
paintColumnContents(PaintInfo & paintInfo,int tx,int ty,bool paintingFloats)2348 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, int tx, int ty, bool paintingFloats)
2349 {
2350 // We need to do multiple passes, breaking up our child painting into strips.
2351 GraphicsContext* context = paintInfo.context;
2352 ColumnInfo* colInfo = columnInfo();
2353 unsigned colCount = columnCount(colInfo);
2354 if (!colCount)
2355 return;
2356 int currLogicalTopOffset = 0;
2357 for (unsigned i = 0; i < colCount; i++) {
2358 // For each rect, we clip to the rect, and then we adjust our coords.
2359 IntRect colRect = columnRectAt(colInfo, i);
2360 flipForWritingMode(colRect);
2361 int logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2362 IntSize offset = isHorizontalWritingMode() ? IntSize(logicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, logicalLeftOffset);
2363 colRect.move(tx, ty);
2364 PaintInfo info(paintInfo);
2365 info.rect.intersect(colRect);
2366
2367 if (!info.rect.isEmpty()) {
2368 context->save();
2369
2370 // Each strip pushes a clip, since column boxes are specified as being
2371 // like overflow:hidden.
2372 context->clip(colRect);
2373
2374 // Adjust our x and y when painting.
2375 int finalX = tx + offset.width();
2376 int finalY = ty + offset.height();
2377 if (paintingFloats)
2378 paintFloats(info, finalX, finalY, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2379 else
2380 paintContents(info, finalX, finalY);
2381
2382 context->restore();
2383 }
2384
2385 int blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2386 if (style()->isFlippedBlocksWritingMode())
2387 currLogicalTopOffset += blockDelta;
2388 else
2389 currLogicalTopOffset -= blockDelta;
2390 }
2391 }
2392
paintContents(PaintInfo & paintInfo,int tx,int ty)2393 void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
2394 {
2395 // Avoid painting descendants of the root element when stylesheets haven't loaded. This eliminates FOUC.
2396 // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
2397 // will do a full repaint().
2398 if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
2399 return;
2400
2401 if (childrenInline())
2402 m_lineBoxes.paint(this, paintInfo, tx, ty);
2403 else
2404 paintChildren(paintInfo, tx, ty);
2405 }
2406
paintChildren(PaintInfo & paintInfo,int tx,int ty)2407 void RenderBlock::paintChildren(PaintInfo& paintInfo, int tx, int ty)
2408 {
2409 PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2410 newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2411
2412 // We don't paint our own background, but we do let the kids paint their backgrounds.
2413 PaintInfo info(paintInfo);
2414 info.phase = newPhase;
2415 info.updatePaintingRootForChildren(this);
2416
2417 // FIXME: Paint-time pagination is obsolete and is now only used by embedded WebViews inside AppKit
2418 // NSViews. Do not add any more code for this.
2419 RenderView* renderView = view();
2420 bool usePrintRect = !renderView->printRect().isEmpty();
2421
2422 for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
2423 // Check for page-break-before: always, and if it's set, break and bail.
2424 bool checkBeforeAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakBefore() == PBALWAYS);
2425 if (checkBeforeAlways
2426 && (ty + child->y()) > paintInfo.rect.y()
2427 && (ty + child->y()) < paintInfo.rect.maxY()) {
2428 view()->setBestTruncatedAt(ty + child->y(), this, true);
2429 return;
2430 }
2431
2432 if (!child->isFloating() && child->isReplaced() && usePrintRect && child->height() <= renderView->printRect().height()) {
2433 // Paginate block-level replaced elements.
2434 if (ty + child->y() + child->height() > renderView->printRect().maxY()) {
2435 if (ty + child->y() < renderView->truncatedAt())
2436 renderView->setBestTruncatedAt(ty + child->y(), child);
2437 // If we were able to truncate, don't paint.
2438 if (ty + child->y() >= renderView->truncatedAt())
2439 break;
2440 }
2441 }
2442
2443 IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment);
2444 if (!child->hasSelfPaintingLayer() && !child->isFloating())
2445 child->paint(info, childPoint.x(), childPoint.y());
2446
2447 // Check for page-break-after: always, and if it's set, break and bail.
2448 bool checkAfterAlways = !childrenInline() && (usePrintRect && child->style()->pageBreakAfter() == PBALWAYS);
2449 if (checkAfterAlways
2450 && (ty + child->y() + child->height()) > paintInfo.rect.y()
2451 && (ty + child->y() + child->height()) < paintInfo.rect.maxY()) {
2452 view()->setBestTruncatedAt(ty + child->y() + child->height() + max(0, child->collapsedMarginAfter()), this, true);
2453 return;
2454 }
2455 }
2456 }
2457
paintCaret(PaintInfo & paintInfo,int tx,int ty,CaretType type)2458 void RenderBlock::paintCaret(PaintInfo& paintInfo, int tx, int ty, CaretType type)
2459 {
2460 SelectionController* selection = type == CursorCaret ? frame()->selection() : frame()->page()->dragCaretController();
2461
2462 // Paint the caret if the SelectionController says so or if caret browsing is enabled
2463 bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2464 RenderObject* caretPainter = selection->caretRenderer();
2465 if (caretPainter == this && (selection->isContentEditable() || caretBrowsing)) {
2466 // Convert the painting offset into the local coordinate system of this renderer,
2467 // to match the localCaretRect computed by the SelectionController
2468 offsetForContents(tx, ty);
2469
2470 if (type == CursorCaret)
2471 frame()->selection()->paintCaret(paintInfo.context, tx, ty, paintInfo.rect);
2472 else
2473 frame()->selection()->paintDragCaret(paintInfo.context, tx, ty, paintInfo.rect);
2474 }
2475 }
2476
paintObject(PaintInfo & paintInfo,int tx,int ty)2477 void RenderBlock::paintObject(PaintInfo& paintInfo, int tx, int ty)
2478 {
2479 PaintPhase paintPhase = paintInfo.phase;
2480
2481 // 1. paint background, borders etc
2482 if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2483 if (hasBoxDecorations())
2484 paintBoxDecorations(paintInfo, tx, ty);
2485 if (hasColumns())
2486 paintColumnRules(paintInfo, tx, ty);
2487 }
2488
2489 if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2490 paintMask(paintInfo, tx, ty);
2491 return;
2492 }
2493
2494 // We're done. We don't bother painting any children.
2495 if (paintPhase == PaintPhaseBlockBackground)
2496 return;
2497
2498 // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2499 int scrolledX = tx;
2500 int scrolledY = ty;
2501 if (hasOverflowClip()) {
2502 IntSize offset = layer()->scrolledContentOffset();
2503 scrolledX -= offset.width();
2504 scrolledY -= offset.height();
2505 }
2506
2507 // 2. paint contents
2508 if (paintPhase != PaintPhaseSelfOutline) {
2509 if (hasColumns())
2510 paintColumnContents(paintInfo, scrolledX, scrolledY);
2511 else
2512 paintContents(paintInfo, scrolledX, scrolledY);
2513 }
2514
2515 // 3. paint selection
2516 // FIXME: Make this work with multi column layouts. For now don't fill gaps.
2517 bool isPrinting = document()->printing();
2518 if (!isPrinting && !hasColumns())
2519 paintSelection(paintInfo, scrolledX, scrolledY); // Fill in gaps in selection on lines and between blocks.
2520
2521 // 4. paint floats.
2522 if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2523 if (hasColumns())
2524 paintColumnContents(paintInfo, scrolledX, scrolledY, true);
2525 else
2526 paintFloats(paintInfo, scrolledX, scrolledY, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2527 }
2528
2529 // 5. paint outline.
2530 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2531 paintOutline(paintInfo.context, tx, ty, width(), height());
2532
2533 // 6. paint continuation outlines.
2534 if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2535 RenderInline* inlineCont = inlineElementContinuation();
2536 if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2537 RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2538 RenderBlock* cb = containingBlock();
2539
2540 bool inlineEnclosedInSelfPaintingLayer = false;
2541 for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2542 if (box->hasSelfPaintingLayer()) {
2543 inlineEnclosedInSelfPaintingLayer = true;
2544 break;
2545 }
2546 }
2547
2548 if (!inlineEnclosedInSelfPaintingLayer)
2549 cb->addContinuationWithOutline(inlineRenderer);
2550 else if (!inlineRenderer->firstLineBox())
2551 inlineRenderer->paintOutline(paintInfo.context, tx - x() + inlineRenderer->containingBlock()->x(),
2552 ty - y() + inlineRenderer->containingBlock()->y());
2553 }
2554 paintContinuationOutlines(paintInfo, tx, ty);
2555 }
2556
2557 // 7. paint caret.
2558 // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2559 // then paint the caret.
2560 if (paintPhase == PaintPhaseForeground) {
2561 paintCaret(paintInfo, scrolledX, scrolledY, CursorCaret);
2562 paintCaret(paintInfo, scrolledX, scrolledY, DragCaret);
2563 }
2564 }
2565
flipFloatForWritingMode(const FloatingObject * child,const IntPoint & point) const2566 IntPoint RenderBlock::flipFloatForWritingMode(const FloatingObject* child, const IntPoint& point) const
2567 {
2568 if (!style()->isFlippedBlocksWritingMode())
2569 return point;
2570
2571 // This is similar to the ParentToChildFlippingAdjustment in RenderBox::flipForWritingMode. We have to subtract out our left/top offsets twice, since
2572 // it's going to get added back in. We hide this complication here so that the calling code looks normal for the unflipped
2573 // case.
2574 if (isHorizontalWritingMode())
2575 return IntPoint(point.x(), point.y() + height() - child->renderer()->height() - 2 * yPositionForFloatIncludingMargin(child));
2576 return IntPoint(point.x() + width() - child->width() - 2 * xPositionForFloatIncludingMargin(child), point.y());
2577 }
2578
paintFloats(PaintInfo & paintInfo,int tx,int ty,bool preservePhase)2579 void RenderBlock::paintFloats(PaintInfo& paintInfo, int tx, int ty, bool preservePhase)
2580 {
2581 if (!m_floatingObjects)
2582 return;
2583
2584 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2585 FloatingObjectSetIterator end = floatingObjectSet.end();
2586 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2587 FloatingObject* r = *it;
2588 // Only paint the object if our m_shouldPaint flag is set.
2589 if (r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer()) {
2590 PaintInfo currentPaintInfo(paintInfo);
2591 currentPaintInfo.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2592 IntPoint childPoint = flipFloatForWritingMode(r, IntPoint(tx + xPositionForFloatIncludingMargin(r) - r->m_renderer->x(), ty + yPositionForFloatIncludingMargin(r) - r->m_renderer->y()));
2593 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2594 if (!preservePhase) {
2595 currentPaintInfo.phase = PaintPhaseChildBlockBackgrounds;
2596 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2597 currentPaintInfo.phase = PaintPhaseFloat;
2598 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2599 currentPaintInfo.phase = PaintPhaseForeground;
2600 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2601 currentPaintInfo.phase = PaintPhaseOutline;
2602 r->m_renderer->paint(currentPaintInfo, childPoint.x(), childPoint.y());
2603 }
2604 }
2605 }
2606 }
2607
paintEllipsisBoxes(PaintInfo & paintInfo,int tx,int ty)2608 void RenderBlock::paintEllipsisBoxes(PaintInfo& paintInfo, int tx, int ty)
2609 {
2610 if (!paintInfo.shouldPaintWithinRoot(this) || !firstLineBox())
2611 return;
2612
2613 if (style()->visibility() == VISIBLE && paintInfo.phase == PaintPhaseForeground) {
2614 // We can check the first box and last box and avoid painting if we don't
2615 // intersect.
2616 int yPos = ty + firstLineBox()->y();
2617 int h = lastLineBox()->y() + lastLineBox()->logicalHeight() - firstLineBox()->y();
2618 if (yPos >= paintInfo.rect.maxY() || yPos + h <= paintInfo.rect.y())
2619 return;
2620
2621 // See if our boxes intersect with the dirty rect. If so, then we paint
2622 // them. Note that boxes can easily overlap, so we can't make any assumptions
2623 // based off positions of our first line box or our last line box.
2624 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2625 yPos = ty + curr->y();
2626 h = curr->logicalHeight();
2627 if (curr->ellipsisBox() && yPos < paintInfo.rect.maxY() && yPos + h > paintInfo.rect.y())
2628 curr->paintEllipsisBox(paintInfo, tx, ty, curr->lineTop(), curr->lineBottom());
2629 }
2630 }
2631 }
2632
inlineElementContinuation() const2633 RenderInline* RenderBlock::inlineElementContinuation() const
2634 {
2635 RenderBoxModelObject* continuation = this->continuation();
2636 return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2637 }
2638
blockElementContinuation() const2639 RenderBlock* RenderBlock::blockElementContinuation() const
2640 {
2641 RenderBoxModelObject* currentContinuation = continuation();
2642 if (!currentContinuation || currentContinuation->isInline())
2643 return 0;
2644 RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2645 if (nextContinuation->isAnonymousBlock())
2646 return nextContinuation->blockElementContinuation();
2647 return nextContinuation;
2648 }
2649
continuationOutlineTable()2650 static ContinuationOutlineTableMap* continuationOutlineTable()
2651 {
2652 DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2653 return &table;
2654 }
2655
addContinuationWithOutline(RenderInline * flow)2656 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2657 {
2658 // We can't make this work if the inline is in a layer. We'll just rely on the broken
2659 // way of painting.
2660 ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2661
2662 ContinuationOutlineTableMap* table = continuationOutlineTable();
2663 ListHashSet<RenderInline*>* continuations = table->get(this);
2664 if (!continuations) {
2665 continuations = new ListHashSet<RenderInline*>;
2666 table->set(this, continuations);
2667 }
2668
2669 continuations->add(flow);
2670 }
2671
paintsContinuationOutline(RenderInline * flow)2672 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2673 {
2674 ContinuationOutlineTableMap* table = continuationOutlineTable();
2675 if (table->isEmpty())
2676 return false;
2677
2678 ListHashSet<RenderInline*>* continuations = table->get(this);
2679 if (!continuations)
2680 return false;
2681
2682 return continuations->contains(flow);
2683 }
2684
paintContinuationOutlines(PaintInfo & info,int tx,int ty)2685 void RenderBlock::paintContinuationOutlines(PaintInfo& info, int tx, int ty)
2686 {
2687 ContinuationOutlineTableMap* table = continuationOutlineTable();
2688 if (table->isEmpty())
2689 return;
2690
2691 ListHashSet<RenderInline*>* continuations = table->get(this);
2692 if (!continuations)
2693 return;
2694
2695 // Paint each continuation outline.
2696 ListHashSet<RenderInline*>::iterator end = continuations->end();
2697 for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2698 // Need to add in the coordinates of the intervening blocks.
2699 RenderInline* flow = *it;
2700 RenderBlock* block = flow->containingBlock();
2701 for ( ; block && block != this; block = block->containingBlock()) {
2702 tx += block->x();
2703 ty += block->y();
2704 }
2705 ASSERT(block);
2706 flow->paintOutline(info.context, tx, ty);
2707 }
2708
2709 // Delete
2710 delete continuations;
2711 table->remove(this);
2712 }
2713
shouldPaintSelectionGaps() const2714 bool RenderBlock::shouldPaintSelectionGaps() const
2715 {
2716 return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2717 }
2718
isSelectionRoot() const2719 bool RenderBlock::isSelectionRoot() const
2720 {
2721 if (!node())
2722 return false;
2723
2724 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2725 if (isTable())
2726 return false;
2727
2728 if (isBody() || isRoot() || hasOverflowClip() || isRelPositioned() ||
2729 isFloatingOrPositioned() || isTableCell() || isInlineBlockOrInlineTable() || hasTransform() ||
2730 hasReflection() || hasMask() || isWritingModeRoot())
2731 return true;
2732
2733 if (view() && view()->selectionStart()) {
2734 Node* startElement = view()->selectionStart()->node();
2735 if (startElement && startElement->rootEditableElement() == node())
2736 return true;
2737 }
2738
2739 return false;
2740 }
2741
selectionGapRectsForRepaint(RenderBoxModelObject * repaintContainer)2742 GapRects RenderBlock::selectionGapRectsForRepaint(RenderBoxModelObject* repaintContainer)
2743 {
2744 ASSERT(!needsLayout());
2745
2746 if (!shouldPaintSelectionGaps())
2747 return GapRects();
2748
2749 // FIXME: this is broken with transforms
2750 TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2751 mapLocalToContainer(repaintContainer, false, false, transformState);
2752 IntPoint offsetFromRepaintContainer = roundedIntPoint(transformState.mappedPoint());
2753
2754 if (hasOverflowClip())
2755 offsetFromRepaintContainer -= layer()->scrolledContentOffset();
2756
2757 int lastTop = 0;
2758 int lastLeft = logicalLeftSelectionOffset(this, lastTop);
2759 int lastRight = logicalRightSelectionOffset(this, lastTop);
2760
2761 return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2762 }
2763
paintSelection(PaintInfo & paintInfo,int tx,int ty)2764 void RenderBlock::paintSelection(PaintInfo& paintInfo, int tx, int ty)
2765 {
2766 if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2767 int lastTop = 0;
2768 int lastLeft = logicalLeftSelectionOffset(this, lastTop);
2769 int lastRight = logicalRightSelectionOffset(this, lastTop);
2770 paintInfo.context->save();
2771 IntRect gapRectsBounds = selectionGaps(this, IntPoint(tx, ty), IntSize(), lastTop, lastLeft, lastRight, &paintInfo);
2772 if (!gapRectsBounds.isEmpty()) {
2773 if (RenderLayer* layer = enclosingLayer()) {
2774 gapRectsBounds.move(IntSize(-tx, -ty));
2775 if (!hasLayer()) {
2776 IntRect localBounds(gapRectsBounds);
2777 flipForWritingMode(localBounds);
2778 gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2779 gapRectsBounds.move(layer->scrolledContentOffset());
2780 }
2781 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2782 }
2783 }
2784 paintInfo.context->restore();
2785 }
2786 }
2787
clipOutPositionedObjects(const PaintInfo * paintInfo,const IntPoint & offset,RenderBlock::PositionedObjectsListHashSet * positionedObjects)2788 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const IntPoint& offset, RenderBlock::PositionedObjectsListHashSet* positionedObjects)
2789 {
2790 if (!positionedObjects)
2791 return;
2792
2793 RenderBlock::PositionedObjectsListHashSet::const_iterator end = positionedObjects->end();
2794 for (RenderBlock::PositionedObjectsListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2795 RenderBox* r = *it;
2796 paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2797 }
2798 }
2799
blockDirectionOffset(RenderBlock * rootBlock,const IntSize & offsetFromRootBlock)2800 static int blockDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2801 {
2802 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.height() : offsetFromRootBlock.width();
2803 }
2804
inlineDirectionOffset(RenderBlock * rootBlock,const IntSize & offsetFromRootBlock)2805 static int inlineDirectionOffset(RenderBlock* rootBlock, const IntSize& offsetFromRootBlock)
2806 {
2807 return rootBlock->isHorizontalWritingMode() ? offsetFromRootBlock.width() : offsetFromRootBlock.height();
2808 }
2809
logicalRectToPhysicalRect(const IntPoint & rootBlockPhysicalPosition,const IntRect & logicalRect)2810 IntRect RenderBlock::logicalRectToPhysicalRect(const IntPoint& rootBlockPhysicalPosition, const IntRect& logicalRect)
2811 {
2812 IntRect result;
2813 if (isHorizontalWritingMode())
2814 result = logicalRect;
2815 else
2816 result = IntRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2817 flipForWritingMode(result);
2818 result.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2819 return result;
2820 }
2821
selectionGaps(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,int & lastLogicalTop,int & lastLogicalLeft,int & lastLogicalRight,const PaintInfo * paintInfo)2822 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2823 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2824 {
2825 // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2826 // Clip out floating and positioned objects when painting selection gaps.
2827 if (paintInfo) {
2828 // Note that we don't clip out overflow for positioned objects. We just stick to the border box.
2829 IntRect flippedBlockRect = IntRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2830 rootBlock->flipForWritingMode(flippedBlockRect);
2831 flippedBlockRect.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2832 clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), m_positionedObjects.get());
2833 if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2834 for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2835 clipOutPositionedObjects(paintInfo, IntPoint(cb->x(), cb->y()), cb->m_positionedObjects.get()); // FIXME: Not right for flipped writing modes.
2836 if (m_floatingObjects) {
2837 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
2838 FloatingObjectSetIterator end = floatingObjectSet.end();
2839 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
2840 FloatingObject* r = *it;
2841 IntRect floatBox = IntRect(offsetFromRootBlock.width() + xPositionForFloatIncludingMargin(r),
2842 offsetFromRootBlock.height() + yPositionForFloatIncludingMargin(r),
2843 r->m_renderer->width(), r->m_renderer->height());
2844 rootBlock->flipForWritingMode(floatBox);
2845 floatBox.move(rootBlockPhysicalPosition.x(), rootBlockPhysicalPosition.y());
2846 paintInfo->context->clipOut(floatBox);
2847 }
2848 }
2849 }
2850
2851 // 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
2852 // fixed).
2853 GapRects result;
2854 if (!isBlockFlow()) // FIXME: Make multi-column selection gap filling work someday.
2855 return result;
2856
2857 if (hasColumns() || hasTransform() || style()->columnSpan()) {
2858 // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2859 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2860 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2861 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2862 return result;
2863 }
2864
2865 if (childrenInline())
2866 result = inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2867 else
2868 result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2869
2870 // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2871 if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2872 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2873 logicalHeight(), paintInfo));
2874 return result;
2875 }
2876
inlineSelectionGaps(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,int & lastLogicalTop,int & lastLogicalLeft,int & lastLogicalRight,const PaintInfo * paintInfo)2877 GapRects RenderBlock::inlineSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2878 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2879 {
2880 GapRects result;
2881
2882 bool containsStart = selectionState() == SelectionStart || selectionState() == SelectionBoth;
2883
2884 if (!firstLineBox()) {
2885 if (containsStart) {
2886 // Go ahead and update our lastLogicalTop to be the bottom of the block. <hr>s or empty blocks with height can trip this
2887 // case.
2888 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalHeight();
2889 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2890 lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2891 }
2892 return result;
2893 }
2894
2895 RootInlineBox* lastSelectedLine = 0;
2896 RootInlineBox* curr;
2897 for (curr = firstRootBox(); curr && !curr->hasSelectedChildren(); curr = curr->nextRootBox()) { }
2898
2899 // Now paint the gaps for the lines.
2900 for (; curr && curr->hasSelectedChildren(); curr = curr->nextRootBox()) {
2901 int selTop = curr->selectionTop();
2902 int selHeight = curr->selectionHeight();
2903
2904 if (!containsStart && !lastSelectedLine &&
2905 selectionState() != SelectionStart && selectionState() != SelectionBoth)
2906 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2907 selTop, paintInfo));
2908
2909 IntRect logicalRect(curr->logicalLeft(), selTop, curr->logicalWidth(), selTop + selHeight);
2910 logicalRect.move(isHorizontalWritingMode() ? offsetFromRootBlock : IntSize(offsetFromRootBlock.height(), offsetFromRootBlock.width()));
2911 IntRect physicalRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, logicalRect);
2912 if (!paintInfo || (isHorizontalWritingMode() && physicalRect.y() < paintInfo->rect.maxY() && physicalRect.maxY() > paintInfo->rect.y())
2913 || (!isHorizontalWritingMode() && physicalRect.x() < paintInfo->rect.maxX() && physicalRect.maxX() > paintInfo->rect.x()))
2914 result.unite(curr->lineSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, selTop, selHeight, paintInfo));
2915
2916 lastSelectedLine = curr;
2917 }
2918
2919 if (containsStart && !lastSelectedLine)
2920 // VisibleSelection must start just after our last line.
2921 lastSelectedLine = lastRootBox();
2922
2923 if (lastSelectedLine && selectionState() != SelectionEnd && selectionState() != SelectionBoth) {
2924 // Go ahead and update our lastY to be the bottom of the last selected line.
2925 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + lastSelectedLine->selectionBottom();
2926 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2927 lastLogicalRight = logicalRightSelectionOffset(rootBlock, lastSelectedLine->selectionBottom());
2928 }
2929 return result;
2930 }
2931
blockSelectionGaps(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,int & lastLogicalTop,int & lastLogicalLeft,int & lastLogicalRight,const PaintInfo * paintInfo)2932 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2933 int& lastLogicalTop, int& lastLogicalLeft, int& lastLogicalRight, const PaintInfo* paintInfo)
2934 {
2935 GapRects result;
2936
2937 // Go ahead and jump right to the first block child that contains some selected objects.
2938 RenderBox* curr;
2939 for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2940
2941 for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2942 SelectionState childState = curr->selectionState();
2943 if (childState == SelectionBoth || childState == SelectionEnd)
2944 sawSelectionEnd = true;
2945
2946 if (curr->isFloatingOrPositioned())
2947 continue; // We must be a normal flow object in order to even be considered.
2948
2949 if (curr->isRelPositioned() && curr->hasLayer()) {
2950 // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2951 // Just disregard it completely.
2952 IntSize relOffset = curr->layer()->relativePositionOffset();
2953 if (relOffset.width() || relOffset.height())
2954 continue;
2955 }
2956
2957 bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2958 bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2959 if (fillBlockGaps) {
2960 // We need to fill the vertical gap above this object.
2961 if (childState == SelectionEnd || childState == SelectionInside)
2962 // Fill the gap above the object.
2963 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2964 curr->logicalTop(), paintInfo));
2965
2966 // 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*
2967 // our object. We know this if the selection did not end inside our object.
2968 if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2969 childState = SelectionNone;
2970
2971 // Fill side gaps on this object based off its state.
2972 bool leftGap, rightGap;
2973 getSelectionGapInfo(childState, leftGap, rightGap);
2974
2975 if (leftGap)
2976 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2977 if (rightGap)
2978 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2979
2980 // Update lastLogicalTop to be just underneath the object. lastLogicalLeft and lastLogicalRight extend as far as
2981 // they can without bumping into floating or positioned objects. Ideally they will go right up
2982 // to the border of the root selection block.
2983 lastLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + curr->logicalBottom();
2984 lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
2985 lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
2986 } else if (childState != SelectionNone)
2987 // We must be a block that has some selected object inside it. Go ahead and recur.
2988 result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, IntSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2989 lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
2990 }
2991 return result;
2992 }
2993
blockSelectionGap(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,int lastLogicalTop,int lastLogicalLeft,int lastLogicalRight,int logicalBottom,const PaintInfo * paintInfo)2994 IntRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
2995 int lastLogicalTop, int lastLogicalLeft, int lastLogicalRight, int logicalBottom, const PaintInfo* paintInfo)
2996 {
2997 int logicalTop = lastLogicalTop;
2998 int logicalHeight = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalBottom - logicalTop;
2999 if (logicalHeight <= 0)
3000 return IntRect();
3001
3002 // Get the selection offsets for the bottom of the gap
3003 int logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
3004 int logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
3005 int logicalWidth = logicalRight - logicalLeft;
3006 if (logicalWidth <= 0)
3007 return IntRect();
3008
3009 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
3010 if (paintInfo)
3011 paintInfo->context->fillRect(gapRect, selectionBackgroundColor(), style()->colorSpace());
3012 return gapRect;
3013 }
3014
logicalLeftSelectionGap(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,RenderObject * selObj,int logicalLeft,int logicalTop,int logicalHeight,const PaintInfo * paintInfo)3015 IntRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
3016 RenderObject* selObj, int logicalLeft, int logicalTop, int logicalHeight, const PaintInfo* paintInfo)
3017 {
3018 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3019 int rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
3020 int rootBlockLogicalRight = min(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalLeft, min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3021 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3022 if (rootBlockLogicalWidth <= 0)
3023 return IntRect();
3024
3025 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3026 if (paintInfo)
3027 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3028 return gapRect;
3029 }
3030
logicalRightSelectionGap(RenderBlock * rootBlock,const IntPoint & rootBlockPhysicalPosition,const IntSize & offsetFromRootBlock,RenderObject * selObj,int logicalRight,int logicalTop,int logicalHeight,const PaintInfo * paintInfo)3031 IntRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const IntPoint& rootBlockPhysicalPosition, const IntSize& offsetFromRootBlock,
3032 RenderObject* selObj, int logicalRight, int logicalTop, int logicalHeight, const PaintInfo* paintInfo)
3033 {
3034 int rootBlockLogicalTop = blockDirectionOffset(rootBlock, offsetFromRootBlock) + logicalTop;
3035 int rootBlockLogicalLeft = max(inlineDirectionOffset(rootBlock, offsetFromRootBlock) + logicalRight, max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
3036 int rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
3037 int rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
3038 if (rootBlockLogicalWidth <= 0)
3039 return IntRect();
3040
3041 IntRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, IntRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
3042 if (paintInfo)
3043 paintInfo->context->fillRect(gapRect, selObj->selectionBackgroundColor(), selObj->style()->colorSpace());
3044 return gapRect;
3045 }
3046
getSelectionGapInfo(SelectionState state,bool & leftGap,bool & rightGap)3047 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
3048 {
3049 bool ltr = style()->isLeftToRightDirection();
3050 leftGap = (state == RenderObject::SelectionInside) ||
3051 (state == RenderObject::SelectionEnd && ltr) ||
3052 (state == RenderObject::SelectionStart && !ltr);
3053 rightGap = (state == RenderObject::SelectionInside) ||
3054 (state == RenderObject::SelectionStart && ltr) ||
3055 (state == RenderObject::SelectionEnd && !ltr);
3056 }
3057
logicalLeftSelectionOffset(RenderBlock * rootBlock,int position)3058 int RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, int position)
3059 {
3060 int logicalLeft = logicalLeftOffsetForLine(position, false);
3061 if (logicalLeft == logicalLeftOffsetForContent()) {
3062 if (rootBlock != this)
3063 // The border can potentially be further extended by our containingBlock().
3064 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
3065 return logicalLeft;
3066 } else {
3067 RenderBlock* cb = this;
3068 while (cb != rootBlock) {
3069 logicalLeft += cb->logicalLeft();
3070 cb = cb->containingBlock();
3071 }
3072 }
3073 return logicalLeft;
3074 }
3075
logicalRightSelectionOffset(RenderBlock * rootBlock,int position)3076 int RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, int position)
3077 {
3078 int logicalRight = logicalRightOffsetForLine(position, false);
3079 if (logicalRight == logicalRightOffsetForContent()) {
3080 if (rootBlock != this)
3081 // The border can potentially be further extended by our containingBlock().
3082 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
3083 return logicalRight;
3084 } else {
3085 RenderBlock* cb = this;
3086 while (cb != rootBlock) {
3087 logicalRight += cb->logicalLeft();
3088 cb = cb->containingBlock();
3089 }
3090 }
3091 return logicalRight;
3092 }
3093
insertPositionedObject(RenderBox * o)3094 void RenderBlock::insertPositionedObject(RenderBox* o)
3095 {
3096 // Create the list of special objects if we don't aleady have one
3097 if (!m_positionedObjects)
3098 m_positionedObjects = adoptPtr(new PositionedObjectsListHashSet);
3099
3100 m_positionedObjects->add(o);
3101 }
3102
removePositionedObject(RenderBox * o)3103 void RenderBlock::removePositionedObject(RenderBox* o)
3104 {
3105 if (m_positionedObjects)
3106 m_positionedObjects->remove(o);
3107 }
3108
removePositionedObjects(RenderBlock * o)3109 void RenderBlock::removePositionedObjects(RenderBlock* o)
3110 {
3111 if (!m_positionedObjects)
3112 return;
3113
3114 RenderBox* r;
3115
3116 Iterator end = m_positionedObjects->end();
3117
3118 Vector<RenderBox*, 16> deadObjects;
3119
3120 for (Iterator it = m_positionedObjects->begin(); it != end; ++it) {
3121 r = *it;
3122 if (!o || r->isDescendantOf(o)) {
3123 if (o)
3124 r->setChildNeedsLayout(true, false);
3125
3126 // It is parent blocks job to add positioned child to positioned objects list of its containing block
3127 // Parent layout needs to be invalidated to ensure this happens.
3128 RenderObject* p = r->parent();
3129 while (p && !p->isRenderBlock())
3130 p = p->parent();
3131 if (p)
3132 p->setChildNeedsLayout(true);
3133
3134 deadObjects.append(r);
3135 }
3136 }
3137
3138 for (unsigned i = 0; i < deadObjects.size(); i++)
3139 m_positionedObjects->remove(deadObjects.at(i));
3140 }
3141
insertFloatingObject(RenderBox * o)3142 RenderBlock::FloatingObject* RenderBlock::insertFloatingObject(RenderBox* o)
3143 {
3144 ASSERT(o->isFloating());
3145
3146 // Create the list of special objects if we don't aleady have one
3147 if (!m_floatingObjects)
3148 m_floatingObjects = adoptPtr(new FloatingObjects);
3149 else {
3150 // Don't insert the object again if it's already in the list
3151 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3152 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3153 if (it != floatingObjectSet.end())
3154 return *it;
3155 }
3156
3157 // Create the special object entry & append it to the list
3158
3159 FloatingObject* newObj = new FloatingObject(o->style()->floating() == FLEFT ? FloatingObject::FloatLeft : FloatingObject::FloatRight);
3160
3161 // Our location is irrelevant if we're unsplittable or no pagination is in effect.
3162 // Just go ahead and lay out the float.
3163 bool isChildRenderBlock = o->isRenderBlock();
3164 if (isChildRenderBlock && !o->needsLayout() && view()->layoutState()->pageLogicalHeightChanged())
3165 o->setChildNeedsLayout(true, false);
3166
3167 bool affectedByPagination = isChildRenderBlock && view()->layoutState()->m_pageLogicalHeight;
3168 if (!affectedByPagination || isWritingModeRoot()) // We are unsplittable if we're a block flow root.
3169 o->layoutIfNeeded();
3170 else {
3171 o->computeLogicalWidth();
3172 o->computeBlockDirectionMargins(this);
3173 }
3174 setLogicalWidthForFloat(newObj, logicalWidthForChild(o) + marginStartForChild(o) + marginEndForChild(o));
3175
3176 newObj->m_shouldPaint = !o->hasSelfPaintingLayer(); // If a layer exists, the float will paint itself. Otherwise someone else will.
3177 newObj->m_isDescendant = true;
3178 newObj->m_renderer = o;
3179
3180 m_floatingObjects->increaseObjectsCount(newObj->type());
3181 m_floatingObjects->set().add(newObj);
3182
3183 return newObj;
3184 }
3185
removeFloatingObject(RenderBox * o)3186 void RenderBlock::removeFloatingObject(RenderBox* o)
3187 {
3188 if (m_floatingObjects) {
3189 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3190 FloatingObjectSet::iterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(o);
3191 if (it != floatingObjectSet.end()) {
3192 FloatingObject* r = *it;
3193 if (childrenInline()) {
3194 int logicalTop = logicalTopForFloat(r);
3195 int logicalBottom = logicalBottomForFloat(r);
3196
3197 // Fix for https://bugs.webkit.org/show_bug.cgi?id=54995.
3198 if (logicalBottom < 0 || logicalBottom < logicalTop || logicalTop == numeric_limits<int>::max())
3199 logicalBottom = numeric_limits<int>::max();
3200 else {
3201 // Special-case zero- and less-than-zero-height floats: those don't touch
3202 // the line that they're on, but it still needs to be dirtied. This is
3203 // accomplished by pretending they have a height of 1.
3204 logicalBottom = max(logicalBottom, logicalTop + 1);
3205 }
3206 if (r->m_originatingLine) {
3207 ASSERT(r->m_originatingLine->renderer() == this);
3208 r->m_originatingLine->markDirty();
3209 #if !ASSERT_DISABLED
3210 r->m_originatingLine = 0;
3211 #endif
3212 }
3213 markLinesDirtyInBlockRange(0, logicalBottom);
3214 }
3215 m_floatingObjects->decreaseObjectsCount(r->type());
3216 floatingObjectSet.remove(it);
3217 ASSERT(!r->m_originatingLine);
3218 delete r;
3219 }
3220 }
3221 }
3222
removeFloatingObjectsBelow(FloatingObject * lastFloat,int logicalOffset)3223 void RenderBlock::removeFloatingObjectsBelow(FloatingObject* lastFloat, int logicalOffset)
3224 {
3225 if (!m_floatingObjects)
3226 return;
3227
3228 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3229 FloatingObject* curr = floatingObjectSet.last();
3230 while (curr != lastFloat && (!curr->isPlaced() || logicalTopForFloat(curr) >= logicalOffset)) {
3231 m_floatingObjects->decreaseObjectsCount(curr->type());
3232 floatingObjectSet.removeLast();
3233 ASSERT(!curr->m_originatingLine);
3234 delete curr;
3235 curr = floatingObjectSet.last();
3236 }
3237 }
3238
positionNewFloats()3239 bool RenderBlock::positionNewFloats()
3240 {
3241 if (!m_floatingObjects)
3242 return false;
3243
3244 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3245 if (floatingObjectSet.isEmpty())
3246 return false;
3247
3248 // If all floats have already been positioned, then we have no work to do.
3249 if (floatingObjectSet.last()->isPlaced())
3250 return false;
3251
3252 // Move backwards through our floating object list until we find a float that has
3253 // already been positioned. Then we'll be able to move forward, positioning all of
3254 // the new floats that need it.
3255 FloatingObjectSetIterator it = floatingObjectSet.end();
3256 --it; // Go to last item.
3257 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3258 FloatingObject* lastPlacedFloatingObject = 0;
3259 while (it != begin) {
3260 --it;
3261 if ((*it)->isPlaced()) {
3262 lastPlacedFloatingObject = *it;
3263 ++it;
3264 break;
3265 }
3266 }
3267
3268 int logicalTop = logicalHeight();
3269
3270 // The float cannot start above the top position of the last positioned float.
3271 if (lastPlacedFloatingObject)
3272 logicalTop = max(logicalTopForFloat(lastPlacedFloatingObject), logicalTop);
3273
3274 FloatingObjectSetIterator end = floatingObjectSet.end();
3275 // Now walk through the set of unpositioned floats and place them.
3276 for (; it != end; ++it) {
3277 FloatingObject* floatingObject = *it;
3278 // The containing block is responsible for positioning floats, so if we have floats in our
3279 // list that come from somewhere else, do not attempt to position them.
3280 if (floatingObject->renderer()->containingBlock() != this)
3281 continue;
3282
3283 RenderBox* childBox = floatingObject->renderer();
3284 int childLogicalLeftMargin = style()->isLeftToRightDirection() ? marginStartForChild(childBox) : marginEndForChild(childBox);
3285
3286 int rightOffset = logicalRightOffsetForContent(); // Constant part of right offset.
3287 int leftOffset = logicalLeftOffsetForContent(); // Constant part of left offset.
3288 int floatLogicalWidth = logicalWidthForFloat(floatingObject); // The width we look for.
3289 if (rightOffset - leftOffset < floatLogicalWidth)
3290 floatLogicalWidth = rightOffset - leftOffset; // Never look for more than what will be available.
3291
3292 IntRect oldRect(childBox->x(), childBox->y() , childBox->width(), childBox->height());
3293
3294 if (childBox->style()->clear() & CLEFT)
3295 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatLeft), logicalTop);
3296 if (childBox->style()->clear() & CRIGHT)
3297 logicalTop = max(lowestFloatLogicalBottom(FloatingObject::FloatRight), logicalTop);
3298
3299 int floatLogicalLeft;
3300 if (childBox->style()->floating() == FLEFT) {
3301 int heightRemainingLeft = 1;
3302 int heightRemainingRight = 1;
3303 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
3304 while (logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight) - floatLogicalLeft < floatLogicalWidth) {
3305 logicalTop += min(heightRemainingLeft, heightRemainingRight);
3306 floatLogicalLeft = logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft);
3307 }
3308 floatLogicalLeft = max(0, floatLogicalLeft);
3309 } else {
3310 int heightRemainingLeft = 1;
3311 int heightRemainingRight = 1;
3312 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
3313 while (floatLogicalLeft - logicalLeftOffsetForLine(logicalTop, leftOffset, false, &heightRemainingLeft) < floatLogicalWidth) {
3314 logicalTop += min(heightRemainingLeft, heightRemainingRight);
3315 floatLogicalLeft = logicalRightOffsetForLine(logicalTop, rightOffset, false, &heightRemainingRight);
3316 }
3317 floatLogicalLeft -= logicalWidthForFloat(floatingObject); // Use the original width of the float here, since the local variable
3318 // |floatLogicalWidth| was capped to the available line width.
3319 // See fast/block/float/clamped-right-float.html.
3320 }
3321
3322 setLogicalLeftForFloat(floatingObject, floatLogicalLeft);
3323 setLogicalLeftForChild(childBox, floatLogicalLeft + childLogicalLeftMargin);
3324 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
3325
3326 if (view()->layoutState()->isPaginated()) {
3327 RenderBlock* childBlock = childBox->isRenderBlock() ? toRenderBlock(childBox) : 0;
3328
3329 if (!childBox->needsLayout())
3330 childBox->markForPaginationRelayoutIfNeeded();;
3331 childBox->layoutIfNeeded();
3332
3333 // If we are unsplittable and don't fit, then we need to move down.
3334 // We include our margins as part of the unsplittable area.
3335 int newLogicalTop = adjustForUnsplittableChild(childBox, logicalTop, true);
3336
3337 // See if we have a pagination strut that is making us move down further.
3338 // Note that an unsplittable child can't also have a pagination strut, so this is
3339 // exclusive with the case above.
3340 if (childBlock && childBlock->paginationStrut()) {
3341 newLogicalTop += childBlock->paginationStrut();
3342 childBlock->setPaginationStrut(0);
3343 }
3344
3345 if (newLogicalTop != logicalTop) {
3346 floatingObject->m_paginationStrut = newLogicalTop - logicalTop;
3347 logicalTop = newLogicalTop;
3348 setLogicalTopForChild(childBox, logicalTop + marginBeforeForChild(childBox));
3349 if (childBlock)
3350 childBlock->setChildNeedsLayout(true, false);
3351 childBox->layoutIfNeeded();
3352 }
3353 }
3354
3355 setLogicalTopForFloat(floatingObject, logicalTop);
3356 setLogicalHeightForFloat(floatingObject, logicalHeightForChild(childBox) + marginBeforeForChild(childBox) + marginAfterForChild(childBox));
3357
3358 floatingObject->setIsPlaced();
3359
3360 // If the child moved, we have to repaint it.
3361 if (childBox->checkForRepaintDuringLayout())
3362 childBox->repaintDuringLayoutIfMoved(oldRect);
3363 }
3364 return true;
3365 }
3366
newLine(EClear clear)3367 void RenderBlock::newLine(EClear clear)
3368 {
3369 positionNewFloats();
3370 // set y position
3371 int newY = 0;
3372 switch (clear)
3373 {
3374 case CLEFT:
3375 newY = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3376 break;
3377 case CRIGHT:
3378 newY = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3379 break;
3380 case CBOTH:
3381 newY = lowestFloatLogicalBottom();
3382 default:
3383 break;
3384 }
3385 if (height() < newY)
3386 setLogicalHeight(newY);
3387 }
3388
addPercentHeightDescendant(RenderBox * descendant)3389 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
3390 {
3391 if (!gPercentHeightDescendantsMap) {
3392 gPercentHeightDescendantsMap = new PercentHeightDescendantsMap;
3393 gPercentHeightContainerMap = new PercentHeightContainerMap;
3394 }
3395
3396 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(this);
3397 if (!descendantSet) {
3398 descendantSet = new HashSet<RenderBox*>;
3399 gPercentHeightDescendantsMap->set(this, descendantSet);
3400 }
3401 bool added = descendantSet->add(descendant).second;
3402 if (!added) {
3403 ASSERT(gPercentHeightContainerMap->get(descendant));
3404 ASSERT(gPercentHeightContainerMap->get(descendant)->contains(this));
3405 return;
3406 }
3407
3408 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->get(descendant);
3409 if (!containerSet) {
3410 containerSet = new HashSet<RenderBlock*>;
3411 gPercentHeightContainerMap->set(descendant, containerSet);
3412 }
3413 ASSERT(!containerSet->contains(this));
3414 containerSet->add(this);
3415 }
3416
removePercentHeightDescendant(RenderBox * descendant)3417 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
3418 {
3419 if (!gPercentHeightContainerMap)
3420 return;
3421
3422 HashSet<RenderBlock*>* containerSet = gPercentHeightContainerMap->take(descendant);
3423 if (!containerSet)
3424 return;
3425
3426 HashSet<RenderBlock*>::iterator end = containerSet->end();
3427 for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
3428 RenderBlock* container = *it;
3429 HashSet<RenderBox*>* descendantSet = gPercentHeightDescendantsMap->get(container);
3430 ASSERT(descendantSet);
3431 if (!descendantSet)
3432 continue;
3433 ASSERT(descendantSet->contains(descendant));
3434 descendantSet->remove(descendant);
3435 if (descendantSet->isEmpty()) {
3436 gPercentHeightDescendantsMap->remove(container);
3437 delete descendantSet;
3438 }
3439 }
3440
3441 delete containerSet;
3442 }
3443
percentHeightDescendants() const3444 HashSet<RenderBox*>* RenderBlock::percentHeightDescendants() const
3445 {
3446 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
3447 }
3448
3449 // FIXME: The logicalLeftOffsetForLine/logicalRightOffsetForLine functions are very slow if there are many floats
3450 // present. We need to add a structure to floating objects to represent "lines" of floats. Then instead of checking
3451 // each float individually, we'd just walk backwards through the "lines" and stop when we hit a line that is fully above
3452 // the vertical offset that we'd like to check. Computing the "lines" would be rather complicated, but could replace the left
3453 // objects and right objects count hack that is currently used here.
logicalLeftOffsetForLine(int logicalTop,int fixedOffset,bool applyTextIndent,int * heightRemaining) const3454 int RenderBlock::logicalLeftOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
3455 {
3456 int left = fixedOffset;
3457 if (m_floatingObjects && m_floatingObjects->hasLeftObjects()) {
3458 if (heightRemaining)
3459 *heightRemaining = 1;
3460
3461 // We know the list is non-empty, since we have "left" objects to search for.
3462 // Therefore we can assume that begin != end, and that we can do at least one
3463 // decrement.
3464 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3465 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3466 FloatingObjectSetIterator it = floatingObjectSet.end();
3467 do {
3468 --it;
3469 FloatingObject* r = *it;
3470 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
3471 && r->type() == FloatingObject::FloatLeft
3472 && logicalRightForFloat(r) > left) {
3473 left = max(left, logicalRightForFloat(r));
3474 if (heightRemaining)
3475 *heightRemaining = logicalBottomForFloat(r) - logicalTop;
3476 }
3477 } while (it != begin);
3478 }
3479
3480 if (applyTextIndent && style()->isLeftToRightDirection()) {
3481 int cw = 0;
3482 if (style()->textIndent().isPercent())
3483 cw = containingBlock()->availableLogicalWidth();
3484 left += style()->textIndent().calcMinValue(cw);
3485 }
3486
3487 return left;
3488 }
3489
logicalRightOffsetForLine(int logicalTop,int fixedOffset,bool applyTextIndent,int * heightRemaining) const3490 int RenderBlock::logicalRightOffsetForLine(int logicalTop, int fixedOffset, bool applyTextIndent, int* heightRemaining) const
3491 {
3492 int right = fixedOffset;
3493
3494 if (m_floatingObjects && m_floatingObjects->hasRightObjects()) {
3495 if (heightRemaining)
3496 *heightRemaining = 1;
3497
3498 // We know the list is non-empty, since we have "right" objects to search for.
3499 // Therefore we can assume that begin != end, and that we can do at least one
3500 // decrement.
3501 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3502 FloatingObjectSetIterator begin = floatingObjectSet.begin();
3503 FloatingObjectSetIterator it = floatingObjectSet.end();
3504 do {
3505 --it;
3506 FloatingObject* r = *it;
3507 if (r->isPlaced() && logicalTopForFloat(r) <= logicalTop && logicalBottomForFloat(r) > logicalTop
3508 && r->type() == FloatingObject::FloatRight
3509 && logicalLeftForFloat(r) < right) {
3510 right = min(right, logicalLeftForFloat(r));
3511 if (heightRemaining)
3512 *heightRemaining = logicalBottomForFloat(r) - logicalTop;
3513 }
3514 } while (it != begin);
3515 }
3516
3517 if (applyTextIndent && !style()->isLeftToRightDirection()) {
3518 int cw = 0;
3519 if (style()->textIndent().isPercent())
3520 cw = containingBlock()->availableLogicalWidth();
3521 right -= style()->textIndent().calcMinValue(cw);
3522 }
3523
3524 return right;
3525 }
3526
availableLogicalWidthForLine(int position,bool firstLine) const3527 int RenderBlock::availableLogicalWidthForLine(int position, bool firstLine) const
3528 {
3529 int result = logicalRightOffsetForLine(position, firstLine) - logicalLeftOffsetForLine(position, firstLine);
3530 return (result < 0) ? 0 : result;
3531 }
3532
nextFloatLogicalBottomBelow(int logicalHeight) const3533 int RenderBlock::nextFloatLogicalBottomBelow(int logicalHeight) const
3534 {
3535 if (!m_floatingObjects)
3536 return 0;
3537
3538 int bottom = INT_MAX;
3539 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3540 FloatingObjectSetIterator end = floatingObjectSet.end();
3541 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3542 FloatingObject* r = *it;
3543 int floatBottom = logicalBottomForFloat(r);
3544 if (floatBottom > logicalHeight)
3545 bottom = min(floatBottom, bottom);
3546 }
3547
3548 return bottom == INT_MAX ? 0 : bottom;
3549 }
3550
lowestFloatLogicalBottom(FloatingObject::Type floatType) const3551 int RenderBlock::lowestFloatLogicalBottom(FloatingObject::Type floatType) const
3552 {
3553 if (!m_floatingObjects)
3554 return 0;
3555 int lowestFloatBottom = 0;
3556 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3557 FloatingObjectSetIterator end = floatingObjectSet.end();
3558 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3559 FloatingObject* r = *it;
3560 if (r->isPlaced() && r->type() & floatType)
3561 lowestFloatBottom = max(lowestFloatBottom, logicalBottomForFloat(r));
3562 }
3563 return lowestFloatBottom;
3564 }
3565
markLinesDirtyInBlockRange(int logicalTop,int logicalBottom,RootInlineBox * highest)3566 void RenderBlock::markLinesDirtyInBlockRange(int logicalTop, int logicalBottom, RootInlineBox* highest)
3567 {
3568 if (logicalTop >= logicalBottom)
3569 return;
3570
3571 RootInlineBox* lowestDirtyLine = lastRootBox();
3572 RootInlineBox* afterLowest = lowestDirtyLine;
3573 while (lowestDirtyLine && lowestDirtyLine->blockLogicalHeight() >= logicalBottom && logicalBottom < numeric_limits<int>::max()) {
3574 afterLowest = lowestDirtyLine;
3575 lowestDirtyLine = lowestDirtyLine->prevRootBox();
3576 }
3577
3578 while (afterLowest && afterLowest != highest && (afterLowest->blockLogicalHeight() >= logicalTop || afterLowest->blockLogicalHeight() < 0)) {
3579 afterLowest->markDirty();
3580 afterLowest = afterLowest->prevRootBox();
3581 }
3582 }
3583
clearFloats()3584 void RenderBlock::clearFloats()
3585 {
3586 // Inline blocks are covered by the isReplaced() check in the avoidFloats method.
3587 if (avoidsFloats() || isRoot() || isRenderView() || isFloatingOrPositioned() || isTableCell()) {
3588 if (m_floatingObjects) {
3589 deleteAllValues(m_floatingObjects->set());
3590 m_floatingObjects->clear();
3591 }
3592 return;
3593 }
3594
3595 typedef HashMap<RenderObject*, FloatingObject*> RendererToFloatInfoMap;
3596 RendererToFloatInfoMap floatMap;
3597
3598 if (m_floatingObjects) {
3599 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3600 if (childrenInline()) {
3601 FloatingObjectSet::iterator end = floatingObjectSet.end();
3602 for (FloatingObjectSet::iterator it = floatingObjectSet.begin(); it != end; ++it) {
3603 FloatingObject* f = *it;
3604 floatMap.add(f->m_renderer, f);
3605 }
3606 } else
3607 deleteAllValues(floatingObjectSet);
3608 m_floatingObjects->clear();
3609 }
3610
3611 // We should not process floats if the parent node is not a RenderBlock. Otherwise, we will add
3612 // floats in an invalid context. This will cause a crash arising from a bad cast on the parent.
3613 // See <rdar://problem/8049753>, where float property is applied on a text node in a SVG.
3614 if (!parent() || !parent()->isRenderBlock())
3615 return;
3616
3617 // Attempt to locate a previous sibling with overhanging floats. We skip any elements that are
3618 // out of flow (like floating/positioned elements), and we also skip over any objects that may have shifted
3619 // to avoid floats.
3620 bool parentHasFloats = false;
3621 RenderBlock* parentBlock = toRenderBlock(parent());
3622 RenderObject* prev = previousSibling();
3623 while (prev && (prev->isFloatingOrPositioned() || !prev->isBox() || !prev->isRenderBlock() || toRenderBlock(prev)->avoidsFloats())) {
3624 if (prev->isFloating())
3625 parentHasFloats = true;
3626 prev = prev->previousSibling();
3627 }
3628
3629 // First add in floats from the parent.
3630 int logicalTopOffset = logicalTop();
3631 if (parentHasFloats)
3632 addIntrudingFloats(parentBlock, parentBlock->logicalLeftOffsetForContent(), logicalTopOffset);
3633
3634 int logicalLeftOffset = 0;
3635 if (prev)
3636 logicalTopOffset -= toRenderBox(prev)->logicalTop();
3637 else {
3638 prev = parentBlock;
3639 logicalLeftOffset += parentBlock->logicalLeftOffsetForContent();
3640 }
3641
3642 // Add overhanging floats from the previous RenderBlock, but only if it has a float that intrudes into our space.
3643 if (!prev || !prev->isRenderBlock())
3644 return;
3645
3646 RenderBlock* block = toRenderBlock(prev);
3647 if (block->m_floatingObjects && block->lowestFloatLogicalBottom() > logicalTopOffset)
3648 addIntrudingFloats(block, logicalLeftOffset, logicalTopOffset);
3649
3650 if (childrenInline()) {
3651 int changeLogicalTop = numeric_limits<int>::max();
3652 int changeLogicalBottom = numeric_limits<int>::min();
3653 if (m_floatingObjects) {
3654 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3655 FloatingObjectSetIterator end = floatingObjectSet.end();
3656 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3657 FloatingObject* f = *it;
3658 FloatingObject* oldFloatingObject = floatMap.get(f->m_renderer);
3659 int logicalBottom = logicalBottomForFloat(f);
3660 if (oldFloatingObject) {
3661 int oldLogicalBottom = logicalBottomForFloat(oldFloatingObject);
3662 if (logicalWidthForFloat(f) != logicalWidthForFloat(oldFloatingObject) || logicalLeftForFloat(f) != logicalLeftForFloat(oldFloatingObject)) {
3663 changeLogicalTop = 0;
3664 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3665 } else if (logicalBottom != oldLogicalBottom) {
3666 changeLogicalTop = min(changeLogicalTop, min(logicalBottom, oldLogicalBottom));
3667 changeLogicalBottom = max(changeLogicalBottom, max(logicalBottom, oldLogicalBottom));
3668 }
3669
3670 floatMap.remove(f->m_renderer);
3671 if (oldFloatingObject->m_originatingLine) {
3672 ASSERT(oldFloatingObject->m_originatingLine->renderer() == this);
3673 oldFloatingObject->m_originatingLine->markDirty();
3674 }
3675 delete oldFloatingObject;
3676 } else {
3677 changeLogicalTop = 0;
3678 changeLogicalBottom = max(changeLogicalBottom, logicalBottom);
3679 }
3680 }
3681 }
3682
3683 RendererToFloatInfoMap::iterator end = floatMap.end();
3684 for (RendererToFloatInfoMap::iterator it = floatMap.begin(); it != end; ++it) {
3685 FloatingObject* floatingObject = (*it).second;
3686 if (!floatingObject->m_isDescendant) {
3687 changeLogicalTop = 0;
3688 changeLogicalBottom = max(changeLogicalBottom, logicalBottomForFloat(floatingObject));
3689 }
3690 }
3691 deleteAllValues(floatMap);
3692
3693 markLinesDirtyInBlockRange(changeLogicalTop, changeLogicalBottom);
3694 }
3695 }
3696
addOverhangingFloats(RenderBlock * child,int logicalLeftOffset,int logicalTopOffset,bool makeChildPaintOtherFloats)3697 int RenderBlock::addOverhangingFloats(RenderBlock* child, int logicalLeftOffset, int logicalTopOffset, bool makeChildPaintOtherFloats)
3698 {
3699 // Prevent floats from being added to the canvas by the root element, e.g., <html>.
3700 if (child->hasOverflowClip() || !child->containsFloats() || child->isRoot() || child->hasColumns() || child->isWritingModeRoot())
3701 return 0;
3702
3703 int childLogicalTop = child->logicalTop();
3704 int lowestFloatLogicalBottom = 0;
3705
3706 // Floats that will remain the child's responsibility to paint should factor into its
3707 // overflow.
3708 FloatingObjectSetIterator childEnd = child->m_floatingObjects->set().end();
3709 for (FloatingObjectSetIterator childIt = child->m_floatingObjects->set().begin(); childIt != childEnd; ++childIt) {
3710 FloatingObject* r = *childIt;
3711 int logicalBottomForFloat = min(this->logicalBottomForFloat(r), numeric_limits<int>::max() - childLogicalTop);
3712 int logicalBottom = childLogicalTop + logicalBottomForFloat;
3713 lowestFloatLogicalBottom = max(lowestFloatLogicalBottom, logicalBottom);
3714
3715 if (logicalBottom > logicalHeight()) {
3716 // If the object is not in the list, we add it now.
3717 if (!containsFloat(r->m_renderer)) {
3718 int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
3719 int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
3720 FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
3721 floatingObj->m_renderer = r->m_renderer;
3722
3723 // The nearest enclosing layer always paints the float (so that zindex and stacking
3724 // behaves properly). We always want to propagate the desire to paint the float as
3725 // far out as we can, to the outermost block that overlaps the float, stopping only
3726 // if we hit a self-painting layer boundary.
3727 if (r->m_renderer->enclosingFloatPaintingLayer() == enclosingFloatPaintingLayer())
3728 r->m_shouldPaint = false;
3729 else
3730 floatingObj->m_shouldPaint = false;
3731
3732 floatingObj->m_isDescendant = true;
3733
3734 // We create the floating object list lazily.
3735 if (!m_floatingObjects)
3736 m_floatingObjects = adoptPtr(new FloatingObjects);
3737
3738 m_floatingObjects->increaseObjectsCount(floatingObj->type());
3739 m_floatingObjects->set().add(floatingObj);
3740 }
3741 } else {
3742 if (makeChildPaintOtherFloats && !r->m_shouldPaint && !r->m_renderer->hasSelfPaintingLayer() &&
3743 r->m_renderer->isDescendantOf(child) && r->m_renderer->enclosingFloatPaintingLayer() == child->enclosingFloatPaintingLayer()) {
3744 // The float is not overhanging from this block, so if it is a descendant of the child, the child should
3745 // paint it (the other case is that it is intruding into the child), unless it has its own layer or enclosing
3746 // layer.
3747 // If makeChildPaintOtherFloats is false, it means that the child must already know about all the floats
3748 // it should paint.
3749 r->m_shouldPaint = true;
3750 }
3751
3752 // Since the float doesn't overhang, it didn't get put into our list. We need to go ahead and add its overflow in to the
3753 // child now.
3754 if (r->m_isDescendant)
3755 child->addOverflowFromChild(r->m_renderer, IntSize(xPositionForFloatIncludingMargin(r), yPositionForFloatIncludingMargin(r)));
3756 }
3757 }
3758 return lowestFloatLogicalBottom;
3759 }
3760
hasOverhangingFloat(RenderBox * renderer)3761 bool RenderBlock::hasOverhangingFloat(RenderBox* renderer)
3762 {
3763 if (!m_floatingObjects || hasColumns() || !parent())
3764 return false;
3765
3766 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3767 FloatingObjectSetIterator it = floatingObjectSet.find<RenderBox*, FloatingObjectHashTranslator>(renderer);
3768 if (it == floatingObjectSet.end())
3769 return false;
3770
3771 return logicalBottomForFloat(*it) > logicalHeight();
3772 }
3773
addIntrudingFloats(RenderBlock * prev,int logicalLeftOffset,int logicalTopOffset)3774 void RenderBlock::addIntrudingFloats(RenderBlock* prev, int logicalLeftOffset, int logicalTopOffset)
3775 {
3776 // If the parent or previous sibling doesn't have any floats to add, don't bother.
3777 if (!prev->m_floatingObjects)
3778 return;
3779
3780 logicalLeftOffset += (isHorizontalWritingMode() ? marginLeft() : marginTop());
3781
3782 FloatingObjectSet& prevSet = prev->m_floatingObjects->set();
3783 FloatingObjectSetIterator prevEnd = prevSet.end();
3784 for (FloatingObjectSetIterator prevIt = prevSet.begin(); prevIt != prevEnd; ++prevIt) {
3785 FloatingObject* r = *prevIt;
3786 if (logicalBottomForFloat(r) > logicalTopOffset) {
3787 if (!m_floatingObjects || !m_floatingObjects->set().contains(r)) {
3788 int leftOffset = isHorizontalWritingMode() ? logicalLeftOffset : logicalTopOffset;
3789 int topOffset = isHorizontalWritingMode() ? logicalTopOffset : logicalLeftOffset;
3790
3791 FloatingObject* floatingObj = new FloatingObject(r->type(), IntRect(r->x() - leftOffset, r->y() - topOffset, r->width(), r->height()));
3792
3793 // Applying the child's margin makes no sense in the case where the child was passed in.
3794 // since this margin was added already through the modification of the |logicalLeftOffset| variable
3795 // above. |logicalLeftOffset| will equal the margin in this case, so it's already been taken
3796 // into account. Only apply this code if prev is the parent, since otherwise the left margin
3797 // will get applied twice.
3798 if (prev != parent()) {
3799 if (isHorizontalWritingMode())
3800 floatingObj->setX(floatingObj->x() + prev->marginLeft());
3801 else
3802 floatingObj->setY(floatingObj->y() + prev->marginTop());
3803 }
3804
3805 floatingObj->m_shouldPaint = false; // We are not in the direct inheritance chain for this float. We will never paint it.
3806 floatingObj->m_renderer = r->m_renderer;
3807
3808 // We create the floating object list lazily.
3809 if (!m_floatingObjects)
3810 m_floatingObjects = adoptPtr(new FloatingObjects);
3811 m_floatingObjects->increaseObjectsCount(floatingObj->type());
3812 m_floatingObjects->set().add(floatingObj);
3813 }
3814 }
3815 }
3816 }
3817
avoidsFloats() const3818 bool RenderBlock::avoidsFloats() const
3819 {
3820 // Floats can't intrude into our box if we have a non-auto column count or width.
3821 return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
3822 }
3823
containsFloat(RenderBox * renderer)3824 bool RenderBlock::containsFloat(RenderBox* renderer)
3825 {
3826 return m_floatingObjects && m_floatingObjects->set().contains<RenderBox*, FloatingObjectHashTranslator>(renderer);
3827 }
3828
markAllDescendantsWithFloatsForLayout(RenderBox * floatToRemove,bool inLayout)3829 void RenderBlock::markAllDescendantsWithFloatsForLayout(RenderBox* floatToRemove, bool inLayout)
3830 {
3831 if (!m_everHadLayout)
3832 return;
3833
3834 setChildNeedsLayout(true, !inLayout);
3835
3836 if (floatToRemove)
3837 removeFloatingObject(floatToRemove);
3838
3839 // Iterate over our children and mark them as needed.
3840 if (!childrenInline()) {
3841 for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
3842 if ((!floatToRemove && child->isFloatingOrPositioned()) || !child->isRenderBlock())
3843 continue;
3844 RenderBlock* childBlock = toRenderBlock(child);
3845 if ((floatToRemove ? childBlock->containsFloat(floatToRemove) : childBlock->containsFloats()) || childBlock->shrinkToAvoidFloats())
3846 childBlock->markAllDescendantsWithFloatsForLayout(floatToRemove, inLayout);
3847 }
3848 }
3849 }
3850
markSiblingsWithFloatsForLayout()3851 void RenderBlock::markSiblingsWithFloatsForLayout()
3852 {
3853 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
3854 FloatingObjectSetIterator end = floatingObjectSet.end();
3855 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
3856 if (logicalBottomForFloat(*it) > logicalHeight()) {
3857 RenderBox* floatingBox = (*it)->renderer();
3858
3859 RenderObject* next = nextSibling();
3860 while (next) {
3861 if (next->isRenderBlock() && !next->isFloatingOrPositioned() && !toRenderBlock(next)->avoidsFloats()) {
3862 RenderBlock* nextBlock = toRenderBlock(next);
3863 if (nextBlock->containsFloat(floatingBox))
3864 nextBlock->markAllDescendantsWithFloatsForLayout(floatingBox);
3865 else
3866 break;
3867 }
3868
3869 next = next->nextSibling();
3870 }
3871 }
3872 }
3873 }
3874
getClearDelta(RenderBox * child,int yPos)3875 int RenderBlock::getClearDelta(RenderBox* child, int yPos)
3876 {
3877 // There is no need to compute clearance if we have no floats.
3878 if (!containsFloats())
3879 return 0;
3880
3881 // At least one float is present. We need to perform the clearance computation.
3882 bool clearSet = child->style()->clear() != CNONE;
3883 int bottom = 0;
3884 switch (child->style()->clear()) {
3885 case CNONE:
3886 break;
3887 case CLEFT:
3888 bottom = lowestFloatLogicalBottom(FloatingObject::FloatLeft);
3889 break;
3890 case CRIGHT:
3891 bottom = lowestFloatLogicalBottom(FloatingObject::FloatRight);
3892 break;
3893 case CBOTH:
3894 bottom = lowestFloatLogicalBottom();
3895 break;
3896 }
3897
3898 // 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).
3899 int result = clearSet ? max(0, bottom - yPos) : 0;
3900 if (!result && child->avoidsFloats()) {
3901 int y = yPos;
3902 while (true) {
3903 int widthAtY = availableLogicalWidthForLine(y, false);
3904 if (widthAtY == availableLogicalWidth())
3905 return y - yPos;
3906
3907 int oldChildY = child->y();
3908 int oldChildWidth = child->width();
3909 child->setY(y);
3910 child->computeLogicalWidth();
3911 int childWidthAtY = child->width();
3912 child->setY(oldChildY);
3913 child->setWidth(oldChildWidth);
3914
3915 if (childWidthAtY <= widthAtY)
3916 return y - yPos;
3917
3918 y = nextFloatLogicalBottomBelow(y);
3919 ASSERT(y >= yPos);
3920 if (y < yPos)
3921 break;
3922 }
3923 ASSERT_NOT_REACHED();
3924 }
3925 return result;
3926 }
3927
isPointInOverflowControl(HitTestResult & result,int _x,int _y,int _tx,int _ty)3928 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, int _x, int _y, int _tx, int _ty)
3929 {
3930 if (!scrollsOverflow())
3931 return false;
3932
3933 return layer()->hitTestOverflowControls(result, IntPoint(_x - _tx, _y - _ty));
3934 }
3935
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,int _x,int _y,int _tx,int _ty,HitTestAction hitTestAction)3936 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, int _x, int _y, int _tx, int _ty, HitTestAction hitTestAction)
3937 {
3938 int tx = _tx + x();
3939 int ty = _ty + y();
3940
3941 if (!isRenderView()) {
3942 // Check if we need to do anything at all.
3943 IntRect overflowBox = visualOverflowRect();
3944 overflowBox.move(tx, ty);
3945 if (!overflowBox.intersects(result.rectForPoint(_x, _y)))
3946 return false;
3947 }
3948
3949 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, _x, _y, tx, ty)) {
3950 updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
3951 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
3952 if (!result.addNodeToRectBasedTestResult(node(), _x, _y))
3953 return true;
3954 }
3955
3956 // If we have clipping, then we can't have any spillout.
3957 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
3958 bool useClip = (hasControlClip() || useOverflowClip);
3959 IntRect hitTestArea(result.rectForPoint(_x, _y));
3960 bool checkChildren = !useClip || (hasControlClip() ? controlClipRect(tx, ty).intersects(hitTestArea) : overflowClipRect(tx, ty, IncludeOverlayScrollbarSize).intersects(hitTestArea));
3961 if (checkChildren) {
3962 // Hit test descendants first.
3963 int scrolledX = tx;
3964 int scrolledY = ty;
3965 if (hasOverflowClip()) {
3966 IntSize offset = layer()->scrolledContentOffset();
3967 scrolledX -= offset.width();
3968 scrolledY -= offset.height();
3969 }
3970
3971 // Hit test contents if we don't have columns.
3972 if (!hasColumns()) {
3973 if (hitTestContents(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) {
3974 updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
3975 return true;
3976 }
3977 if (hitTestAction == HitTestFloat && hitTestFloats(request, result, _x, _y, scrolledX, scrolledY))
3978 return true;
3979 } else if (hitTestColumns(request, result, _x, _y, scrolledX, scrolledY, hitTestAction)) {
3980 updateHitTestResult(result, IntPoint(_x - tx, _y - ty));
3981 return true;
3982 }
3983 }
3984
3985 // Now hit test our background
3986 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
3987 IntRect boundsRect(tx, ty, width(), height());
3988 if (visibleToHitTesting() && boundsRect.intersects(result.rectForPoint(_x, _y))) {
3989 updateHitTestResult(result, flipForWritingMode(IntPoint(_x - tx, _y - ty)));
3990 if (!result.addNodeToRectBasedTestResult(node(), _x, _y, boundsRect))
3991 return true;
3992 }
3993 }
3994
3995 return false;
3996 }
3997
hitTestFloats(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty)3998 bool RenderBlock::hitTestFloats(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty)
3999 {
4000 if (!m_floatingObjects)
4001 return false;
4002
4003 if (isRenderView()) {
4004 tx += toRenderView(this)->frameView()->scrollX();
4005 ty += toRenderView(this)->frameView()->scrollY();
4006 }
4007
4008 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
4009 FloatingObjectSetIterator begin = floatingObjectSet.begin();
4010 for (FloatingObjectSetIterator it = floatingObjectSet.end(); it != begin;) {
4011 --it;
4012 FloatingObject* floatingObject = *it;
4013 if (floatingObject->m_shouldPaint && !floatingObject->m_renderer->hasSelfPaintingLayer()) {
4014 int xOffset = xPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->x();
4015 int yOffset = yPositionForFloatIncludingMargin(floatingObject) - floatingObject->m_renderer->y();
4016 IntPoint childPoint = flipFloatForWritingMode(floatingObject, IntPoint(tx + xOffset, ty + yOffset));
4017 if (floatingObject->m_renderer->hitTest(request, result, IntPoint(x, y), childPoint.x(), childPoint.y())) {
4018 updateHitTestResult(result, IntPoint(x - childPoint.x(), y - childPoint.y()));
4019 return true;
4020 }
4021 }
4022 }
4023
4024 return false;
4025 }
4026
hitTestColumns(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)4027 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
4028 {
4029 // We need to do multiple passes, breaking up our hit testing into strips.
4030 ColumnInfo* colInfo = columnInfo();
4031 int colCount = columnCount(colInfo);
4032 if (!colCount)
4033 return false;
4034 int logicalLeft = logicalLeftOffsetForContent();
4035 int currLogicalTopOffset = 0;
4036 int i;
4037 bool isHorizontal = isHorizontalWritingMode();
4038 for (i = 0; i < colCount; i++) {
4039 IntRect colRect = columnRectAt(colInfo, i);
4040 int blockDelta = (isHorizontal ? colRect.height() : colRect.width());
4041 if (style()->isFlippedBlocksWritingMode())
4042 currLogicalTopOffset += blockDelta;
4043 else
4044 currLogicalTopOffset -= blockDelta;
4045 }
4046 for (i = colCount - 1; i >= 0; i--) {
4047 IntRect colRect = columnRectAt(colInfo, i);
4048 flipForWritingMode(colRect);
4049 int currLogicalLeftOffset = (isHorizontal ? colRect.x() : colRect.y()) - logicalLeft;
4050 int blockDelta = (isHorizontal ? colRect.height() : colRect.width());
4051 if (style()->isFlippedBlocksWritingMode())
4052 currLogicalTopOffset -= blockDelta;
4053 else
4054 currLogicalTopOffset += blockDelta;
4055 colRect.move(tx, ty);
4056
4057 if (colRect.intersects(result.rectForPoint(x, y))) {
4058 // The point is inside this column.
4059 // Adjust tx and ty to change where we hit test.
4060
4061 IntSize offset = isHorizontal ? IntSize(currLogicalLeftOffset, currLogicalTopOffset) : IntSize(currLogicalTopOffset, currLogicalLeftOffset);
4062 int finalX = tx + offset.width();
4063 int finalY = ty + offset.height();
4064 if (result.isRectBasedTest() && !colRect.contains(result.rectForPoint(x, y)))
4065 hitTestContents(request, result, x, y, finalX, finalY, hitTestAction);
4066 else
4067 return hitTestContents(request, result, x, y, finalX, finalY, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, x, y, finalX, finalY));
4068 }
4069 }
4070
4071 return false;
4072 }
4073
hitTestContents(const HitTestRequest & request,HitTestResult & result,int x,int y,int tx,int ty,HitTestAction hitTestAction)4074 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, int x, int y, int tx, int ty, HitTestAction hitTestAction)
4075 {
4076 if (childrenInline() && !isTable()) {
4077 // We have to hit-test our line boxes.
4078 if (m_lineBoxes.hitTest(this, request, result, x, y, tx, ty, hitTestAction))
4079 return true;
4080 } else {
4081 // Hit test our children.
4082 HitTestAction childHitTest = hitTestAction;
4083 if (hitTestAction == HitTestChildBlockBackgrounds)
4084 childHitTest = HitTestChildBlockBackground;
4085 for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
4086 IntPoint childPoint = flipForWritingMode(child, IntPoint(tx, ty), ParentToChildFlippingAdjustment);
4087 if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, x, y, childPoint.x(), childPoint.y(), childHitTest))
4088 return true;
4089 }
4090 }
4091
4092 return false;
4093 }
4094
positionForBox(InlineBox * box,bool start) const4095 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
4096 {
4097 if (!box)
4098 return Position();
4099
4100 if (!box->renderer()->node())
4101 return Position(node(), start ? caretMinOffset() : caretMaxOffset());
4102
4103 if (!box->isInlineTextBox())
4104 return Position(box->renderer()->node(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
4105
4106 InlineTextBox *textBox = static_cast<InlineTextBox *>(box);
4107 return Position(box->renderer()->node(), start ? textBox->start() : textBox->start() + textBox->len());
4108 }
4109
4110 // FIXME: This function should go on RenderObject as an instance method. Then
4111 // all cases in which positionForPoint recurs could call this instead to
4112 // prevent crossing editable boundaries. This would require many tests.
positionForPointRespectingEditingBoundaries(RenderBlock * parent,RenderBox * child,const IntPoint & pointInParentCoordinates)4113 static VisiblePosition positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const IntPoint& pointInParentCoordinates)
4114 {
4115 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
4116 IntPoint pointInChildCoordinates(pointInParentCoordinates - child->location());
4117
4118 // If this is an anonymous renderer, we just recur normally
4119 Node* childNode = child->node();
4120 if (!childNode)
4121 return child->positionForPoint(pointInChildCoordinates);
4122
4123 // Otherwise, first make sure that the editability of the parent and child agree.
4124 // If they don't agree, then we return a visible position just before or after the child
4125 RenderObject* ancestor = parent;
4126 while (ancestor && !ancestor->node())
4127 ancestor = ancestor->parent();
4128
4129 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
4130 if (!ancestor || ancestor->node()->rendererIsEditable() == childNode->rendererIsEditable())
4131 return child->positionForPoint(pointInChildCoordinates);
4132
4133 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
4134 int childMiddle = parent->logicalWidthForChild(child) / 2;
4135 int logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
4136 if (logicalLeft < childMiddle)
4137 return ancestor->createVisiblePosition(childNode->nodeIndex(), DOWNSTREAM);
4138 return ancestor->createVisiblePosition(childNode->nodeIndex() + 1, UPSTREAM);
4139 }
4140
positionForPointWithInlineChildren(const IntPoint & pointInLogicalContents)4141 VisiblePosition RenderBlock::positionForPointWithInlineChildren(const IntPoint& pointInLogicalContents)
4142 {
4143 ASSERT(childrenInline());
4144
4145 if (!firstRootBox())
4146 return createVisiblePosition(0, DOWNSTREAM);
4147
4148 // look for the closest line box in the root box which is at the passed-in y coordinate
4149 InlineBox* closestBox = 0;
4150 RootInlineBox* firstRootBoxWithChildren = 0;
4151 RootInlineBox* lastRootBoxWithChildren = 0;
4152 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
4153 if (!root->firstLeafChild())
4154 continue;
4155 if (!firstRootBoxWithChildren)
4156 firstRootBoxWithChildren = root;
4157 lastRootBoxWithChildren = root;
4158
4159 // check if this root line box is located at this y coordinate
4160 if (pointInLogicalContents.y() < root->selectionBottom()) {
4161 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4162 if (closestBox)
4163 break;
4164 }
4165 }
4166
4167 bool moveCaretToBoundary = document()->frame()->editor()->behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
4168
4169 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
4170 // y coordinate is below last root line box, pretend we hit it
4171 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
4172 }
4173
4174 if (closestBox) {
4175 if (moveCaretToBoundary && pointInLogicalContents.y() < firstRootBoxWithChildren->selectionTop()) {
4176 // y coordinate is above first root line box, so return the start of the first
4177 return VisiblePosition(positionForBox(firstRootBoxWithChildren->firstLeafChild(), true), DOWNSTREAM);
4178 }
4179
4180 // pass the box a top position that is inside it
4181 IntPoint point(pointInLogicalContents.x(), closestBox->logicalTop());
4182 if (!isHorizontalWritingMode())
4183 point = point.transposedPoint();
4184 if (closestBox->renderer()->isReplaced())
4185 return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
4186 return closestBox->renderer()->positionForPoint(point);
4187 }
4188
4189 if (lastRootBoxWithChildren) {
4190 // We hit this case for Mac behavior when the Y coordinate is below the last box.
4191 ASSERT(moveCaretToBoundary);
4192 InlineBox* logicallyLastBox;
4193 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
4194 return VisiblePosition(positionForBox(logicallyLastBox, false), DOWNSTREAM);
4195 }
4196
4197 // Can't reach this. We have a root line box, but it has no kids.
4198 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
4199 // seems to hit this code path.
4200 return createVisiblePosition(0, DOWNSTREAM);
4201 }
4202
isChildHitTestCandidate(RenderBox * box)4203 static inline bool isChildHitTestCandidate(RenderBox* box)
4204 {
4205 return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrPositioned();
4206 }
4207
positionForPoint(const IntPoint & point)4208 VisiblePosition RenderBlock::positionForPoint(const IntPoint& point)
4209 {
4210 if (isTable())
4211 return RenderBox::positionForPoint(point);
4212
4213 if (isReplaced()) {
4214 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
4215 int pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
4216 int pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
4217
4218 if (pointLogicalTop < 0 || (pointLogicalTop < logicalHeight() && pointLogicalLeft < 0))
4219 return createVisiblePosition(caretMinOffset(), DOWNSTREAM);
4220 if (pointLogicalTop >= logicalHeight() || (pointLogicalTop >= 0 && pointLogicalLeft >= logicalWidth()))
4221 return createVisiblePosition(caretMaxOffset(), DOWNSTREAM);
4222 }
4223
4224 int contentsX = point.x();
4225 int contentsY = point.y();
4226 offsetForContents(contentsX, contentsY);
4227 IntPoint pointInContents(contentsX, contentsY);
4228 IntPoint pointInLogicalContents(pointInContents);
4229 if (!isHorizontalWritingMode())
4230 pointInLogicalContents = pointInLogicalContents.transposedPoint();
4231
4232 if (childrenInline())
4233 return positionForPointWithInlineChildren(pointInLogicalContents);
4234
4235 if (lastChildBox() && pointInContents.y() > lastChildBox()->logicalTop()) {
4236 for (RenderBox* childBox = lastChildBox(); childBox; childBox = childBox->previousSiblingBox()) {
4237 if (isChildHitTestCandidate(childBox))
4238 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
4239 }
4240 } else {
4241 for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
4242 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
4243 if (isChildHitTestCandidate(childBox) && pointInContents.y() < childBox->logicalBottom())
4244 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
4245 }
4246 }
4247
4248 // We only get here if there are no hit test candidate children below the click.
4249 return RenderBox::positionForPoint(point);
4250 }
4251
offsetForContents(int & tx,int & ty) const4252 void RenderBlock::offsetForContents(int& tx, int& ty) const
4253 {
4254 IntPoint contentsPoint(tx, ty);
4255
4256 if (hasOverflowClip())
4257 contentsPoint += layer()->scrolledContentOffset();
4258
4259 if (hasColumns())
4260 adjustPointToColumnContents(contentsPoint);
4261
4262 tx = contentsPoint.x();
4263 ty = contentsPoint.y();
4264 }
4265
availableLogicalWidth() const4266 int RenderBlock::availableLogicalWidth() const
4267 {
4268 // If we have multiple columns, then the available logical width is reduced to our column width.
4269 if (hasColumns())
4270 return desiredColumnWidth();
4271 return RenderBox::availableLogicalWidth();
4272 }
4273
columnGap() const4274 int RenderBlock::columnGap() const
4275 {
4276 if (style()->hasNormalColumnGap())
4277 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
4278 return static_cast<int>(style()->columnGap());
4279 }
4280
calcColumnWidth()4281 void RenderBlock::calcColumnWidth()
4282 {
4283 // Calculate our column width and column count.
4284 unsigned desiredColumnCount = 1;
4285 int desiredColumnWidth = contentLogicalWidth();
4286
4287 // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
4288 if (document()->paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth())) {
4289 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
4290 return;
4291 }
4292
4293 int availWidth = desiredColumnWidth;
4294 int colGap = columnGap();
4295 int colWidth = max(1, static_cast<int>(style()->columnWidth()));
4296 int colCount = max(1, static_cast<int>(style()->columnCount()));
4297
4298 if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
4299 desiredColumnCount = colCount;
4300 desiredColumnWidth = max<int>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
4301 } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
4302 desiredColumnCount = max<int>(1, (float)(availWidth + colGap) / (colWidth + colGap));
4303 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
4304 } else {
4305 desiredColumnCount = max(min<int>(colCount, (float)(availWidth + colGap) / (colWidth + colGap)), 1);
4306 desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
4307 }
4308 setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
4309 }
4310
setDesiredColumnCountAndWidth(int count,int width)4311 void RenderBlock::setDesiredColumnCountAndWidth(int count, int width)
4312 {
4313 bool destroyColumns = !firstChild()
4314 || (count == 1 && style()->hasAutoColumnWidth())
4315 || firstChild()->isAnonymousColumnsBlock()
4316 || firstChild()->isAnonymousColumnSpanBlock();
4317 if (destroyColumns) {
4318 if (hasColumns()) {
4319 delete gColumnInfoMap->take(this);
4320 setHasColumns(false);
4321 }
4322 } else {
4323 ColumnInfo* info;
4324 if (hasColumns())
4325 info = gColumnInfoMap->get(this);
4326 else {
4327 if (!gColumnInfoMap)
4328 gColumnInfoMap = new ColumnInfoMap;
4329 info = new ColumnInfo;
4330 gColumnInfoMap->add(this, info);
4331 setHasColumns(true);
4332 }
4333 info->setDesiredColumnCount(count);
4334 info->setDesiredColumnWidth(width);
4335 }
4336 }
4337
desiredColumnWidth() const4338 int RenderBlock::desiredColumnWidth() const
4339 {
4340 if (!hasColumns())
4341 return contentLogicalWidth();
4342 return gColumnInfoMap->get(this)->desiredColumnWidth();
4343 }
4344
desiredColumnCount() const4345 unsigned RenderBlock::desiredColumnCount() const
4346 {
4347 if (!hasColumns())
4348 return 1;
4349 return gColumnInfoMap->get(this)->desiredColumnCount();
4350 }
4351
columnInfo() const4352 ColumnInfo* RenderBlock::columnInfo() const
4353 {
4354 if (!hasColumns())
4355 return 0;
4356 return gColumnInfoMap->get(this);
4357 }
4358
columnCount(ColumnInfo * colInfo) const4359 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
4360 {
4361 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
4362 return colInfo->columnCount();
4363 }
4364
columnRectAt(ColumnInfo * colInfo,unsigned index) const4365 IntRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
4366 {
4367 ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
4368
4369 // Compute the appropriate rect based off our information.
4370 int colLogicalWidth = colInfo->desiredColumnWidth();
4371 int colLogicalHeight = colInfo->columnHeight();
4372 int colLogicalTop = borderBefore() + paddingBefore();
4373 int colGap = columnGap();
4374 int colLogicalLeft = style()->isLeftToRightDirection() ?
4375 logicalLeftOffsetForContent() + (index * (colLogicalWidth + colGap))
4376 : logicalLeftOffsetForContent() + contentLogicalWidth() - colLogicalWidth - (index * (colLogicalWidth + colGap));
4377 IntRect rect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
4378 if (isHorizontalWritingMode())
4379 return IntRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
4380 return IntRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
4381 }
4382
layoutColumns(bool hasSpecifiedPageLogicalHeight,int pageLogicalHeight,LayoutStateMaintainer & statePusher)4383 bool RenderBlock::layoutColumns(bool hasSpecifiedPageLogicalHeight, int pageLogicalHeight, LayoutStateMaintainer& statePusher)
4384 {
4385 if (!hasColumns())
4386 return false;
4387
4388 // FIXME: We don't balance properly at all in the presence of forced page breaks. We need to understand what
4389 // the distance between forced page breaks is so that we can avoid making the minimum column height too tall.
4390 ColumnInfo* colInfo = columnInfo();
4391 int desiredColumnCount = colInfo->desiredColumnCount();
4392 if (!hasSpecifiedPageLogicalHeight) {
4393 int columnHeight = pageLogicalHeight;
4394 int minColumnCount = colInfo->forcedBreaks() + 1;
4395 if (minColumnCount >= desiredColumnCount) {
4396 // The forced page breaks are in control of the balancing. Just set the column height to the
4397 // maximum page break distance.
4398 if (!pageLogicalHeight) {
4399 int distanceBetweenBreaks = max(colInfo->maximumDistanceBetweenForcedBreaks(),
4400 view()->layoutState()->pageLogicalOffset(borderBefore() + paddingBefore() + contentLogicalHeight()) - colInfo->forcedBreakOffset());
4401 columnHeight = max(colInfo->minimumColumnHeight(), distanceBetweenBreaks);
4402 }
4403 } else if (contentLogicalHeight() > pageLogicalHeight * desiredColumnCount) {
4404 // Now that we know the intrinsic height of the columns, we have to rebalance them.
4405 columnHeight = max(colInfo->minimumColumnHeight(), (int)ceilf((float)contentLogicalHeight() / desiredColumnCount));
4406 }
4407
4408 if (columnHeight && columnHeight != pageLogicalHeight) {
4409 statePusher.pop();
4410 m_everHadLayout = true;
4411 layoutBlock(false, columnHeight);
4412 return true;
4413 }
4414 }
4415
4416 if (pageLogicalHeight)
4417 colInfo->setColumnCountAndHeight(ceilf((float)contentLogicalHeight() / pageLogicalHeight), pageLogicalHeight);
4418
4419 if (columnCount(colInfo)) {
4420 setLogicalHeight(borderBefore() + paddingBefore() + colInfo->columnHeight() + borderAfter() + paddingAfter() + scrollbarLogicalHeight());
4421 m_overflow.clear();
4422 }
4423
4424 return false;
4425 }
4426
adjustPointToColumnContents(IntPoint & point) const4427 void RenderBlock::adjustPointToColumnContents(IntPoint& point) const
4428 {
4429 // Just bail if we have no columns.
4430 if (!hasColumns())
4431 return;
4432
4433 ColumnInfo* colInfo = columnInfo();
4434 if (!columnCount(colInfo))
4435 return;
4436
4437 // Determine which columns we intersect.
4438 int colGap = columnGap();
4439 int halfColGap = colGap / 2;
4440 IntPoint columnPoint(columnRectAt(colInfo, 0).location());
4441 int logicalOffset = 0;
4442 for (unsigned i = 0; i < colInfo->columnCount(); i++) {
4443 // Add in half the column gap to the left and right of the rect.
4444 IntRect colRect = columnRectAt(colInfo, i);
4445 if (isHorizontalWritingMode()) {
4446 IntRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
4447 if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
4448 // FIXME: The clamping that follows is not completely right for right-to-left
4449 // content.
4450 // Clamp everything above the column to its top left.
4451 if (point.y() < gapAndColumnRect.y())
4452 point = gapAndColumnRect.location();
4453 // Clamp everything below the column to the next column's top left. If there is
4454 // no next column, this still maps to just after this column.
4455 else if (point.y() >= gapAndColumnRect.maxY()) {
4456 point = gapAndColumnRect.location();
4457 point.move(0, gapAndColumnRect.height());
4458 }
4459
4460 // We're inside the column. Translate the x and y into our column coordinate space.
4461 point.move(columnPoint.x() - colRect.x(), logicalOffset);
4462 return;
4463 }
4464
4465 // Move to the next position.
4466 logicalOffset += colRect.height();
4467 } else {
4468 IntRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
4469 if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
4470 // FIXME: The clamping that follows is not completely right for right-to-left
4471 // content.
4472 // Clamp everything above the column to its top left.
4473 if (point.x() < gapAndColumnRect.x())
4474 point = gapAndColumnRect.location();
4475 // Clamp everything below the column to the next column's top left. If there is
4476 // no next column, this still maps to just after this column.
4477 else if (point.x() >= gapAndColumnRect.maxX()) {
4478 point = gapAndColumnRect.location();
4479 point.move(gapAndColumnRect.width(), 0);
4480 }
4481
4482 // We're inside the column. Translate the x and y into our column coordinate space.
4483 point.move(logicalOffset, columnPoint.y() - colRect.y());
4484 return;
4485 }
4486
4487 // Move to the next position.
4488 logicalOffset += colRect.width();
4489 }
4490 }
4491 }
4492
adjustRectForColumns(IntRect & r) const4493 void RenderBlock::adjustRectForColumns(IntRect& r) const
4494 {
4495 // Just bail if we have no columns.
4496 if (!hasColumns())
4497 return;
4498
4499 ColumnInfo* colInfo = columnInfo();
4500
4501 // Begin with a result rect that is empty.
4502 IntRect result;
4503
4504 // Determine which columns we intersect.
4505 unsigned colCount = columnCount(colInfo);
4506 if (!colCount)
4507 return;
4508
4509 int logicalLeft = logicalLeftOffsetForContent();
4510 int currLogicalOffset = 0;
4511
4512 for (unsigned i = 0; i < colCount; i++) {
4513 IntRect colRect = columnRectAt(colInfo, i);
4514 IntRect repaintRect = r;
4515 if (isHorizontalWritingMode()) {
4516 int currXOffset = colRect.x() - logicalLeft;
4517 repaintRect.move(currXOffset, currLogicalOffset);
4518 currLogicalOffset -= colRect.height();
4519 } else {
4520 int currYOffset = colRect.y() - logicalLeft;
4521 repaintRect.move(currLogicalOffset, currYOffset);
4522 currLogicalOffset -= colRect.width();
4523 }
4524 repaintRect.intersect(colRect);
4525 result.unite(repaintRect);
4526 }
4527
4528 r = result;
4529 }
4530
flipForWritingModeIncludingColumns(const IntPoint & point) const4531 IntPoint RenderBlock::flipForWritingModeIncludingColumns(const IntPoint& point) const
4532 {
4533 ASSERT(hasColumns());
4534 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4535 return point;
4536 ColumnInfo* colInfo = columnInfo();
4537 int columnLogicalHeight = colInfo->columnHeight();
4538 int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
4539 if (isHorizontalWritingMode())
4540 return IntPoint(point.x(), expandedLogicalHeight - point.y());
4541 return IntPoint(expandedLogicalHeight - point.x(), point.y());
4542 }
4543
flipForWritingModeIncludingColumns(IntRect & rect) const4544 void RenderBlock::flipForWritingModeIncludingColumns(IntRect& rect) const
4545 {
4546 ASSERT(hasColumns());
4547 if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
4548 return;
4549
4550 ColumnInfo* colInfo = columnInfo();
4551 int columnLogicalHeight = colInfo->columnHeight();
4552 int expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
4553 if (isHorizontalWritingMode())
4554 rect.setY(expandedLogicalHeight - rect.maxY());
4555 else
4556 rect.setX(expandedLogicalHeight - rect.maxX());
4557 }
4558
adjustForColumns(IntSize & offset,const IntPoint & point) const4559 void RenderBlock::adjustForColumns(IntSize& offset, const IntPoint& point) const
4560 {
4561 if (!hasColumns())
4562 return;
4563
4564 ColumnInfo* colInfo = columnInfo();
4565
4566 int logicalLeft = logicalLeftOffsetForContent();
4567 size_t colCount = columnCount(colInfo);
4568 int colLogicalWidth = colInfo->desiredColumnWidth();
4569 int colLogicalHeight = colInfo->columnHeight();
4570
4571 for (size_t i = 0; i < colCount; ++i) {
4572 // Compute the edges for a given column in the block progression direction.
4573 IntRect sliceRect = IntRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
4574 if (!isHorizontalWritingMode())
4575 sliceRect = sliceRect.transposedRect();
4576
4577 // If we have a flipped blocks writing mode, then convert the column so that it's coming from the after edge (either top or left edge).
4578 flipForWritingModeIncludingColumns(sliceRect);
4579
4580 int logicalOffset = style()->isFlippedBlocksWritingMode() ? (colCount - 1 - i) * colLogicalHeight : i * colLogicalHeight;
4581
4582 // Now we're in the same coordinate space as the point. See if it is inside the rectangle.
4583 if (isHorizontalWritingMode()) {
4584 if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
4585 offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
4586 return;
4587 }
4588 } else {
4589 if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
4590 offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
4591 return;
4592 }
4593 }
4594 }
4595 }
4596
computePreferredLogicalWidths()4597 void RenderBlock::computePreferredLogicalWidths()
4598 {
4599 ASSERT(preferredLogicalWidthsDirty());
4600
4601 updateFirstLetter();
4602
4603 if (!isTableCell() && style()->logicalWidth().isFixed() && style()->logicalWidth().value() > 0)
4604 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = computeContentBoxLogicalWidth(style()->logicalWidth().value());
4605 else {
4606 m_minPreferredLogicalWidth = 0;
4607 m_maxPreferredLogicalWidth = 0;
4608
4609 if (childrenInline())
4610 computeInlinePreferredLogicalWidths();
4611 else
4612 computeBlockPreferredLogicalWidths();
4613
4614 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
4615
4616 if (!style()->autoWrap() && childrenInline()) {
4617 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth;
4618
4619 // A horizontal marquee with inline children has no minimum width.
4620 if (layer() && layer()->marquee() && layer()->marquee()->isHorizontal())
4621 m_minPreferredLogicalWidth = 0;
4622 }
4623
4624 int scrollbarWidth = 0;
4625 if (hasOverflowClip() && style()->overflowY() == OSCROLL) {
4626 layer()->setHasVerticalScrollbar(true);
4627 scrollbarWidth = verticalScrollbarWidth();
4628 m_maxPreferredLogicalWidth += scrollbarWidth;
4629 }
4630
4631 if (isTableCell()) {
4632 Length w = toRenderTableCell(this)->styleOrColLogicalWidth();
4633 if (w.isFixed() && w.value() > 0) {
4634 m_maxPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(w.value()));
4635 scrollbarWidth = 0;
4636 }
4637 }
4638
4639 m_minPreferredLogicalWidth += scrollbarWidth;
4640 }
4641
4642 if (style()->logicalMinWidth().isFixed() && style()->logicalMinWidth().value() > 0) {
4643 m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
4644 m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMinWidth().value()));
4645 }
4646
4647 if (style()->logicalMaxWidth().isFixed() && style()->logicalMaxWidth().value() != undefinedLength) {
4648 m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
4649 m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, computeContentBoxLogicalWidth(style()->logicalMaxWidth().value()));
4650 }
4651
4652 int borderAndPadding = borderAndPaddingLogicalWidth();
4653 m_minPreferredLogicalWidth += borderAndPadding;
4654 m_maxPreferredLogicalWidth += borderAndPadding;
4655
4656 setPreferredLogicalWidthsDirty(false);
4657 }
4658
4659 struct InlineMinMaxIterator {
4660 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
4661 inline min/max width calculations. Note the following about the way it walks:
4662 (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
4663 (2) We do not drill into the children of floats or replaced elements, since you can't break
4664 in the middle of such an element.
4665 (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
4666 distinct borders/margin/padding that contribute to the min/max width.
4667 */
4668 RenderObject* parent;
4669 RenderObject* current;
4670 bool endOfInline;
4671
InlineMinMaxIteratorWebCore::InlineMinMaxIterator4672 InlineMinMaxIterator(RenderObject* p, bool end = false)
4673 :parent(p), current(p), endOfInline(end) {}
4674
4675 RenderObject* next();
4676 };
4677
next()4678 RenderObject* InlineMinMaxIterator::next()
4679 {
4680 RenderObject* result = 0;
4681 bool oldEndOfInline = endOfInline;
4682 endOfInline = false;
4683 while (current || current == parent) {
4684 if (!oldEndOfInline &&
4685 (current == parent ||
4686 (!current->isFloating() && !current->isReplaced() && !current->isPositioned())))
4687 result = current->firstChild();
4688 if (!result) {
4689 // We hit the end of our inline. (It was empty, e.g., <span></span>.)
4690 if (!oldEndOfInline && current->isRenderInline()) {
4691 result = current;
4692 endOfInline = true;
4693 break;
4694 }
4695
4696 while (current && current != parent) {
4697 result = current->nextSibling();
4698 if (result) break;
4699 current = current->parent();
4700 if (current && current != parent && current->isRenderInline()) {
4701 result = current;
4702 endOfInline = true;
4703 break;
4704 }
4705 }
4706 }
4707
4708 if (!result)
4709 break;
4710
4711 if (!result->isPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4712 break;
4713
4714 current = result;
4715 result = 0;
4716 }
4717
4718 // Update our position.
4719 current = result;
4720 return current;
4721 }
4722
getBPMWidth(int childValue,Length cssUnit)4723 static int getBPMWidth(int childValue, Length cssUnit)
4724 {
4725 if (cssUnit.type() != Auto)
4726 return (cssUnit.isFixed() ? cssUnit.value() : childValue);
4727 return 0;
4728 }
4729
getBorderPaddingMargin(const RenderBoxModelObject * child,bool endOfInline)4730 static int getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
4731 {
4732 RenderStyle* cstyle = child->style();
4733 if (endOfInline)
4734 return getBPMWidth(child->marginEnd(), cstyle->marginEnd()) +
4735 getBPMWidth(child->paddingEnd(), cstyle->paddingEnd()) +
4736 child->borderEnd();
4737 return getBPMWidth(child->marginStart(), cstyle->marginStart()) +
4738 getBPMWidth(child->paddingStart(), cstyle->paddingStart()) +
4739 child->borderStart();
4740 }
4741
stripTrailingSpace(float & inlineMax,float & inlineMin,RenderObject * trailingSpaceChild)4742 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
4743 RenderObject* trailingSpaceChild)
4744 {
4745 if (trailingSpaceChild && trailingSpaceChild->isText()) {
4746 // Collapse away the trailing space at the end of a block.
4747 RenderText* t = toRenderText(trailingSpaceChild);
4748 const UChar space = ' ';
4749 const Font& font = t->style()->font(); // FIXME: This ignores first-line.
4750 float spaceWidth = font.width(TextRun(&space, 1));
4751 inlineMax -= spaceWidth + font.wordSpacing();
4752 if (inlineMin > inlineMax)
4753 inlineMin = inlineMax;
4754 }
4755 }
4756
updatePreferredWidth(int & preferredWidth,float & result)4757 static inline void updatePreferredWidth(int& preferredWidth, float& result)
4758 {
4759 int snappedResult = ceilf(result);
4760 preferredWidth = max(snappedResult, preferredWidth);
4761 }
4762
computeInlinePreferredLogicalWidths()4763 void RenderBlock::computeInlinePreferredLogicalWidths()
4764 {
4765 float inlineMax = 0;
4766 float inlineMin = 0;
4767
4768 int cw = containingBlock()->contentLogicalWidth();
4769
4770 // If we are at the start of a line, we want to ignore all white-space.
4771 // Also strip spaces if we previously had text that ended in a trailing space.
4772 bool stripFrontSpaces = true;
4773 RenderObject* trailingSpaceChild = 0;
4774
4775 // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4776 // very specific cirucumstances (in order to match common WinIE renderings).
4777 // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4778 bool allowImagesToBreak = !document()->inQuirksMode() || !isTableCell() || !style()->logicalWidth().isIntrinsicOrAuto();
4779
4780 bool autoWrap, oldAutoWrap;
4781 autoWrap = oldAutoWrap = style()->autoWrap();
4782
4783 InlineMinMaxIterator childIterator(this);
4784 bool addedTextIndent = false; // Only gets added in once.
4785 RenderObject* prevFloat = 0;
4786 while (RenderObject* child = childIterator.next()) {
4787 autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
4788 child->style()->autoWrap();
4789
4790 if (!child->isBR()) {
4791 // Step One: determine whether or not we need to go ahead and
4792 // terminate our current line. Each discrete chunk can become
4793 // the new min-width, if it is the widest chunk seen so far, and
4794 // it can also become the max-width.
4795
4796 // Children fall into three categories:
4797 // (1) An inline flow object. These objects always have a min/max of 0,
4798 // and are included in the iteration solely so that their margins can
4799 // be added in.
4800 //
4801 // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4802 // These objects can always be on a line by themselves, so in this situation
4803 // we need to go ahead and break the current line, and then add in our own
4804 // margins and min/max width on its own line, and then terminate the line.
4805 //
4806 // (3) A text object. Text runs can have breakable characters at the start,
4807 // the middle or the end. They may also lose whitespace off the front if
4808 // we're already ignoring whitespace. In order to compute accurate min-width
4809 // information, we need three pieces of information.
4810 // (a) the min-width of the first non-breakable run. Should be 0 if the text string
4811 // starts with whitespace.
4812 // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4813 // ends with whitespace.
4814 // (c) the min/max width of the string (trimmed for whitespace).
4815 //
4816 // If the text string starts with whitespace, then we need to go ahead and
4817 // terminate our current line (unless we're already in a whitespace stripping
4818 // mode.
4819 //
4820 // If the text string has a breakable character in the middle, but didn't start
4821 // with whitespace, then we add the width of the first non-breakable run and
4822 // then end the current line. We then need to use the intermediate min/max width
4823 // values (if any of them are larger than our current min/max). We then look at
4824 // the width of the last non-breakable run and use that to start a new line
4825 // (unless we end in whitespace).
4826 RenderStyle* cstyle = child->style();
4827 float childMin = 0;
4828 float childMax = 0;
4829
4830 if (!child->isText()) {
4831 // Case (1) and (2). Inline replaced and inline flow elements.
4832 if (child->isRenderInline()) {
4833 // Add in padding/border/margin from the appropriate side of
4834 // the element.
4835 float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
4836 childMin += bpm;
4837 childMax += bpm;
4838
4839 inlineMin += childMin;
4840 inlineMax += childMax;
4841
4842 child->setPreferredLogicalWidthsDirty(false);
4843 } else {
4844 // Inline replaced elts add in their margins to their min/max values.
4845 float margins = 0;
4846 Length startMargin = cstyle->marginStart();
4847 Length endMargin = cstyle->marginEnd();
4848 if (startMargin.isFixed())
4849 margins += startMargin.value();
4850 if (endMargin.isFixed())
4851 margins += endMargin.value();
4852 childMin += margins;
4853 childMax += margins;
4854 }
4855 }
4856
4857 if (!child->isRenderInline() && !child->isText()) {
4858 // Case (2). Inline replaced elements and floats.
4859 // Go ahead and terminate the current line as far as
4860 // minwidth is concerned.
4861 childMin += child->minPreferredLogicalWidth();
4862 childMax += child->maxPreferredLogicalWidth();
4863
4864 bool clearPreviousFloat;
4865 if (child->isFloating()) {
4866 clearPreviousFloat = (prevFloat
4867 && ((prevFloat->style()->floating() == FLEFT && (child->style()->clear() & CLEFT))
4868 || (prevFloat->style()->floating() == FRIGHT && (child->style()->clear() & CRIGHT))));
4869 prevFloat = child;
4870 } else
4871 clearPreviousFloat = false;
4872
4873 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4874 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap)) || clearPreviousFloat) {
4875 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4876 inlineMin = 0;
4877 }
4878
4879 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4880 if (clearPreviousFloat) {
4881 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
4882 inlineMax = 0;
4883 }
4884
4885 // Add in text-indent. This is added in only once.
4886 int ti = 0;
4887 if (!addedTextIndent) {
4888 addedTextIndent = true;
4889 ti = style()->textIndent().calcMinValue(cw);
4890 childMin += ti;
4891 childMax += ti;
4892 }
4893
4894 // Add our width to the max.
4895 inlineMax += childMax;
4896
4897 if (!autoWrap || !canBreakReplacedElement) {
4898 if (child->isFloating())
4899 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
4900 else
4901 inlineMin += childMin;
4902 } else {
4903 // Now check our line.
4904 updatePreferredWidth(m_minPreferredLogicalWidth, childMin);
4905
4906 // Now start a new line.
4907 inlineMin = 0;
4908 }
4909
4910 // We are no longer stripping whitespace at the start of
4911 // a line.
4912 if (!child->isFloating()) {
4913 stripFrontSpaces = false;
4914 trailingSpaceChild = 0;
4915 }
4916 } else if (child->isText()) {
4917 // Case (3). Text.
4918 RenderText* t = toRenderText(child);
4919
4920 if (t->isWordBreak()) {
4921 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4922 inlineMin = 0;
4923 continue;
4924 }
4925
4926 if (t->style()->hasTextCombine() && t->isCombineText())
4927 toRenderCombineText(t)->combineText();
4928
4929 // Determine if we have a breakable character. Pass in
4930 // whether or not we should ignore any spaces at the front
4931 // of the string. If those are going to be stripped out,
4932 // then they shouldn't be considered in the breakable char
4933 // check.
4934 bool hasBreakableChar, hasBreak;
4935 float beginMin, endMin;
4936 bool beginWS, endWS;
4937 float beginMax, endMax;
4938 t->trimmedPrefWidths(inlineMax, beginMin, beginWS, endMin, endWS,
4939 hasBreakableChar, hasBreak, beginMax, endMax,
4940 childMin, childMax, stripFrontSpaces);
4941
4942 // This text object will not be rendered, but it may still provide a breaking opportunity.
4943 if (!hasBreak && childMax == 0) {
4944 if (autoWrap && (beginWS || endWS)) {
4945 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4946 inlineMin = 0;
4947 }
4948 continue;
4949 }
4950
4951 if (stripFrontSpaces)
4952 trailingSpaceChild = child;
4953 else
4954 trailingSpaceChild = 0;
4955
4956 // Add in text-indent. This is added in only once.
4957 int ti = 0;
4958 if (!addedTextIndent) {
4959 addedTextIndent = true;
4960 ti = style()->textIndent().calcMinValue(cw);
4961 childMin+=ti; beginMin += ti;
4962 childMax+=ti; beginMax += ti;
4963 }
4964
4965 // If we have no breakable characters at all,
4966 // then this is the easy case. We add ourselves to the current
4967 // min and max and continue.
4968 if (!hasBreakableChar) {
4969 inlineMin += childMin;
4970 } else {
4971 // We have a breakable character. Now we need to know if
4972 // we start and end with whitespace.
4973 if (beginWS)
4974 // Go ahead and end the current line.
4975 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4976 else {
4977 inlineMin += beginMin;
4978 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4979 childMin -= ti;
4980 }
4981
4982 inlineMin = childMin;
4983
4984 if (endWS) {
4985 // We end in whitespace, which means we can go ahead
4986 // and end our current line.
4987 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4988 inlineMin = 0;
4989 } else {
4990 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
4991 inlineMin = endMin;
4992 }
4993 }
4994
4995 if (hasBreak) {
4996 inlineMax += beginMax;
4997 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
4998 updatePreferredWidth(m_maxPreferredLogicalWidth, childMax);
4999 inlineMax = endMax;
5000 } else
5001 inlineMax += childMax;
5002 }
5003
5004 // Ignore spaces after a list marker.
5005 if (child->isListMarker())
5006 stripFrontSpaces = true;
5007 } else {
5008 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5009 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5010 inlineMin = inlineMax = 0;
5011 stripFrontSpaces = true;
5012 trailingSpaceChild = 0;
5013 }
5014
5015 oldAutoWrap = autoWrap;
5016 }
5017
5018 if (style()->collapseWhiteSpace())
5019 stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
5020
5021 updatePreferredWidth(m_minPreferredLogicalWidth, inlineMin);
5022 updatePreferredWidth(m_maxPreferredLogicalWidth, inlineMax);
5023 }
5024
5025 // Use a very large value (in effect infinite).
5026 #define BLOCK_MAX_WIDTH 15000
5027
computeBlockPreferredLogicalWidths()5028 void RenderBlock::computeBlockPreferredLogicalWidths()
5029 {
5030 bool nowrap = style()->whiteSpace() == NOWRAP;
5031
5032 RenderObject *child = firstChild();
5033 int floatLeftWidth = 0, floatRightWidth = 0;
5034 while (child) {
5035 // Positioned children don't affect the min/max width
5036 if (child->isPositioned()) {
5037 child = child->nextSibling();
5038 continue;
5039 }
5040
5041 if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
5042 int floatTotalWidth = floatLeftWidth + floatRightWidth;
5043 if (child->style()->clear() & CLEFT) {
5044 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5045 floatLeftWidth = 0;
5046 }
5047 if (child->style()->clear() & CRIGHT) {
5048 m_maxPreferredLogicalWidth = max(floatTotalWidth, m_maxPreferredLogicalWidth);
5049 floatRightWidth = 0;
5050 }
5051 }
5052
5053 // A margin basically has three types: fixed, percentage, and auto (variable).
5054 // Auto and percentage margins simply become 0 when computing min/max width.
5055 // Fixed margins can be added in as is.
5056 Length startMarginLength = child->style()->marginStart();
5057 Length endMarginLength = child->style()->marginEnd();
5058 int margin = 0;
5059 int marginStart = 0;
5060 int marginEnd = 0;
5061 if (startMarginLength.isFixed())
5062 marginStart += startMarginLength.value();
5063 if (endMarginLength.isFixed())
5064 marginEnd += endMarginLength.value();
5065 margin = marginStart + marginEnd;
5066
5067 int w = child->minPreferredLogicalWidth() + margin;
5068 m_minPreferredLogicalWidth = max(w, m_minPreferredLogicalWidth);
5069
5070 // IE ignores tables for calculation of nowrap. Makes some sense.
5071 if (nowrap && !child->isTable())
5072 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
5073
5074 w = child->maxPreferredLogicalWidth() + margin;
5075
5076 if (!child->isFloating()) {
5077 if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
5078 // Determine a left and right max value based off whether or not the floats can fit in the
5079 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
5080 // is smaller than the float width.
5081 bool ltr = containingBlock()->style()->isLeftToRightDirection();
5082 int marginLogicalLeft = ltr ? marginStart : marginEnd;
5083 int marginLogicalRight = ltr ? marginEnd : marginStart;
5084 int maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
5085 int maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
5086 w = child->maxPreferredLogicalWidth() + maxLeft + maxRight;
5087 w = max(w, floatLeftWidth + floatRightWidth);
5088 }
5089 else
5090 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
5091 floatLeftWidth = floatRightWidth = 0;
5092 }
5093
5094 if (child->isFloating()) {
5095 if (style()->floating() == FLEFT)
5096 floatLeftWidth += w;
5097 else
5098 floatRightWidth += w;
5099 } else
5100 m_maxPreferredLogicalWidth = max(w, m_maxPreferredLogicalWidth);
5101
5102 // A very specific WinIE quirk.
5103 // Example:
5104 /*
5105 <div style="position:absolute; width:100px; top:50px;">
5106 <div style="position:absolute;left:0px;top:50px;height:50px;background-color:green">
5107 <table style="width:100%"><tr><td></table>
5108 </div>
5109 </div>
5110 */
5111 // In the above example, the inner absolute positioned block should have a computed width
5112 // of 100px because of the table.
5113 // We can achieve this effect by making the maxwidth of blocks that contain tables
5114 // with percentage widths be infinite (as long as they are not inside a table cell).
5115 if (document()->inQuirksMode() && child->style()->logicalWidth().isPercent() &&
5116 !isTableCell() && child->isTable() && m_maxPreferredLogicalWidth < BLOCK_MAX_WIDTH) {
5117 RenderBlock* cb = containingBlock();
5118 while (!cb->isRenderView() && !cb->isTableCell())
5119 cb = cb->containingBlock();
5120 if (!cb->isTableCell())
5121 m_maxPreferredLogicalWidth = BLOCK_MAX_WIDTH;
5122 }
5123
5124 child = child->nextSibling();
5125 }
5126
5127 // Always make sure these values are non-negative.
5128 m_minPreferredLogicalWidth = max(0, m_minPreferredLogicalWidth);
5129 m_maxPreferredLogicalWidth = max(0, m_maxPreferredLogicalWidth);
5130
5131 m_maxPreferredLogicalWidth = max(floatLeftWidth + floatRightWidth, m_maxPreferredLogicalWidth);
5132 }
5133
hasLineIfEmpty() const5134 bool RenderBlock::hasLineIfEmpty() const
5135 {
5136 if (!node())
5137 return false;
5138
5139 if (node()->rendererIsEditable() && node()->rootEditableElement() == node())
5140 return true;
5141
5142 if (node()->isShadowRoot() && (node()->shadowHost()->hasTagName(inputTag)))
5143 return true;
5144
5145 return false;
5146 }
5147
lineHeight(bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const5148 int RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
5149 {
5150 // Inline blocks are replaced elements. Otherwise, just pass off to
5151 // the base class. If we're being queried as though we're the root line
5152 // box, then the fact that we're an inline-block is irrelevant, and we behave
5153 // just like a block.
5154 if (isReplaced() && linePositionMode == PositionOnContainingLine)
5155 return RenderBox::lineHeight(firstLine, direction, linePositionMode);
5156
5157 if (firstLine && document()->usesFirstLineRules()) {
5158 RenderStyle* s = style(firstLine);
5159 if (s != style())
5160 return s->computedLineHeight();
5161 }
5162
5163 if (m_lineHeight == -1)
5164 m_lineHeight = style()->computedLineHeight();
5165
5166 return m_lineHeight;
5167 }
5168
baselinePosition(FontBaseline baselineType,bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const5169 int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
5170 {
5171 // Inline blocks are replaced elements. Otherwise, just pass off to
5172 // the base class. If we're being queried as though we're the root line
5173 // box, then the fact that we're an inline-block is irrelevant, and we behave
5174 // just like a block.
5175 if (isReplaced() && linePositionMode == PositionOnContainingLine) {
5176 // For "leaf" theme objects, let the theme decide what the baseline position is.
5177 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
5178 // is turned off, checkboxes/radios will still have decent baselines.
5179 // FIXME: Need to patch form controls to deal with vertical lines.
5180 if (style()->hasAppearance() && !theme()->isControlContainer(style()->appearance()))
5181 return theme()->baselinePosition(this);
5182
5183 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
5184 // the normal flow. We make an exception for marquees, since their baselines are meaningless
5185 // (the content inside them moves). This matches WinIE as well, which just bottom-aligns them.
5186 // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
5187 // vertically (e.g., an overflow:hidden block that has had scrollTop moved) or if the baseline is outside
5188 // of our content box.
5189 bool ignoreBaseline = (layer() && (layer()->marquee() || (direction == HorizontalLine ? (layer()->verticalScrollbar() || layer()->scrollYOffset() != 0)
5190 : (layer()->horizontalScrollbar() || layer()->scrollXOffset() != 0)))) || (isWritingModeRoot() && !isRubyRun());
5191
5192 int baselinePos = ignoreBaseline ? -1 : lastLineBoxBaseline();
5193
5194 int bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
5195 if (baselinePos != -1 && baselinePos <= bottomOfContent)
5196 return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
5197
5198 return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
5199 }
5200
5201 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
5202 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
5203 }
5204
firstLineBoxBaseline() const5205 int RenderBlock::firstLineBoxBaseline() const
5206 {
5207 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
5208 return -1;
5209
5210 if (childrenInline()) {
5211 if (firstLineBox())
5212 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
5213 else
5214 return -1;
5215 }
5216 else {
5217 for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
5218 if (!curr->isFloatingOrPositioned()) {
5219 int result = curr->firstLineBoxBaseline();
5220 if (result != -1)
5221 return curr->logicalTop() + result; // Translate to our coordinate space.
5222 }
5223 }
5224 }
5225
5226 return -1;
5227 }
5228
lastLineBoxBaseline() const5229 int RenderBlock::lastLineBoxBaseline() const
5230 {
5231 if (!isBlockFlow() || (isWritingModeRoot() && !isRubyRun()))
5232 return -1;
5233
5234 LineDirectionMode lineDirection = isHorizontalWritingMode() ? HorizontalLine : VerticalLine;
5235
5236 if (childrenInline()) {
5237 if (!firstLineBox() && hasLineIfEmpty()) {
5238 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
5239 return fontMetrics.ascent()
5240 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
5241 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
5242 }
5243 if (lastLineBox())
5244 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
5245 return -1;
5246 } else {
5247 bool haveNormalFlowChild = false;
5248 for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
5249 if (!curr->isFloatingOrPositioned()) {
5250 haveNormalFlowChild = true;
5251 int result = curr->lastLineBoxBaseline();
5252 if (result != -1)
5253 return curr->logicalTop() + result; // Translate to our coordinate space.
5254 }
5255 }
5256 if (!haveNormalFlowChild && hasLineIfEmpty()) {
5257 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
5258 return fontMetrics.ascent()
5259 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
5260 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
5261 }
5262 }
5263
5264 return -1;
5265 }
5266
containsNonZeroBidiLevel() const5267 bool RenderBlock::containsNonZeroBidiLevel() const
5268 {
5269 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
5270 for (InlineBox* box = root->firstLeafChild(); box; box = box->nextLeafChild()) {
5271 if (box->bidiLevel())
5272 return true;
5273 }
5274 }
5275 return false;
5276 }
5277
firstLineBlock() const5278 RenderBlock* RenderBlock::firstLineBlock() const
5279 {
5280 RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
5281 bool hasPseudo = false;
5282 while (true) {
5283 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
5284 if (hasPseudo)
5285 break;
5286 RenderObject* parentBlock = firstLineBlock->parent();
5287 if (firstLineBlock->isReplaced() || firstLineBlock->isFloating() ||
5288 !parentBlock || parentBlock->firstChild() != firstLineBlock || !parentBlock->isBlockFlow())
5289 break;
5290 ASSERT(parentBlock->isRenderBlock());
5291 firstLineBlock = toRenderBlock(parentBlock);
5292 }
5293
5294 if (!hasPseudo)
5295 return 0;
5296
5297 return firstLineBlock;
5298 }
5299
styleForFirstLetter(RenderObject * firstLetterBlock,RenderObject * firstLetterContainer)5300 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
5301 {
5302 RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
5303 // Force inline display (except for floating first-letters).
5304 pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
5305 // CSS2 says first-letter can't be positioned.
5306 pseudoStyle->setPosition(StaticPosition);
5307 return pseudoStyle;
5308 }
5309
5310 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
5311 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
5312 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
isPunctuationForFirstLetter(UChar c)5313 static inline bool isPunctuationForFirstLetter(UChar c)
5314 {
5315 CharCategory charCategory = category(c);
5316 return charCategory == Punctuation_Open
5317 || charCategory == Punctuation_Close
5318 || charCategory == Punctuation_InitialQuote
5319 || charCategory == Punctuation_FinalQuote
5320 || charCategory == Punctuation_Other;
5321 }
5322
shouldSkipForFirstLetter(UChar c)5323 static inline bool shouldSkipForFirstLetter(UChar c)
5324 {
5325 return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
5326 }
5327
updateFirstLetter()5328 void RenderBlock::updateFirstLetter()
5329 {
5330 if (!document()->usesFirstLetterRules())
5331 return;
5332 // Don't recur
5333 if (style()->styleType() == FIRST_LETTER)
5334 return;
5335
5336 // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
5337 // an efficient way to check for that situation though before implementing anything.
5338 RenderObject* firstLetterBlock = this;
5339 bool hasPseudoStyle = false;
5340 while (true) {
5341 // We only honor first-letter if the firstLetterBlock can have children in the DOM. This correctly
5342 // prevents form controls from honoring first-letter.
5343 hasPseudoStyle = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
5344 && firstLetterBlock->canHaveChildren();
5345 if (hasPseudoStyle)
5346 break;
5347 RenderObject* parentBlock = firstLetterBlock->parent();
5348 if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
5349 !parentBlock->isBlockFlow())
5350 break;
5351 firstLetterBlock = parentBlock;
5352 }
5353
5354 if (!hasPseudoStyle)
5355 return;
5356
5357 // Drill into inlines looking for our first text child.
5358 RenderObject* currChild = firstLetterBlock->firstChild();
5359 while (currChild && ((!currChild->isReplaced() && !currChild->isRenderButton() && !currChild->isMenuList()) || currChild->isFloatingOrPositioned()) && !currChild->isText()) {
5360 if (currChild->isFloatingOrPositioned()) {
5361 if (currChild->style()->styleType() == FIRST_LETTER) {
5362 currChild = currChild->firstChild();
5363 break;
5364 }
5365 currChild = currChild->nextSibling();
5366 } else
5367 currChild = currChild->firstChild();
5368 }
5369
5370 // Get list markers out of the way.
5371 while (currChild && currChild->isListMarker())
5372 currChild = currChild->nextSibling();
5373
5374 if (!currChild)
5375 return;
5376
5377 // If the child already has style, then it has already been created, so we just want
5378 // to update it.
5379 if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
5380 RenderObject* firstLetter = currChild->parent();
5381 RenderObject* firstLetterContainer = firstLetter->parent();
5382 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
5383
5384 if (Node::diff(firstLetter->style(), pseudoStyle) == Node::Detach) {
5385 // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
5386 RenderObject* newFirstLetter;
5387 if (pseudoStyle->display() == INLINE)
5388 newFirstLetter = new (renderArena()) RenderInline(document());
5389 else
5390 newFirstLetter = new (renderArena()) RenderBlock(document());
5391 newFirstLetter->setStyle(pseudoStyle);
5392
5393 // Move the first letter into the new renderer.
5394 view()->disableLayoutState();
5395 while (RenderObject* child = firstLetter->firstChild()) {
5396 if (child->isText())
5397 toRenderText(child)->removeAndDestroyTextBoxes();
5398 firstLetter->removeChild(child);
5399 newFirstLetter->addChild(child, 0);
5400 }
5401
5402 RenderTextFragment* remainingText = 0;
5403 RenderObject* nextSibling = firstLetter->nextSibling();
5404 RenderObject* next = nextSibling;
5405 while (next) {
5406 if (next->isText() && toRenderText(next)->isTextFragment()) {
5407 remainingText = toRenderTextFragment(next);
5408 break;
5409 }
5410 next = next->nextSibling();
5411 }
5412 if (remainingText) {
5413 ASSERT(remainingText->node()->renderer() == remainingText);
5414 // Replace the old renderer with the new one.
5415 remainingText->setFirstLetter(newFirstLetter);
5416 }
5417 firstLetter->destroy();
5418 firstLetter = newFirstLetter;
5419 firstLetterContainer->addChild(firstLetter, nextSibling);
5420 view()->enableLayoutState();
5421 } else
5422 firstLetter->setStyle(pseudoStyle);
5423
5424 for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
5425 if (genChild->isText())
5426 genChild->setStyle(pseudoStyle);
5427 }
5428
5429 return;
5430 }
5431
5432 if (!currChild->isText() || currChild->isBR())
5433 return;
5434
5435 // If the child does not already have style, we create it here.
5436 RenderObject* firstLetterContainer = currChild->parent();
5437
5438 // Our layout state is not valid for the repaints we are going to trigger by
5439 // adding and removing children of firstLetterContainer.
5440 view()->disableLayoutState();
5441
5442 RenderText* textObj = toRenderText(currChild);
5443
5444 // Create our pseudo style now that we have our firstLetterContainer determined.
5445 RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
5446
5447 RenderObject* firstLetter = 0;
5448 if (pseudoStyle->display() == INLINE)
5449 firstLetter = new (renderArena()) RenderInline(document());
5450 else
5451 firstLetter = new (renderArena()) RenderBlock(document());
5452 firstLetter->setStyle(pseudoStyle);
5453 firstLetterContainer->addChild(firstLetter, currChild);
5454
5455 // The original string is going to be either a generated content string or a DOM node's
5456 // string. We want the original string before it got transformed in case first-letter has
5457 // no text-transform or a different text-transform applied to it.
5458 RefPtr<StringImpl> oldText = textObj->originalText();
5459 ASSERT(oldText);
5460
5461 if (oldText && oldText->length() > 0) {
5462 unsigned length = 0;
5463
5464 // Account for leading spaces and punctuation.
5465 while (length < oldText->length() && shouldSkipForFirstLetter((*oldText)[length]))
5466 length++;
5467
5468 // Account for first letter.
5469 length++;
5470
5471 // Keep looking for whitespace and allowed punctuation, but avoid
5472 // accumulating just whitespace into the :first-letter.
5473 for (unsigned scanLength = length; scanLength < oldText->length(); ++scanLength) {
5474 UChar c = (*oldText)[scanLength];
5475
5476 if (!shouldSkipForFirstLetter(c))
5477 break;
5478
5479 if (isPunctuationForFirstLetter(c))
5480 length = scanLength + 1;
5481 }
5482
5483 // Construct a text fragment for the text after the first letter.
5484 // This text fragment might be empty.
5485 RenderTextFragment* remainingText =
5486 new (renderArena()) RenderTextFragment(textObj->node() ? textObj->node() : textObj->document(), oldText.get(), length, oldText->length() - length);
5487 remainingText->setStyle(textObj->style());
5488 if (remainingText->node())
5489 remainingText->node()->setRenderer(remainingText);
5490
5491 firstLetterContainer->addChild(remainingText, textObj);
5492 firstLetterContainer->removeChild(textObj);
5493 remainingText->setFirstLetter(firstLetter);
5494
5495 // construct text fragment for the first letter
5496 RenderTextFragment* letter =
5497 new (renderArena()) RenderTextFragment(remainingText->node() ? remainingText->node() : remainingText->document(), oldText.get(), 0, length);
5498 letter->setStyle(pseudoStyle);
5499 firstLetter->addChild(letter);
5500
5501 textObj->destroy();
5502 }
5503 view()->enableLayoutState();
5504 }
5505
5506 // Helper methods for obtaining the last line, computing line counts and heights for line counts
5507 // (crawling into blocks).
shouldCheckLines(RenderObject * obj)5508 static bool shouldCheckLines(RenderObject* obj)
5509 {
5510 return !obj->isFloatingOrPositioned() && !obj->isRunIn() &&
5511 obj->isBlockFlow() && obj->style()->height().isAuto() &&
5512 (!obj->isFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
5513 }
5514
getLineAtIndex(RenderBlock * block,int i,int & count)5515 static RootInlineBox* getLineAtIndex(RenderBlock* block, int i, int& count)
5516 {
5517 if (block->style()->visibility() == VISIBLE) {
5518 if (block->childrenInline()) {
5519 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
5520 if (count++ == i)
5521 return box;
5522 }
5523 }
5524 else {
5525 for (RenderObject* obj = block->firstChild(); obj; obj = obj->nextSibling()) {
5526 if (shouldCheckLines(obj)) {
5527 RootInlineBox *box = getLineAtIndex(toRenderBlock(obj), i, count);
5528 if (box)
5529 return box;
5530 }
5531 }
5532 }
5533 }
5534 return 0;
5535 }
5536
getHeightForLineCount(RenderBlock * block,int l,bool includeBottom,int & count)5537 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
5538 {
5539 if (block->style()->visibility() == VISIBLE) {
5540 if (block->childrenInline()) {
5541 for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
5542 if (++count == l)
5543 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
5544 }
5545 }
5546 else {
5547 RenderBox* normalFlowChildWithoutLines = 0;
5548 for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
5549 if (shouldCheckLines(obj)) {
5550 int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
5551 if (result != -1)
5552 return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : 0);
5553 }
5554 else if (!obj->isFloatingOrPositioned() && !obj->isRunIn())
5555 normalFlowChildWithoutLines = obj;
5556 }
5557 if (normalFlowChildWithoutLines && l == 0)
5558 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
5559 }
5560 }
5561
5562 return -1;
5563 }
5564
lineAtIndex(int i)5565 RootInlineBox* RenderBlock::lineAtIndex(int i)
5566 {
5567 int count = 0;
5568 return getLineAtIndex(this, i, count);
5569 }
5570
lineCount()5571 int RenderBlock::lineCount()
5572 {
5573 int count = 0;
5574 if (style()->visibility() == VISIBLE) {
5575 if (childrenInline())
5576 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
5577 count++;
5578 else
5579 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
5580 if (shouldCheckLines(obj))
5581 count += toRenderBlock(obj)->lineCount();
5582 }
5583 return count;
5584 }
5585
heightForLineCount(int l)5586 int RenderBlock::heightForLineCount(int l)
5587 {
5588 int count = 0;
5589 return getHeightForLineCount(this, l, true, count);
5590 }
5591
adjustForBorderFit(int x,int & left,int & right) const5592 void RenderBlock::adjustForBorderFit(int x, int& left, int& right) const
5593 {
5594 // We don't deal with relative positioning. Our assumption is that you shrink to fit the lines without accounting
5595 // for either overflow or translations via relative positioning.
5596 if (style()->visibility() == VISIBLE) {
5597 if (childrenInline()) {
5598 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
5599 if (box->firstChild())
5600 left = min(left, x + static_cast<int>(box->firstChild()->x()));
5601 if (box->lastChild())
5602 right = max(right, x + static_cast<int>(ceilf(box->lastChild()->logicalRight())));
5603 }
5604 }
5605 else {
5606 for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
5607 if (!obj->isFloatingOrPositioned()) {
5608 if (obj->isBlockFlow() && !obj->hasOverflowClip())
5609 toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
5610 else if (obj->style()->visibility() == VISIBLE) {
5611 // We are a replaced element or some kind of non-block-flow object.
5612 left = min(left, x + obj->x());
5613 right = max(right, x + obj->x() + obj->width());
5614 }
5615 }
5616 }
5617 }
5618
5619 if (m_floatingObjects) {
5620 FloatingObjectSet& floatingObjectSet = m_floatingObjects->set();
5621 FloatingObjectSetIterator end = floatingObjectSet.end();
5622 for (FloatingObjectSetIterator it = floatingObjectSet.begin(); it != end; ++it) {
5623 FloatingObject* r = *it;
5624 // Only examine the object if our m_shouldPaint flag is set.
5625 if (r->m_shouldPaint) {
5626 int floatLeft = xPositionForFloatIncludingMargin(r) - r->m_renderer->x();
5627 int floatRight = floatLeft + r->m_renderer->width();
5628 left = min(left, floatLeft);
5629 right = max(right, floatRight);
5630 }
5631 }
5632 }
5633 }
5634 }
5635
borderFitAdjust(int & x,int & w) const5636 void RenderBlock::borderFitAdjust(int& x, int& w) const
5637 {
5638 if (style()->borderFit() == BorderFitBorder)
5639 return;
5640
5641 // Walk any normal flow lines to snugly fit.
5642 int left = INT_MAX;
5643 int right = INT_MIN;
5644 int oldWidth = w;
5645 adjustForBorderFit(0, left, right);
5646 if (left != INT_MAX) {
5647 left -= (borderLeft() + paddingLeft());
5648 if (left > 0) {
5649 x += left;
5650 w -= left;
5651 }
5652 }
5653 if (right != INT_MIN) {
5654 right += (borderRight() + paddingRight());
5655 if (right < oldWidth)
5656 w -= (oldWidth - right);
5657 }
5658 }
5659
clearTruncation()5660 void RenderBlock::clearTruncation()
5661 {
5662 if (style()->visibility() == VISIBLE) {
5663 if (childrenInline() && hasMarkupTruncation()) {
5664 setHasMarkupTruncation(false);
5665 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
5666 box->clearTruncation();
5667 }
5668 else
5669 for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
5670 if (shouldCheckLines(obj))
5671 toRenderBlock(obj)->clearTruncation();
5672 }
5673 }
5674
setMaxMarginBeforeValues(int pos,int neg)5675 void RenderBlock::setMaxMarginBeforeValues(int pos, int neg)
5676 {
5677 if (!m_rareData) {
5678 if (pos == RenderBlockRareData::positiveMarginBeforeDefault(this) && neg == RenderBlockRareData::negativeMarginBeforeDefault(this))
5679 return;
5680 m_rareData = new RenderBlockRareData(this);
5681 }
5682 m_rareData->m_margins.setPositiveMarginBefore(pos);
5683 m_rareData->m_margins.setNegativeMarginBefore(neg);
5684 }
5685
setMaxMarginAfterValues(int pos,int neg)5686 void RenderBlock::setMaxMarginAfterValues(int pos, int neg)
5687 {
5688 if (!m_rareData) {
5689 if (pos == RenderBlockRareData::positiveMarginAfterDefault(this) && neg == RenderBlockRareData::negativeMarginAfterDefault(this))
5690 return;
5691 m_rareData = new RenderBlockRareData(this);
5692 }
5693 m_rareData->m_margins.setPositiveMarginAfter(pos);
5694 m_rareData->m_margins.setNegativeMarginAfter(neg);
5695 }
5696
setPaginationStrut(int strut)5697 void RenderBlock::setPaginationStrut(int strut)
5698 {
5699 if (!m_rareData) {
5700 if (!strut)
5701 return;
5702 m_rareData = new RenderBlockRareData(this);
5703 }
5704 m_rareData->m_paginationStrut = strut;
5705 }
5706
setPageLogicalOffset(int logicalOffset)5707 void RenderBlock::setPageLogicalOffset(int logicalOffset)
5708 {
5709 if (!m_rareData) {
5710 if (!logicalOffset)
5711 return;
5712 m_rareData = new RenderBlockRareData(this);
5713 }
5714 m_rareData->m_pageLogicalOffset = logicalOffset;
5715 }
5716
absoluteRects(Vector<IntRect> & rects,int tx,int ty)5717 void RenderBlock::absoluteRects(Vector<IntRect>& rects, int tx, int ty)
5718 {
5719 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5720 // inline boxes above and below us (thus getting merged with them to form a single irregular
5721 // shape).
5722 if (isAnonymousBlockContinuation()) {
5723 // FIXME: This is wrong for block-flows that are horizontal.
5724 // https://bugs.webkit.org/show_bug.cgi?id=46781
5725 rects.append(IntRect(tx, ty - collapsedMarginBefore(),
5726 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
5727 continuation()->absoluteRects(rects,
5728 tx - x() + inlineElementContinuation()->containingBlock()->x(),
5729 ty - y() + inlineElementContinuation()->containingBlock()->y());
5730 } else
5731 rects.append(IntRect(tx, ty, width(), height()));
5732 }
5733
absoluteQuads(Vector<FloatQuad> & quads)5734 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads)
5735 {
5736 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5737 // inline boxes above and below us (thus getting merged with them to form a single irregular
5738 // shape).
5739 if (isAnonymousBlockContinuation()) {
5740 // FIXME: This is wrong for block-flows that are horizontal.
5741 // https://bugs.webkit.org/show_bug.cgi?id=46781
5742 FloatRect localRect(0, -collapsedMarginBefore(),
5743 width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
5744 quads.append(localToAbsoluteQuad(localRect));
5745 continuation()->absoluteQuads(quads);
5746 } else
5747 quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height())));
5748 }
5749
rectWithOutlineForRepaint(RenderBoxModelObject * repaintContainer,int outlineWidth)5750 IntRect RenderBlock::rectWithOutlineForRepaint(RenderBoxModelObject* repaintContainer, int outlineWidth)
5751 {
5752 IntRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
5753 if (isAnonymousBlockContinuation())
5754 r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
5755 return r;
5756 }
5757
hoverAncestor() const5758 RenderObject* RenderBlock::hoverAncestor() const
5759 {
5760 return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
5761 }
5762
updateDragState(bool dragOn)5763 void RenderBlock::updateDragState(bool dragOn)
5764 {
5765 RenderBox::updateDragState(dragOn);
5766 if (continuation())
5767 continuation()->updateDragState(dragOn);
5768 }
5769
outlineStyleForRepaint() const5770 RenderStyle* RenderBlock::outlineStyleForRepaint() const
5771 {
5772 return isAnonymousBlockContinuation() ? continuation()->style() : style();
5773 }
5774
childBecameNonInline(RenderObject *)5775 void RenderBlock::childBecameNonInline(RenderObject*)
5776 {
5777 makeChildrenNonInline();
5778 if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
5779 toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
5780 // |this| may be dead here
5781 }
5782
updateHitTestResult(HitTestResult & result,const IntPoint & point)5783 void RenderBlock::updateHitTestResult(HitTestResult& result, const IntPoint& point)
5784 {
5785 if (result.innerNode())
5786 return;
5787
5788 Node* n = node();
5789 if (isAnonymousBlockContinuation())
5790 // We are in the margins of block elements that are part of a continuation. In
5791 // this case we're actually still inside the enclosing element that was
5792 // split. Go ahead and set our inner node accordingly.
5793 n = continuation()->node();
5794
5795 if (n) {
5796 result.setInnerNode(n);
5797 if (!result.innerNonSharedNode())
5798 result.setInnerNonSharedNode(n);
5799 result.setLocalPoint(point);
5800 }
5801 }
5802
localCaretRect(InlineBox * inlineBox,int caretOffset,int * extraWidthToEndOfLine)5803 IntRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, int* extraWidthToEndOfLine)
5804 {
5805 // Do the normal calculation in most cases.
5806 if (firstChild())
5807 return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
5808
5809 // This is a special case:
5810 // The element is not an inline element, and it's empty. So we have to
5811 // calculate a fake position to indicate where objects are to be inserted.
5812
5813 // FIXME: This does not take into account either :first-line or :first-letter
5814 // However, as soon as some content is entered, the line boxes will be
5815 // constructed and this kludge is not called any more. So only the caret size
5816 // of an empty :first-line'd block is wrong. I think we can live with that.
5817 RenderStyle* currentStyle = firstLineStyle();
5818 int height = lineHeight(true, currentStyle->isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
5819
5820 enum CaretAlignment { alignLeft, alignRight, alignCenter };
5821
5822 CaretAlignment alignment = alignLeft;
5823
5824 switch (currentStyle->textAlign()) {
5825 case TAAUTO:
5826 case JUSTIFY:
5827 if (!currentStyle->isLeftToRightDirection())
5828 alignment = alignRight;
5829 break;
5830 case LEFT:
5831 case WEBKIT_LEFT:
5832 break;
5833 case CENTER:
5834 case WEBKIT_CENTER:
5835 alignment = alignCenter;
5836 break;
5837 case RIGHT:
5838 case WEBKIT_RIGHT:
5839 alignment = alignRight;
5840 break;
5841 case TASTART:
5842 if (!currentStyle->isLeftToRightDirection())
5843 alignment = alignRight;
5844 break;
5845 case TAEND:
5846 if (currentStyle->isLeftToRightDirection())
5847 alignment = alignRight;
5848 break;
5849 }
5850
5851 int x = borderLeft() + paddingLeft();
5852 int w = width();
5853
5854 switch (alignment) {
5855 case alignLeft:
5856 break;
5857 case alignCenter:
5858 x = (x + w - (borderRight() + paddingRight())) / 2;
5859 break;
5860 case alignRight:
5861 x = w - (borderRight() + paddingRight()) - caretWidth;
5862 break;
5863 }
5864
5865 if (extraWidthToEndOfLine) {
5866 if (isRenderBlock()) {
5867 *extraWidthToEndOfLine = w - (x + caretWidth);
5868 } else {
5869 // FIXME: This code looks wrong.
5870 // myRight and containerRight are set up, but then clobbered.
5871 // So *extraWidthToEndOfLine will always be 0 here.
5872
5873 int myRight = x + caretWidth;
5874 // FIXME: why call localToAbsoluteForContent() twice here, too?
5875 FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
5876
5877 int containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
5878 FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
5879
5880 *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
5881 }
5882 }
5883
5884 int y = paddingTop() + borderTop();
5885
5886 return IntRect(x, y, caretWidth, height);
5887 }
5888
addFocusRingRects(Vector<IntRect> & rects,int tx,int ty)5889 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, int tx, int ty)
5890 {
5891 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5892 // inline boxes above and below us (thus getting merged with them to form a single irregular
5893 // shape).
5894 if (inlineElementContinuation()) {
5895 // FIXME: This check really isn't accurate.
5896 bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
5897 // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
5898 // FIXME: This is wrong for block-flows that are horizontal.
5899 // https://bugs.webkit.org/show_bug.cgi?id=46781
5900 bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
5901 int topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : 0;
5902 int bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : 0;
5903 IntRect rect(tx, ty - topMargin, width(), height() + topMargin + bottomMargin);
5904 if (!rect.isEmpty())
5905 rects.append(rect);
5906 } else if (width() && height())
5907 rects.append(IntRect(tx, ty, width(), height()));
5908
5909 if (!hasOverflowClip() && !hasControlClip()) {
5910 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5911 int top = max(curr->lineTop(), curr->logicalTop());
5912 int bottom = min(curr->lineBottom(), curr->logicalTop() + curr->logicalHeight());
5913 IntRect rect(tx + curr->x(), ty + top, curr->logicalWidth(), bottom - top);
5914 if (!rect.isEmpty())
5915 rects.append(rect);
5916 }
5917
5918 for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
5919 if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
5920 RenderBox* box = toRenderBox(curr);
5921 FloatPoint pos;
5922 // FIXME: This doesn't work correctly with transforms.
5923 if (box->layer())
5924 pos = curr->localToAbsolute();
5925 else
5926 pos = FloatPoint(tx + box->x(), ty + box->y());
5927 box->addFocusRingRects(rects, pos.x(), pos.y());
5928 }
5929 }
5930 }
5931
5932 if (inlineElementContinuation())
5933 inlineElementContinuation()->addFocusRingRects(rects,
5934 tx - x() + inlineElementContinuation()->containingBlock()->x(),
5935 ty - y() + inlineElementContinuation()->containingBlock()->y());
5936 }
5937
createAnonymousBlock(bool isFlexibleBox) const5938 RenderBlock* RenderBlock::createAnonymousBlock(bool isFlexibleBox) const
5939 {
5940 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
5941
5942 RenderBlock* newBox = 0;
5943 if (isFlexibleBox) {
5944 newStyle->setDisplay(BOX);
5945 newBox = new (renderArena()) RenderFlexibleBox(document() /* anonymous box */);
5946 } else {
5947 newStyle->setDisplay(BLOCK);
5948 newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
5949 }
5950
5951 newBox->setStyle(newStyle.release());
5952 return newBox;
5953 }
5954
createAnonymousBlockWithSameTypeAs(RenderBlock * otherAnonymousBlock) const5955 RenderBlock* RenderBlock::createAnonymousBlockWithSameTypeAs(RenderBlock* otherAnonymousBlock) const
5956 {
5957 if (otherAnonymousBlock->isAnonymousColumnsBlock())
5958 return createAnonymousColumnsBlock();
5959 if (otherAnonymousBlock->isAnonymousColumnSpanBlock())
5960 return createAnonymousColumnSpanBlock();
5961 return createAnonymousBlock(otherAnonymousBlock->style()->display() == BOX);
5962 }
5963
createAnonymousColumnsBlock() const5964 RenderBlock* RenderBlock::createAnonymousColumnsBlock() const
5965 {
5966 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
5967 newStyle->inheritColumnPropertiesFrom(style());
5968 newStyle->setDisplay(BLOCK);
5969
5970 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
5971 newBox->setStyle(newStyle.release());
5972 return newBox;
5973 }
5974
createAnonymousColumnSpanBlock() const5975 RenderBlock* RenderBlock::createAnonymousColumnSpanBlock() const
5976 {
5977 RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyle(style());
5978 newStyle->setColumnSpan(true);
5979 newStyle->setDisplay(BLOCK);
5980
5981 RenderBlock* newBox = new (renderArena()) RenderBlock(document() /* anonymous box */);
5982 newBox->setStyle(newStyle.release());
5983 return newBox;
5984 }
5985
nextPageLogicalTop(int logicalOffset) const5986 int RenderBlock::nextPageLogicalTop(int logicalOffset) const
5987 {
5988 LayoutState* layoutState = view()->layoutState();
5989 if (!layoutState->m_pageLogicalHeight)
5990 return logicalOffset;
5991
5992 // The logicalOffset is in our coordinate space. We can add in our pushed offset.
5993 int pageLogicalHeight = layoutState->m_pageLogicalHeight;
5994 IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
5995 int offset = isHorizontalWritingMode() ? delta.height() : delta.width();
5996 int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight;
5997 return logicalOffset + remainingLogicalHeight;
5998 }
5999
inNormalFlow(RenderBox * child)6000 static bool inNormalFlow(RenderBox* child)
6001 {
6002 RenderBlock* curr = child->containingBlock();
6003 RenderBlock* initialBlock = child->view();
6004 while (curr && curr != initialBlock) {
6005 if (curr->hasColumns())
6006 return true;
6007 if (curr->isFloatingOrPositioned())
6008 return false;
6009 curr = curr->containingBlock();
6010 }
6011 return true;
6012 }
6013
applyBeforeBreak(RenderBox * child,int logicalOffset)6014 int RenderBlock::applyBeforeBreak(RenderBox* child, int logicalOffset)
6015 {
6016 // FIXME: Add page break checking here when we support printing.
6017 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6018 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6019 bool checkBeforeAlways = (checkColumnBreaks && child->style()->columnBreakBefore() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakBefore() == PBALWAYS);
6020 if (checkBeforeAlways && inNormalFlow(child)) {
6021 if (checkColumnBreaks)
6022 view()->layoutState()->addForcedColumnBreak(logicalOffset);
6023 return nextPageLogicalTop(logicalOffset);
6024 }
6025 return logicalOffset;
6026 }
6027
applyAfterBreak(RenderBox * child,int logicalOffset,MarginInfo & marginInfo)6028 int RenderBlock::applyAfterBreak(RenderBox* child, int logicalOffset, MarginInfo& marginInfo)
6029 {
6030 // FIXME: Add page break checking here when we support printing.
6031 bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
6032 bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight; // FIXME: Once columns can print we have to check this.
6033 bool checkAfterAlways = (checkColumnBreaks && child->style()->columnBreakAfter() == PBALWAYS) || (checkPageBreaks && child->style()->pageBreakAfter() == PBALWAYS);
6034 if (checkAfterAlways && inNormalFlow(child)) {
6035 marginInfo.setMarginAfterQuirk(true); // Cause margins to be discarded for any following content.
6036 if (checkColumnBreaks)
6037 view()->layoutState()->addForcedColumnBreak(logicalOffset);
6038 return nextPageLogicalTop(logicalOffset);
6039 }
6040 return logicalOffset;
6041 }
6042
adjustForUnsplittableChild(RenderBox * child,int logicalOffset,bool includeMargins)6043 int RenderBlock::adjustForUnsplittableChild(RenderBox* child, int logicalOffset, bool includeMargins)
6044 {
6045 bool isUnsplittable = child->isReplaced() || child->scrollsOverflow();
6046 if (!isUnsplittable)
6047 return logicalOffset;
6048 int childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : 0);
6049 LayoutState* layoutState = view()->layoutState();
6050 if (layoutState->m_columnInfo)
6051 layoutState->m_columnInfo->updateMinimumColumnHeight(childLogicalHeight);
6052 int pageLogicalHeight = layoutState->m_pageLogicalHeight;
6053 if (!pageLogicalHeight || childLogicalHeight > pageLogicalHeight)
6054 return logicalOffset;
6055 IntSize delta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
6056 int offset = isHorizontalWritingMode() ? delta.height() : delta.width();
6057 int remainingLogicalHeight = (pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight) % pageLogicalHeight;
6058 if (remainingLogicalHeight < childLogicalHeight)
6059 return logicalOffset + remainingLogicalHeight;
6060 return logicalOffset;
6061 }
6062
adjustLinePositionForPagination(RootInlineBox * lineBox,int & delta)6063 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, int& delta)
6064 {
6065 // FIXME: For now we paginate using line overflow. This ensures that lines don't overlap at all when we
6066 // put a strut between them for pagination purposes. However, this really isn't the desired rendering, since
6067 // the line on the top of the next page will appear too far down relative to the same kind of line at the top
6068 // of the first column.
6069 //
6070 // The rendering we would like to see is one where the lineTop is at the top of the column, and any line overflow
6071 // simply spills out above the top of the column. This effect would match what happens at the top of the first column.
6072 // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
6073 // for overflow to occur), and then cache visible overflow for each column rect.
6074 //
6075 // Furthermore, the paint we have to do when a column has overflow has to be special. We need to exclude
6076 // content that paints in a previous column (and content that paints in the following column).
6077 //
6078 // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
6079 // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
6080 // line and all following lines.
6081 LayoutState* layoutState = view()->layoutState();
6082 int pageLogicalHeight = layoutState->m_pageLogicalHeight;
6083 IntRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
6084 int logicalOffset = logicalVisualOverflow.y();
6085 int lineHeight = logicalVisualOverflow.maxY() - logicalOffset;
6086 if (layoutState->m_columnInfo)
6087 layoutState->m_columnInfo->updateMinimumColumnHeight(lineHeight);
6088 logicalOffset += delta;
6089 lineBox->setPaginationStrut(0);
6090 if (!pageLogicalHeight || lineHeight > pageLogicalHeight)
6091 return;
6092 IntSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
6093 int offset = isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
6094 int remainingLogicalHeight = pageLogicalHeight - (offset + logicalOffset) % pageLogicalHeight;
6095 if (remainingLogicalHeight < lineHeight) {
6096 int totalLogicalHeight = lineHeight + max(0, logicalOffset);
6097 if (lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeight && !isPositioned() && !isTableCell())
6098 setPaginationStrut(remainingLogicalHeight + max(0, logicalOffset));
6099 else {
6100 delta += remainingLogicalHeight;
6101 lineBox->setPaginationStrut(remainingLogicalHeight);
6102 }
6103 }
6104 }
6105
collapsedMarginBeforeForChild(RenderBox * child) const6106 int RenderBlock::collapsedMarginBeforeForChild(RenderBox* child) const
6107 {
6108 // If the child has the same directionality as we do, then we can just return its
6109 // collapsed margin.
6110 if (!child->isWritingModeRoot())
6111 return child->collapsedMarginBefore();
6112
6113 // The child has a different directionality. If the child is parallel, then it's just
6114 // flipped relative to us. We can use the collapsed margin for the opposite edge.
6115 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
6116 return child->collapsedMarginAfter();
6117
6118 // The child is perpendicular to us, which means its margins don't collapse but are on the
6119 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
6120 return marginBeforeForChild(child);
6121 }
6122
collapsedMarginAfterForChild(RenderBox * child) const6123 int RenderBlock::collapsedMarginAfterForChild(RenderBox* child) const
6124 {
6125 // If the child has the same directionality as we do, then we can just return its
6126 // collapsed margin.
6127 if (!child->isWritingModeRoot())
6128 return child->collapsedMarginAfter();
6129
6130 // The child has a different directionality. If the child is parallel, then it's just
6131 // flipped relative to us. We can use the collapsed margin for the opposite edge.
6132 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
6133 return child->collapsedMarginBefore();
6134
6135 // The child is perpendicular to us, which means its margins don't collapse but are on the
6136 // "logical left/right" side of the child box. We can just return the raw margin in this case.
6137 return marginAfterForChild(child);
6138 }
6139
marginBeforeForChild(RenderBoxModelObject * child) const6140 int RenderBlock::marginBeforeForChild(RenderBoxModelObject* child) const
6141 {
6142 switch (style()->writingMode()) {
6143 case TopToBottomWritingMode:
6144 return child->marginTop();
6145 case BottomToTopWritingMode:
6146 return child->marginBottom();
6147 case LeftToRightWritingMode:
6148 return child->marginLeft();
6149 case RightToLeftWritingMode:
6150 return child->marginRight();
6151 }
6152 ASSERT_NOT_REACHED();
6153 return child->marginTop();
6154 }
6155
marginAfterForChild(RenderBoxModelObject * child) const6156 int RenderBlock::marginAfterForChild(RenderBoxModelObject* child) const
6157 {
6158 switch (style()->writingMode()) {
6159 case TopToBottomWritingMode:
6160 return child->marginBottom();
6161 case BottomToTopWritingMode:
6162 return child->marginTop();
6163 case LeftToRightWritingMode:
6164 return child->marginRight();
6165 case RightToLeftWritingMode:
6166 return child->marginLeft();
6167 }
6168 ASSERT_NOT_REACHED();
6169 return child->marginBottom();
6170 }
6171
marginStartForChild(RenderBoxModelObject * child) const6172 int RenderBlock::marginStartForChild(RenderBoxModelObject* child) const
6173 {
6174 if (isHorizontalWritingMode())
6175 return style()->isLeftToRightDirection() ? child->marginLeft() : child->marginRight();
6176 return style()->isLeftToRightDirection() ? child->marginTop() : child->marginBottom();
6177 }
6178
marginEndForChild(RenderBoxModelObject * child) const6179 int RenderBlock::marginEndForChild(RenderBoxModelObject* child) const
6180 {
6181 if (isHorizontalWritingMode())
6182 return style()->isLeftToRightDirection() ? child->marginRight() : child->marginLeft();
6183 return style()->isLeftToRightDirection() ? child->marginBottom() : child->marginTop();
6184 }
6185
setMarginStartForChild(RenderBox * child,int margin)6186 void RenderBlock::setMarginStartForChild(RenderBox* child, int margin)
6187 {
6188 if (isHorizontalWritingMode()) {
6189 if (style()->isLeftToRightDirection())
6190 child->setMarginLeft(margin);
6191 else
6192 child->setMarginRight(margin);
6193 } else {
6194 if (style()->isLeftToRightDirection())
6195 child->setMarginTop(margin);
6196 else
6197 child->setMarginBottom(margin);
6198 }
6199 }
6200
setMarginEndForChild(RenderBox * child,int margin)6201 void RenderBlock::setMarginEndForChild(RenderBox* child, int margin)
6202 {
6203 if (isHorizontalWritingMode()) {
6204 if (style()->isLeftToRightDirection())
6205 child->setMarginRight(margin);
6206 else
6207 child->setMarginLeft(margin);
6208 } else {
6209 if (style()->isLeftToRightDirection())
6210 child->setMarginBottom(margin);
6211 else
6212 child->setMarginTop(margin);
6213 }
6214 }
6215
setMarginBeforeForChild(RenderBox * child,int margin)6216 void RenderBlock::setMarginBeforeForChild(RenderBox* child, int margin)
6217 {
6218 switch (style()->writingMode()) {
6219 case TopToBottomWritingMode:
6220 child->setMarginTop(margin);
6221 break;
6222 case BottomToTopWritingMode:
6223 child->setMarginBottom(margin);
6224 break;
6225 case LeftToRightWritingMode:
6226 child->setMarginLeft(margin);
6227 break;
6228 case RightToLeftWritingMode:
6229 child->setMarginRight(margin);
6230 break;
6231 }
6232 }
6233
setMarginAfterForChild(RenderBox * child,int margin)6234 void RenderBlock::setMarginAfterForChild(RenderBox* child, int margin)
6235 {
6236 switch (style()->writingMode()) {
6237 case TopToBottomWritingMode:
6238 child->setMarginBottom(margin);
6239 break;
6240 case BottomToTopWritingMode:
6241 child->setMarginTop(margin);
6242 break;
6243 case LeftToRightWritingMode:
6244 child->setMarginRight(margin);
6245 break;
6246 case RightToLeftWritingMode:
6247 child->setMarginLeft(margin);
6248 break;
6249 }
6250 }
6251
marginValuesForChild(RenderBox * child)6252 RenderBlock::MarginValues RenderBlock::marginValuesForChild(RenderBox* child)
6253 {
6254 int childBeforePositive = 0;
6255 int childBeforeNegative = 0;
6256 int childAfterPositive = 0;
6257 int childAfterNegative = 0;
6258
6259 int beforeMargin = 0;
6260 int afterMargin = 0;
6261
6262 RenderBlock* childRenderBlock = child->isRenderBlock() ? toRenderBlock(child) : 0;
6263
6264 // If the child has the same directionality as we do, then we can just return its
6265 // margins in the same direction.
6266 if (!child->isWritingModeRoot()) {
6267 if (childRenderBlock) {
6268 childBeforePositive = childRenderBlock->maxPositiveMarginBefore();
6269 childBeforeNegative = childRenderBlock->maxNegativeMarginBefore();
6270 childAfterPositive = childRenderBlock->maxPositiveMarginAfter();
6271 childAfterNegative = childRenderBlock->maxNegativeMarginAfter();
6272 } else {
6273 beforeMargin = child->marginBefore();
6274 afterMargin = child->marginAfter();
6275 }
6276 } else if (child->isHorizontalWritingMode() == isHorizontalWritingMode()) {
6277 // The child has a different directionality. If the child is parallel, then it's just
6278 // flipped relative to us. We can use the margins for the opposite edges.
6279 if (childRenderBlock) {
6280 childBeforePositive = childRenderBlock->maxPositiveMarginAfter();
6281 childBeforeNegative = childRenderBlock->maxNegativeMarginAfter();
6282 childAfterPositive = childRenderBlock->maxPositiveMarginBefore();
6283 childAfterNegative = childRenderBlock->maxNegativeMarginBefore();
6284 } else {
6285 beforeMargin = child->marginAfter();
6286 afterMargin = child->marginBefore();
6287 }
6288 } else {
6289 // The child is perpendicular to us, which means its margins don't collapse but are on the
6290 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
6291 beforeMargin = marginBeforeForChild(child);
6292 afterMargin = marginAfterForChild(child);
6293 }
6294
6295 // Resolve uncollapsing margins into their positive/negative buckets.
6296 if (beforeMargin) {
6297 if (beforeMargin > 0)
6298 childBeforePositive = beforeMargin;
6299 else
6300 childBeforeNegative = -beforeMargin;
6301 }
6302 if (afterMargin) {
6303 if (afterMargin > 0)
6304 childAfterPositive = afterMargin;
6305 else
6306 childAfterNegative = -afterMargin;
6307 }
6308
6309 return MarginValues(childBeforePositive, childBeforeNegative, childAfterPositive, childAfterNegative);
6310 }
6311
renderName() const6312 const char* RenderBlock::renderName() const
6313 {
6314 if (isBody())
6315 return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
6316
6317 if (isFloating())
6318 return "RenderBlock (floating)";
6319 if (isPositioned())
6320 return "RenderBlock (positioned)";
6321 if (isAnonymousColumnsBlock())
6322 return "RenderBlock (anonymous multi-column)";
6323 if (isAnonymousColumnSpanBlock())
6324 return "RenderBlock (anonymous multi-column span)";
6325 if (isAnonymousBlock())
6326 return "RenderBlock (anonymous)";
6327 else if (isAnonymous())
6328 return "RenderBlock (generated)";
6329 if (isRelPositioned())
6330 return "RenderBlock (relative positioned)";
6331 if (isRunIn())
6332 return "RenderBlock (run-in)";
6333 return "RenderBlock";
6334 }
6335
clear()6336 inline void RenderBlock::FloatingObjects::clear()
6337 {
6338 m_set.clear();
6339 m_leftObjectsCount = 0;
6340 m_rightObjectsCount = 0;
6341 }
6342
increaseObjectsCount(FloatingObject::Type type)6343 inline void RenderBlock::FloatingObjects::increaseObjectsCount(FloatingObject::Type type)
6344 {
6345 if (type == FloatingObject::FloatLeft)
6346 m_leftObjectsCount++;
6347 else
6348 m_rightObjectsCount++;
6349 }
6350
decreaseObjectsCount(FloatingObject::Type type)6351 inline void RenderBlock::FloatingObjects::decreaseObjectsCount(FloatingObject::Type type)
6352 {
6353 if (type == FloatingObject::FloatLeft)
6354 m_leftObjectsCount--;
6355 else
6356 m_rightObjectsCount--;
6357 }
6358
6359 } // namespace WebCore
6360