• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2007 David Smith (catfish.man@gmail.com)
5  * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 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 "core/rendering/RenderBlock.h"
26 
27 #include "HTMLNames.h"
28 #include "core/accessibility/AXObjectCache.h"
29 #include "core/dom/Document.h"
30 #include "core/dom/Element.h"
31 #include "core/events/OverflowEvent.h"
32 #include "core/dom/shadow/ShadowRoot.h"
33 #include "core/editing/Editor.h"
34 #include "core/editing/FrameSelection.h"
35 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
36 #include "core/frame/Frame.h"
37 #include "core/frame/FrameView.h"
38 #include "core/page/Page.h"
39 #include "core/frame/Settings.h"
40 #include "core/rendering/FastTextAutosizer.h"
41 #include "core/rendering/GraphicsContextAnnotator.h"
42 #include "core/rendering/HitTestLocation.h"
43 #include "core/rendering/HitTestResult.h"
44 #include "core/rendering/InlineIterator.h"
45 #include "core/rendering/InlineTextBox.h"
46 #include "core/rendering/LayoutRectRecorder.h"
47 #include "core/rendering/LayoutRepainter.h"
48 #include "core/rendering/PaintInfo.h"
49 #include "core/rendering/RenderCombineText.h"
50 #include "core/rendering/RenderDeprecatedFlexibleBox.h"
51 #include "core/rendering/RenderFlexibleBox.h"
52 #include "core/rendering/RenderInline.h"
53 #include "core/rendering/RenderLayer.h"
54 #include "core/rendering/RenderMarquee.h"
55 #include "core/rendering/RenderNamedFlowThread.h"
56 #include "core/rendering/RenderRegion.h"
57 #include "core/rendering/RenderTableCell.h"
58 #include "core/rendering/RenderTextFragment.h"
59 #include "core/rendering/RenderTheme.h"
60 #include "core/rendering/RenderView.h"
61 #include "core/rendering/shapes/ShapeOutsideInfo.h"
62 #include "core/rendering/style/ContentData.h"
63 #include "core/rendering/style/RenderStyle.h"
64 #include "platform/geometry/FloatQuad.h"
65 #include "platform/geometry/TransformState.h"
66 #include "platform/graphics/GraphicsContextStateSaver.h"
67 #include "wtf/StdLibExtras.h"
68 #include "wtf/TemporaryChange.h"
69 
70 using namespace std;
71 using namespace WTF;
72 using namespace Unicode;
73 
74 namespace WebCore {
75 
76 using namespace HTMLNames;
77 
78 struct SameSizeAsRenderBlock : public RenderBox {
79     void* pointers[1];
80     RenderObjectChildList children;
81     RenderLineBoxList lineBoxes;
82     uint32_t bitfields;
83 };
84 
85 COMPILE_ASSERT(sizeof(RenderBlock) == sizeof(SameSizeAsRenderBlock), RenderBlock_should_stay_small);
86 
87 typedef WTF::HashMap<const RenderBox*, OwnPtr<ColumnInfo> > ColumnInfoMap;
88 static ColumnInfoMap* gColumnInfoMap = 0;
89 
90 static TrackedDescendantsMap* gPositionedDescendantsMap = 0;
91 static TrackedDescendantsMap* gPercentHeightDescendantsMap = 0;
92 
93 static TrackedContainerMap* gPositionedContainerMap = 0;
94 static TrackedContainerMap* gPercentHeightContainerMap = 0;
95 
96 typedef WTF::HashMap<RenderBlock*, OwnPtr<ListHashSet<RenderInline*> > > ContinuationOutlineTableMap;
97 
98 typedef WTF::HashSet<RenderBlock*> DelayedUpdateScrollInfoSet;
99 static int gDelayUpdateScrollInfo = 0;
100 static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
101 
102 static bool gColumnFlowSplitEnabled = true;
103 
104 // This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
105 // only works on RenderBlocks. If this changes, this class should be shared with other RenderBoxes.
106 class OverflowEventDispatcher {
107     WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
108 public:
OverflowEventDispatcher(const RenderBlock * block)109     OverflowEventDispatcher(const RenderBlock* block)
110         : m_block(block)
111     {
112         m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document().hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
113         if (m_shouldDispatchEvent) {
114             m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
115             m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
116         }
117     }
118 
~OverflowEventDispatcher()119     ~OverflowEventDispatcher()
120     {
121         if (!m_shouldDispatchEvent)
122             return;
123 
124         bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
125         bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
126 
127         bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
128         bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
129 
130         if (!horizontalLayoutOverflowChanged && !verticalLayoutOverflowChanged)
131             return;
132 
133         RefPtr<OverflowEvent> event = OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow);
134         event->setTarget(m_block->node());
135         m_block->document().enqueueAnimationFrameEvent(event.release());
136     }
137 
138 private:
139     const RenderBlock* m_block;
140     bool m_shouldDispatchEvent;
141     bool m_hadHorizontalLayoutOverflow;
142     bool m_hadVerticalLayoutOverflow;
143 };
144 
RenderBlock(ContainerNode * node)145 RenderBlock::RenderBlock(ContainerNode* node)
146     : RenderBox(node)
147     , m_lineHeight(-1)
148     , m_hasMarginBeforeQuirk(false)
149     , m_hasMarginAfterQuirk(false)
150     , m_beingDestroyed(false)
151     , m_hasMarkupTruncation(false)
152     , m_hasBorderOrPaddingLogicalWidthChanged(false)
153 {
154     setChildrenInline(true);
155 }
156 
removeBlockFromDescendantAndContainerMaps(RenderBlock * block,TrackedDescendantsMap * & descendantMap,TrackedContainerMap * & containerMap)157 static void removeBlockFromDescendantAndContainerMaps(RenderBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
158 {
159     if (OwnPtr<TrackedRendererListHashSet> descendantSet = descendantMap->take(block)) {
160         TrackedRendererListHashSet::iterator end = descendantSet->end();
161         for (TrackedRendererListHashSet::iterator descendant = descendantSet->begin(); descendant != end; ++descendant) {
162             TrackedContainerMap::iterator it = containerMap->find(*descendant);
163             ASSERT(it != containerMap->end());
164             if (it == containerMap->end())
165                 continue;
166             HashSet<RenderBlock*>* containerSet = it->value.get();
167             ASSERT(containerSet->contains(block));
168             containerSet->remove(block);
169             if (containerSet->isEmpty())
170                 containerMap->remove(it);
171         }
172     }
173 }
174 
appendImageIfNotNull(Vector<ImageResource * > & imageResources,const StyleImage * styleImage)175 static void appendImageIfNotNull(Vector<ImageResource*>& imageResources, const StyleImage* styleImage)
176 {
177     if (styleImage && styleImage->cachedImage())
178         imageResources.append(styleImage->cachedImage());
179 }
180 
appendLayers(Vector<ImageResource * > & images,const FillLayer * styleLayer)181 static void appendLayers(Vector<ImageResource*>& images, const FillLayer* styleLayer)
182 {
183     for (const FillLayer* layer = styleLayer; layer; layer = layer->next()) {
184         appendImageIfNotNull(images, layer->image());
185     }
186 }
187 
~RenderBlock()188 RenderBlock::~RenderBlock()
189 {
190     if (hasColumns())
191         gColumnInfoMap->take(this);
192     if (gPercentHeightDescendantsMap)
193         removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
194     if (gPositionedDescendantsMap)
195         removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
196 }
197 
willBeDestroyed()198 void RenderBlock::willBeDestroyed()
199 {
200     // Mark as being destroyed to avoid trouble with merges in removeChild().
201     m_beingDestroyed = true;
202 
203     // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
204     // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
205     children()->destroyLeftoverChildren();
206 
207     // Destroy our continuation before anything other than anonymous children.
208     // The reason we don't destroy it before anonymous children is that they may
209     // have continuations of their own that are anonymous children of our continuation.
210     RenderBoxModelObject* continuation = this->continuation();
211     if (continuation) {
212         continuation->destroy();
213         setContinuation(0);
214     }
215 
216     if (!documentBeingDestroyed()) {
217         if (firstLineBox()) {
218             // We can't wait for RenderBox::destroy to clear the selection,
219             // because by then we will have nuked the line boxes.
220             // FIXME: The FrameSelection should be responsible for this when it
221             // is notified of DOM mutations.
222             if (isSelectionBorder())
223                 view()->clearSelection();
224 
225             // If we are an anonymous block, then our line boxes might have children
226             // that will outlast this block. In the non-anonymous block case those
227             // children will be destroyed by the time we return from this function.
228             if (isAnonymousBlock()) {
229                 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
230                     while (InlineBox* childBox = box->firstChild())
231                         childBox->remove();
232                 }
233             }
234         } else if (parent())
235             parent()->dirtyLinesFromChangedChild(this);
236     }
237 
238     m_lineBoxes.deleteLineBoxes();
239 
240     if (UNLIKELY(gDelayedUpdateScrollInfoSet != 0))
241         gDelayedUpdateScrollInfoSet->remove(this);
242 
243     FastTextAutosizer* textAutosizer = document().fastTextAutosizer();
244     if (textAutosizer)
245         textAutosizer->destroy(this);
246 
247     RenderBox::willBeDestroyed();
248 }
249 
styleWillChange(StyleDifference diff,const RenderStyle * newStyle)250 void RenderBlock::styleWillChange(StyleDifference diff, const RenderStyle* newStyle)
251 {
252     RenderStyle* oldStyle = style();
253 
254     setReplaced(newStyle->isDisplayInlineType());
255 
256     if (oldStyle && parent() && diff == StyleDifferenceLayout && oldStyle->position() != newStyle->position()) {
257         if (newStyle->position() == StaticPosition)
258             // Clear our positioned objects list. Our absolutely positioned descendants will be
259             // inserted into our containing block's positioned objects list during layout.
260             removePositionedObjects(0, NewContainingBlock);
261         else if (oldStyle->position() == StaticPosition) {
262             // Remove our absolutely positioned descendants from their current containing block.
263             // They will be inserted into our positioned objects list during layout.
264             RenderObject* cb = parent();
265             while (cb && (cb->style()->position() == StaticPosition || (cb->isInline() && !cb->isReplaced())) && !cb->isRenderView()) {
266                 if (cb->style()->position() == RelativePosition && cb->isInline() && !cb->isReplaced()) {
267                     cb = cb->containingBlock();
268                     break;
269                 }
270                 cb = cb->parent();
271             }
272 
273             if (cb->isRenderBlock())
274                 toRenderBlock(cb)->removePositionedObjects(this, NewContainingBlock);
275         }
276     }
277 
278     RenderBox::styleWillChange(diff, newStyle);
279 }
280 
borderOrPaddingLogicalWidthChanged(const RenderStyle * oldStyle,const RenderStyle * newStyle)281 static bool borderOrPaddingLogicalWidthChanged(const RenderStyle* oldStyle, const RenderStyle* newStyle)
282 {
283     if (newStyle->isHorizontalWritingMode())
284         return oldStyle->borderLeftWidth() != newStyle->borderLeftWidth()
285             || oldStyle->borderRightWidth() != newStyle->borderRightWidth()
286             || oldStyle->paddingLeft() != newStyle->paddingLeft()
287             || oldStyle->paddingRight() != newStyle->paddingRight();
288 
289     return oldStyle->borderTopWidth() != newStyle->borderTopWidth()
290         || oldStyle->borderBottomWidth() != newStyle->borderBottomWidth()
291         || oldStyle->paddingTop() != newStyle->paddingTop()
292         || oldStyle->paddingBottom() != newStyle->paddingBottom();
293 }
294 
styleDidChange(StyleDifference diff,const RenderStyle * oldStyle)295 void RenderBlock::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
296 {
297     RenderBox::styleDidChange(diff, oldStyle);
298 
299     RenderStyle* newStyle = style();
300 
301     updateShapeInsideInfoAfterStyleChange(newStyle->resolvedShapeInside(), oldStyle ? oldStyle->resolvedShapeInside() : RenderStyle::initialShapeInside());
302 
303     if (!isAnonymousBlock()) {
304         // Ensure that all of our continuation blocks pick up the new style.
305         for (RenderBlock* currCont = blockElementContinuation(); currCont; currCont = currCont->blockElementContinuation()) {
306             RenderBoxModelObject* nextCont = currCont->continuation();
307             currCont->setContinuation(0);
308             currCont->setStyle(newStyle);
309             currCont->setContinuation(nextCont);
310         }
311     }
312 
313     FastTextAutosizer* textAutosizer = document().fastTextAutosizer();
314     if (textAutosizer)
315         textAutosizer->record(this);
316 
317     propagateStyleToAnonymousChildren(true);
318     m_lineHeight = -1;
319 
320     // It's possible for our border/padding to change, but for the overall logical width of the block to
321     // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
322     m_hasBorderOrPaddingLogicalWidthChanged = oldStyle && diff == StyleDifferenceLayout && needsLayout() && borderOrPaddingLogicalWidthChanged(oldStyle, newStyle);
323 }
324 
continuationBefore(RenderObject * beforeChild)325 RenderBlock* RenderBlock::continuationBefore(RenderObject* beforeChild)
326 {
327     if (beforeChild && beforeChild->parent() == this)
328         return this;
329 
330     RenderBlock* curr = toRenderBlock(continuation());
331     RenderBlock* nextToLast = this;
332     RenderBlock* last = this;
333     while (curr) {
334         if (beforeChild && beforeChild->parent() == curr) {
335             if (curr->firstChild() == beforeChild)
336                 return last;
337             return curr;
338         }
339 
340         nextToLast = last;
341         last = curr;
342         curr = toRenderBlock(curr->continuation());
343     }
344 
345     if (!beforeChild && !last->firstChild())
346         return nextToLast;
347     return last;
348 }
349 
addChildToContinuation(RenderObject * newChild,RenderObject * beforeChild)350 void RenderBlock::addChildToContinuation(RenderObject* newChild, RenderObject* beforeChild)
351 {
352     RenderBlock* flow = continuationBefore(beforeChild);
353     ASSERT(!beforeChild || beforeChild->parent()->isAnonymousColumnSpanBlock() || beforeChild->parent()->isRenderBlock());
354     RenderBoxModelObject* beforeChildParent = 0;
355     if (beforeChild)
356         beforeChildParent = toRenderBoxModelObject(beforeChild->parent());
357     else {
358         RenderBoxModelObject* cont = flow->continuation();
359         if (cont)
360             beforeChildParent = cont;
361         else
362             beforeChildParent = flow;
363     }
364 
365     if (newChild->isFloatingOrOutOfFlowPositioned()) {
366         beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
367         return;
368     }
369 
370     // A continuation always consists of two potential candidates: a block or an anonymous
371     // column span box holding column span children.
372     bool childIsNormal = newChild->isInline() || !newChild->style()->columnSpan();
373     bool bcpIsNormal = beforeChildParent->isInline() || !beforeChildParent->style()->columnSpan();
374     bool flowIsNormal = flow->isInline() || !flow->style()->columnSpan();
375 
376     if (flow == beforeChildParent) {
377         flow->addChildIgnoringContinuation(newChild, beforeChild);
378         return;
379     }
380 
381     // The goal here is to match up if we can, so that we can coalesce and create the
382     // minimal # of continuations needed for the inline.
383     if (childIsNormal == bcpIsNormal) {
384         beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
385         return;
386     }
387     if (flowIsNormal == childIsNormal) {
388         flow->addChildIgnoringContinuation(newChild, 0); // Just treat like an append.
389         return;
390     }
391     beforeChildParent->addChildIgnoringContinuation(newChild, beforeChild);
392 }
393 
394 
addChildToAnonymousColumnBlocks(RenderObject * newChild,RenderObject * beforeChild)395 void RenderBlock::addChildToAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
396 {
397     ASSERT(!continuation()); // We don't yet support column spans that aren't immediate children of the multi-column block.
398 
399     // The goal is to locate a suitable box in which to place our child.
400     RenderBlock* beforeChildParent = 0;
401     if (beforeChild) {
402         RenderObject* curr = beforeChild;
403         while (curr && curr->parent() != this)
404             curr = curr->parent();
405         beforeChildParent = toRenderBlock(curr);
406         ASSERT(beforeChildParent);
407         ASSERT(beforeChildParent->isAnonymousColumnsBlock() || beforeChildParent->isAnonymousColumnSpanBlock());
408     } else
409         beforeChildParent = toRenderBlock(lastChild());
410 
411     // If the new child is floating or positioned it can just go in that block.
412     if (newChild->isFloatingOrOutOfFlowPositioned()) {
413         beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
414         return;
415     }
416 
417     // See if the child can be placed in the box.
418     bool newChildHasColumnSpan = newChild->style()->columnSpan() && !newChild->isInline();
419     bool beforeChildParentHoldsColumnSpans = beforeChildParent->isAnonymousColumnSpanBlock();
420 
421     if (newChildHasColumnSpan == beforeChildParentHoldsColumnSpans) {
422         beforeChildParent->addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
423         return;
424     }
425 
426     if (!beforeChild) {
427         // Create a new block of the correct type.
428         RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
429         children()->appendChildNode(this, newBox);
430         newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
431         return;
432     }
433 
434     RenderObject* immediateChild = beforeChild;
435     bool isPreviousBlockViable = true;
436     while (immediateChild->parent() != this) {
437         if (isPreviousBlockViable)
438             isPreviousBlockViable = !immediateChild->previousSibling();
439         immediateChild = immediateChild->parent();
440     }
441     if (isPreviousBlockViable && immediateChild->previousSibling()) {
442         toRenderBlock(immediateChild->previousSibling())->addChildIgnoringAnonymousColumnBlocks(newChild, 0); // Treat like an append.
443         return;
444     }
445 
446     // Split our anonymous blocks.
447     RenderObject* newBeforeChild = splitAnonymousBoxesAroundChild(beforeChild);
448 
449 
450     // Create a new anonymous box of the appropriate type.
451     RenderBlock* newBox = newChildHasColumnSpan ? createAnonymousColumnSpanBlock() : createAnonymousColumnsBlock();
452     children()->insertChildNode(this, newBox, newBeforeChild);
453     newBox->addChildIgnoringAnonymousColumnBlocks(newChild, 0);
454     return;
455 }
456 
containingColumnsBlock(bool allowAnonymousColumnBlock)457 RenderBlockFlow* RenderBlock::containingColumnsBlock(bool allowAnonymousColumnBlock)
458 {
459     RenderBlock* firstChildIgnoringAnonymousWrappers = 0;
460     for (RenderObject* curr = this; curr; curr = curr->parent()) {
461         if (!curr->isRenderBlock() || curr->isFloatingOrOutOfFlowPositioned() || curr->isTableCell() || curr->isRoot() || curr->isRenderView() || curr->hasOverflowClip()
462             || curr->isInlineBlockOrInlineTable())
463             return 0;
464 
465         // FIXME: Renderers that do special management of their children (tables, buttons,
466         // lists, flexboxes, etc.) breaks when the flow is split through them. Disabling
467         // multi-column for them to avoid this problem.)
468         if (!curr->isRenderBlockFlow() || curr->isListItem())
469             return 0;
470 
471         RenderBlockFlow* currBlock = toRenderBlockFlow(curr);
472         if (!currBlock->createsAnonymousWrapper())
473             firstChildIgnoringAnonymousWrappers = currBlock;
474 
475         if (currBlock->style()->specifiesColumns() && (allowAnonymousColumnBlock || !currBlock->isAnonymousColumnsBlock()))
476             return toRenderBlockFlow(firstChildIgnoringAnonymousWrappers);
477 
478         if (currBlock->isAnonymousColumnSpanBlock())
479             return 0;
480     }
481     return 0;
482 }
483 
clone() const484 RenderBlock* RenderBlock::clone() const
485 {
486     RenderBlock* cloneBlock;
487     if (isAnonymousBlock()) {
488         cloneBlock = createAnonymousBlock();
489         cloneBlock->setChildrenInline(childrenInline());
490     }
491     else {
492         RenderObject* cloneRenderer = toElement(node())->createRenderer(style());
493         cloneBlock = toRenderBlock(cloneRenderer);
494         cloneBlock->setStyle(style());
495 
496         // This takes care of setting the right value of childrenInline in case
497         // generated content is added to cloneBlock and 'this' does not have
498         // generated content added yet.
499         cloneBlock->setChildrenInline(cloneBlock->firstChild() ? cloneBlock->firstChild()->isInline() : childrenInline());
500     }
501     cloneBlock->setFlowThreadState(flowThreadState());
502     return cloneBlock;
503 }
504 
splitBlocks(RenderBlock * fromBlock,RenderBlock * toBlock,RenderBlock * middleBlock,RenderObject * beforeChild,RenderBoxModelObject * oldCont)505 void RenderBlock::splitBlocks(RenderBlock* fromBlock, RenderBlock* toBlock,
506                               RenderBlock* middleBlock,
507                               RenderObject* beforeChild, RenderBoxModelObject* oldCont)
508 {
509     // Create a clone of this inline.
510     RenderBlock* cloneBlock = clone();
511     if (!isAnonymousBlock())
512         cloneBlock->setContinuation(oldCont);
513 
514     if (!beforeChild && isAfterContent(lastChild()))
515         beforeChild = lastChild();
516 
517     // If we are moving inline children from |this| to cloneBlock, then we need
518     // to clear our line box tree.
519     if (beforeChild && childrenInline())
520         deleteLineBoxTree();
521 
522     // Now take all of the children from beforeChild to the end and remove
523     // them from |this| and place them in the clone.
524     moveChildrenTo(cloneBlock, beforeChild, 0, true);
525 
526     // Hook |clone| up as the continuation of the middle block.
527     if (!cloneBlock->isAnonymousBlock())
528         middleBlock->setContinuation(cloneBlock);
529 
530     // We have been reparented and are now under the fromBlock.  We need
531     // to walk up our block parent chain until we hit the containing anonymous columns block.
532     // Once we hit the anonymous columns block we're done.
533     RenderBoxModelObject* curr = toRenderBoxModelObject(parent());
534     RenderBoxModelObject* currChild = this;
535     RenderObject* currChildNextSibling = currChild->nextSibling();
536 
537     while (curr && curr->isDescendantOf(fromBlock) && curr != fromBlock) {
538         ASSERT_WITH_SECURITY_IMPLICATION(curr->isRenderBlock());
539 
540         RenderBlock* blockCurr = toRenderBlock(curr);
541 
542         // Create a new clone.
543         RenderBlock* cloneChild = cloneBlock;
544         cloneBlock = blockCurr->clone();
545 
546         // Insert our child clone as the first child.
547         cloneBlock->addChildIgnoringContinuation(cloneChild, 0);
548 
549         // Hook the clone up as a continuation of |curr|.  Note we do encounter
550         // anonymous blocks possibly as we walk up the block chain.  When we split an
551         // anonymous block, there's no need to do any continuation hookup, since we haven't
552         // actually split a real element.
553         if (!blockCurr->isAnonymousBlock()) {
554             oldCont = blockCurr->continuation();
555             blockCurr->setContinuation(cloneBlock);
556             cloneBlock->setContinuation(oldCont);
557         }
558 
559         // Now we need to take all of the children starting from the first child
560         // *after* currChild and append them all to the clone.
561         blockCurr->moveChildrenTo(cloneBlock, currChildNextSibling, 0, true);
562 
563         // Keep walking up the chain.
564         currChild = curr;
565         currChildNextSibling = currChild->nextSibling();
566         curr = toRenderBoxModelObject(curr->parent());
567     }
568 
569     // Now we are at the columns block level. We need to put the clone into the toBlock.
570     toBlock->children()->appendChildNode(toBlock, cloneBlock);
571 
572     // Now take all the children after currChild and remove them from the fromBlock
573     // and put them in the toBlock.
574     fromBlock->moveChildrenTo(toBlock, currChildNextSibling, 0, true);
575 }
576 
splitFlow(RenderObject * beforeChild,RenderBlock * newBlockBox,RenderObject * newChild,RenderBoxModelObject * oldCont)577 void RenderBlock::splitFlow(RenderObject* beforeChild, RenderBlock* newBlockBox,
578                             RenderObject* newChild, RenderBoxModelObject* oldCont)
579 {
580     RenderBlock* pre = 0;
581     RenderBlock* block = containingColumnsBlock();
582 
583     // Delete our line boxes before we do the inline split into continuations.
584     block->deleteLineBoxTree();
585 
586     bool madeNewBeforeBlock = false;
587     if (block->isAnonymousColumnsBlock()) {
588         // We can reuse this block and make it the preBlock of the next continuation.
589         pre = block;
590         pre->removePositionedObjects(0);
591         if (block->isRenderBlockFlow())
592             toRenderBlockFlow(pre)->removeFloatingObjects();
593         block = toRenderBlock(block->parent());
594     } else {
595         // No anonymous block available for use.  Make one.
596         pre = block->createAnonymousColumnsBlock();
597         pre->setChildrenInline(false);
598         madeNewBeforeBlock = true;
599     }
600 
601     RenderBlock* post = block->createAnonymousColumnsBlock();
602     post->setChildrenInline(false);
603 
604     RenderObject* boxFirst = madeNewBeforeBlock ? block->firstChild() : pre->nextSibling();
605     if (madeNewBeforeBlock)
606         block->children()->insertChildNode(block, pre, boxFirst);
607     block->children()->insertChildNode(block, newBlockBox, boxFirst);
608     block->children()->insertChildNode(block, post, boxFirst);
609     block->setChildrenInline(false);
610 
611     if (madeNewBeforeBlock)
612         block->moveChildrenTo(pre, boxFirst, 0, true);
613 
614     splitBlocks(pre, post, newBlockBox, beforeChild, oldCont);
615 
616     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
617     // time in makeChildrenNonInline by just setting this explicitly up front.
618     newBlockBox->setChildrenInline(false);
619 
620     newBlockBox->addChild(newChild);
621 
622     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
623     // get deleted properly.  Because objects moves from the pre block into the post block, we want to
624     // make new line boxes instead of leaving the old line boxes around.
625     pre->setNeedsLayoutAndPrefWidthsRecalc();
626     block->setNeedsLayoutAndPrefWidthsRecalc();
627     post->setNeedsLayoutAndPrefWidthsRecalc();
628 }
629 
makeChildrenAnonymousColumnBlocks(RenderObject * beforeChild,RenderBlockFlow * newBlockBox,RenderObject * newChild)630 void RenderBlock::makeChildrenAnonymousColumnBlocks(RenderObject* beforeChild, RenderBlockFlow* newBlockBox, RenderObject* newChild)
631 {
632     RenderBlockFlow* pre = 0;
633     RenderBlockFlow* post = 0;
634     RenderBlock* block = this; // Eventually block will not just be |this|, but will also be a block nested inside |this|.  Assign to a variable
635                                // so that we don't have to patch all of the rest of the code later on.
636 
637     // Delete the block's line boxes before we do the split.
638     block->deleteLineBoxTree();
639 
640     if (beforeChild && beforeChild->parent() != this)
641         beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
642 
643     if (beforeChild != firstChild()) {
644         pre = block->createAnonymousColumnsBlock();
645         pre->setChildrenInline(block->childrenInline());
646     }
647 
648     if (beforeChild) {
649         post = block->createAnonymousColumnsBlock();
650         post->setChildrenInline(block->childrenInline());
651     }
652 
653     RenderObject* boxFirst = block->firstChild();
654     if (pre)
655         block->children()->insertChildNode(block, pre, boxFirst);
656     block->children()->insertChildNode(block, newBlockBox, boxFirst);
657     if (post)
658         block->children()->insertChildNode(block, post, boxFirst);
659     block->setChildrenInline(false);
660 
661     // 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).
662     block->moveChildrenTo(pre, boxFirst, beforeChild, true);
663     block->moveChildrenTo(post, beforeChild, 0, true);
664 
665     // We already know the newBlockBox isn't going to contain inline kids, so avoid wasting
666     // time in makeChildrenNonInline by just setting this explicitly up front.
667     newBlockBox->setChildrenInline(false);
668 
669     newBlockBox->addChild(newChild);
670 
671     // Always just do a full layout in order to ensure that line boxes (especially wrappers for images)
672     // get deleted properly.  Because objects moved from the pre block into the post block, we want to
673     // make new line boxes instead of leaving the old line boxes around.
674     if (pre)
675         pre->setNeedsLayoutAndPrefWidthsRecalc();
676     block->setNeedsLayoutAndPrefWidthsRecalc();
677     if (post)
678         post->setNeedsLayoutAndPrefWidthsRecalc();
679 }
680 
columnsBlockForSpanningElement(RenderObject * newChild)681 RenderBlockFlow* RenderBlock::columnsBlockForSpanningElement(RenderObject* newChild)
682 {
683     // FIXME: This function is the gateway for the addition of column-span support.  It will
684     // be added to in three stages:
685     // (1) Immediate children of a multi-column block can span.
686     // (2) Nested block-level children with only block-level ancestors between them and the multi-column block can span.
687     // (3) Nested children with block or inline ancestors between them and the multi-column block can span (this is when we
688     // cross the streams and have to cope with both types of continuations mixed together).
689     // This function currently supports (1) and (2).
690     RenderBlockFlow* columnsBlockAncestor = 0;
691     if (!newChild->isText() && newChild->style()->columnSpan() && !newChild->isBeforeOrAfterContent()
692         && !newChild->isFloatingOrOutOfFlowPositioned() && !newChild->isInline() && !isAnonymousColumnSpanBlock()) {
693         columnsBlockAncestor = containingColumnsBlock(false);
694         if (columnsBlockAncestor) {
695             // Make sure that none of the parent ancestors have a continuation.
696             // If yes, we do not want split the block into continuations.
697             RenderObject* curr = this;
698             while (curr && curr != columnsBlockAncestor) {
699                 if (curr->isRenderBlock() && toRenderBlock(curr)->continuation()) {
700                     columnsBlockAncestor = 0;
701                     break;
702                 }
703                 curr = curr->parent();
704             }
705         }
706     }
707     return columnsBlockAncestor;
708 }
709 
addChildIgnoringAnonymousColumnBlocks(RenderObject * newChild,RenderObject * beforeChild)710 void RenderBlock::addChildIgnoringAnonymousColumnBlocks(RenderObject* newChild, RenderObject* beforeChild)
711 {
712     if (beforeChild && beforeChild->parent() != this) {
713         RenderObject* beforeChildContainer = beforeChild->parent();
714         while (beforeChildContainer->parent() != this)
715             beforeChildContainer = beforeChildContainer->parent();
716         ASSERT(beforeChildContainer);
717 
718         if (beforeChildContainer->isAnonymous()) {
719             // If the requested beforeChild is not one of our children, then this is because
720             // there is an anonymous container within this object that contains the beforeChild.
721             RenderObject* beforeChildAnonymousContainer = beforeChildContainer;
722             if (beforeChildAnonymousContainer->isAnonymousBlock()
723                 // Full screen renderers and full screen placeholders act as anonymous blocks, not tables:
724                 || beforeChildAnonymousContainer->isRenderFullScreen()
725                 || beforeChildAnonymousContainer->isRenderFullScreenPlaceholder()
726                 ) {
727                 // Insert the child into the anonymous block box instead of here.
728                 if (newChild->isInline() || beforeChild->parent()->firstChild() != beforeChild)
729                     beforeChild->parent()->addChild(newChild, beforeChild);
730                 else
731                     addChild(newChild, beforeChild->parent());
732                 return;
733             }
734 
735             ASSERT(beforeChildAnonymousContainer->isTable());
736             if (newChild->isTablePart()) {
737                 // Insert into the anonymous table.
738                 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
739                 return;
740             }
741 
742             beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
743 
744             ASSERT(beforeChild->parent() == this);
745             if (beforeChild->parent() != this) {
746                 // We should never reach here. If we do, we need to use the
747                 // safe fallback to use the topmost beforeChild container.
748                 beforeChild = beforeChildContainer;
749             }
750         }
751     }
752 
753     // Check for a spanning element in columns.
754     if (gColumnFlowSplitEnabled) {
755         RenderBlockFlow* columnsBlockAncestor = columnsBlockForSpanningElement(newChild);
756         if (columnsBlockAncestor) {
757             TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
758             // We are placing a column-span element inside a block.
759             RenderBlockFlow* newBox = createAnonymousColumnSpanBlock();
760 
761             if (columnsBlockAncestor != this && !isRenderFlowThread()) {
762                 // We are nested inside a multi-column element and are being split by the span. We have to break up
763                 // our block into continuations.
764                 RenderBoxModelObject* oldContinuation = continuation();
765 
766                 // When we split an anonymous block, there's no need to do any continuation hookup,
767                 // since we haven't actually split a real element.
768                 if (!isAnonymousBlock())
769                     setContinuation(newBox);
770 
771                 splitFlow(beforeChild, newBox, newChild, oldContinuation);
772                 return;
773             }
774 
775             // We have to perform a split of this block's children. This involves creating an anonymous block box to hold
776             // the column-spanning |newChild|. We take all of the children from before |newChild| and put them into
777             // one anonymous columns block, and all of the children after |newChild| go into another anonymous block.
778             makeChildrenAnonymousColumnBlocks(beforeChild, newBox, newChild);
779             return;
780         }
781     }
782 
783     bool madeBoxesNonInline = false;
784 
785     // A block has to either have all of its children inline, or all of its children as blocks.
786     // So, if our children are currently inline and a block child has to be inserted, we move all our
787     // inline children into anonymous block boxes.
788     if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
789         // This is a block with inline content. Wrap the inline content in anonymous blocks.
790         makeChildrenNonInline(beforeChild);
791         madeBoxesNonInline = true;
792 
793         if (beforeChild && beforeChild->parent() != this) {
794             beforeChild = beforeChild->parent();
795             ASSERT(beforeChild->isAnonymousBlock());
796             ASSERT(beforeChild->parent() == this);
797         }
798     } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
799         // If we're inserting an inline child but all of our children are blocks, then we have to make sure
800         // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
801         // a new one is created and inserted into our list of children in the appropriate position.
802         RenderObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
803 
804         if (afterChild && afterChild->isAnonymousBlock()) {
805             afterChild->addChild(newChild);
806             return;
807         }
808 
809         if (newChild->isInline()) {
810             // No suitable existing anonymous box - create a new one.
811             RenderBlock* newBox = createAnonymousBlock();
812             RenderBox::addChild(newBox, beforeChild);
813             newBox->addChild(newChild);
814             return;
815         }
816     }
817 
818     RenderBox::addChild(newChild, beforeChild);
819 
820     if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isRenderBlock())
821         toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
822     // this object may be dead here
823 }
824 
addChild(RenderObject * newChild,RenderObject * beforeChild)825 void RenderBlock::addChild(RenderObject* newChild, RenderObject* beforeChild)
826 {
827     if (continuation() && !isAnonymousBlock())
828         addChildToContinuation(newChild, beforeChild);
829     else
830         addChildIgnoringContinuation(newChild, beforeChild);
831 }
832 
addChildIgnoringContinuation(RenderObject * newChild,RenderObject * beforeChild)833 void RenderBlock::addChildIgnoringContinuation(RenderObject* newChild, RenderObject* beforeChild)
834 {
835     if (!isAnonymousBlock() && firstChild() && (firstChild()->isAnonymousColumnsBlock() || firstChild()->isAnonymousColumnSpanBlock()))
836         addChildToAnonymousColumnBlocks(newChild, beforeChild);
837     else
838         addChildIgnoringAnonymousColumnBlocks(newChild, beforeChild);
839 }
840 
getInlineRun(RenderObject * start,RenderObject * boundary,RenderObject * & inlineRunStart,RenderObject * & inlineRunEnd)841 static void getInlineRun(RenderObject* start, RenderObject* boundary,
842                          RenderObject*& inlineRunStart,
843                          RenderObject*& inlineRunEnd)
844 {
845     // Beginning at |start| we find the largest contiguous run of inlines that
846     // we can.  We denote the run with start and end points, |inlineRunStart|
847     // and |inlineRunEnd|.  Note that these two values may be the same if
848     // we encounter only one inline.
849     //
850     // We skip any non-inlines we encounter as long as we haven't found any
851     // inlines yet.
852     //
853     // |boundary| indicates a non-inclusive boundary point.  Regardless of whether |boundary|
854     // is inline or not, we will not include it in a run with inlines before it.  It's as though we encountered
855     // a non-inline.
856 
857     // Start by skipping as many non-inlines as we can.
858     RenderObject * curr = start;
859     bool sawInline;
860     do {
861         while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
862             curr = curr->nextSibling();
863 
864         inlineRunStart = inlineRunEnd = curr;
865 
866         if (!curr)
867             return; // No more inline children to be found.
868 
869         sawInline = curr->isInline();
870 
871         curr = curr->nextSibling();
872         while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
873             inlineRunEnd = curr;
874             if (curr->isInline())
875                 sawInline = true;
876             curr = curr->nextSibling();
877         }
878     } while (!sawInline);
879 }
880 
deleteLineBoxTree()881 void RenderBlock::deleteLineBoxTree()
882 {
883     m_lineBoxes.deleteLineBoxTree();
884 
885     if (AXObjectCache* cache = document().existingAXObjectCache())
886         cache->recomputeIsIgnored(this);
887 }
888 
createAndAppendRootInlineBox()889 RootInlineBox* RenderBlock::createAndAppendRootInlineBox()
890 {
891     RootInlineBox* rootBox = createRootInlineBox();
892     m_lineBoxes.appendLineBox(rootBox);
893 
894     if (UNLIKELY(AXObjectCache::accessibilityEnabled()) && m_lineBoxes.firstLineBox() == rootBox) {
895         if (AXObjectCache* cache = document().existingAXObjectCache())
896             cache->recomputeIsIgnored(this);
897     }
898 
899     return rootBox;
900 }
901 
makeChildrenNonInline(RenderObject * insertionPoint)902 void RenderBlock::makeChildrenNonInline(RenderObject *insertionPoint)
903 {
904     // makeChildrenNonInline takes a block whose children are *all* inline and it
905     // makes sure that inline children are coalesced under anonymous
906     // blocks.  If |insertionPoint| is defined, then it represents the insertion point for
907     // the new block child that is causing us to have to wrap all the inlines.  This
908     // means that we cannot coalesce inlines before |insertionPoint| with inlines following
909     // |insertionPoint|, because the new child is going to be inserted in between the inlines,
910     // splitting them.
911     ASSERT(isInlineBlockOrInlineTable() || !isInline());
912     ASSERT(!insertionPoint || insertionPoint->parent() == this);
913 
914     setChildrenInline(false);
915 
916     RenderObject *child = firstChild();
917     if (!child)
918         return;
919 
920     deleteLineBoxTree();
921 
922     while (child) {
923         RenderObject *inlineRunStart, *inlineRunEnd;
924         getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
925 
926         if (!inlineRunStart)
927             break;
928 
929         child = inlineRunEnd->nextSibling();
930 
931         RenderBlock* block = createAnonymousBlock();
932         children()->insertChildNode(this, block, inlineRunStart);
933         moveChildrenTo(block, inlineRunStart, child);
934     }
935 
936 #ifndef NDEBUG
937     for (RenderObject *c = firstChild(); c; c = c->nextSibling())
938         ASSERT(!c->isInline());
939 #endif
940 
941     repaint();
942 }
943 
removeLeftoverAnonymousBlock(RenderBlock * child)944 void RenderBlock::removeLeftoverAnonymousBlock(RenderBlock* child)
945 {
946     ASSERT(child->isAnonymousBlock());
947     ASSERT(!child->childrenInline());
948 
949     if (child->continuation() || (child->firstChild() && (child->isAnonymousColumnSpanBlock() || child->isAnonymousColumnsBlock())))
950         return;
951 
952     RenderObject* firstAnChild = child->m_children.firstChild();
953     RenderObject* lastAnChild = child->m_children.lastChild();
954     if (firstAnChild) {
955         RenderObject* o = firstAnChild;
956         while (o) {
957             o->setParent(this);
958             o = o->nextSibling();
959         }
960         firstAnChild->setPreviousSibling(child->previousSibling());
961         lastAnChild->setNextSibling(child->nextSibling());
962         if (child->previousSibling())
963             child->previousSibling()->setNextSibling(firstAnChild);
964         if (child->nextSibling())
965             child->nextSibling()->setPreviousSibling(lastAnChild);
966 
967         if (child == m_children.firstChild())
968             m_children.setFirstChild(firstAnChild);
969         if (child == m_children.lastChild())
970             m_children.setLastChild(lastAnChild);
971     } else {
972         if (child == m_children.firstChild())
973             m_children.setFirstChild(child->nextSibling());
974         if (child == m_children.lastChild())
975             m_children.setLastChild(child->previousSibling());
976 
977         if (child->previousSibling())
978             child->previousSibling()->setNextSibling(child->nextSibling());
979         if (child->nextSibling())
980             child->nextSibling()->setPreviousSibling(child->previousSibling());
981     }
982 
983     child->children()->setFirstChild(0);
984     child->m_next = 0;
985 
986     // Remove all the information in the flow thread associated with the leftover anonymous block.
987     child->removeFromRenderFlowThread();
988 
989     child->setParent(0);
990     child->setPreviousSibling(0);
991     child->setNextSibling(0);
992 
993     child->destroy();
994 }
995 
canMergeContiguousAnonymousBlocks(RenderObject * oldChild,RenderObject * prev,RenderObject * next)996 static bool canMergeContiguousAnonymousBlocks(RenderObject* oldChild, RenderObject* prev, RenderObject* next)
997 {
998     if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
999         return false;
1000 
1001     if ((prev && (!prev->isAnonymousBlock() || toRenderBlock(prev)->continuation() || toRenderBlock(prev)->beingDestroyed()))
1002         || (next && (!next->isAnonymousBlock() || toRenderBlock(next)->continuation() || toRenderBlock(next)->beingDestroyed())))
1003         return false;
1004 
1005     if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
1006         || (next && (next->isRubyRun() || next->isRubyBase())))
1007         return false;
1008 
1009     if (!prev || !next)
1010         return true;
1011 
1012     // Make sure the types of the anonymous blocks match up.
1013     return prev->isAnonymousColumnsBlock() == next->isAnonymousColumnsBlock()
1014            && prev->isAnonymousColumnSpanBlock() == next->isAnonymousColumnSpanBlock();
1015 }
1016 
collapseAnonymousBlockChild(RenderBlock * parent,RenderBlock * child)1017 void RenderBlock::collapseAnonymousBlockChild(RenderBlock* parent, RenderBlock* child)
1018 {
1019     // It's possible that this block's destruction may have been triggered by the
1020     // child's removal. Just bail if the anonymous child block is already being
1021     // destroyed. See crbug.com/282088
1022     if (child->beingDestroyed())
1023         return;
1024     parent->setNeedsLayoutAndPrefWidthsRecalc();
1025     parent->setChildrenInline(child->childrenInline());
1026     RenderObject* nextSibling = child->nextSibling();
1027 
1028     RenderFlowThread* childFlowThread = child->flowThreadContainingBlock();
1029     CurrentRenderFlowThreadMaintainer flowThreadMaintainer(childFlowThread);
1030 
1031     parent->children()->removeChildNode(parent, child, child->hasLayer());
1032     child->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
1033     // Explicitly delete the child's line box tree, or the special anonymous
1034     // block handling in willBeDestroyed will cause problems.
1035     child->deleteLineBoxTree();
1036     if (childFlowThread && childFlowThread->isRenderNamedFlowThread())
1037         toRenderNamedFlowThread(childFlowThread)->removeFlowChildInfo(child);
1038     child->destroy();
1039 }
1040 
removeChild(RenderObject * oldChild)1041 void RenderBlock::removeChild(RenderObject* oldChild)
1042 {
1043     // No need to waste time in merging or removing empty anonymous blocks.
1044     // We can just bail out if our document is getting destroyed.
1045     if (documentBeingDestroyed()) {
1046         RenderBox::removeChild(oldChild);
1047         return;
1048     }
1049 
1050     // This protects against column split flows when anonymous blocks are getting merged.
1051     TemporaryChange<bool> columnFlowSplitEnabled(gColumnFlowSplitEnabled, false);
1052 
1053     // If this child is a block, and if our previous and next siblings are
1054     // both anonymous blocks with inline content, then we can go ahead and
1055     // fold the inline content back together.
1056     RenderObject* prev = oldChild->previousSibling();
1057     RenderObject* next = oldChild->nextSibling();
1058     bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
1059     if (canMergeAnonymousBlocks && prev && next) {
1060         prev->setNeedsLayoutAndPrefWidthsRecalc();
1061         RenderBlock* nextBlock = toRenderBlock(next);
1062         RenderBlock* prevBlock = toRenderBlock(prev);
1063 
1064         if (prev->childrenInline() != next->childrenInline()) {
1065             RenderBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
1066             RenderBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
1067 
1068             // Place the inline children block inside of the block children block instead of deleting it.
1069             // In order to reuse it, we have to reset it to just be a generic anonymous block.  Make sure
1070             // to clear out inherited column properties by just making a new style, and to also clear the
1071             // column span flag if it is set.
1072             ASSERT(!inlineChildrenBlock->continuation());
1073             RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(style(), BLOCK);
1074             // Cache this value as it might get changed in setStyle() call.
1075             bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
1076             inlineChildrenBlock->setStyle(newStyle);
1077             children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer);
1078 
1079             // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
1080             blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
1081                                                             inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer());
1082             next->setNeedsLayoutAndPrefWidthsRecalc();
1083 
1084             // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
1085             // of "this". we null out prev or next so that is not used later in the function.
1086             if (inlineChildrenBlock == prevBlock)
1087                 prev = 0;
1088             else
1089                 next = 0;
1090         } else {
1091             // Take all the children out of the |next| block and put them in
1092             // the |prev| block.
1093             nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
1094 
1095             // Delete the now-empty block's lines and nuke it.
1096             nextBlock->deleteLineBoxTree();
1097             nextBlock->destroy();
1098             next = 0;
1099         }
1100     }
1101 
1102     RenderBox::removeChild(oldChild);
1103 
1104     RenderObject* child = prev ? prev : next;
1105     if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
1106         // The removal has knocked us down to containing only a single anonymous
1107         // box.  We can go ahead and pull the content right back up into our
1108         // box.
1109         collapseAnonymousBlockChild(this, toRenderBlock(child));
1110     } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
1111         // It's possible that the removal has knocked us down to a single anonymous
1112         // block with pseudo-style element siblings (e.g. first-letter). If these
1113         // are floating, then we need to pull the content up also.
1114         RenderBlock* anonymousBlock = toRenderBlock((prev && prev->isAnonymousBlock()) ? prev : next);
1115         if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling())
1116             && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling()))
1117             && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) {
1118             collapseAnonymousBlockChild(this, anonymousBlock);
1119         }
1120     }
1121 
1122     if (!firstChild()) {
1123         // If this was our last child be sure to clear out our line boxes.
1124         if (childrenInline())
1125             deleteLineBoxTree();
1126 
1127         // If we are an empty anonymous block in the continuation chain,
1128         // we need to remove ourself and fix the continuation chain.
1129         if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
1130             RenderObject* containingBlockIgnoringAnonymous = containingBlock();
1131             while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymousBlock())
1132                 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
1133             for (RenderObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
1134                 if (curr->virtualContinuation() != this)
1135                     continue;
1136 
1137                 // Found our previous continuation. We just need to point it to
1138                 // |this|'s next continuation.
1139                 RenderBoxModelObject* nextContinuation = continuation();
1140                 if (curr->isRenderInline())
1141                     toRenderInline(curr)->setContinuation(nextContinuation);
1142                 else if (curr->isRenderBlock())
1143                     toRenderBlock(curr)->setContinuation(nextContinuation);
1144                 else
1145                     ASSERT_NOT_REACHED();
1146 
1147                 break;
1148             }
1149             setContinuation(0);
1150             destroy();
1151         }
1152     }
1153 }
1154 
isSelfCollapsingBlock() const1155 bool RenderBlock::isSelfCollapsingBlock() const
1156 {
1157     // We are not self-collapsing if we
1158     // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
1159     // (b) are a table,
1160     // (c) have border/padding,
1161     // (d) have a min-height
1162     // (e) have specified that one of our margins can't collapse using a CSS extension
1163     if (logicalHeight() > 0
1164         || isTable() || borderAndPaddingLogicalHeight()
1165         || style()->logicalMinHeight().isPositive()
1166         || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
1167         return false;
1168 
1169     Length logicalHeightLength = style()->logicalHeight();
1170     bool hasAutoHeight = logicalHeightLength.isAuto();
1171     if (logicalHeightLength.isPercent() && !document().inQuirksMode()) {
1172         hasAutoHeight = true;
1173         for (RenderBlock* cb = containingBlock(); !cb->isRenderView(); cb = cb->containingBlock()) {
1174             if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
1175                 hasAutoHeight = false;
1176         }
1177     }
1178 
1179     // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
1180     // on whether we have content that is all self-collapsing or not.
1181     if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.isPercent()) && logicalHeightLength.isZero())) {
1182         // If the block has inline children, see if we generated any line boxes.  If we have any
1183         // line boxes, then we can't be self-collapsing, since we have content.
1184         if (childrenInline())
1185             return !firstLineBox();
1186 
1187         // Whether or not we collapse is dependent on whether all our normal flow children
1188         // are also self-collapsing.
1189         for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1190             if (child->isFloatingOrOutOfFlowPositioned())
1191                 continue;
1192             if (!child->isSelfCollapsingBlock())
1193                 return false;
1194         }
1195         return true;
1196     }
1197     return false;
1198 }
1199 
startDelayUpdateScrollInfo()1200 void RenderBlock::startDelayUpdateScrollInfo()
1201 {
1202     if (gDelayUpdateScrollInfo == 0) {
1203         ASSERT(!gDelayedUpdateScrollInfoSet);
1204         gDelayedUpdateScrollInfoSet = new DelayedUpdateScrollInfoSet;
1205     }
1206     ASSERT(gDelayedUpdateScrollInfoSet);
1207     ++gDelayUpdateScrollInfo;
1208 }
1209 
finishDelayUpdateScrollInfo()1210 void RenderBlock::finishDelayUpdateScrollInfo()
1211 {
1212     --gDelayUpdateScrollInfo;
1213     ASSERT(gDelayUpdateScrollInfo >= 0);
1214     if (gDelayUpdateScrollInfo == 0) {
1215         ASSERT(gDelayedUpdateScrollInfoSet);
1216 
1217         OwnPtr<DelayedUpdateScrollInfoSet> infoSet(adoptPtr(gDelayedUpdateScrollInfoSet));
1218         gDelayedUpdateScrollInfoSet = 0;
1219 
1220         for (DelayedUpdateScrollInfoSet::iterator it = infoSet->begin(); it != infoSet->end(); ++it) {
1221             RenderBlock* block = *it;
1222             if (block->hasOverflowClip()) {
1223                 block->layer()->scrollableArea()->updateAfterLayout();
1224             }
1225         }
1226     }
1227 }
1228 
updateScrollInfoAfterLayout()1229 void RenderBlock::updateScrollInfoAfterLayout()
1230 {
1231     if (hasOverflowClip()) {
1232         if (style()->isFlippedBlocksWritingMode()) {
1233             // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
1234             // Workaround for now. We cannot delay the scroll info for overflow
1235             // for items with opposite writing directions, as the contents needs
1236             // to overflow in that direction
1237             layer()->scrollableArea()->updateAfterLayout();
1238             return;
1239         }
1240 
1241         if (gDelayUpdateScrollInfo)
1242             gDelayedUpdateScrollInfoSet->add(this);
1243         else
1244             layer()->scrollableArea()->updateAfterLayout();
1245     }
1246 }
1247 
layout()1248 void RenderBlock::layout()
1249 {
1250     OverflowEventDispatcher dispatcher(this);
1251     LayoutRectRecorder recorder(*this);
1252 
1253     // Update our first letter info now.
1254     updateFirstLetter();
1255 
1256     // Table cells call layoutBlock directly, so don't add any logic here.  Put code into
1257     // layoutBlock().
1258     layoutBlock(false);
1259 
1260     if (frameView()->partialLayout().isStopping())
1261         return;
1262 
1263     // It's safe to check for control clip here, since controls can never be table cells.
1264     // If we have a lightweight clip, there can never be any overflow from children.
1265     if (hasControlClip() && m_overflow)
1266         clearLayoutOverflow();
1267 
1268     invalidateBackgroundObscurationStatus();
1269 }
1270 
didLayout(ResourceLoadPriorityOptimizer & optimizer)1271 void RenderBlock::didLayout(ResourceLoadPriorityOptimizer& optimizer)
1272 {
1273     RenderBox::didLayout(optimizer);
1274     updateStyleImageLoadingPriorities(optimizer);
1275 }
1276 
didScroll(ResourceLoadPriorityOptimizer & optimizer)1277 void RenderBlock::didScroll(ResourceLoadPriorityOptimizer& optimizer)
1278 {
1279     RenderBox::didScroll(optimizer);
1280     updateStyleImageLoadingPriorities(optimizer);
1281 }
1282 
updateStyleImageLoadingPriorities(ResourceLoadPriorityOptimizer & optimizer)1283 void RenderBlock::updateStyleImageLoadingPriorities(ResourceLoadPriorityOptimizer& optimizer)
1284 {
1285     RenderStyle* blockStyle = style();
1286     if (!blockStyle)
1287         return;
1288 
1289     Vector<ImageResource*> images;
1290 
1291     appendLayers(images, blockStyle->backgroundLayers());
1292     appendLayers(images, blockStyle->maskLayers());
1293 
1294     const ContentData* contentData = blockStyle->contentData();
1295     if (contentData && contentData->isImage()) {
1296         const ImageContentData* imageContentData = static_cast<const ImageContentData*>(contentData);
1297         appendImageIfNotNull(images, imageContentData->image());
1298     }
1299     if (blockStyle->boxReflect())
1300         appendImageIfNotNull(images, blockStyle->boxReflect()->mask().image());
1301     appendImageIfNotNull(images, blockStyle->listStyleImage());
1302     appendImageIfNotNull(images, blockStyle->borderImageSource());
1303     appendImageIfNotNull(images, blockStyle->maskBoxImageSource());
1304 
1305     if (images.isEmpty())
1306         return;
1307 
1308     LayoutRect viewBounds = viewRect();
1309     LayoutRect objectBounds = absoluteContentBox();
1310     // The object bounds might be empty right now, so intersects will fail since it doesn't deal
1311     // with empty rects. Use LayoutRect::contains in that case.
1312     bool isVisible;
1313     if (!objectBounds.isEmpty())
1314         isVisible =  viewBounds.intersects(objectBounds);
1315     else
1316         isVisible = viewBounds.contains(objectBounds);
1317 
1318     ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ?
1319         ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible;
1320 
1321     for (Vector<ImageResource*>::iterator it = images.begin(), end = images.end(); it != end; ++it)
1322         optimizer.notifyImageResourceVisibility(*it, status);
1323 }
1324 
relayoutShapeDescendantIfMoved(RenderBlock * child,LayoutSize offset)1325 void RenderBlock::relayoutShapeDescendantIfMoved(RenderBlock* child, LayoutSize offset)
1326 {
1327     LayoutUnit left = isHorizontalWritingMode() ? offset.width() : offset.height();
1328     if (!left || !child || child->shapeInsideInfo() || !layoutShapeInsideInfo())
1329         return;
1330     // Propagate layout markers only up to the child, as we are still in the middle
1331     // of a layout pass
1332     child->setNormalChildNeedsLayout(true);
1333     child->markShapeInsideDescendantsForLayout();
1334     child->layoutIfNeeded();
1335 }
1336 
layoutShapeInsideInfo() const1337 ShapeInsideInfo* RenderBlock::layoutShapeInsideInfo() const
1338 {
1339     if (ShapeInsideInfo* shapeInsideInfo = view()->layoutState()->shapeInsideInfo())
1340         return shapeInsideInfo;
1341 
1342     RenderFlowThread* flowThread = flowThreadContainingBlock();
1343     if (allowsShapeInsideInfoSharing(flowThread)) {
1344         LayoutUnit lineHeight = this->lineHeight(false, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes);
1345         // regionAtBlockOffset returns regions like an array first={0,N-1}, second={N,M-1}, ...
1346         LayoutUnit offset = logicalHeight() + lineHeight - LayoutUnit(1);
1347         RenderRegion* region = regionAtBlockOffset(offset);
1348         if (region && region->logicalHeight())
1349             return region->shapeInsideInfo();
1350     }
1351 
1352     return 0;
1353 }
1354 
logicalOffsetFromShapeAncestorContainer(const RenderBlock * container) const1355 LayoutSize RenderBlock::logicalOffsetFromShapeAncestorContainer(const RenderBlock* container) const
1356 {
1357     const RenderBlock* currentBlock = this;
1358     LayoutRect blockRect(currentBlock->borderBoxRect());
1359     while (currentBlock && !currentBlock->isRenderFlowThread() && currentBlock != container) {
1360         RenderBlock* containerBlock = currentBlock->containingBlock();
1361         ASSERT(containerBlock);
1362         if (!containerBlock)
1363             return LayoutSize();
1364 
1365         if (containerBlock->style()->writingMode() != currentBlock->style()->writingMode()) {
1366             // We have to put the block rect in container coordinates
1367             // and we have to take into account both the container and current block flipping modes
1368             // Bug: Flipping inline and block directions at the same time will not work,
1369             // as one of the flipped dimensions will not yet have been set to its final size
1370             if (containerBlock->style()->isFlippedBlocksWritingMode()) {
1371                 if (containerBlock->isHorizontalWritingMode())
1372                     blockRect.setY(currentBlock->height() - blockRect.maxY());
1373                 else
1374                     blockRect.setX(currentBlock->width() - blockRect.maxX());
1375             }
1376             currentBlock->flipForWritingMode(blockRect);
1377         }
1378 
1379         blockRect.moveBy(currentBlock->location());
1380         currentBlock = containerBlock;
1381     }
1382 
1383     LayoutSize result = isHorizontalWritingMode() ? LayoutSize(blockRect.x(), blockRect.y()) : LayoutSize(blockRect.y(), blockRect.x());
1384     return result;
1385 }
1386 
imageChanged(WrappedImagePtr image,const IntRect *)1387 void RenderBlock::imageChanged(WrappedImagePtr image, const IntRect*)
1388 {
1389     RenderBox::imageChanged(image);
1390 
1391     if (!parent() || !everHadLayout())
1392         return;
1393 
1394     ShapeValue* shapeValue = style()->shapeInside();
1395     if (shapeValue && shapeValue->image() && shapeValue->image()->data() == image) {
1396         ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1397         shapeInsideInfo->dirtyShapeSize();
1398         markShapeInsideDescendantsForLayout();
1399     }
1400 
1401     ShapeValue* shapeOutsideValue = style()->shapeOutside();
1402     if (isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image)
1403         parent()->setNeedsLayoutAndPrefWidthsRecalc();
1404 }
1405 
updateShapeInsideInfoAfterStyleChange(const ShapeValue * shapeInside,const ShapeValue * oldShapeInside)1406 void RenderBlock::updateShapeInsideInfoAfterStyleChange(const ShapeValue* shapeInside, const ShapeValue* oldShapeInside)
1407 {
1408     // FIXME: A future optimization would do a deep comparison for equality.
1409     if (shapeInside == oldShapeInside)
1410         return;
1411 
1412     if (shapeInside) {
1413         ShapeInsideInfo* shapeInsideInfo = ensureShapeInsideInfo();
1414         shapeInsideInfo->dirtyShapeSize();
1415     } else {
1416         setShapeInsideInfo(nullptr);
1417         markShapeInsideDescendantsForLayout();
1418     }
1419 }
1420 
shapeInfoRequiresRelayout(const RenderBlock * block)1421 static inline bool shapeInfoRequiresRelayout(const RenderBlock* block)
1422 {
1423     ShapeInsideInfo* info = block->shapeInsideInfo();
1424     if (info)
1425         info->setNeedsLayout(info->shapeSizeDirty());
1426     else
1427         info = block->layoutShapeInsideInfo();
1428     return info && info->needsLayout();
1429 }
1430 
updateRegionsAndShapesLogicalSize(RenderFlowThread * flowThread)1431 bool RenderBlock::updateRegionsAndShapesLogicalSize(RenderFlowThread* flowThread)
1432 {
1433     if (!flowThread && !shapeInsideInfo())
1434         return shapeInfoRequiresRelayout(this);
1435 
1436     LayoutUnit oldHeight = logicalHeight();
1437     LayoutUnit oldTop = logicalTop();
1438 
1439     // Compute the maximum logical height content may cause this block to expand to
1440     // FIXME: These should eventually use the const computeLogicalHeight rather than updateLogicalHeight
1441     setLogicalHeight(RenderFlowThread::maxLogicalHeight());
1442     updateLogicalHeight();
1443 
1444     computeShapeSize();
1445 
1446     // Set our start and end regions. No regions above or below us will be considered by our children. They are
1447     // effectively clamped to our region range.
1448     computeRegionRangeForBlock(flowThread);
1449 
1450     setLogicalHeight(oldHeight);
1451     setLogicalTop(oldTop);
1452 
1453     return shapeInfoRequiresRelayout(this);
1454 }
1455 
computeShapeSize()1456 void RenderBlock::computeShapeSize()
1457 {
1458     ShapeInsideInfo* shapeInsideInfo = this->shapeInsideInfo();
1459     if (!shapeInsideInfo)
1460         return;
1461 
1462     if (isRenderNamedFlowFragment()) {
1463         ShapeInsideInfo* parentShapeInsideInfo = toRenderBlock(parent())->shapeInsideInfo();
1464         ASSERT(parentShapeInsideInfo);
1465         shapeInsideInfo->setShapeSize(parentShapeInsideInfo->shapeSize().width(), parentShapeInsideInfo->shapeSize().height());
1466     } else {
1467         bool percentageLogicalHeightResolvable = percentageLogicalHeightIsResolvableFromBlock(this, false);
1468         shapeInsideInfo->setShapeSize(logicalWidth(), percentageLogicalHeightResolvable ? logicalHeight() : LayoutUnit());
1469     }
1470 }
1471 
updateRegionsAndShapesAfterChildLayout(RenderFlowThread * flowThread,bool heightChanged)1472 void RenderBlock::updateRegionsAndShapesAfterChildLayout(RenderFlowThread* flowThread, bool heightChanged)
1473 {
1474     // A previous sibling has changed dimension, so we need to relayout the shape with the content
1475     ShapeInsideInfo* shapeInsideInfo = layoutShapeInsideInfo();
1476     if (heightChanged && shapeInsideInfo)
1477         shapeInsideInfo->dirtyShapeSize();
1478 
1479     computeRegionRangeForBlock(flowThread);
1480 }
1481 
computeRegionRangeForBlock(RenderFlowThread * flowThread)1482 void RenderBlock::computeRegionRangeForBlock(RenderFlowThread* flowThread)
1483 {
1484     if (flowThread)
1485         flowThread->setRegionRangeForBox(this, offsetFromLogicalTopOfFirstPage());
1486 }
1487 
updateLogicalWidthAndColumnWidth()1488 bool RenderBlock::updateLogicalWidthAndColumnWidth()
1489 {
1490     LayoutUnit oldWidth = logicalWidth();
1491     LayoutUnit oldColumnWidth = desiredColumnWidth();
1492 
1493     updateLogicalWidth();
1494     calcColumnWidth();
1495 
1496     bool hasBorderOrPaddingLogicalWidthChanged = m_hasBorderOrPaddingLogicalWidthChanged;
1497     m_hasBorderOrPaddingLogicalWidthChanged = false;
1498 
1499     return oldWidth != logicalWidth() || oldColumnWidth != desiredColumnWidth() || hasBorderOrPaddingLogicalWidthChanged;
1500 }
1501 
checkForPaginationLogicalHeightChange(LayoutUnit & pageLogicalHeight,bool & pageLogicalHeightChanged,bool & hasSpecifiedPageLogicalHeight)1502 void RenderBlock::checkForPaginationLogicalHeightChange(LayoutUnit& pageLogicalHeight, bool& pageLogicalHeightChanged, bool& hasSpecifiedPageLogicalHeight)
1503 {
1504     ColumnInfo* colInfo = columnInfo();
1505     if (hasColumns()) {
1506         if (!pageLogicalHeight) {
1507             // We need to go ahead and set our explicit page height if one exists, so that we can
1508             // avoid doing two layout passes.
1509             updateLogicalHeight();
1510             LayoutUnit columnHeight = contentLogicalHeight();
1511             if (columnHeight > 0) {
1512                 pageLogicalHeight = columnHeight;
1513                 hasSpecifiedPageLogicalHeight = true;
1514             }
1515             setLogicalHeight(0);
1516         }
1517         if (colInfo->columnHeight() != pageLogicalHeight && everHadLayout()) {
1518             colInfo->setColumnHeight(pageLogicalHeight);
1519             pageLogicalHeightChanged = true;
1520         }
1521 
1522         if (!hasSpecifiedPageLogicalHeight && !pageLogicalHeight)
1523             colInfo->clearForcedBreaks();
1524 
1525         colInfo->setPaginationUnit(paginationUnit());
1526     } else if (isRenderFlowThread()) {
1527         pageLogicalHeight = 1; // This is just a hack to always make sure we have a page logical height.
1528         pageLogicalHeightChanged = toRenderFlowThread(this)->pageLogicalSizeChanged();
1529     }
1530 }
1531 
layoutBlock(bool,LayoutUnit)1532 void RenderBlock::layoutBlock(bool, LayoutUnit)
1533 {
1534     ASSERT_NOT_REACHED();
1535     clearNeedsLayout();
1536 }
1537 
addOverflowFromChildren()1538 void RenderBlock::addOverflowFromChildren()
1539 {
1540     if (!hasColumns()) {
1541         if (childrenInline())
1542             toRenderBlockFlow(this)->addOverflowFromInlineChildren();
1543         else
1544             addOverflowFromBlockChildren();
1545     } else {
1546         ColumnInfo* colInfo = columnInfo();
1547         if (columnCount(colInfo)) {
1548             LayoutRect lastRect = columnRectAt(colInfo, columnCount(colInfo) - 1);
1549             addLayoutOverflow(lastRect);
1550             addContentsVisualOverflow(lastRect);
1551         }
1552     }
1553 }
1554 
computeOverflow(LayoutUnit oldClientAfterEdge,bool)1555 void RenderBlock::computeOverflow(LayoutUnit oldClientAfterEdge, bool)
1556 {
1557     m_overflow.clear();
1558 
1559     // Add overflow from children.
1560     addOverflowFromChildren();
1561 
1562     // Add in the overflow from positioned objects.
1563     addOverflowFromPositionedObjects();
1564 
1565     if (hasOverflowClip()) {
1566         // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1567         // and bottom padding.  Set the axis we don't care about to be 1, since we want this overflow to always
1568         // be considered reachable.
1569         LayoutRect clientRect(noOverflowRect());
1570         LayoutRect rectToApply;
1571         if (isHorizontalWritingMode())
1572             rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1573         else
1574             rectToApply = LayoutRect(clientRect.x(), clientRect.y(), max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1575         addLayoutOverflow(rectToApply);
1576         if (hasRenderOverflow())
1577             m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
1578     }
1579 
1580     // Add visual overflow from box-shadow and border-image-outset.
1581     addVisualEffectOverflow();
1582 
1583     // Add visual overflow from theme.
1584     addVisualOverflowFromTheme();
1585 
1586     if (isRenderNamedFlowThread())
1587         toRenderNamedFlowThread(this)->computeOversetStateForRegions(oldClientAfterEdge);
1588 }
1589 
addOverflowFromBlockChildren()1590 void RenderBlock::addOverflowFromBlockChildren()
1591 {
1592     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1593         if (!child->isFloatingOrOutOfFlowPositioned())
1594             addOverflowFromChild(child);
1595     }
1596 }
1597 
addOverflowFromPositionedObjects()1598 void RenderBlock::addOverflowFromPositionedObjects()
1599 {
1600     TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1601     if (!positionedDescendants)
1602         return;
1603 
1604     RenderBox* positionedObject;
1605     TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1606     for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1607         positionedObject = *it;
1608 
1609         // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1610         if (positionedObject->style()->position() != FixedPosition)
1611             addOverflowFromChild(positionedObject, LayoutSize(positionedObject->x(), positionedObject->y()));
1612     }
1613 }
1614 
addVisualOverflowFromTheme()1615 void RenderBlock::addVisualOverflowFromTheme()
1616 {
1617     if (!style()->hasAppearance())
1618         return;
1619 
1620     IntRect inflatedRect = pixelSnappedBorderBoxRect();
1621     RenderTheme::theme().adjustRepaintRect(this, inflatedRect);
1622     addVisualOverflow(inflatedRect);
1623 }
1624 
expandsToEncloseOverhangingFloats() const1625 bool RenderBlock::expandsToEncloseOverhangingFloats() const
1626 {
1627     return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || (parent() && parent()->isFlexibleBoxIncludingDeprecated())
1628            || hasColumns() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot() || isRoot();
1629 }
1630 
computeStartPositionDeltaForChildAvoidingFloats(const RenderBox * child,LayoutUnit childMarginStart,RenderRegion * region)1631 LayoutUnit RenderBlock::computeStartPositionDeltaForChildAvoidingFloats(const RenderBox* child, LayoutUnit childMarginStart, RenderRegion* region)
1632 {
1633     LayoutUnit startPosition = startOffsetForContent(region);
1634 
1635     // Add in our start margin.
1636     LayoutUnit oldPosition = startPosition + childMarginStart;
1637     LayoutUnit newPosition = oldPosition;
1638 
1639     LayoutUnit blockOffset = logicalTopForChild(child);
1640     if (region)
1641         blockOffset = max(blockOffset, blockOffset + (region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage()));
1642 
1643     LayoutUnit startOff = startOffsetForLineInRegion(blockOffset, false, region, logicalHeightForChild(child));
1644 
1645     if (style()->textAlign() != WEBKIT_CENTER && !child->style()->marginStartUsing(style()).isAuto()) {
1646         if (childMarginStart < 0)
1647             startOff += childMarginStart;
1648         newPosition = max(newPosition, startOff); // Let the float sit in the child's margin if it can fit.
1649     } else if (startOff != startPosition)
1650         newPosition = startOff + childMarginStart;
1651 
1652     return newPosition - oldPosition;
1653 }
1654 
determineLogicalLeftPositionForChild(RenderBox * child,ApplyLayoutDeltaMode applyDelta)1655 void RenderBlock::determineLogicalLeftPositionForChild(RenderBox* child, ApplyLayoutDeltaMode applyDelta)
1656 {
1657     LayoutUnit startPosition = borderStart() + paddingStart();
1658     if (style()->shouldPlaceBlockDirectionScrollbarOnLogicalLeft())
1659         startPosition -= verticalScrollbarWidth();
1660     LayoutUnit totalAvailableLogicalWidth = borderAndPaddingLogicalWidth() + availableLogicalWidth();
1661 
1662     // Add in our start margin.
1663     LayoutUnit childMarginStart = marginStartForChild(child);
1664     LayoutUnit newPosition = startPosition + childMarginStart;
1665 
1666     // Some objects (e.g., tables, horizontal rules, overflow:auto blocks) avoid floats.  They need
1667     // to shift over as necessary to dodge any floats that might get in the way.
1668     if (child->avoidsFloats() && containsFloats() && !flowThreadContainingBlock())
1669         newPosition += computeStartPositionDeltaForChildAvoidingFloats(child, marginStartForChild(child));
1670 
1671     setLogicalLeftForChild(child, style()->isLeftToRightDirection() ? newPosition : totalAvailableLogicalWidth - newPosition - logicalWidthForChild(child), applyDelta);
1672 }
1673 
setLogicalLeftForChild(RenderBox * child,LayoutUnit logicalLeft,ApplyLayoutDeltaMode applyDelta)1674 void RenderBlock::setLogicalLeftForChild(RenderBox* child, LayoutUnit logicalLeft, ApplyLayoutDeltaMode applyDelta)
1675 {
1676     if (isHorizontalWritingMode()) {
1677         if (applyDelta == ApplyLayoutDelta)
1678             view()->addLayoutDelta(LayoutSize(child->x() - logicalLeft, 0));
1679         child->setX(logicalLeft);
1680     } else {
1681         if (applyDelta == ApplyLayoutDelta)
1682             view()->addLayoutDelta(LayoutSize(0, child->y() - logicalLeft));
1683         child->setY(logicalLeft);
1684     }
1685 }
1686 
setLogicalTopForChild(RenderBox * child,LayoutUnit logicalTop,ApplyLayoutDeltaMode applyDelta)1687 void RenderBlock::setLogicalTopForChild(RenderBox* child, LayoutUnit logicalTop, ApplyLayoutDeltaMode applyDelta)
1688 {
1689     if (isHorizontalWritingMode()) {
1690         if (applyDelta == ApplyLayoutDelta)
1691             view()->addLayoutDelta(LayoutSize(0, child->y() - logicalTop));
1692         child->setY(logicalTop);
1693     } else {
1694         if (applyDelta == ApplyLayoutDelta)
1695             view()->addLayoutDelta(LayoutSize(child->x() - logicalTop, 0));
1696         child->setX(logicalTop);
1697     }
1698 }
1699 
updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren,RenderBox * child)1700 void RenderBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, RenderBox* child)
1701 {
1702     // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1703     // an auto value. Add a method to determine this, so that we can avoid the relayout.
1704     if (relayoutChildren || (child->hasRelativeLogicalHeight() && !isRenderView()))
1705         child->setChildNeedsLayout(MarkOnlyThis);
1706 
1707     // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1708     if (relayoutChildren && child->needsPreferredWidthsRecalculation())
1709         child->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1710 }
1711 
simplifiedNormalFlowLayout()1712 void RenderBlock::simplifiedNormalFlowLayout()
1713 {
1714     if (childrenInline()) {
1715         ListHashSet<RootInlineBox*> lineBoxes;
1716         for (InlineWalker walker(this); !walker.atEnd(); walker.advance()) {
1717             RenderObject* o = walker.current();
1718             if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
1719                 o->layoutIfNeeded();
1720                 if (toRenderBox(o)->inlineBoxWrapper()) {
1721                     RootInlineBox* box = toRenderBox(o)->inlineBoxWrapper()->root();
1722                     lineBoxes.add(box);
1723                 }
1724             } else if (o->isText() || (o->isRenderInline() && !walker.atEndOfInline())) {
1725                 o->clearNeedsLayout();
1726             }
1727         }
1728 
1729         // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
1730         GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1731         for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
1732             RootInlineBox* box = *it;
1733             box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
1734         }
1735     } else {
1736         for (RenderBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
1737             if (!box->isOutOfFlowPositioned())
1738                 box->layoutIfNeeded();
1739         }
1740     }
1741 }
1742 
simplifiedLayout()1743 bool RenderBlock::simplifiedLayout()
1744 {
1745     if ((!posChildNeedsLayout() && !needsSimplifiedNormalFlowLayout()) || normalChildNeedsLayout() || selfNeedsLayout())
1746         return false;
1747 
1748     LayoutStateMaintainer statePusher(view(), this, locationOffset(), hasColumns() || hasTransform() || hasReflection() || style()->isFlippedBlocksWritingMode());
1749 
1750     if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
1751         return false;
1752 
1753     // Lay out positioned descendants or objects that just need to recompute overflow.
1754     if (needsSimplifiedNormalFlowLayout())
1755         simplifiedNormalFlowLayout();
1756 
1757     // Make sure a forced break is applied after the content if we are a flow thread in a simplified layout.
1758     // This ensures the size information is correctly computed for the last auto-height region receiving content.
1759     if (isRenderFlowThread())
1760         toRenderFlowThread(this)->applyBreakAfterContent(clientLogicalBottom());
1761 
1762     // Lay out our positioned objects if our positioned child bit is set.
1763     // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
1764     // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
1765     // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
1766     // are statically positioned and thus need to move with their absolute ancestors.
1767     bool canContainFixedPosObjects = canContainFixedPositionObjects();
1768     if (posChildNeedsLayout() || canContainFixedPosObjects)
1769         layoutPositionedObjects(false, !posChildNeedsLayout() && canContainFixedPosObjects);
1770 
1771     // Recompute our overflow information.
1772     // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
1773     // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
1774     // For now just always recompute overflow.  This is no worse performance-wise than the old code that called rightmostPosition and
1775     // lowestPosition on every relayout so it's not a regression.
1776     // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
1777     // simplifiedLayout, we cache the value in m_overflow.
1778     LayoutUnit oldClientAfterEdge = hasRenderOverflow() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
1779     computeOverflow(oldClientAfterEdge, true);
1780 
1781     statePusher.pop();
1782 
1783     updateLayerTransform();
1784 
1785     updateScrollInfoAfterLayout();
1786 
1787     clearNeedsLayout();
1788     return true;
1789 }
1790 
markFixedPositionObjectForLayoutIfNeeded(RenderObject * child,SubtreeLayoutScope & layoutScope)1791 void RenderBlock::markFixedPositionObjectForLayoutIfNeeded(RenderObject* child, SubtreeLayoutScope& layoutScope)
1792 {
1793     if (child->style()->position() != FixedPosition)
1794         return;
1795 
1796     bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
1797     bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
1798     if (!hasStaticBlockPosition && !hasStaticInlinePosition)
1799         return;
1800 
1801     RenderObject* o = child->parent();
1802     while (o && !o->isRenderView() && o->style()->position() != AbsolutePosition)
1803         o = o->parent();
1804     if (o->style()->position() != AbsolutePosition)
1805         return;
1806 
1807     RenderBox* box = toRenderBox(child);
1808     if (hasStaticInlinePosition) {
1809         LayoutUnit oldLeft = box->logicalLeft();
1810         box->updateLogicalWidth();
1811         if (box->logicalLeft() != oldLeft)
1812             layoutScope.setChildNeedsLayout(child);
1813     } else if (hasStaticBlockPosition) {
1814         LayoutUnit oldTop = box->logicalTop();
1815         box->updateLogicalHeight();
1816         if (box->logicalTop() != oldTop)
1817             layoutScope.setChildNeedsLayout(child);
1818     }
1819 }
1820 
marginIntrinsicLogicalWidthForChild(RenderBox * child) const1821 LayoutUnit RenderBlock::marginIntrinsicLogicalWidthForChild(RenderBox* child) const
1822 {
1823     // A margin has three types: fixed, percentage, and auto (variable).
1824     // Auto and percentage margins become 0 when computing min/max width.
1825     // Fixed margins can be added in as is.
1826     Length marginLeft = child->style()->marginStartUsing(style());
1827     Length marginRight = child->style()->marginEndUsing(style());
1828     LayoutUnit margin = 0;
1829     if (marginLeft.isFixed())
1830         margin += marginLeft.value();
1831     if (marginRight.isFixed())
1832         margin += marginRight.value();
1833     return margin;
1834 }
1835 
layoutPositionedObjects(bool relayoutChildren,bool fixedPositionObjectsOnly)1836 void RenderBlock::layoutPositionedObjects(bool relayoutChildren, bool fixedPositionObjectsOnly)
1837 {
1838     TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1839     if (!positionedDescendants)
1840         return;
1841 
1842     if (hasColumns())
1843         view()->layoutState()->clearPaginationInformation(); // Positioned objects are not part of the column flow, so they don't paginate with the columns.
1844 
1845     RenderBox* r;
1846     TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1847     for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1848         r = *it;
1849 
1850         SubtreeLayoutScope layoutScope(r);
1851         // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
1852         // if this is a fixed position element, mark it for layout if it has an abspos ancestor and needs to move with that ancestor, i.e.
1853         // it has static position.
1854         markFixedPositionObjectForLayoutIfNeeded(r, layoutScope);
1855         if (fixedPositionObjectsOnly) {
1856             r->layoutIfNeeded();
1857             continue;
1858         }
1859 
1860         // When a non-positioned block element moves, it may have positioned children that are implicitly positioned relative to the
1861         // non-positioned block.  Rather than trying to detect all of these movement cases, we just always lay out positioned
1862         // objects that are positioned implicitly like this.  Such objects are rare, and so in typical DHTML menu usage (where everything is
1863         // positioned explicitly) this should not incur a performance penalty.
1864         if (relayoutChildren || (r->style()->hasStaticBlockPosition(isHorizontalWritingMode()) && r->parent() != this))
1865             layoutScope.setChildNeedsLayout(r);
1866 
1867         // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1868         if (relayoutChildren && r->needsPreferredWidthsRecalculation())
1869             r->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1870 
1871         if (!r->needsLayout())
1872             r->markForPaginationRelayoutIfNeeded(layoutScope);
1873 
1874         // 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
1875         // and we hit the available width constraint, the layoutIfNeeded() will catch it and do a full layout.
1876         if (r->needsPositionedMovementLayoutOnly() && r->tryLayoutDoingPositionedMovementOnly())
1877             r->clearNeedsLayout();
1878 
1879         // If we are paginated or in a line grid, go ahead and compute a vertical position for our object now.
1880         // If it's wrong we'll lay out again.
1881         LayoutUnit oldLogicalTop = 0;
1882         bool needsBlockDirectionLocationSetBeforeLayout = r->needsLayout() && view()->layoutState()->needsBlockDirectionLocationSetBeforeLayout();
1883         if (needsBlockDirectionLocationSetBeforeLayout) {
1884             if (isHorizontalWritingMode() == r->isHorizontalWritingMode())
1885                 r->updateLogicalHeight();
1886             else
1887                 r->updateLogicalWidth();
1888             oldLogicalTop = logicalTopForChild(r);
1889         }
1890 
1891         r->layoutIfNeeded();
1892 
1893         // Lay out again if our estimate was wrong.
1894         if (needsBlockDirectionLocationSetBeforeLayout && logicalTopForChild(r) != oldLogicalTop)
1895             r->forceChildLayout();
1896     }
1897 
1898     if (hasColumns())
1899         view()->layoutState()->m_columnInfo = columnInfo(); // FIXME: Kind of gross. We just put this back into the layout state so that pop() will work.
1900 }
1901 
markPositionedObjectsForLayout()1902 void RenderBlock::markPositionedObjectsForLayout()
1903 {
1904     TrackedRendererListHashSet* positionedDescendants = positionedObjects();
1905     if (positionedDescendants) {
1906         RenderBox* r;
1907         TrackedRendererListHashSet::iterator end = positionedDescendants->end();
1908         for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
1909             r = *it;
1910             r->setChildNeedsLayout();
1911         }
1912     }
1913 }
1914 
markForPaginationRelayoutIfNeeded(SubtreeLayoutScope & layoutScope)1915 void RenderBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
1916 {
1917     ASSERT(!needsLayout());
1918     if (needsLayout())
1919         return;
1920 
1921     if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(this, logicalTop()) != pageLogicalOffset()))
1922         layoutScope.setChildNeedsLayout(this);
1923 }
1924 
paint(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1925 void RenderBlock::paint(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1926 {
1927     ANNOTATE_GRAPHICS_CONTEXT(paintInfo, this);
1928 
1929     LayoutPoint adjustedPaintOffset = paintOffset + location();
1930 
1931     PaintPhase phase = paintInfo.phase;
1932 
1933     // Check if we need to do anything at all.
1934     // FIXME: Could eliminate the isRoot() check if we fix background painting so that the RenderView
1935     // paints the root's background.
1936     if (!isRoot()) {
1937         LayoutRect overflowBox = overflowRectForPaintRejection();
1938         flipForWritingMode(overflowBox);
1939         overflowBox.inflate(maximalOutlineSize(paintInfo.phase));
1940         overflowBox.moveBy(adjustedPaintOffset);
1941         if (!overflowBox.intersects(paintInfo.rect))
1942             return;
1943     }
1944 
1945     // There are some cases where not all clipped visual overflow is accounted for.
1946     // FIXME: reduce the number of such cases.
1947     ContentsClipBehavior contentsClipBehavior = ForceContentsClip;
1948     if (hasOverflowClip() && !hasControlClip() && !(shouldPaintSelectionGaps() && phase == PaintPhaseForeground) && !hasCaret())
1949         contentsClipBehavior = SkipContentsClipIfPossible;
1950 
1951     bool pushedClip = pushContentsClip(paintInfo, adjustedPaintOffset, contentsClipBehavior);
1952     paintObject(paintInfo, adjustedPaintOffset);
1953     if (pushedClip)
1954         popContentsClip(paintInfo, phase, adjustedPaintOffset);
1955 
1956     // Our scrollbar widgets paint exactly when we tell them to, so that they work properly with
1957     // z-index.  We paint after we painted the background/border, so that the scrollbars will
1958     // sit above the background/border.
1959     if (hasOverflowClip() && style()->visibility() == VISIBLE && (phase == PaintPhaseBlockBackground || phase == PaintPhaseChildBlockBackground) && paintInfo.shouldPaintWithinRoot(this) && !paintInfo.paintRootBackgroundOnly())
1960         layer()->scrollableArea()->paintOverflowControls(paintInfo.context, roundedIntPoint(adjustedPaintOffset), paintInfo.rect, false /* paintingOverlayControls */);
1961 }
1962 
paintColumnRules(PaintInfo & paintInfo,const LayoutPoint & paintOffset)1963 void RenderBlock::paintColumnRules(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1964 {
1965     if (paintInfo.context->paintingDisabled())
1966         return;
1967 
1968     const Color& ruleColor = resolveColor(CSSPropertyWebkitColumnRuleColor);
1969     bool ruleTransparent = style()->columnRuleIsTransparent();
1970     EBorderStyle ruleStyle = style()->columnRuleStyle();
1971     LayoutUnit ruleThickness = style()->columnRuleWidth();
1972     LayoutUnit colGap = columnGap();
1973     bool renderRule = ruleStyle > BHIDDEN && !ruleTransparent;
1974     if (!renderRule)
1975         return;
1976 
1977     ColumnInfo* colInfo = columnInfo();
1978     unsigned colCount = columnCount(colInfo);
1979 
1980     bool antialias = shouldAntialiasLines(paintInfo.context);
1981 
1982     if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
1983         bool leftToRight = style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed();
1984         LayoutUnit currLogicalLeftOffset = leftToRight ? LayoutUnit() : contentLogicalWidth();
1985         LayoutUnit ruleAdd = logicalLeftOffsetForContent();
1986         LayoutUnit ruleLogicalLeft = leftToRight ? LayoutUnit() : contentLogicalWidth();
1987         LayoutUnit inlineDirectionSize = colInfo->desiredColumnWidth();
1988         BoxSide boxSide = isHorizontalWritingMode()
1989             ? leftToRight ? BSLeft : BSRight
1990             : leftToRight ? BSTop : BSBottom;
1991 
1992         for (unsigned i = 0; i < colCount; i++) {
1993             // Move to the next position.
1994             if (leftToRight) {
1995                 ruleLogicalLeft += inlineDirectionSize + colGap / 2;
1996                 currLogicalLeftOffset += inlineDirectionSize + colGap;
1997             } else {
1998                 ruleLogicalLeft -= (inlineDirectionSize + colGap / 2);
1999                 currLogicalLeftOffset -= (inlineDirectionSize + colGap);
2000             }
2001 
2002             // Now paint the column rule.
2003             if (i < colCount - 1) {
2004                 LayoutUnit ruleLeft = isHorizontalWritingMode() ? paintOffset.x() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd : paintOffset.x() + borderLeft() + paddingLeft();
2005                 LayoutUnit ruleRight = isHorizontalWritingMode() ? ruleLeft + ruleThickness : ruleLeft + contentWidth();
2006                 LayoutUnit ruleTop = isHorizontalWritingMode() ? paintOffset.y() + borderTop() + paddingTop() : paintOffset.y() + ruleLogicalLeft - ruleThickness / 2 + ruleAdd;
2007                 LayoutUnit ruleBottom = isHorizontalWritingMode() ? ruleTop + contentHeight() : ruleTop + ruleThickness;
2008                 IntRect pixelSnappedRuleRect = pixelSnappedIntRectFromEdges(ruleLeft, ruleTop, ruleRight, ruleBottom);
2009                 drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2010             }
2011 
2012             ruleLogicalLeft = currLogicalLeftOffset;
2013         }
2014     } else {
2015         bool topToBottom = !style()->isFlippedBlocksWritingMode() ^ colInfo->progressionIsReversed();
2016         LayoutUnit ruleLeft = isHorizontalWritingMode()
2017             ? borderLeft() + paddingLeft()
2018             : colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter());
2019         LayoutUnit ruleWidth = isHorizontalWritingMode() ? contentWidth() : ruleThickness;
2020         LayoutUnit ruleTop = isHorizontalWritingMode()
2021             ? colGap / 2 - colGap - ruleThickness / 2 + (!colInfo->progressionIsReversed() ? borderBefore() + paddingBefore() : borderAfter() + paddingAfter())
2022             : borderStart() + paddingStart();
2023         LayoutUnit ruleHeight = isHorizontalWritingMode() ? ruleThickness : contentHeight();
2024         LayoutRect ruleRect(ruleLeft, ruleTop, ruleWidth, ruleHeight);
2025 
2026         if (!topToBottom) {
2027             if (isHorizontalWritingMode())
2028                 ruleRect.setY(height() - ruleRect.maxY());
2029             else
2030                 ruleRect.setX(width() - ruleRect.maxX());
2031         }
2032 
2033         ruleRect.moveBy(paintOffset);
2034 
2035         BoxSide boxSide = isHorizontalWritingMode()
2036             ? topToBottom ? BSTop : BSBottom
2037             : topToBottom ? BSLeft : BSRight;
2038 
2039         LayoutSize step(0, topToBottom ? colInfo->columnHeight() + colGap : -(colInfo->columnHeight() + colGap));
2040         if (!isHorizontalWritingMode())
2041             step = step.transposedSize();
2042 
2043         for (unsigned i = 1; i < colCount; i++) {
2044             ruleRect.move(step);
2045             IntRect pixelSnappedRuleRect = pixelSnappedIntRect(ruleRect);
2046             drawLineForBoxSide(paintInfo.context, pixelSnappedRuleRect.x(), pixelSnappedRuleRect.y(), pixelSnappedRuleRect.maxX(), pixelSnappedRuleRect.maxY(), boxSide, ruleColor, ruleStyle, 0, 0, antialias);
2047         }
2048     }
2049 }
2050 
paintColumnContents(PaintInfo & paintInfo,const LayoutPoint & paintOffset,bool paintingFloats)2051 void RenderBlock::paintColumnContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset, bool paintingFloats)
2052 {
2053     // We need to do multiple passes, breaking up our child painting into strips.
2054     GraphicsContext* context = paintInfo.context;
2055     ColumnInfo* colInfo = columnInfo();
2056     unsigned colCount = columnCount(colInfo);
2057     if (!colCount)
2058         return;
2059     LayoutUnit currLogicalTopOffset = 0;
2060     LayoutUnit colGap = columnGap();
2061     for (unsigned i = 0; i < colCount; i++) {
2062         // For each rect, we clip to the rect, and then we adjust our coords.
2063         LayoutRect colRect = columnRectAt(colInfo, i);
2064         flipForWritingMode(colRect);
2065         LayoutUnit logicalLeftOffset = (isHorizontalWritingMode() ? colRect.x() : colRect.y()) - logicalLeftOffsetForContent();
2066         LayoutSize offset = isHorizontalWritingMode() ? LayoutSize(logicalLeftOffset, currLogicalTopOffset) : LayoutSize(currLogicalTopOffset, logicalLeftOffset);
2067         if (colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
2068             if (isHorizontalWritingMode())
2069                 offset.expand(0, colRect.y() - borderTop() - paddingTop());
2070             else
2071                 offset.expand(colRect.x() - borderLeft() - paddingLeft(), 0);
2072         }
2073         colRect.moveBy(paintOffset);
2074         PaintInfo info(paintInfo);
2075         info.rect.intersect(pixelSnappedIntRect(colRect));
2076 
2077         if (!info.rect.isEmpty()) {
2078             GraphicsContextStateSaver stateSaver(*context);
2079             LayoutRect clipRect(colRect);
2080 
2081             if (i < colCount - 1) {
2082                 if (isHorizontalWritingMode())
2083                     clipRect.expand(colGap / 2, 0);
2084                 else
2085                     clipRect.expand(0, colGap / 2);
2086             }
2087             // Each strip pushes a clip, since column boxes are specified as being
2088             // like overflow:hidden.
2089             // FIXME: Content and column rules that extend outside column boxes at the edges of the multi-column element
2090             // are clipped according to the 'overflow' property.
2091             context->clip(pixelSnappedIntRect(clipRect));
2092 
2093             // Adjust our x and y when painting.
2094             LayoutPoint adjustedPaintOffset = paintOffset + offset;
2095             if (paintingFloats)
2096                 paintFloats(info, adjustedPaintOffset, paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip);
2097             else
2098                 paintContents(info, adjustedPaintOffset);
2099         }
2100 
2101         LayoutUnit blockDelta = (isHorizontalWritingMode() ? colRect.height() : colRect.width());
2102         if (style()->isFlippedBlocksWritingMode())
2103             currLogicalTopOffset += blockDelta;
2104         else
2105             currLogicalTopOffset -= blockDelta;
2106     }
2107 }
2108 
paintContents(PaintInfo & paintInfo,const LayoutPoint & paintOffset)2109 void RenderBlock::paintContents(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2110 {
2111     // Avoid painting descendants of the root element when stylesheets haven't loaded.  This eliminates FOUC.
2112     // It's ok not to draw, because later on, when all the stylesheets do load, styleResolverChanged() on the Document
2113     // will do a full repaint.
2114     if (document().didLayoutWithPendingStylesheets() && !isRenderView())
2115         return;
2116 
2117     if (childrenInline())
2118         m_lineBoxes.paint(this, paintInfo, paintOffset);
2119     else {
2120         PaintPhase newPhase = (paintInfo.phase == PaintPhaseChildOutlines) ? PaintPhaseOutline : paintInfo.phase;
2121         newPhase = (newPhase == PaintPhaseChildBlockBackgrounds) ? PaintPhaseChildBlockBackground : newPhase;
2122 
2123         // We don't paint our own background, but we do let the kids paint their backgrounds.
2124         PaintInfo paintInfoForChild(paintInfo);
2125         paintInfoForChild.phase = newPhase;
2126         paintInfoForChild.updatePaintingRootForChildren(this);
2127         paintChildren(paintInfoForChild, paintOffset);
2128     }
2129 }
2130 
paintChildren(PaintInfo & paintInfo,const LayoutPoint & paintOffset)2131 void RenderBlock::paintChildren(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2132 {
2133     for (RenderBox* child = firstChildBox(); child; child = child->nextSiblingBox())
2134         paintChild(child, paintInfo, paintOffset);
2135 }
2136 
paintChild(RenderBox * child,PaintInfo & paintInfo,const LayoutPoint & paintOffset)2137 void RenderBlock::paintChild(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2138 {
2139     LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2140     if (!child->hasSelfPaintingLayer() && !child->isFloating())
2141         child->paint(paintInfo, childPoint);
2142 }
2143 
paintChildAsInlineBlock(RenderBox * child,PaintInfo & paintInfo,const LayoutPoint & paintOffset)2144 void RenderBlock::paintChildAsInlineBlock(RenderBox* child, PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2145 {
2146     LayoutPoint childPoint = flipForWritingModeForChild(child, paintOffset);
2147     if (!child->hasSelfPaintingLayer() && !child->isFloating())
2148         paintAsInlineBlock(child, paintInfo, childPoint);
2149 }
2150 
paintAsInlineBlock(RenderObject * renderer,PaintInfo & paintInfo,const LayoutPoint & childPoint)2151 void RenderBlock::paintAsInlineBlock(RenderObject* renderer, PaintInfo& paintInfo, const LayoutPoint& childPoint)
2152 {
2153     if (paintInfo.phase != PaintPhaseForeground && paintInfo.phase != PaintPhaseSelection)
2154         return;
2155 
2156     // Paint all phases atomically, as though the element established its own
2157     // stacking context.  (See Appendix E.2, section 7.2.1.4 on
2158     // inline block/table/replaced elements in the CSS2.1 specification.)
2159     // This is also used by other elements (e.g. flex items and grid items).
2160     bool preservePhase = paintInfo.phase == PaintPhaseSelection || paintInfo.phase == PaintPhaseTextClip;
2161     PaintInfo info(paintInfo);
2162     info.phase = preservePhase ? paintInfo.phase : PaintPhaseBlockBackground;
2163     renderer->paint(info, childPoint);
2164     if (!preservePhase) {
2165         info.phase = PaintPhaseChildBlockBackgrounds;
2166         renderer->paint(info, childPoint);
2167         info.phase = PaintPhaseFloat;
2168         renderer->paint(info, childPoint);
2169         info.phase = PaintPhaseForeground;
2170         renderer->paint(info, childPoint);
2171         info.phase = PaintPhaseOutline;
2172         renderer->paint(info, childPoint);
2173     }
2174 }
2175 
hasCaret(CaretType type) const2176 bool RenderBlock::hasCaret(CaretType type) const
2177 {
2178     // Paint the caret if the FrameSelection says so or if caret browsing is enabled
2179     bool caretBrowsing = frame()->settings() && frame()->settings()->caretBrowsingEnabled();
2180     RenderObject* caretPainter;
2181     bool isContentEditable;
2182     if (type == CursorCaret) {
2183         caretPainter = frame()->selection().caretRenderer();
2184         isContentEditable = frame()->selection().rendererIsEditable();
2185     } else {
2186         caretPainter = frame()->page()->dragCaretController().caretRenderer();
2187         isContentEditable = frame()->page()->dragCaretController().isContentEditable();
2188     }
2189     return caretPainter == this && (isContentEditable || caretBrowsing);
2190 }
2191 
paintCaret(PaintInfo & paintInfo,const LayoutPoint & paintOffset,CaretType type)2192 void RenderBlock::paintCaret(PaintInfo& paintInfo, const LayoutPoint& paintOffset, CaretType type)
2193 {
2194     if (!hasCaret(type))
2195         return;
2196 
2197     if (type == CursorCaret)
2198         frame()->selection().paintCaret(paintInfo.context, paintOffset, paintInfo.rect);
2199     else
2200         frame()->page()->dragCaretController().paintDragCaret(frame(), paintInfo.context, paintOffset, paintInfo.rect);
2201 }
2202 
paintObject(PaintInfo & paintInfo,const LayoutPoint & paintOffset)2203 void RenderBlock::paintObject(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2204 {
2205     PaintPhase paintPhase = paintInfo.phase;
2206 
2207     // Adjust our painting position if we're inside a scrolled layer (e.g., an overflow:auto div).
2208     LayoutPoint scrolledOffset = paintOffset;
2209     if (hasOverflowClip())
2210         scrolledOffset.move(-scrolledContentOffset());
2211 
2212     // 1. paint background, borders etc
2213     if ((paintPhase == PaintPhaseBlockBackground || paintPhase == PaintPhaseChildBlockBackground) && style()->visibility() == VISIBLE) {
2214         if (hasBoxDecorations())
2215             paintBoxDecorations(paintInfo, paintOffset);
2216         if (hasColumns() && !paintInfo.paintRootBackgroundOnly())
2217             paintColumnRules(paintInfo, scrolledOffset);
2218     }
2219 
2220     if (paintPhase == PaintPhaseMask && style()->visibility() == VISIBLE) {
2221         paintMask(paintInfo, paintOffset);
2222         return;
2223     }
2224 
2225     if (paintPhase == PaintPhaseClippingMask && style()->visibility() == VISIBLE) {
2226         paintClippingMask(paintInfo, paintOffset);
2227         return;
2228     }
2229 
2230     // We're done.  We don't bother painting any children.
2231     if (paintPhase == PaintPhaseBlockBackground || paintInfo.paintRootBackgroundOnly())
2232         return;
2233 
2234     // 2. paint contents
2235     if (paintPhase != PaintPhaseSelfOutline) {
2236         if (hasColumns())
2237             paintColumnContents(paintInfo, scrolledOffset);
2238         else
2239             paintContents(paintInfo, scrolledOffset);
2240     }
2241 
2242     // 3. paint selection
2243     // FIXME: Make this work with multi column layouts.  For now don't fill gaps.
2244     bool isPrinting = document().printing();
2245     if (!isPrinting && !hasColumns())
2246         paintSelection(paintInfo, scrolledOffset); // Fill in gaps in selection on lines and between blocks.
2247 
2248     // 4. paint floats.
2249     if (paintPhase == PaintPhaseFloat || paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip) {
2250         if (hasColumns())
2251             paintColumnContents(paintInfo, scrolledOffset, true);
2252         else
2253             paintFloats(paintInfo, scrolledOffset, paintPhase == PaintPhaseSelection || paintPhase == PaintPhaseTextClip);
2254     }
2255 
2256     // 5. paint outline.
2257     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseSelfOutline) && hasOutline() && style()->visibility() == VISIBLE)
2258         paintOutline(paintInfo, LayoutRect(paintOffset, size()));
2259 
2260     // 6. paint continuation outlines.
2261     if ((paintPhase == PaintPhaseOutline || paintPhase == PaintPhaseChildOutlines)) {
2262         RenderInline* inlineCont = inlineElementContinuation();
2263         if (inlineCont && inlineCont->hasOutline() && inlineCont->style()->visibility() == VISIBLE) {
2264             RenderInline* inlineRenderer = toRenderInline(inlineCont->node()->renderer());
2265             RenderBlock* cb = containingBlock();
2266 
2267             bool inlineEnclosedInSelfPaintingLayer = false;
2268             for (RenderBoxModelObject* box = inlineRenderer; box != cb; box = box->parent()->enclosingBoxModelObject()) {
2269                 if (box->hasSelfPaintingLayer()) {
2270                     inlineEnclosedInSelfPaintingLayer = true;
2271                     break;
2272                 }
2273             }
2274 
2275             // Do not add continuations for outline painting by our containing block if we are a relative positioned
2276             // anonymous block (i.e. have our own layer), paint them straightaway instead. This is because a block depends on renderers in its continuation table being
2277             // in the same layer.
2278             if (!inlineEnclosedInSelfPaintingLayer && !hasLayer())
2279                 cb->addContinuationWithOutline(inlineRenderer);
2280             else if (!inlineRenderer->firstLineBox() || (!inlineEnclosedInSelfPaintingLayer && hasLayer()))
2281                 inlineRenderer->paintOutline(paintInfo, paintOffset - locationOffset() + inlineRenderer->containingBlock()->location());
2282         }
2283         paintContinuationOutlines(paintInfo, paintOffset);
2284     }
2285 
2286     // 7. paint caret.
2287     // If the caret's node's render object's containing block is this block, and the paint action is PaintPhaseForeground,
2288     // then paint the caret.
2289     if (paintPhase == PaintPhaseForeground) {
2290         paintCaret(paintInfo, paintOffset, CursorCaret);
2291         paintCaret(paintInfo, paintOffset, DragCaret);
2292     }
2293 }
2294 
inlineElementContinuation() const2295 RenderInline* RenderBlock::inlineElementContinuation() const
2296 {
2297     RenderBoxModelObject* continuation = this->continuation();
2298     return continuation && continuation->isInline() ? toRenderInline(continuation) : 0;
2299 }
2300 
blockElementContinuation() const2301 RenderBlock* RenderBlock::blockElementContinuation() const
2302 {
2303     RenderBoxModelObject* currentContinuation = continuation();
2304     if (!currentContinuation || currentContinuation->isInline())
2305         return 0;
2306     RenderBlock* nextContinuation = toRenderBlock(currentContinuation);
2307     if (nextContinuation->isAnonymousBlock())
2308         return nextContinuation->blockElementContinuation();
2309     return nextContinuation;
2310 }
2311 
continuationOutlineTable()2312 static ContinuationOutlineTableMap* continuationOutlineTable()
2313 {
2314     DEFINE_STATIC_LOCAL(ContinuationOutlineTableMap, table, ());
2315     return &table;
2316 }
2317 
addContinuationWithOutline(RenderInline * flow)2318 void RenderBlock::addContinuationWithOutline(RenderInline* flow)
2319 {
2320     // We can't make this work if the inline is in a layer.  We'll just rely on the broken
2321     // way of painting.
2322     ASSERT(!flow->layer() && !flow->isInlineElementContinuation());
2323 
2324     ContinuationOutlineTableMap* table = continuationOutlineTable();
2325     ListHashSet<RenderInline*>* continuations = table->get(this);
2326     if (!continuations) {
2327         continuations = new ListHashSet<RenderInline*>;
2328         table->set(this, adoptPtr(continuations));
2329     }
2330 
2331     continuations->add(flow);
2332 }
2333 
paintsContinuationOutline(RenderInline * flow)2334 bool RenderBlock::paintsContinuationOutline(RenderInline* flow)
2335 {
2336     ContinuationOutlineTableMap* table = continuationOutlineTable();
2337     if (table->isEmpty())
2338         return false;
2339 
2340     ListHashSet<RenderInline*>* continuations = table->get(this);
2341     if (!continuations)
2342         return false;
2343 
2344     return continuations->contains(flow);
2345 }
2346 
paintContinuationOutlines(PaintInfo & info,const LayoutPoint & paintOffset)2347 void RenderBlock::paintContinuationOutlines(PaintInfo& info, const LayoutPoint& paintOffset)
2348 {
2349     ContinuationOutlineTableMap* table = continuationOutlineTable();
2350     if (table->isEmpty())
2351         return;
2352 
2353     OwnPtr<ListHashSet<RenderInline*> > continuations = table->take(this);
2354     if (!continuations)
2355         return;
2356 
2357     LayoutPoint accumulatedPaintOffset = paintOffset;
2358     // Paint each continuation outline.
2359     ListHashSet<RenderInline*>::iterator end = continuations->end();
2360     for (ListHashSet<RenderInline*>::iterator it = continuations->begin(); it != end; ++it) {
2361         // Need to add in the coordinates of the intervening blocks.
2362         RenderInline* flow = *it;
2363         RenderBlock* block = flow->containingBlock();
2364         for ( ; block && block != this; block = block->containingBlock())
2365             accumulatedPaintOffset.moveBy(block->location());
2366         ASSERT(block);
2367         flow->paintOutline(info, accumulatedPaintOffset);
2368     }
2369 }
2370 
shouldPaintSelectionGaps() const2371 bool RenderBlock::shouldPaintSelectionGaps() const
2372 {
2373     return selectionState() != SelectionNone && style()->visibility() == VISIBLE && isSelectionRoot();
2374 }
2375 
isSelectionRoot() const2376 bool RenderBlock::isSelectionRoot() const
2377 {
2378     if (isPseudoElement())
2379         return false;
2380     ASSERT(node() || isAnonymous());
2381 
2382     // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
2383     if (isTable())
2384         return false;
2385 
2386     if (isBody() || isRoot() || hasOverflowClip()
2387         || isPositioned() || isFloating()
2388         || isTableCell() || isInlineBlockOrInlineTable()
2389         || hasTransform() || hasReflection() || hasMask() || isWritingModeRoot()
2390         || isRenderFlowThread())
2391         return true;
2392 
2393     if (view() && view()->selectionStart()) {
2394         Node* startElement = view()->selectionStart()->node();
2395         if (startElement && startElement->rootEditableElement() == node())
2396             return true;
2397     }
2398 
2399     return false;
2400 }
2401 
selectionGapRectsForRepaint(const RenderLayerModelObject * repaintContainer)2402 GapRects RenderBlock::selectionGapRectsForRepaint(const RenderLayerModelObject* repaintContainer)
2403 {
2404     ASSERT(!needsLayout());
2405 
2406     if (!shouldPaintSelectionGaps())
2407         return GapRects();
2408 
2409     TransformState transformState(TransformState::ApplyTransformDirection, FloatPoint());
2410     mapLocalToContainer(repaintContainer, transformState, ApplyContainerFlip | UseTransforms);
2411     LayoutPoint offsetFromRepaintContainer = roundedLayoutPoint(transformState.mappedPoint());
2412 
2413     if (hasOverflowClip())
2414         offsetFromRepaintContainer -= scrolledContentOffset();
2415 
2416     LayoutUnit lastTop = 0;
2417     LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2418     LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2419 
2420     return selectionGaps(this, offsetFromRepaintContainer, IntSize(), lastTop, lastLeft, lastRight);
2421 }
2422 
paintSelection(PaintInfo & paintInfo,const LayoutPoint & paintOffset)2423 void RenderBlock::paintSelection(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
2424 {
2425     if (shouldPaintSelectionGaps() && paintInfo.phase == PaintPhaseForeground) {
2426         LayoutUnit lastTop = 0;
2427         LayoutUnit lastLeft = logicalLeftSelectionOffset(this, lastTop);
2428         LayoutUnit lastRight = logicalRightSelectionOffset(this, lastTop);
2429         GraphicsContextStateSaver stateSaver(*paintInfo.context);
2430 
2431         LayoutRect gapRectsBounds = selectionGaps(this, paintOffset, LayoutSize(), lastTop, lastLeft, lastRight, &paintInfo);
2432         if (!gapRectsBounds.isEmpty()) {
2433             if (RenderLayer* layer = enclosingLayer()) {
2434                 gapRectsBounds.moveBy(-paintOffset);
2435                 if (!hasLayer()) {
2436                     LayoutRect localBounds(gapRectsBounds);
2437                     flipForWritingMode(localBounds);
2438                     gapRectsBounds = localToContainerQuad(FloatRect(localBounds), layer->renderer()).enclosingBoundingBox();
2439                     if (layer->renderer()->hasOverflowClip())
2440                         gapRectsBounds.move(layer->renderBox()->scrolledContentOffset());
2441                 }
2442                 layer->addBlockSelectionGapsBounds(gapRectsBounds);
2443             }
2444         }
2445     }
2446 }
2447 
clipOutPositionedObjects(const PaintInfo * paintInfo,const LayoutPoint & offset,TrackedRendererListHashSet * positionedObjects)2448 static void clipOutPositionedObjects(const PaintInfo* paintInfo, const LayoutPoint& offset, TrackedRendererListHashSet* positionedObjects)
2449 {
2450     if (!positionedObjects)
2451         return;
2452 
2453     TrackedRendererListHashSet::const_iterator end = positionedObjects->end();
2454     for (TrackedRendererListHashSet::const_iterator it = positionedObjects->begin(); it != end; ++it) {
2455         RenderBox* r = *it;
2456         paintInfo->context->clipOut(IntRect(offset.x() + r->x(), offset.y() + r->y(), r->width(), r->height()));
2457     }
2458 }
2459 
blockDirectionOffset(const LayoutSize & offsetFromBlock) const2460 LayoutUnit RenderBlock::blockDirectionOffset(const LayoutSize& offsetFromBlock) const
2461 {
2462     return isHorizontalWritingMode() ? offsetFromBlock.height() : offsetFromBlock.width();
2463 }
2464 
inlineDirectionOffset(const LayoutSize & offsetFromBlock) const2465 LayoutUnit RenderBlock::inlineDirectionOffset(const LayoutSize& offsetFromBlock) const
2466 {
2467     return isHorizontalWritingMode() ? offsetFromBlock.width() : offsetFromBlock.height();
2468 }
2469 
logicalRectToPhysicalRect(const LayoutPoint & rootBlockPhysicalPosition,const LayoutRect & logicalRect)2470 LayoutRect RenderBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect)
2471 {
2472     LayoutRect result;
2473     if (isHorizontalWritingMode())
2474         result = logicalRect;
2475     else
2476         result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
2477     flipForWritingMode(result);
2478     result.moveBy(rootBlockPhysicalPosition);
2479     return result;
2480 }
2481 
selectionGaps(RenderBlock * rootBlock,const LayoutPoint & rootBlockPhysicalPosition,const LayoutSize & offsetFromRootBlock,LayoutUnit & lastLogicalTop,LayoutUnit & lastLogicalLeft,LayoutUnit & lastLogicalRight,const PaintInfo * paintInfo)2482 GapRects RenderBlock::selectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2483                                     LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2484 {
2485     // IMPORTANT: Callers of this method that intend for painting to happen need to do a save/restore.
2486     // Clip out floating and positioned objects when painting selection gaps.
2487     if (paintInfo) {
2488         // Note that we don't clip out overflow for positioned objects.  We just stick to the border box.
2489         LayoutRect flippedBlockRect(offsetFromRootBlock.width(), offsetFromRootBlock.height(), width(), height());
2490         rootBlock->flipForWritingMode(flippedBlockRect);
2491         flippedBlockRect.moveBy(rootBlockPhysicalPosition);
2492         clipOutPositionedObjects(paintInfo, flippedBlockRect.location(), positionedObjects());
2493         if (isBody() || isRoot()) // The <body> must make sure to examine its containingBlock's positioned objects.
2494             for (RenderBlock* cb = containingBlock(); cb && !cb->isRenderView(); cb = cb->containingBlock())
2495                 clipOutPositionedObjects(paintInfo, LayoutPoint(cb->x(), cb->y()), cb->positionedObjects()); // FIXME: Not right for flipped writing modes.
2496         clipOutFloatingObjects(rootBlock, paintInfo, rootBlockPhysicalPosition, offsetFromRootBlock);
2497     }
2498 
2499     // 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
2500     // fixed).
2501     GapRects result;
2502     if (!isRenderBlockFlow() && !isFlexibleBoxIncludingDeprecated()) // FIXME: Make multi-column selection gap filling work someday.
2503         return result;
2504 
2505     if (hasColumns() || hasTransform() || style()->columnSpan()) {
2506         // FIXME: We should learn how to gap fill multiple columns and transforms eventually.
2507         lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalHeight();
2508         lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, logicalHeight());
2509         lastLogicalRight = logicalRightSelectionOffset(rootBlock, logicalHeight());
2510         return result;
2511     }
2512 
2513     if (childrenInline())
2514         result = toRenderBlockFlow(this)->inlineSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2515     else
2516         result = blockSelectionGaps(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo);
2517 
2518     // Go ahead and fill the vertical gap all the way to the bottom of our block if the selection extends past our block.
2519     if (rootBlock == this && (selectionState() != SelectionBoth && selectionState() != SelectionEnd))
2520         result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2521                                              logicalHeight(), paintInfo));
2522     return result;
2523 }
2524 
blockSelectionGaps(RenderBlock * rootBlock,const LayoutPoint & rootBlockPhysicalPosition,const LayoutSize & offsetFromRootBlock,LayoutUnit & lastLogicalTop,LayoutUnit & lastLogicalLeft,LayoutUnit & lastLogicalRight,const PaintInfo * paintInfo)2525 GapRects RenderBlock::blockSelectionGaps(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2526                                          LayoutUnit& lastLogicalTop, LayoutUnit& lastLogicalLeft, LayoutUnit& lastLogicalRight, const PaintInfo* paintInfo)
2527 {
2528     GapRects result;
2529 
2530     // Go ahead and jump right to the first block child that contains some selected objects.
2531     RenderBox* curr;
2532     for (curr = firstChildBox(); curr && curr->selectionState() == SelectionNone; curr = curr->nextSiblingBox()) { }
2533 
2534     for (bool sawSelectionEnd = false; curr && !sawSelectionEnd; curr = curr->nextSiblingBox()) {
2535         SelectionState childState = curr->selectionState();
2536         if (childState == SelectionBoth || childState == SelectionEnd)
2537             sawSelectionEnd = true;
2538 
2539         if (curr->isFloatingOrOutOfFlowPositioned())
2540             continue; // We must be a normal flow object in order to even be considered.
2541 
2542         if (curr->isInFlowPositioned() && curr->hasLayer()) {
2543             // If the relposition offset is anything other than 0, then treat this just like an absolute positioned element.
2544             // Just disregard it completely.
2545             LayoutSize relOffset = curr->layer()->offsetForInFlowPosition();
2546             if (relOffset.width() || relOffset.height())
2547                 continue;
2548         }
2549 
2550         bool paintsOwnSelection = curr->shouldPaintSelectionGaps() || curr->isTable(); // FIXME: Eventually we won't special-case table like this.
2551         bool fillBlockGaps = paintsOwnSelection || (curr->canBeSelectionLeaf() && childState != SelectionNone);
2552         if (fillBlockGaps) {
2553             // We need to fill the vertical gap above this object.
2554             if (childState == SelectionEnd || childState == SelectionInside)
2555                 // Fill the gap above the object.
2556                 result.uniteCenter(blockSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, lastLogicalTop, lastLogicalLeft, lastLogicalRight,
2557                                                      curr->logicalTop(), paintInfo));
2558 
2559             // 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*
2560             // our object.  We know this if the selection did not end inside our object.
2561             if (paintsOwnSelection && (childState == SelectionStart || sawSelectionEnd))
2562                 childState = SelectionNone;
2563 
2564             // Fill side gaps on this object based off its state.
2565             bool leftGap, rightGap;
2566             getSelectionGapInfo(childState, leftGap, rightGap);
2567 
2568             if (leftGap)
2569                 result.uniteLeft(logicalLeftSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalLeft(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2570             if (rightGap)
2571                 result.uniteRight(logicalRightSelectionGap(rootBlock, rootBlockPhysicalPosition, offsetFromRootBlock, this, curr->logicalRight(), curr->logicalTop(), curr->logicalHeight(), paintInfo));
2572 
2573             // Update lastLogicalTop to be just underneath the object.  lastLogicalLeft and lastLogicalRight extend as far as
2574             // they can without bumping into floating or positioned objects.  Ideally they will go right up
2575             // to the border of the root selection block.
2576             lastLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + curr->logicalBottom();
2577             lastLogicalLeft = logicalLeftSelectionOffset(rootBlock, curr->logicalBottom());
2578             lastLogicalRight = logicalRightSelectionOffset(rootBlock, curr->logicalBottom());
2579         } else if (childState != SelectionNone)
2580             // We must be a block that has some selected object inside it.  Go ahead and recur.
2581             result.unite(toRenderBlock(curr)->selectionGaps(rootBlock, rootBlockPhysicalPosition, LayoutSize(offsetFromRootBlock.width() + curr->x(), offsetFromRootBlock.height() + curr->y()),
2582                                                             lastLogicalTop, lastLogicalLeft, lastLogicalRight, paintInfo));
2583     }
2584     return result;
2585 }
2586 
blockSelectionGap(RenderBlock * rootBlock,const LayoutPoint & rootBlockPhysicalPosition,const LayoutSize & offsetFromRootBlock,LayoutUnit lastLogicalTop,LayoutUnit lastLogicalLeft,LayoutUnit lastLogicalRight,LayoutUnit logicalBottom,const PaintInfo * paintInfo)2587 LayoutRect RenderBlock::blockSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2588                                           LayoutUnit lastLogicalTop, LayoutUnit lastLogicalLeft, LayoutUnit lastLogicalRight, LayoutUnit logicalBottom, const PaintInfo* paintInfo)
2589 {
2590     LayoutUnit logicalTop = lastLogicalTop;
2591     LayoutUnit logicalHeight = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalBottom - logicalTop;
2592     if (logicalHeight <= 0)
2593         return LayoutRect();
2594 
2595     // Get the selection offsets for the bottom of the gap
2596     LayoutUnit logicalLeft = max(lastLogicalLeft, logicalLeftSelectionOffset(rootBlock, logicalBottom));
2597     LayoutUnit logicalRight = min(lastLogicalRight, logicalRightSelectionOffset(rootBlock, logicalBottom));
2598     LayoutUnit logicalWidth = logicalRight - logicalLeft;
2599     if (logicalWidth <= 0)
2600         return LayoutRect();
2601 
2602     LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(logicalLeft, logicalTop, logicalWidth, logicalHeight));
2603     if (paintInfo)
2604         paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selectionBackgroundColor());
2605     return gapRect;
2606 }
2607 
logicalLeftSelectionGap(RenderBlock * rootBlock,const LayoutPoint & rootBlockPhysicalPosition,const LayoutSize & offsetFromRootBlock,RenderObject * selObj,LayoutUnit logicalLeft,LayoutUnit logicalTop,LayoutUnit logicalHeight,const PaintInfo * paintInfo)2608 LayoutRect RenderBlock::logicalLeftSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2609                                                 RenderObject* selObj, LayoutUnit logicalLeft, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2610 {
2611     LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2612     LayoutUnit rootBlockLogicalLeft = max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight));
2613     LayoutUnit rootBlockLogicalRight = min(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalLeft), min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2614     LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2615     if (rootBlockLogicalWidth <= 0)
2616         return LayoutRect();
2617 
2618     LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2619     if (paintInfo)
2620         paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2621     return gapRect;
2622 }
2623 
logicalRightSelectionGap(RenderBlock * rootBlock,const LayoutPoint & rootBlockPhysicalPosition,const LayoutSize & offsetFromRootBlock,RenderObject * selObj,LayoutUnit logicalRight,LayoutUnit logicalTop,LayoutUnit logicalHeight,const PaintInfo * paintInfo)2624 LayoutRect RenderBlock::logicalRightSelectionGap(RenderBlock* rootBlock, const LayoutPoint& rootBlockPhysicalPosition, const LayoutSize& offsetFromRootBlock,
2625                                                  RenderObject* selObj, LayoutUnit logicalRight, LayoutUnit logicalTop, LayoutUnit logicalHeight, const PaintInfo* paintInfo)
2626 {
2627     LayoutUnit rootBlockLogicalTop = rootBlock->blockDirectionOffset(offsetFromRootBlock) + logicalTop;
2628     LayoutUnit rootBlockLogicalLeft = max(rootBlock->inlineDirectionOffset(offsetFromRootBlock) + floorToInt(logicalRight), max(logicalLeftSelectionOffset(rootBlock, logicalTop), logicalLeftSelectionOffset(rootBlock, logicalTop + logicalHeight)));
2629     LayoutUnit rootBlockLogicalRight = min(logicalRightSelectionOffset(rootBlock, logicalTop), logicalRightSelectionOffset(rootBlock, logicalTop + logicalHeight));
2630     LayoutUnit rootBlockLogicalWidth = rootBlockLogicalRight - rootBlockLogicalLeft;
2631     if (rootBlockLogicalWidth <= 0)
2632         return LayoutRect();
2633 
2634     LayoutRect gapRect = rootBlock->logicalRectToPhysicalRect(rootBlockPhysicalPosition, LayoutRect(rootBlockLogicalLeft, rootBlockLogicalTop, rootBlockLogicalWidth, logicalHeight));
2635     if (paintInfo)
2636         paintInfo->context->fillRect(pixelSnappedIntRect(gapRect), selObj->selectionBackgroundColor());
2637     return gapRect;
2638 }
2639 
getSelectionGapInfo(SelectionState state,bool & leftGap,bool & rightGap)2640 void RenderBlock::getSelectionGapInfo(SelectionState state, bool& leftGap, bool& rightGap)
2641 {
2642     bool ltr = style()->isLeftToRightDirection();
2643     leftGap = (state == RenderObject::SelectionInside) ||
2644               (state == RenderObject::SelectionEnd && ltr) ||
2645               (state == RenderObject::SelectionStart && !ltr);
2646     rightGap = (state == RenderObject::SelectionInside) ||
2647                (state == RenderObject::SelectionStart && ltr) ||
2648                (state == RenderObject::SelectionEnd && !ltr);
2649 }
2650 
logicalLeftSelectionOffset(RenderBlock * rootBlock,LayoutUnit position)2651 LayoutUnit RenderBlock::logicalLeftSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2652 {
2653     LayoutUnit logicalLeft = logicalLeftOffsetForLine(position, false);
2654     if (logicalLeft == logicalLeftOffsetForContent()) {
2655         if (rootBlock != this)
2656             // The border can potentially be further extended by our containingBlock().
2657             return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
2658         return logicalLeft;
2659     } else {
2660         RenderBlock* cb = this;
2661         while (cb != rootBlock) {
2662             logicalLeft += cb->logicalLeft();
2663             cb = cb->containingBlock();
2664         }
2665     }
2666     return logicalLeft;
2667 }
2668 
logicalRightSelectionOffset(RenderBlock * rootBlock,LayoutUnit position)2669 LayoutUnit RenderBlock::logicalRightSelectionOffset(RenderBlock* rootBlock, LayoutUnit position)
2670 {
2671     LayoutUnit logicalRight = logicalRightOffsetForLine(position, false);
2672     if (logicalRight == logicalRightOffsetForContent()) {
2673         if (rootBlock != this)
2674             // The border can potentially be further extended by our containingBlock().
2675             return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
2676         return logicalRight;
2677     } else {
2678         RenderBlock* cb = this;
2679         while (cb != rootBlock) {
2680             logicalRight += cb->logicalLeft();
2681             cb = cb->containingBlock();
2682         }
2683     }
2684     return logicalRight;
2685 }
2686 
blockBeforeWithinSelectionRoot(LayoutSize & offset) const2687 RenderBlock* RenderBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
2688 {
2689     if (isSelectionRoot())
2690         return 0;
2691 
2692     const RenderObject* object = this;
2693     RenderObject* sibling;
2694     do {
2695         sibling = object->previousSibling();
2696         while (sibling && (!sibling->isRenderBlock() || toRenderBlock(sibling)->isSelectionRoot()))
2697             sibling = sibling->previousSibling();
2698 
2699         offset -= LayoutSize(toRenderBlock(object)->logicalLeft(), toRenderBlock(object)->logicalTop());
2700         object = object->parent();
2701     } while (!sibling && object && object->isRenderBlock() && !toRenderBlock(object)->isSelectionRoot());
2702 
2703     if (!sibling)
2704         return 0;
2705 
2706     RenderBlock* beforeBlock = toRenderBlock(sibling);
2707 
2708     offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2709 
2710     RenderObject* child = beforeBlock->lastChild();
2711     while (child && child->isRenderBlock()) {
2712         beforeBlock = toRenderBlock(child);
2713         offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
2714         child = beforeBlock->lastChild();
2715     }
2716     return beforeBlock;
2717 }
2718 
insertIntoTrackedRendererMaps(RenderBox * descendant,TrackedDescendantsMap * & descendantsMap,TrackedContainerMap * & containerMap)2719 void RenderBlock::insertIntoTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2720 {
2721     if (!descendantsMap) {
2722         descendantsMap = new TrackedDescendantsMap;
2723         containerMap = new TrackedContainerMap;
2724     }
2725 
2726     TrackedRendererListHashSet* descendantSet = descendantsMap->get(this);
2727     if (!descendantSet) {
2728         descendantSet = new TrackedRendererListHashSet;
2729         descendantsMap->set(this, adoptPtr(descendantSet));
2730     }
2731     bool added = descendantSet->add(descendant).isNewEntry;
2732     if (!added) {
2733         ASSERT(containerMap->get(descendant));
2734         ASSERT(containerMap->get(descendant)->contains(this));
2735         return;
2736     }
2737 
2738     HashSet<RenderBlock*>* containerSet = containerMap->get(descendant);
2739     if (!containerSet) {
2740         containerSet = new HashSet<RenderBlock*>;
2741         containerMap->set(descendant, adoptPtr(containerSet));
2742     }
2743     ASSERT(!containerSet->contains(this));
2744     containerSet->add(this);
2745 }
2746 
removeFromTrackedRendererMaps(RenderBox * descendant,TrackedDescendantsMap * & descendantsMap,TrackedContainerMap * & containerMap)2747 void RenderBlock::removeFromTrackedRendererMaps(RenderBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
2748 {
2749     if (!descendantsMap)
2750         return;
2751 
2752     OwnPtr<HashSet<RenderBlock*> > containerSet = containerMap->take(descendant);
2753     if (!containerSet)
2754         return;
2755 
2756     HashSet<RenderBlock*>::iterator end = containerSet->end();
2757     for (HashSet<RenderBlock*>::iterator it = containerSet->begin(); it != end; ++it) {
2758         RenderBlock* container = *it;
2759 
2760         // FIXME: Disabling this assert temporarily until we fix the layout
2761         // bugs associated with positioned objects not properly cleared from
2762         // their ancestor chain before being moved. See webkit bug 93766.
2763         // ASSERT(descendant->isDescendantOf(container));
2764 
2765         TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
2766         ASSERT(descendantsMapIterator != descendantsMap->end());
2767         if (descendantsMapIterator == descendantsMap->end())
2768             continue;
2769         TrackedRendererListHashSet* descendantSet = descendantsMapIterator->value.get();
2770         ASSERT(descendantSet->contains(descendant));
2771         descendantSet->remove(descendant);
2772         if (descendantSet->isEmpty())
2773             descendantsMap->remove(descendantsMapIterator);
2774     }
2775 }
2776 
positionedObjects() const2777 TrackedRendererListHashSet* RenderBlock::positionedObjects() const
2778 {
2779     if (gPositionedDescendantsMap)
2780         return gPositionedDescendantsMap->get(this);
2781     return 0;
2782 }
2783 
insertPositionedObject(RenderBox * o)2784 void RenderBlock::insertPositionedObject(RenderBox* o)
2785 {
2786     ASSERT(!isAnonymousBlock());
2787 
2788     if (o->isRenderFlowThread())
2789         return;
2790 
2791     insertIntoTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2792 }
2793 
removePositionedObject(RenderBox * o)2794 void RenderBlock::removePositionedObject(RenderBox* o)
2795 {
2796     removeFromTrackedRendererMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
2797 }
2798 
removePositionedObjects(RenderBlock * o,ContainingBlockState containingBlockState)2799 void RenderBlock::removePositionedObjects(RenderBlock* o, ContainingBlockState containingBlockState)
2800 {
2801     TrackedRendererListHashSet* positionedDescendants = positionedObjects();
2802     if (!positionedDescendants)
2803         return;
2804 
2805     RenderBox* r;
2806 
2807     TrackedRendererListHashSet::iterator end = positionedDescendants->end();
2808 
2809     Vector<RenderBox*, 16> deadObjects;
2810 
2811     for (TrackedRendererListHashSet::iterator it = positionedDescendants->begin(); it != end; ++it) {
2812         r = *it;
2813         if (!o || r->isDescendantOf(o)) {
2814             if (containingBlockState == NewContainingBlock)
2815                 r->setChildNeedsLayout(MarkOnlyThis);
2816 
2817             // It is parent blocks job to add positioned child to positioned objects list of its containing block
2818             // Parent layout needs to be invalidated to ensure this happens.
2819             RenderObject* p = r->parent();
2820             while (p && !p->isRenderBlock())
2821                 p = p->parent();
2822             if (p)
2823                 p->setChildNeedsLayout();
2824 
2825             deadObjects.append(r);
2826         }
2827     }
2828 
2829     for (unsigned i = 0; i < deadObjects.size(); i++)
2830         removePositionedObject(deadObjects.at(i));
2831 }
2832 
addPercentHeightDescendant(RenderBox * descendant)2833 void RenderBlock::addPercentHeightDescendant(RenderBox* descendant)
2834 {
2835     insertIntoTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2836 }
2837 
removePercentHeightDescendant(RenderBox * descendant)2838 void RenderBlock::removePercentHeightDescendant(RenderBox* descendant)
2839 {
2840     removeFromTrackedRendererMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
2841 }
2842 
percentHeightDescendants() const2843 TrackedRendererListHashSet* RenderBlock::percentHeightDescendants() const
2844 {
2845     return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
2846 }
2847 
hasPercentHeightContainerMap()2848 bool RenderBlock::hasPercentHeightContainerMap()
2849 {
2850     return gPercentHeightContainerMap;
2851 }
2852 
hasPercentHeightDescendant(RenderBox * descendant)2853 bool RenderBlock::hasPercentHeightDescendant(RenderBox* descendant)
2854 {
2855     // We don't null check gPercentHeightContainerMap since the caller
2856     // already ensures this and we need to call this function on every
2857     // descendant in clearPercentHeightDescendantsFrom().
2858     ASSERT(gPercentHeightContainerMap);
2859     return gPercentHeightContainerMap->contains(descendant);
2860 }
2861 
dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope & layoutScope)2862 void RenderBlock::dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope& layoutScope)
2863 {
2864     if (!gPercentHeightDescendantsMap)
2865         return;
2866 
2867     TrackedRendererListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
2868     if (!descendants)
2869         return;
2870 
2871     TrackedRendererListHashSet::iterator end = descendants->end();
2872     for (TrackedRendererListHashSet::iterator it = descendants->begin(); it != end; ++it) {
2873         RenderBox* box = *it;
2874         while (box != this) {
2875             if (box->normalChildNeedsLayout())
2876                 break;
2877             layoutScope.setChildNeedsLayout(box);
2878             box = box->containingBlock();
2879             ASSERT(box);
2880             if (!box)
2881                 break;
2882         }
2883     }
2884 }
2885 
removePercentHeightDescendantIfNeeded(RenderBox * descendant)2886 void RenderBlock::removePercentHeightDescendantIfNeeded(RenderBox* descendant)
2887 {
2888     // We query the map directly, rather than looking at style's
2889     // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
2890     // can change with writing mode/directional changes.
2891     if (!hasPercentHeightContainerMap())
2892         return;
2893 
2894     if (!hasPercentHeightDescendant(descendant))
2895         return;
2896 
2897     removePercentHeightDescendant(descendant);
2898 }
2899 
clearPercentHeightDescendantsFrom(RenderBox * parent)2900 void RenderBlock::clearPercentHeightDescendantsFrom(RenderBox* parent)
2901 {
2902     ASSERT(gPercentHeightContainerMap);
2903     for (RenderObject* curr = parent->firstChild(); curr; curr = curr->nextInPreOrder(parent)) {
2904         if (!curr->isBox())
2905             continue;
2906 
2907         RenderBox* box = toRenderBox(curr);
2908         if (!hasPercentHeightDescendant(box))
2909             continue;
2910 
2911         removePercentHeightDescendant(box);
2912     }
2913 }
2914 
textIndentOffset() const2915 LayoutUnit RenderBlock::textIndentOffset() const
2916 {
2917     LayoutUnit cw = 0;
2918     RenderView* renderView = 0;
2919     if (style()->textIndent().isPercent())
2920         cw = containingBlock()->availableLogicalWidth();
2921     else if (style()->textIndent().isViewportPercentage())
2922         renderView = view();
2923     return minimumValueForLength(style()->textIndent(), cw, renderView);
2924 }
2925 
logicalLeftOffsetForContent(RenderRegion * region) const2926 LayoutUnit RenderBlock::logicalLeftOffsetForContent(RenderRegion* region) const
2927 {
2928     LayoutUnit logicalLeftOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
2929     if (!region)
2930         return logicalLeftOffset;
2931     LayoutRect boxRect = borderBoxRectInRegion(region);
2932     return logicalLeftOffset + (isHorizontalWritingMode() ? boxRect.x() : boxRect.y());
2933 }
2934 
logicalRightOffsetForContent(RenderRegion * region) const2935 LayoutUnit RenderBlock::logicalRightOffsetForContent(RenderRegion* region) const
2936 {
2937     LayoutUnit logicalRightOffset = style()->isHorizontalWritingMode() ? borderLeft() + paddingLeft() : borderTop() + paddingTop();
2938     logicalRightOffset += availableLogicalWidth();
2939     if (!region)
2940         return logicalRightOffset;
2941     LayoutRect boxRect = borderBoxRectInRegion(region);
2942     return logicalRightOffset - (logicalWidth() - (isHorizontalWritingMode() ? boxRect.maxX() : boxRect.maxY()));
2943 }
2944 
adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats,bool applyTextIndent) const2945 LayoutUnit RenderBlock::adjustLogicalLeftOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
2946 {
2947     LayoutUnit left = offsetFromFloats;
2948 
2949     if (applyTextIndent && style()->isLeftToRightDirection())
2950         left += textIndentOffset();
2951 
2952     if (style()->lineAlign() == LineAlignNone)
2953         return left;
2954 
2955     // Push in our left offset so that it is aligned with the character grid.
2956     LayoutState* layoutState = view()->layoutState();
2957     if (!layoutState)
2958         return left;
2959 
2960     RenderBlock* lineGrid = layoutState->lineGrid();
2961     if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
2962         return left;
2963 
2964     // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
2965     float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
2966     if (!maxCharWidth)
2967         return left;
2968 
2969     LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
2970     LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
2971 
2972     // Push in to the nearest character width.
2973     // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
2974     // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
2975     // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
2976     // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
2977     // (https://bugs.webkit.org/show_bug.cgi?id=79944)
2978     float remainder = fmodf(maxCharWidth - fmodf(left + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
2979     left += remainder;
2980     return left;
2981 }
2982 
adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats,bool applyTextIndent) const2983 LayoutUnit RenderBlock::adjustLogicalRightOffsetForLine(LayoutUnit offsetFromFloats, bool applyTextIndent) const
2984 {
2985     LayoutUnit right = offsetFromFloats;
2986 
2987     if (applyTextIndent && !style()->isLeftToRightDirection())
2988         right -= textIndentOffset();
2989 
2990     if (style()->lineAlign() == LineAlignNone)
2991         return right;
2992 
2993     // Push in our right offset so that it is aligned with the character grid.
2994     LayoutState* layoutState = view()->layoutState();
2995     if (!layoutState)
2996         return right;
2997 
2998     RenderBlock* lineGrid = layoutState->lineGrid();
2999     if (!lineGrid || lineGrid->style()->writingMode() != style()->writingMode())
3000         return right;
3001 
3002     // FIXME: Should letter-spacing apply? This is complicated since it doesn't apply at the edge?
3003     float maxCharWidth = lineGrid->style()->font().primaryFont()->maxCharWidth();
3004     if (!maxCharWidth)
3005         return right;
3006 
3007     LayoutUnit lineGridOffset = lineGrid->isHorizontalWritingMode() ? layoutState->lineGridOffset().width(): layoutState->lineGridOffset().height();
3008     LayoutUnit layoutOffset = lineGrid->isHorizontalWritingMode() ? layoutState->layoutOffset().width() : layoutState->layoutOffset().height();
3009 
3010     // Push in to the nearest character width.
3011     // FIXME: This is wrong for RTL (https://bugs.webkit.org/show_bug.cgi?id=79945).
3012     // FIXME: This doesn't work with columns or regions (https://bugs.webkit.org/show_bug.cgi?id=79942).
3013     // FIXME: This doesn't work when the inline position of the object isn't set ahead of time.
3014     // FIXME: Dynamic changes to the font or to the inline position need to result in a deep relayout.
3015     // (https://bugs.webkit.org/show_bug.cgi?id=79944)
3016     float remainder = fmodf(fmodf(right + layoutOffset - lineGridOffset, maxCharWidth), maxCharWidth);
3017     right -= LayoutUnit::fromFloatCeil(remainder);
3018     return right;
3019 }
3020 
markLinesDirtyInBlockRange(LayoutUnit logicalTop,LayoutUnit logicalBottom,RootInlineBox * highest)3021 void RenderBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
3022 {
3023     if (logicalTop >= logicalBottom)
3024         return;
3025 
3026     RootInlineBox* lowestDirtyLine = lastRootBox();
3027     RootInlineBox* afterLowest = lowestDirtyLine;
3028     while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
3029         afterLowest = lowestDirtyLine;
3030         lowestDirtyLine = lowestDirtyLine->prevRootBox();
3031     }
3032 
3033     while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
3034         afterLowest->markDirty();
3035         afterLowest = afterLowest->prevRootBox();
3036     }
3037 }
3038 
avoidsFloats() const3039 bool RenderBlock::avoidsFloats() const
3040 {
3041     // Floats can't intrude into our box if we have a non-auto column count or width.
3042     return RenderBox::avoidsFloats() || !style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth();
3043 }
3044 
markShapeInsideDescendantsForLayout()3045 void RenderBlock::markShapeInsideDescendantsForLayout()
3046 {
3047     if (!everHadLayout())
3048         return;
3049     if (childrenInline()) {
3050         setNeedsLayout();
3051         return;
3052     }
3053     for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
3054         if (!child->isRenderBlock())
3055             continue;
3056         RenderBlock* childBlock = toRenderBlock(child);
3057         childBlock->markShapeInsideDescendantsForLayout();
3058     }
3059 }
3060 
isPointInOverflowControl(HitTestResult & result,const LayoutPoint & locationInContainer,const LayoutPoint & accumulatedOffset)3061 bool RenderBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
3062 {
3063     if (!scrollsOverflow())
3064         return false;
3065 
3066     return layer()->scrollableArea()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset)));
3067 }
3068 
nodeForHitTest() const3069 Node* RenderBlock::nodeForHitTest() const
3070 {
3071     // If we are in the margins of block elements that are part of a
3072     // continuation we're actually still inside the enclosing element
3073     // that was split. Use the appropriate inner node.
3074     return isAnonymousBlockContinuation() ? continuation()->node() : node();
3075 }
3076 
nodeAtPoint(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction hitTestAction)3077 bool RenderBlock::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3078 {
3079     LayoutPoint adjustedLocation(accumulatedOffset + location());
3080     LayoutSize localOffset = toLayoutSize(adjustedLocation);
3081 
3082     if (!isRenderView()) {
3083         // Check if we need to do anything at all.
3084         LayoutRect overflowBox = visualOverflowRect();
3085         flipForWritingMode(overflowBox);
3086         overflowBox.moveBy(adjustedLocation);
3087         if (!locationInContainer.intersects(overflowBox))
3088             return false;
3089     }
3090 
3091     if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
3092         updateHitTestResult(result, locationInContainer.point() - localOffset);
3093         // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
3094         if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer))
3095            return true;
3096     }
3097 
3098     // If we have clipping, then we can't have any spillout.
3099     bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
3100     bool useClip = (hasControlClip() || useOverflowClip);
3101     bool checkChildren = !useClip || (hasControlClip() ? locationInContainer.intersects(controlClipRect(adjustedLocation)) : locationInContainer.intersects(overflowClipRect(adjustedLocation, locationInContainer.region(), IncludeOverlayScrollbarSize)));
3102     if (checkChildren) {
3103         // Hit test descendants first.
3104         LayoutSize scrolledOffset(localOffset);
3105         if (hasOverflowClip())
3106             scrolledOffset -= scrolledContentOffset();
3107 
3108         // Hit test contents if we don't have columns.
3109         if (!hasColumns()) {
3110             if (hitTestContents(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
3111                 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
3112                 return true;
3113             }
3114             if (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, toLayoutPoint(scrolledOffset)))
3115                 return true;
3116         } else if (hitTestColumns(request, result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
3117             updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
3118             return true;
3119         }
3120     }
3121 
3122     // Check if the point is outside radii.
3123     if (!isRenderView() && style()->hasBorderRadius()) {
3124         LayoutRect borderRect = borderBoxRect();
3125         borderRect.moveBy(adjustedLocation);
3126         RoundedRect border = style()->getRoundedBorderFor(borderRect, view());
3127         if (!locationInContainer.intersects(border))
3128             return false;
3129     }
3130 
3131     // Now hit test our background
3132     if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
3133         LayoutRect boundsRect(adjustedLocation, size());
3134         if (visibleToHitTestRequest(request) && locationInContainer.intersects(boundsRect)) {
3135             updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
3136             if (!result.addNodeToRectBasedTestResult(nodeForHitTest(), request, locationInContainer, boundsRect))
3137                 return true;
3138         }
3139     }
3140 
3141     return false;
3142 }
3143 
3144 class ColumnRectIterator {
3145     WTF_MAKE_NONCOPYABLE(ColumnRectIterator);
3146 public:
ColumnRectIterator(const RenderBlock & block)3147     ColumnRectIterator(const RenderBlock& block)
3148         : m_block(block)
3149         , m_colInfo(block.columnInfo())
3150         , m_direction(m_block.style()->isFlippedBlocksWritingMode() ? 1 : -1)
3151         , m_isHorizontal(block.isHorizontalWritingMode())
3152         , m_logicalLeft(block.logicalLeftOffsetForContent())
3153     {
3154         int colCount = m_colInfo->columnCount();
3155         m_colIndex = colCount - 1;
3156         m_currLogicalTopOffset = colCount * m_colInfo->columnHeight() * m_direction;
3157         update();
3158     }
3159 
advance()3160     void advance()
3161     {
3162         ASSERT(hasMore());
3163         m_colIndex--;
3164         update();
3165     }
3166 
columnRect() const3167     LayoutRect columnRect() const { return m_colRect; }
hasMore() const3168     bool hasMore() const { return m_colIndex >= 0; }
3169 
adjust(LayoutSize & offset) const3170     void adjust(LayoutSize& offset) const
3171     {
3172         LayoutUnit currLogicalLeftOffset = (m_isHorizontal ? m_colRect.x() : m_colRect.y()) - m_logicalLeft;
3173         offset += m_isHorizontal ? LayoutSize(currLogicalLeftOffset, m_currLogicalTopOffset) : LayoutSize(m_currLogicalTopOffset, currLogicalLeftOffset);
3174         if (m_colInfo->progressionAxis() == ColumnInfo::BlockAxis) {
3175             if (m_isHorizontal)
3176                 offset.expand(0, m_colRect.y() - m_block.borderTop() - m_block.paddingTop());
3177             else
3178                 offset.expand(m_colRect.x() - m_block.borderLeft() - m_block.paddingLeft(), 0);
3179         }
3180     }
3181 
3182 private:
update()3183     void update()
3184     {
3185         if (m_colIndex < 0)
3186             return;
3187 
3188         m_colRect = m_block.columnRectAt(const_cast<ColumnInfo*>(m_colInfo), m_colIndex);
3189         m_block.flipForWritingMode(m_colRect);
3190         m_currLogicalTopOffset -= (m_isHorizontal ? m_colRect.height() : m_colRect.width()) * m_direction;
3191     }
3192 
3193     const RenderBlock& m_block;
3194     const ColumnInfo* const m_colInfo;
3195     const int m_direction;
3196     const bool m_isHorizontal;
3197     const LayoutUnit m_logicalLeft;
3198     int m_colIndex;
3199     LayoutUnit m_currLogicalTopOffset;
3200     LayoutRect m_colRect;
3201 };
3202 
hitTestColumns(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction hitTestAction)3203 bool RenderBlock::hitTestColumns(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3204 {
3205     // We need to do multiple passes, breaking up our hit testing into strips.
3206     if (!hasColumns())
3207         return false;
3208 
3209     for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3210         LayoutRect hitRect = locationInContainer.boundingBox();
3211         LayoutRect colRect = it.columnRect();
3212         colRect.moveBy(accumulatedOffset);
3213         if (locationInContainer.intersects(colRect)) {
3214             // The point is inside this column.
3215             // Adjust accumulatedOffset to change where we hit test.
3216             LayoutSize offset;
3217             it.adjust(offset);
3218             LayoutPoint finalLocation = accumulatedOffset + offset;
3219             if (!result.isRectBasedTest() || colRect.contains(hitRect))
3220                 return hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction) || (hitTestAction == HitTestFloat && hitTestFloats(request, result, locationInContainer, finalLocation));
3221 
3222             hitTestContents(request, result, locationInContainer, finalLocation, hitTestAction);
3223         }
3224     }
3225 
3226     return false;
3227 }
3228 
adjustForColumnRect(LayoutSize & offset,const LayoutPoint & locationInContainer) const3229 void RenderBlock::adjustForColumnRect(LayoutSize& offset, const LayoutPoint& locationInContainer) const
3230 {
3231     for (ColumnRectIterator it(*this); it.hasMore(); it.advance()) {
3232         LayoutRect colRect = it.columnRect();
3233         if (colRect.contains(locationInContainer)) {
3234             it.adjust(offset);
3235             return;
3236         }
3237     }
3238 }
3239 
hitTestContents(const HitTestRequest & request,HitTestResult & result,const HitTestLocation & locationInContainer,const LayoutPoint & accumulatedOffset,HitTestAction hitTestAction)3240 bool RenderBlock::hitTestContents(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
3241 {
3242     if (isRenderRegion())
3243         return toRenderRegion(this)->hitTestFlowThreadContents(request, result, locationInContainer, accumulatedOffset, hitTestAction);
3244 
3245     if (childrenInline() && !isTable()) {
3246         // We have to hit-test our line boxes.
3247         if (m_lineBoxes.hitTest(this, request, result, locationInContainer, accumulatedOffset, hitTestAction))
3248             return true;
3249     } else {
3250         // Hit test our children.
3251         HitTestAction childHitTest = hitTestAction;
3252         if (hitTestAction == HitTestChildBlockBackgrounds)
3253             childHitTest = HitTestChildBlockBackground;
3254         for (RenderBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
3255             LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
3256             if (!child->hasSelfPaintingLayer() && !child->isFloating() && child->nodeAtPoint(request, result, locationInContainer, childPoint, childHitTest))
3257                 return true;
3258         }
3259     }
3260 
3261     return false;
3262 }
3263 
positionForBox(InlineBox * box,bool start) const3264 Position RenderBlock::positionForBox(InlineBox *box, bool start) const
3265 {
3266     if (!box)
3267         return Position();
3268 
3269     if (!box->renderer()->nonPseudoNode())
3270         return createLegacyEditingPosition(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
3271 
3272     if (!box->isInlineTextBox())
3273         return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? box->renderer()->caretMinOffset() : box->renderer()->caretMaxOffset());
3274 
3275     InlineTextBox* textBox = toInlineTextBox(box);
3276     return createLegacyEditingPosition(box->renderer()->nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
3277 }
3278 
isEditingBoundary(RenderObject * ancestor,RenderObject * child)3279 static inline bool isEditingBoundary(RenderObject* ancestor, RenderObject* child)
3280 {
3281     ASSERT(!ancestor || ancestor->nonPseudoNode());
3282     ASSERT(child && child->nonPseudoNode());
3283     return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isRenderView())
3284         || ancestor->nonPseudoNode()->rendererIsEditable() == child->nonPseudoNode()->rendererIsEditable();
3285 }
3286 
3287 // FIXME: This function should go on RenderObject as an instance method. Then
3288 // all cases in which positionForPoint recurs could call this instead to
3289 // prevent crossing editable boundaries. This would require many tests.
positionForPointRespectingEditingBoundaries(RenderBlock * parent,RenderBox * child,const LayoutPoint & pointInParentCoordinates)3290 static PositionWithAffinity positionForPointRespectingEditingBoundaries(RenderBlock* parent, RenderBox* child, const LayoutPoint& pointInParentCoordinates)
3291 {
3292     LayoutPoint childLocation = child->location();
3293     if (child->isInFlowPositioned())
3294         childLocation += child->offsetForInFlowPosition();
3295 
3296     // FIXME: This is wrong if the child's writing-mode is different from the parent's.
3297     LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
3298 
3299     // If this is an anonymous renderer, we just recur normally
3300     Node* childNode = child->nonPseudoNode();
3301     if (!childNode)
3302         return child->positionForPoint(pointInChildCoordinates);
3303 
3304     // Otherwise, first make sure that the editability of the parent and child agree.
3305     // If they don't agree, then we return a visible position just before or after the child
3306     RenderObject* ancestor = parent;
3307     while (ancestor && !ancestor->nonPseudoNode())
3308         ancestor = ancestor->parent();
3309 
3310     // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
3311     if (isEditingBoundary(ancestor, child))
3312         return child->positionForPoint(pointInChildCoordinates);
3313 
3314     // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
3315     LayoutUnit childMiddle = parent->logicalWidthForChild(child) / 2;
3316     LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
3317     if (logicalLeft < childMiddle)
3318         return ancestor->createPositionWithAffinity(childNode->nodeIndex(), DOWNSTREAM);
3319     return ancestor->createPositionWithAffinity(childNode->nodeIndex() + 1, UPSTREAM);
3320 }
3321 
positionForPointWithInlineChildren(const LayoutPoint & pointInLogicalContents)3322 PositionWithAffinity RenderBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
3323 {
3324     ASSERT(childrenInline());
3325 
3326     if (!firstRootBox())
3327         return createPositionWithAffinity(0, DOWNSTREAM);
3328 
3329     bool linesAreFlipped = style()->isFlippedLinesWritingMode();
3330     bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3331 
3332     // look for the closest line box in the root box which is at the passed-in y coordinate
3333     InlineBox* closestBox = 0;
3334     RootInlineBox* firstRootBoxWithChildren = 0;
3335     RootInlineBox* lastRootBoxWithChildren = 0;
3336     for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
3337         if (!root->firstLeafChild())
3338             continue;
3339         if (!firstRootBoxWithChildren)
3340             firstRootBoxWithChildren = root;
3341 
3342         if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
3343             || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
3344             break;
3345 
3346         lastRootBoxWithChildren = root;
3347 
3348         // check if this root line box is located at this y coordinate
3349         if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
3350             if (linesAreFlipped) {
3351                 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
3352                 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
3353                     nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
3354 
3355                 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
3356                     || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
3357                     continue;
3358             }
3359             closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3360             if (closestBox)
3361                 break;
3362         }
3363     }
3364 
3365     bool moveCaretToBoundary = document().frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
3366 
3367     if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
3368         // y coordinate is below last root line box, pretend we hit it
3369         closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
3370     }
3371 
3372     if (closestBox) {
3373         if (moveCaretToBoundary) {
3374             LayoutUnit firstRootBoxWithChildrenTop = min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
3375             if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
3376                 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
3377                 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
3378                 if (box->isLineBreak()) {
3379                     if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
3380                         box = newBox;
3381                 }
3382                 // y coordinate is above first root line box, so return the start of the first
3383                 return PositionWithAffinity(positionForBox(box, true), DOWNSTREAM);
3384             }
3385         }
3386 
3387         // pass the box a top position that is inside it
3388         LayoutPoint point(pointInLogicalContents.x(), closestBox->root()->blockDirectionPointInLine());
3389         if (!isHorizontalWritingMode())
3390             point = point.transposedPoint();
3391         if (closestBox->renderer()->isReplaced())
3392             return positionForPointRespectingEditingBoundaries(this, toRenderBox(closestBox->renderer()), point);
3393         return closestBox->renderer()->positionForPoint(point);
3394     }
3395 
3396     if (lastRootBoxWithChildren) {
3397         // We hit this case for Mac behavior when the Y coordinate is below the last box.
3398         ASSERT(moveCaretToBoundary);
3399         InlineBox* logicallyLastBox;
3400         if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
3401             return PositionWithAffinity(positionForBox(logicallyLastBox, false), DOWNSTREAM);
3402     }
3403 
3404     // Can't reach this. We have a root line box, but it has no kids.
3405     // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
3406     // seems to hit this code path.
3407     return createPositionWithAffinity(0, DOWNSTREAM);
3408 }
3409 
isChildHitTestCandidate(RenderBox * box)3410 static inline bool isChildHitTestCandidate(RenderBox* box)
3411 {
3412     return box->height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned();
3413 }
3414 
positionForPoint(const LayoutPoint & point)3415 PositionWithAffinity RenderBlock::positionForPoint(const LayoutPoint& point)
3416 {
3417     if (isTable())
3418         return RenderBox::positionForPoint(point);
3419 
3420     if (isReplaced()) {
3421         // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
3422         LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
3423         LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
3424 
3425         if (pointLogicalLeft < 0)
3426             return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3427         if (pointLogicalLeft >= logicalWidth())
3428             return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3429         if (pointLogicalTop < 0)
3430             return createPositionWithAffinity(caretMinOffset(), DOWNSTREAM);
3431         if (pointLogicalTop >= logicalHeight())
3432             return createPositionWithAffinity(caretMaxOffset(), DOWNSTREAM);
3433     }
3434 
3435     LayoutPoint pointInContents = point;
3436     offsetForContents(pointInContents);
3437     LayoutPoint pointInLogicalContents(pointInContents);
3438     if (!isHorizontalWritingMode())
3439         pointInLogicalContents = pointInLogicalContents.transposedPoint();
3440 
3441     if (childrenInline())
3442         return positionForPointWithInlineChildren(pointInLogicalContents);
3443 
3444     RenderBox* lastCandidateBox = lastChildBox();
3445     while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
3446         lastCandidateBox = lastCandidateBox->previousSiblingBox();
3447 
3448     bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
3449     if (lastCandidateBox) {
3450         if (pointInLogicalContents.y() > logicalTopForChild(lastCandidateBox)
3451             || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(lastCandidateBox)))
3452             return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
3453 
3454         for (RenderBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
3455             if (!isChildHitTestCandidate(childBox))
3456                 continue;
3457             LayoutUnit childLogicalBottom = logicalTopForChild(childBox) + logicalHeightForChild(childBox);
3458             // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
3459             if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
3460                 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
3461                 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
3462         }
3463     }
3464 
3465     // We only get here if there are no hit test candidate children below the click.
3466     return RenderBox::positionForPoint(point);
3467 }
3468 
offsetForContents(LayoutPoint & offset) const3469 void RenderBlock::offsetForContents(LayoutPoint& offset) const
3470 {
3471     offset = flipForWritingMode(offset);
3472 
3473     if (hasOverflowClip())
3474         offset += scrolledContentOffset();
3475 
3476     if (hasColumns())
3477         adjustPointToColumnContents(offset);
3478 
3479     offset = flipForWritingMode(offset);
3480 }
3481 
availableLogicalWidth() const3482 LayoutUnit RenderBlock::availableLogicalWidth() const
3483 {
3484     // If we have multiple columns, then the available logical width is reduced to our column width.
3485     if (hasColumns())
3486         return desiredColumnWidth();
3487     return RenderBox::availableLogicalWidth();
3488 }
3489 
columnGap() const3490 int RenderBlock::columnGap() const
3491 {
3492     if (style()->hasNormalColumnGap())
3493         return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
3494     return static_cast<int>(style()->columnGap());
3495 }
3496 
calcColumnWidth()3497 void RenderBlock::calcColumnWidth()
3498 {
3499     if (document().regionBasedColumnsEnabled())
3500         return;
3501 
3502     // Calculate our column width and column count.
3503     // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3504     unsigned desiredColumnCount = 1;
3505     LayoutUnit desiredColumnWidth = contentLogicalWidth();
3506 
3507     // For now, we don't support multi-column layouts when printing, since we have to do a lot of work for proper pagination.
3508     if (document().paginated() || (style()->hasAutoColumnCount() && style()->hasAutoColumnWidth()) || !style()->hasInlineColumnAxis()) {
3509         setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3510         return;
3511     }
3512 
3513     LayoutUnit availWidth = desiredColumnWidth;
3514     LayoutUnit colGap = columnGap();
3515     LayoutUnit colWidth = max<LayoutUnit>(1, LayoutUnit(style()->columnWidth()));
3516     int colCount = max<int>(1, style()->columnCount());
3517 
3518     if (style()->hasAutoColumnWidth() && !style()->hasAutoColumnCount()) {
3519         desiredColumnCount = colCount;
3520         desiredColumnWidth = max<LayoutUnit>(0, (availWidth - ((desiredColumnCount - 1) * colGap)) / desiredColumnCount);
3521     } else if (!style()->hasAutoColumnWidth() && style()->hasAutoColumnCount()) {
3522         desiredColumnCount = max<LayoutUnit>(1, (availWidth + colGap) / (colWidth + colGap));
3523         desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3524     } else {
3525         desiredColumnCount = max<LayoutUnit>(min<LayoutUnit>(colCount, (availWidth + colGap) / (colWidth + colGap)), 1);
3526         desiredColumnWidth = ((availWidth + colGap) / desiredColumnCount) - colGap;
3527     }
3528     setDesiredColumnCountAndWidth(desiredColumnCount, desiredColumnWidth);
3529 }
3530 
requiresColumns(int desiredColumnCount) const3531 bool RenderBlock::requiresColumns(int desiredColumnCount) const
3532 {
3533     // If overflow-y is set to paged-x or paged-y on the body or html element, we'll handle the paginating
3534     // in the RenderView instead.
3535     bool isPaginated = (style()->overflowY() == OPAGEDX || style()->overflowY() == OPAGEDY) && !(isRoot() || isBody());
3536 
3537     return firstChild()
3538         && (desiredColumnCount != 1 || !style()->hasAutoColumnWidth() || !style()->hasInlineColumnAxis() || isPaginated)
3539         && !firstChild()->isAnonymousColumnsBlock()
3540         && !firstChild()->isAnonymousColumnSpanBlock();
3541 }
3542 
setDesiredColumnCountAndWidth(int count,LayoutUnit width)3543 void RenderBlock::setDesiredColumnCountAndWidth(int count, LayoutUnit width)
3544 {
3545     bool destroyColumns = !requiresColumns(count);
3546     if (destroyColumns) {
3547         if (hasColumns()) {
3548             gColumnInfoMap->take(this);
3549             setHasColumns(false);
3550         }
3551     } else {
3552         ColumnInfo* info;
3553         if (hasColumns())
3554             info = gColumnInfoMap->get(this);
3555         else {
3556             if (!gColumnInfoMap)
3557                 gColumnInfoMap = new ColumnInfoMap;
3558             info = new ColumnInfo;
3559             gColumnInfoMap->add(this, adoptPtr(info));
3560             setHasColumns(true);
3561         }
3562         info->setDesiredColumnCount(count);
3563         info->setDesiredColumnWidth(width);
3564         info->setProgressionAxis(style()->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis);
3565         info->setProgressionIsReversed(style()->columnProgression() == ReverseColumnProgression);
3566     }
3567 }
3568 
updateColumnInfoFromStyle(RenderStyle * style)3569 void RenderBlock::updateColumnInfoFromStyle(RenderStyle* style)
3570 {
3571     if (!hasColumns())
3572         return;
3573 
3574     ColumnInfo* info = gColumnInfoMap->get(this);
3575 
3576     bool needsLayout = false;
3577     ColumnInfo::Axis oldAxis = info->progressionAxis();
3578     ColumnInfo::Axis newAxis = style->hasInlineColumnAxis() ? ColumnInfo::InlineAxis : ColumnInfo::BlockAxis;
3579     if (oldAxis != newAxis) {
3580         info->setProgressionAxis(newAxis);
3581         needsLayout = true;
3582     }
3583 
3584     bool oldProgressionIsReversed = info->progressionIsReversed();
3585     bool newProgressionIsReversed = style->columnProgression() == ReverseColumnProgression;
3586     if (oldProgressionIsReversed != newProgressionIsReversed) {
3587         info->setProgressionIsReversed(newProgressionIsReversed);
3588         needsLayout = true;
3589     }
3590 
3591     if (needsLayout)
3592         setNeedsLayoutAndPrefWidthsRecalc();
3593 }
3594 
desiredColumnWidth() const3595 LayoutUnit RenderBlock::desiredColumnWidth() const
3596 {
3597     if (!hasColumns())
3598         return contentLogicalWidth();
3599     return gColumnInfoMap->get(this)->desiredColumnWidth();
3600 }
3601 
columnInfo() const3602 ColumnInfo* RenderBlock::columnInfo() const
3603 {
3604     if (!hasColumns())
3605         return 0;
3606     return gColumnInfoMap->get(this);
3607 }
3608 
columnCount(ColumnInfo * colInfo) const3609 unsigned RenderBlock::columnCount(ColumnInfo* colInfo) const
3610 {
3611     ASSERT(hasColumns());
3612     ASSERT(gColumnInfoMap->get(this) == colInfo);
3613     return colInfo->columnCount();
3614 }
3615 
columnRectAt(ColumnInfo * colInfo,unsigned index) const3616 LayoutRect RenderBlock::columnRectAt(ColumnInfo* colInfo, unsigned index) const
3617 {
3618     ASSERT(hasColumns() && gColumnInfoMap->get(this) == colInfo);
3619 
3620     // Compute the appropriate rect based off our information.
3621     LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3622     LayoutUnit colLogicalHeight = colInfo->columnHeight();
3623     LayoutUnit colLogicalTop = borderBefore() + paddingBefore();
3624     LayoutUnit colLogicalLeft = logicalLeftOffsetForContent();
3625     LayoutUnit colGap = columnGap();
3626     if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3627         if (style()->isLeftToRightDirection() ^ colInfo->progressionIsReversed())
3628             colLogicalLeft += index * (colLogicalWidth + colGap);
3629         else
3630             colLogicalLeft += contentLogicalWidth() - colLogicalWidth - index * (colLogicalWidth + colGap);
3631     } else {
3632         if (!colInfo->progressionIsReversed())
3633             colLogicalTop += index * (colLogicalHeight + colGap);
3634         else
3635             colLogicalTop += contentLogicalHeight() - colLogicalHeight - index * (colLogicalHeight + colGap);
3636     }
3637 
3638     if (isHorizontalWritingMode())
3639         return LayoutRect(colLogicalLeft, colLogicalTop, colLogicalWidth, colLogicalHeight);
3640     return LayoutRect(colLogicalTop, colLogicalLeft, colLogicalHeight, colLogicalWidth);
3641 }
3642 
relayoutToAvoidWidows(LayoutStateMaintainer & statePusher)3643 bool RenderBlock::relayoutToAvoidWidows(LayoutStateMaintainer& statePusher)
3644 {
3645     if (!shouldBreakAtLineToAvoidWidow())
3646         return false;
3647 
3648     statePusher.pop();
3649     setEverHadLayout(true);
3650     layoutBlock(false);
3651     return true;
3652 }
3653 
adjustPointToColumnContents(LayoutPoint & point) const3654 void RenderBlock::adjustPointToColumnContents(LayoutPoint& point) const
3655 {
3656     // Just bail if we have no columns.
3657     if (!hasColumns())
3658         return;
3659 
3660     ColumnInfo* colInfo = columnInfo();
3661     if (!columnCount(colInfo))
3662         return;
3663 
3664     // Determine which columns we intersect.
3665     LayoutUnit colGap = columnGap();
3666     LayoutUnit halfColGap = colGap / 2;
3667     LayoutPoint columnPoint(columnRectAt(colInfo, 0).location());
3668     LayoutUnit logicalOffset = 0;
3669     for (unsigned i = 0; i < colInfo->columnCount(); i++) {
3670         // Add in half the column gap to the left and right of the rect.
3671         LayoutRect colRect = columnRectAt(colInfo, i);
3672         flipForWritingMode(colRect);
3673         if (isHorizontalWritingMode() == (colInfo->progressionAxis() == ColumnInfo::InlineAxis)) {
3674             LayoutRect gapAndColumnRect(colRect.x() - halfColGap, colRect.y(), colRect.width() + colGap, colRect.height());
3675             if (point.x() >= gapAndColumnRect.x() && point.x() < gapAndColumnRect.maxX()) {
3676                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3677                     // FIXME: The clamping that follows is not completely right for right-to-left
3678                     // content.
3679                     // Clamp everything above the column to its top left.
3680                     if (point.y() < gapAndColumnRect.y())
3681                         point = gapAndColumnRect.location();
3682                     // Clamp everything below the column to the next column's top left. If there is
3683                     // no next column, this still maps to just after this column.
3684                     else if (point.y() >= gapAndColumnRect.maxY()) {
3685                         point = gapAndColumnRect.location();
3686                         point.move(0, gapAndColumnRect.height());
3687                     }
3688                 } else {
3689                     if (point.x() < colRect.x())
3690                         point.setX(colRect.x());
3691                     else if (point.x() >= colRect.maxX())
3692                         point.setX(colRect.maxX() - 1);
3693                 }
3694 
3695                 // We're inside the column.  Translate the x and y into our column coordinate space.
3696                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3697                     point.move(columnPoint.x() - colRect.x(), (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset));
3698                 else
3699                     point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.x() + borderLeft() + paddingLeft(), 0);
3700                 return;
3701             }
3702 
3703             // Move to the next position.
3704             logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.height() : colRect.width();
3705         } else {
3706             LayoutRect gapAndColumnRect(colRect.x(), colRect.y() - halfColGap, colRect.width(), colRect.height() + colGap);
3707             if (point.y() >= gapAndColumnRect.y() && point.y() < gapAndColumnRect.maxY()) {
3708                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3709                     // FIXME: The clamping that follows is not completely right for right-to-left
3710                     // content.
3711                     // Clamp everything above the column to its top left.
3712                     if (point.x() < gapAndColumnRect.x())
3713                         point = gapAndColumnRect.location();
3714                     // Clamp everything below the column to the next column's top left. If there is
3715                     // no next column, this still maps to just after this column.
3716                     else if (point.x() >= gapAndColumnRect.maxX()) {
3717                         point = gapAndColumnRect.location();
3718                         point.move(gapAndColumnRect.width(), 0);
3719                     }
3720                 } else {
3721                     if (point.y() < colRect.y())
3722                         point.setY(colRect.y());
3723                     else if (point.y() >= colRect.maxY())
3724                         point.setY(colRect.maxY() - 1);
3725                 }
3726 
3727                 // We're inside the column.  Translate the x and y into our column coordinate space.
3728                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3729                     point.move((!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset), columnPoint.y() - colRect.y());
3730                 else
3731                     point.move(0, (!style()->isFlippedBlocksWritingMode() ? logicalOffset : -logicalOffset) - colRect.y() + borderTop() + paddingTop());
3732                 return;
3733             }
3734 
3735             // Move to the next position.
3736             logicalOffset += colInfo->progressionAxis() == ColumnInfo::InlineAxis ? colRect.width() : colRect.height();
3737         }
3738     }
3739 }
3740 
adjustRectForColumns(LayoutRect & r) const3741 void RenderBlock::adjustRectForColumns(LayoutRect& r) const
3742 {
3743     // Just bail if we have no columns.
3744     if (!hasColumns())
3745         return;
3746 
3747     ColumnInfo* colInfo = columnInfo();
3748 
3749     // Determine which columns we intersect.
3750     unsigned colCount = columnCount(colInfo);
3751     if (!colCount)
3752         return;
3753 
3754     // Begin with a result rect that is empty.
3755     LayoutRect result;
3756 
3757     bool isHorizontal = isHorizontalWritingMode();
3758     LayoutUnit beforeBorderPadding = borderBefore() + paddingBefore();
3759     LayoutUnit colHeight = colInfo->columnHeight();
3760     if (!colHeight)
3761         return;
3762 
3763     LayoutUnit startOffset = max(isHorizontal ? r.y() : r.x(), beforeBorderPadding);
3764     LayoutUnit endOffset = max(min<LayoutUnit>(isHorizontal ? r.maxY() : r.maxX(), beforeBorderPadding + colCount * colHeight), beforeBorderPadding);
3765 
3766     // FIXME: Can overflow on fast/block/float/float-not-removed-from-next-sibling4.html, see https://bugs.webkit.org/show_bug.cgi?id=68744
3767     unsigned startColumn = (startOffset - beforeBorderPadding) / colHeight;
3768     unsigned endColumn = (endOffset - beforeBorderPadding) / colHeight;
3769 
3770     if (startColumn == endColumn) {
3771         // The rect is fully contained within one column. Adjust for our offsets
3772         // and repaint only that portion.
3773         LayoutUnit logicalLeftOffset = logicalLeftOffsetForContent();
3774         LayoutRect colRect = columnRectAt(colInfo, startColumn);
3775         LayoutRect repaintRect = r;
3776 
3777         if (colInfo->progressionAxis() == ColumnInfo::InlineAxis) {
3778             if (isHorizontal)
3779                 repaintRect.move(colRect.x() - logicalLeftOffset, - static_cast<int>(startColumn) * colHeight);
3780             else
3781                 repaintRect.move(- static_cast<int>(startColumn) * colHeight, colRect.y() - logicalLeftOffset);
3782         } else {
3783             if (isHorizontal)
3784                 repaintRect.move(0, colRect.y() - startColumn * colHeight - beforeBorderPadding);
3785             else
3786                 repaintRect.move(colRect.x() - startColumn * colHeight - beforeBorderPadding, 0);
3787         }
3788         repaintRect.intersect(colRect);
3789         result.unite(repaintRect);
3790     } else {
3791         // We span multiple columns. We can just unite the start and end column to get the final
3792         // repaint rect.
3793         result.unite(columnRectAt(colInfo, startColumn));
3794         result.unite(columnRectAt(colInfo, endColumn));
3795     }
3796 
3797     r = result;
3798 }
3799 
flipForWritingModeIncludingColumns(const LayoutPoint & point) const3800 LayoutPoint RenderBlock::flipForWritingModeIncludingColumns(const LayoutPoint& point) const
3801 {
3802     ASSERT(hasColumns());
3803     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3804         return point;
3805     ColumnInfo* colInfo = columnInfo();
3806     LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3807     LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3808     if (isHorizontalWritingMode())
3809         return LayoutPoint(point.x(), expandedLogicalHeight - point.y());
3810     return LayoutPoint(expandedLogicalHeight - point.x(), point.y());
3811 }
3812 
adjustStartEdgeForWritingModeIncludingColumns(LayoutRect & rect) const3813 void RenderBlock::adjustStartEdgeForWritingModeIncludingColumns(LayoutRect& rect) const
3814 {
3815     ASSERT(hasColumns());
3816     if (!hasColumns() || !style()->isFlippedBlocksWritingMode())
3817         return;
3818 
3819     ColumnInfo* colInfo = columnInfo();
3820     LayoutUnit columnLogicalHeight = colInfo->columnHeight();
3821     LayoutUnit expandedLogicalHeight = borderBefore() + paddingBefore() + columnCount(colInfo) * columnLogicalHeight + borderAfter() + paddingAfter() + scrollbarLogicalHeight();
3822 
3823     if (isHorizontalWritingMode())
3824         rect.setY(expandedLogicalHeight - rect.maxY());
3825     else
3826         rect.setX(expandedLogicalHeight - rect.maxX());
3827 }
3828 
adjustForColumns(LayoutSize & offset,const LayoutPoint & point) const3829 void RenderBlock::adjustForColumns(LayoutSize& offset, const LayoutPoint& point) const
3830 {
3831     if (!hasColumns())
3832         return;
3833 
3834     ColumnInfo* colInfo = columnInfo();
3835 
3836     LayoutUnit logicalLeft = logicalLeftOffsetForContent();
3837     unsigned colCount = columnCount(colInfo);
3838     LayoutUnit colLogicalWidth = colInfo->desiredColumnWidth();
3839     LayoutUnit colLogicalHeight = colInfo->columnHeight();
3840 
3841     for (unsigned i = 0; i < colCount; ++i) {
3842         // Compute the edges for a given column in the block progression direction.
3843         LayoutRect sliceRect = LayoutRect(logicalLeft, borderBefore() + paddingBefore() + i * colLogicalHeight, colLogicalWidth, colLogicalHeight);
3844         if (!isHorizontalWritingMode())
3845             sliceRect = sliceRect.transposedRect();
3846 
3847         LayoutUnit logicalOffset = i * colLogicalHeight;
3848 
3849         // Now we're in the same coordinate space as the point.  See if it is inside the rectangle.
3850         if (isHorizontalWritingMode()) {
3851             if (point.y() >= sliceRect.y() && point.y() < sliceRect.maxY()) {
3852                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3853                     offset.expand(columnRectAt(colInfo, i).x() - logicalLeft, -logicalOffset);
3854                 else
3855                     offset.expand(0, columnRectAt(colInfo, i).y() - logicalOffset - borderBefore() - paddingBefore());
3856                 return;
3857             }
3858         } else {
3859             if (point.x() >= sliceRect.x() && point.x() < sliceRect.maxX()) {
3860                 if (colInfo->progressionAxis() == ColumnInfo::InlineAxis)
3861                     offset.expand(-logicalOffset, columnRectAt(colInfo, i).y() - logicalLeft);
3862                 else
3863                     offset.expand(columnRectAt(colInfo, i).x() - logicalOffset - borderBefore() - paddingBefore(), 0);
3864                 return;
3865             }
3866         }
3867     }
3868 }
3869 
computeIntrinsicLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const3870 void RenderBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3871 {
3872     if (childrenInline()) {
3873         // FIXME: Remove this const_cast.
3874         const_cast<RenderBlock*>(this)->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3875     } else
3876         computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
3877 
3878     maxLogicalWidth = max(minLogicalWidth, maxLogicalWidth);
3879 
3880     adjustIntrinsicLogicalWidthsForColumns(minLogicalWidth, maxLogicalWidth);
3881 
3882     // A horizontal marquee with inline children has no minimum width.
3883     if (childrenInline() && isMarquee() && toRenderMarquee(this)->isHorizontal())
3884         minLogicalWidth = 0;
3885 
3886     if (isTableCell()) {
3887         Length tableCellWidth = toRenderTableCell(this)->styleOrColLogicalWidth();
3888         if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
3889             maxLogicalWidth = max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
3890     }
3891 
3892     int scrollbarWidth = instrinsicScrollbarLogicalWidth();
3893     maxLogicalWidth += scrollbarWidth;
3894     minLogicalWidth += scrollbarWidth;
3895 }
3896 
computePreferredLogicalWidths()3897 void RenderBlock::computePreferredLogicalWidths()
3898 {
3899     ASSERT(preferredLogicalWidthsDirty());
3900 
3901     updateFirstLetter();
3902 
3903     m_minPreferredLogicalWidth = 0;
3904     m_maxPreferredLogicalWidth = 0;
3905 
3906     // FIXME: The isFixed() calls here should probably be checking for isSpecified since you
3907     // should be able to use percentage, calc or viewport relative values for width.
3908     RenderStyle* styleToUse = style();
3909     if (!isTableCell() && styleToUse->logicalWidth().isFixed() && styleToUse->logicalWidth().value() >= 0
3910         && !(isDeprecatedFlexItem() && !styleToUse->logicalWidth().intValue()))
3911         m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalWidth().value());
3912     else
3913         computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
3914 
3915     if (styleToUse->logicalMinWidth().isFixed() && styleToUse->logicalMinWidth().value() > 0) {
3916         m_maxPreferredLogicalWidth = max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3917         m_minPreferredLogicalWidth = max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMinWidth().value()));
3918     }
3919 
3920     if (styleToUse->logicalMaxWidth().isFixed()) {
3921         m_maxPreferredLogicalWidth = min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3922         m_minPreferredLogicalWidth = min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse->logicalMaxWidth().value()));
3923     }
3924 
3925     // Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents.
3926     if (isTableCell()) {
3927         m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil();
3928         m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil();
3929     }
3930 
3931     LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
3932     m_minPreferredLogicalWidth += borderAndPadding;
3933     m_maxPreferredLogicalWidth += borderAndPadding;
3934 
3935     clearPreferredLogicalWidthsDirty();
3936 }
3937 
adjustIntrinsicLogicalWidthsForColumns(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const3938 void RenderBlock::adjustIntrinsicLogicalWidthsForColumns(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
3939 {
3940     // FIXME: make this method virtual and move the code to RenderMultiColumnBlock once the old
3941     // multicol code is gone.
3942 
3943     if (!style()->hasAutoColumnCount() || !style()->hasAutoColumnWidth()) {
3944         // The min/max intrinsic widths calculated really tell how much space elements need when
3945         // laid out inside the columns. In order to eventually end up with the desired column width,
3946         // we need to convert them to values pertaining to the multicol container.
3947         int columnCount = style()->hasAutoColumnCount() ? 1 : style()->columnCount();
3948         LayoutUnit columnWidth;
3949         LayoutUnit gapExtra = (columnCount - 1) * columnGap();
3950         if (style()->hasAutoColumnWidth()) {
3951             minLogicalWidth = minLogicalWidth * columnCount + gapExtra;
3952         } else {
3953             columnWidth = style()->columnWidth();
3954             minLogicalWidth = min(minLogicalWidth, columnWidth);
3955         }
3956         // FIXME: If column-count is auto here, we should resolve it to calculate the maximum
3957         // intrinsic width, instead of pretending that it's 1. The only way to do that is by
3958         // performing a layout pass, but this is not an appropriate time or place for layout. The
3959         // good news is that if height is unconstrained and there are no explicit breaks, the
3960         // resolved column-count really should be 1.
3961         maxLogicalWidth = max(maxLogicalWidth, columnWidth) * columnCount + gapExtra;
3962     }
3963 }
3964 
3965 struct InlineMinMaxIterator {
3966 /* InlineMinMaxIterator is a class that will iterate over all render objects that contribute to
3967    inline min/max width calculations.  Note the following about the way it walks:
3968    (1) Positioned content is skipped (since it does not contribute to min/max width of a block)
3969    (2) We do not drill into the children of floats or replaced elements, since you can't break
3970        in the middle of such an element.
3971    (3) Inline flows (e.g., <a>, <span>, <i>) are walked twice, since each side can have
3972        distinct borders/margin/padding that contribute to the min/max width.
3973 */
3974     RenderObject* parent;
3975     RenderObject* current;
3976     bool endOfInline;
3977 
InlineMinMaxIteratorWebCore::InlineMinMaxIterator3978     InlineMinMaxIterator(RenderObject* p, bool end = false)
3979         :parent(p), current(p), endOfInline(end) {}
3980 
3981     RenderObject* next();
3982 };
3983 
next()3984 RenderObject* InlineMinMaxIterator::next()
3985 {
3986     RenderObject* result = 0;
3987     bool oldEndOfInline = endOfInline;
3988     endOfInline = false;
3989     while (current || current == parent) {
3990         if (!oldEndOfInline &&
3991             (current == parent ||
3992              (!current->isFloating() && !current->isReplaced() && !current->isOutOfFlowPositioned())))
3993             result = current->firstChild();
3994         if (!result) {
3995             // We hit the end of our inline. (It was empty, e.g., <span></span>.)
3996             if (!oldEndOfInline && current->isRenderInline()) {
3997                 result = current;
3998                 endOfInline = true;
3999                 break;
4000             }
4001 
4002             while (current && current != parent) {
4003                 result = current->nextSibling();
4004                 if (result) break;
4005                 current = current->parent();
4006                 if (current && current != parent && current->isRenderInline()) {
4007                     result = current;
4008                     endOfInline = true;
4009                     break;
4010                 }
4011             }
4012         }
4013 
4014         if (!result)
4015             break;
4016 
4017         if (!result->isOutOfFlowPositioned() && (result->isText() || result->isFloating() || result->isReplaced() || result->isRenderInline()))
4018              break;
4019 
4020         current = result;
4021         result = 0;
4022     }
4023 
4024     // Update our position.
4025     current = result;
4026     return current;
4027 }
4028 
getBPMWidth(LayoutUnit childValue,Length cssUnit)4029 static LayoutUnit getBPMWidth(LayoutUnit childValue, Length cssUnit)
4030 {
4031     if (cssUnit.type() != Auto)
4032         return (cssUnit.isFixed() ? static_cast<LayoutUnit>(cssUnit.value()) : childValue);
4033     return 0;
4034 }
4035 
getBorderPaddingMargin(const RenderBoxModelObject * child,bool endOfInline)4036 static LayoutUnit getBorderPaddingMargin(const RenderBoxModelObject* child, bool endOfInline)
4037 {
4038     RenderStyle* childStyle = child->style();
4039     if (endOfInline)
4040         return getBPMWidth(child->marginEnd(), childStyle->marginEnd()) +
4041                getBPMWidth(child->paddingEnd(), childStyle->paddingEnd()) +
4042                child->borderEnd();
4043     return getBPMWidth(child->marginStart(), childStyle->marginStart()) +
4044                getBPMWidth(child->paddingStart(), childStyle->paddingStart()) +
4045                child->borderStart();
4046 }
4047 
stripTrailingSpace(float & inlineMax,float & inlineMin,RenderObject * trailingSpaceChild)4048 static inline void stripTrailingSpace(float& inlineMax, float& inlineMin,
4049                                       RenderObject* trailingSpaceChild)
4050 {
4051     if (trailingSpaceChild && trailingSpaceChild->isText()) {
4052         // Collapse away the trailing space at the end of a block.
4053         RenderText* t = toRenderText(trailingSpaceChild);
4054         const UChar space = ' ';
4055         const Font& font = t->style()->font(); // FIXME: This ignores first-line.
4056         float spaceWidth = font.width(RenderBlockFlow::constructTextRun(t, font, &space, 1, t->style()));
4057         inlineMax -= spaceWidth + font.wordSpacing();
4058         if (inlineMin > inlineMax)
4059             inlineMin = inlineMax;
4060     }
4061 }
4062 
updatePreferredWidth(LayoutUnit & preferredWidth,float & result)4063 static inline void updatePreferredWidth(LayoutUnit& preferredWidth, float& result)
4064 {
4065     LayoutUnit snappedResult = LayoutUnit::fromFloatCeil(result);
4066     preferredWidth = max(snappedResult, preferredWidth);
4067 }
4068 
4069 // When converting between floating point and LayoutUnits we risk losing precision
4070 // with each conversion. When this occurs while accumulating our preferred widths,
4071 // we can wind up with a line width that's larger than our maxPreferredWidth due to
4072 // pure float accumulation.
adjustFloatForSubPixelLayout(float value)4073 static inline LayoutUnit adjustFloatForSubPixelLayout(float value)
4074 {
4075     return LayoutUnit::fromFloatCeil(value);
4076 }
4077 
4078 
computeInlinePreferredLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth)4079 void RenderBlock::computeInlinePreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth)
4080 {
4081     float inlineMax = 0;
4082     float inlineMin = 0;
4083 
4084     RenderStyle* styleToUse = style();
4085     RenderBlock* containingBlock = this->containingBlock();
4086     LayoutUnit cw = containingBlock ? containingBlock->contentLogicalWidth() : LayoutUnit();
4087 
4088     // If we are at the start of a line, we want to ignore all white-space.
4089     // Also strip spaces if we previously had text that ended in a trailing space.
4090     bool stripFrontSpaces = true;
4091     RenderObject* trailingSpaceChild = 0;
4092 
4093     // Firefox and Opera will allow a table cell to grow to fit an image inside it under
4094     // very specific cirucumstances (in order to match common WinIE renderings).
4095     // Not supporting the quirk has caused us to mis-render some real sites. (See Bugzilla 10517.)
4096     bool allowImagesToBreak = !document().inQuirksMode() || !isTableCell() || !styleToUse->logicalWidth().isIntrinsicOrAuto();
4097 
4098     bool autoWrap, oldAutoWrap;
4099     autoWrap = oldAutoWrap = styleToUse->autoWrap();
4100 
4101     InlineMinMaxIterator childIterator(this);
4102 
4103     // Only gets added to the max preffered width once.
4104     bool addedTextIndent = false;
4105     // Signals the text indent was more negative than the min preferred width
4106     bool hasRemainingNegativeTextIndent = false;
4107 
4108     LayoutUnit textIndent = minimumValueForLength(styleToUse->textIndent(), cw, view());
4109     RenderObject* prevFloat = 0;
4110     bool isPrevChildInlineFlow = false;
4111     bool shouldBreakLineAfterText = false;
4112     while (RenderObject* child = childIterator.next()) {
4113         autoWrap = child->isReplaced() ? child->parent()->style()->autoWrap() :
4114             child->style()->autoWrap();
4115 
4116         if (!child->isBR()) {
4117             // Step One: determine whether or not we need to go ahead and
4118             // terminate our current line.  Each discrete chunk can become
4119             // the new min-width, if it is the widest chunk seen so far, and
4120             // it can also become the max-width.
4121 
4122             // Children fall into three categories:
4123             // (1) An inline flow object.  These objects always have a min/max of 0,
4124             // and are included in the iteration solely so that their margins can
4125             // be added in.
4126             //
4127             // (2) An inline non-text non-flow object, e.g., an inline replaced element.
4128             // These objects can always be on a line by themselves, so in this situation
4129             // we need to go ahead and break the current line, and then add in our own
4130             // margins and min/max width on its own line, and then terminate the line.
4131             //
4132             // (3) A text object.  Text runs can have breakable characters at the start,
4133             // the middle or the end.  They may also lose whitespace off the front if
4134             // we're already ignoring whitespace.  In order to compute accurate min-width
4135             // information, we need three pieces of information.
4136             // (a) the min-width of the first non-breakable run.  Should be 0 if the text string
4137             // starts with whitespace.
4138             // (b) the min-width of the last non-breakable run. Should be 0 if the text string
4139             // ends with whitespace.
4140             // (c) the min/max width of the string (trimmed for whitespace).
4141             //
4142             // If the text string starts with whitespace, then we need to go ahead and
4143             // terminate our current line (unless we're already in a whitespace stripping
4144             // mode.
4145             //
4146             // If the text string has a breakable character in the middle, but didn't start
4147             // with whitespace, then we add the width of the first non-breakable run and
4148             // then end the current line.  We then need to use the intermediate min/max width
4149             // values (if any of them are larger than our current min/max).  We then look at
4150             // the width of the last non-breakable run and use that to start a new line
4151             // (unless we end in whitespace).
4152             RenderStyle* childStyle = child->style();
4153             float childMin = 0;
4154             float childMax = 0;
4155 
4156             if (!child->isText()) {
4157                 // Case (1) and (2).  Inline replaced and inline flow elements.
4158                 if (child->isRenderInline()) {
4159                     // Add in padding/border/margin from the appropriate side of
4160                     // the element.
4161                     float bpm = getBorderPaddingMargin(toRenderInline(child), childIterator.endOfInline);
4162                     childMin += bpm;
4163                     childMax += bpm;
4164 
4165                     inlineMin += childMin;
4166                     inlineMax += childMax;
4167 
4168                     child->clearPreferredLogicalWidthsDirty();
4169                 } else {
4170                     // Inline replaced elts add in their margins to their min/max values.
4171                     LayoutUnit margins = 0;
4172                     Length startMargin = childStyle->marginStart();
4173                     Length endMargin = childStyle->marginEnd();
4174                     if (startMargin.isFixed())
4175                         margins += adjustFloatForSubPixelLayout(startMargin.value());
4176                     if (endMargin.isFixed())
4177                         margins += adjustFloatForSubPixelLayout(endMargin.value());
4178                     childMin += margins.ceilToFloat();
4179                     childMax += margins.ceilToFloat();
4180                 }
4181             }
4182 
4183             if (!child->isRenderInline() && !child->isText()) {
4184                 // Case (2). Inline replaced elements and floats.
4185                 // Go ahead and terminate the current line as far as
4186                 // minwidth is concerned.
4187                 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4188                 if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
4189                     RenderBox* childBox = toRenderBox(child);
4190                     LogicalExtentComputedValues computedValues;
4191                     childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
4192                     childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
4193                 } else {
4194                     childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
4195                     childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
4196                 }
4197                 childMin += childMinPreferredLogicalWidth.ceilToFloat();
4198                 childMax += childMaxPreferredLogicalWidth.ceilToFloat();
4199 
4200                 bool clearPreviousFloat;
4201                 if (child->isFloating()) {
4202                     clearPreviousFloat = (prevFloat
4203                         && ((prevFloat->style()->floating() == LeftFloat && (childStyle->clear() & CLEFT))
4204                             || (prevFloat->style()->floating() == RightFloat && (childStyle->clear() & CRIGHT))));
4205                     prevFloat = child;
4206                 } else
4207                     clearPreviousFloat = false;
4208 
4209                 bool canBreakReplacedElement = !child->isImage() || allowImagesToBreak;
4210                 if ((canBreakReplacedElement && (autoWrap || oldAutoWrap) && (!isPrevChildInlineFlow || shouldBreakLineAfterText)) || clearPreviousFloat) {
4211                     updatePreferredWidth(minLogicalWidth, inlineMin);
4212                     inlineMin = 0;
4213                 }
4214 
4215                 // If we're supposed to clear the previous float, then terminate maxwidth as well.
4216                 if (clearPreviousFloat) {
4217                     updatePreferredWidth(maxLogicalWidth, inlineMax);
4218                     inlineMax = 0;
4219                 }
4220 
4221                 // Add in text-indent.  This is added in only once.
4222                 if (!addedTextIndent && !child->isFloating()) {
4223                     float ceiledTextIndent = textIndent.ceilToFloat();
4224                     childMin += ceiledTextIndent;
4225                     childMax += ceiledTextIndent;
4226 
4227                     if (childMin < 0)
4228                         textIndent = adjustFloatForSubPixelLayout(childMin);
4229                     else
4230                         addedTextIndent = true;
4231                 }
4232 
4233                 // Add our width to the max.
4234                 inlineMax += max<float>(0, childMax);
4235 
4236                 if (!autoWrap || !canBreakReplacedElement || (isPrevChildInlineFlow && !shouldBreakLineAfterText)) {
4237                     if (child->isFloating())
4238                         updatePreferredWidth(minLogicalWidth, childMin);
4239                     else
4240                         inlineMin += childMin;
4241                 } else {
4242                     // Now check our line.
4243                     updatePreferredWidth(minLogicalWidth, childMin);
4244 
4245                     // Now start a new line.
4246                     inlineMin = 0;
4247                 }
4248 
4249                 if (autoWrap && canBreakReplacedElement && isPrevChildInlineFlow) {
4250                     updatePreferredWidth(minLogicalWidth, inlineMin);
4251                     inlineMin = 0;
4252                 }
4253 
4254                 // We are no longer stripping whitespace at the start of
4255                 // a line.
4256                 if (!child->isFloating()) {
4257                     stripFrontSpaces = false;
4258                     trailingSpaceChild = 0;
4259                 }
4260             } else if (child->isText()) {
4261                 // Case (3). Text.
4262                 RenderText* t = toRenderText(child);
4263 
4264                 if (t->isWordBreak()) {
4265                     updatePreferredWidth(minLogicalWidth, inlineMin);
4266                     inlineMin = 0;
4267                     continue;
4268                 }
4269 
4270                 if (t->style()->hasTextCombine() && t->isCombineText())
4271                     toRenderCombineText(t)->combineText();
4272 
4273                 // Determine if we have a breakable character.  Pass in
4274                 // whether or not we should ignore any spaces at the front
4275                 // of the string.  If those are going to be stripped out,
4276                 // then they shouldn't be considered in the breakable char
4277                 // check.
4278                 bool hasBreakableChar, hasBreak;
4279                 float firstLineMinWidth, lastLineMinWidth;
4280                 bool hasBreakableStart, hasBreakableEnd;
4281                 float firstLineMaxWidth, lastLineMaxWidth;
4282                 t->trimmedPrefWidths(inlineMax,
4283                     firstLineMinWidth, hasBreakableStart, lastLineMinWidth, hasBreakableEnd,
4284                     hasBreakableChar, hasBreak, firstLineMaxWidth, lastLineMaxWidth,
4285                     childMin, childMax, stripFrontSpaces);
4286 
4287                 // This text object will not be rendered, but it may still provide a breaking opportunity.
4288                 if (!hasBreak && childMax == 0) {
4289                     if (autoWrap && (hasBreakableStart || hasBreakableEnd)) {
4290                         updatePreferredWidth(minLogicalWidth, inlineMin);
4291                         inlineMin = 0;
4292                     }
4293                     continue;
4294                 }
4295 
4296                 if (stripFrontSpaces)
4297                     trailingSpaceChild = child;
4298                 else
4299                     trailingSpaceChild = 0;
4300 
4301                 // Add in text-indent.  This is added in only once.
4302                 float ti = 0;
4303                 if (!addedTextIndent || hasRemainingNegativeTextIndent) {
4304                     ti = textIndent.ceilToFloat();
4305                     childMin += ti;
4306                     firstLineMinWidth += ti;
4307 
4308                     // It the text indent negative and larger than the child minimum, we re-use the remainder
4309                     // in future minimum calculations, but using the negative value again on the maximum
4310                     // will lead to under-counting the max pref width.
4311                     if (!addedTextIndent) {
4312                         childMax += ti;
4313                         firstLineMaxWidth += ti;
4314                         addedTextIndent = true;
4315                     }
4316 
4317                     if (childMin < 0) {
4318                         textIndent = childMin;
4319                         hasRemainingNegativeTextIndent = true;
4320                     }
4321                 }
4322 
4323                 // If we have no breakable characters at all,
4324                 // then this is the easy case. We add ourselves to the current
4325                 // min and max and continue.
4326                 if (!hasBreakableChar) {
4327                     inlineMin += childMin;
4328                 } else {
4329                     if (hasBreakableStart) {
4330                         updatePreferredWidth(minLogicalWidth, inlineMin);
4331                     } else {
4332                         inlineMin += firstLineMinWidth;
4333                         updatePreferredWidth(minLogicalWidth, inlineMin);
4334                         childMin -= ti;
4335                     }
4336 
4337                     inlineMin = childMin;
4338 
4339                     if (hasBreakableEnd) {
4340                         updatePreferredWidth(minLogicalWidth, inlineMin);
4341                         inlineMin = 0;
4342                         shouldBreakLineAfterText = false;
4343                     } else {
4344                         updatePreferredWidth(minLogicalWidth, inlineMin);
4345                         inlineMin = lastLineMinWidth;
4346                         shouldBreakLineAfterText = true;
4347                     }
4348                 }
4349 
4350                 if (hasBreak) {
4351                     inlineMax += firstLineMaxWidth;
4352                     updatePreferredWidth(maxLogicalWidth, inlineMax);
4353                     updatePreferredWidth(maxLogicalWidth, childMax);
4354                     inlineMax = lastLineMaxWidth;
4355                     addedTextIndent = true;
4356                 } else {
4357                     inlineMax += max<float>(0, childMax);
4358                 }
4359             }
4360 
4361             // Ignore spaces after a list marker.
4362             if (child->isListMarker())
4363                 stripFrontSpaces = true;
4364         } else {
4365             updatePreferredWidth(minLogicalWidth, inlineMin);
4366             updatePreferredWidth(maxLogicalWidth, inlineMax);
4367             inlineMin = inlineMax = 0;
4368             stripFrontSpaces = true;
4369             trailingSpaceChild = 0;
4370             addedTextIndent = true;
4371         }
4372 
4373         if (!child->isText() && child->isRenderInline())
4374             isPrevChildInlineFlow = true;
4375         else
4376             isPrevChildInlineFlow = false;
4377 
4378         oldAutoWrap = autoWrap;
4379     }
4380 
4381     if (styleToUse->collapseWhiteSpace())
4382         stripTrailingSpace(inlineMax, inlineMin, trailingSpaceChild);
4383 
4384     updatePreferredWidth(minLogicalWidth, inlineMin);
4385     updatePreferredWidth(maxLogicalWidth, inlineMax);
4386 }
4387 
computeBlockPreferredLogicalWidths(LayoutUnit & minLogicalWidth,LayoutUnit & maxLogicalWidth) const4388 void RenderBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
4389 {
4390     RenderStyle* styleToUse = style();
4391     bool nowrap = styleToUse->whiteSpace() == NOWRAP;
4392 
4393     RenderObject* child = firstChild();
4394     RenderBlock* containingBlock = this->containingBlock();
4395     LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
4396     while (child) {
4397         // Positioned children don't affect the min/max width
4398         if (child->isOutOfFlowPositioned()) {
4399             child = child->nextSibling();
4400             continue;
4401         }
4402 
4403         RenderStyle* childStyle = child->style();
4404         if (child->isFloating() || (child->isBox() && toRenderBox(child)->avoidsFloats())) {
4405             LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
4406             if (childStyle->clear() & CLEFT) {
4407                 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4408                 floatLeftWidth = 0;
4409             }
4410             if (childStyle->clear() & CRIGHT) {
4411                 maxLogicalWidth = max(floatTotalWidth, maxLogicalWidth);
4412                 floatRightWidth = 0;
4413             }
4414         }
4415 
4416         // A margin basically has three types: fixed, percentage, and auto (variable).
4417         // Auto and percentage margins simply become 0 when computing min/max width.
4418         // Fixed margins can be added in as is.
4419         Length startMarginLength = childStyle->marginStartUsing(styleToUse);
4420         Length endMarginLength = childStyle->marginEndUsing(styleToUse);
4421         LayoutUnit margin = 0;
4422         LayoutUnit marginStart = 0;
4423         LayoutUnit marginEnd = 0;
4424         if (startMarginLength.isFixed())
4425             marginStart += startMarginLength.value();
4426         if (endMarginLength.isFixed())
4427             marginEnd += endMarginLength.value();
4428         margin = marginStart + marginEnd;
4429 
4430         LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
4431         if (child->isBox() && child->isHorizontalWritingMode() != isHorizontalWritingMode()) {
4432             RenderBox* childBox = toRenderBox(child);
4433             LogicalExtentComputedValues computedValues;
4434             childBox->computeLogicalHeight(childBox->borderAndPaddingLogicalHeight(), 0, computedValues);
4435             childMinPreferredLogicalWidth = childMaxPreferredLogicalWidth = computedValues.m_extent;
4436         } else {
4437             childMinPreferredLogicalWidth = child->minPreferredLogicalWidth();
4438             childMaxPreferredLogicalWidth = child->maxPreferredLogicalWidth();
4439         }
4440 
4441         LayoutUnit w = childMinPreferredLogicalWidth + margin;
4442         minLogicalWidth = max(w, minLogicalWidth);
4443 
4444         // IE ignores tables for calculation of nowrap. Makes some sense.
4445         if (nowrap && !child->isTable())
4446             maxLogicalWidth = max(w, maxLogicalWidth);
4447 
4448         w = childMaxPreferredLogicalWidth + margin;
4449 
4450         if (!child->isFloating()) {
4451             if (child->isBox() && toRenderBox(child)->avoidsFloats()) {
4452                 // Determine a left and right max value based off whether or not the floats can fit in the
4453                 // margins of the object.  For negative margins, we will attempt to overlap the float if the negative margin
4454                 // is smaller than the float width.
4455                 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse->isLeftToRightDirection();
4456                 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
4457                 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
4458                 LayoutUnit maxLeft = marginLogicalLeft > 0 ? max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
4459                 LayoutUnit maxRight = marginLogicalRight > 0 ? max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
4460                 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
4461                 w = max(w, floatLeftWidth + floatRightWidth);
4462             }
4463             else
4464                 maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4465             floatLeftWidth = floatRightWidth = 0;
4466         }
4467 
4468         if (child->isFloating()) {
4469             if (childStyle->floating() == LeftFloat)
4470                 floatLeftWidth += w;
4471             else
4472                 floatRightWidth += w;
4473         } else
4474             maxLogicalWidth = max(w, maxLogicalWidth);
4475 
4476         child = child->nextSibling();
4477     }
4478 
4479     // Always make sure these values are non-negative.
4480     minLogicalWidth = max<LayoutUnit>(0, minLogicalWidth);
4481     maxLogicalWidth = max<LayoutUnit>(0, maxLogicalWidth);
4482 
4483     maxLogicalWidth = max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
4484 }
4485 
hasLineIfEmpty() const4486 bool RenderBlock::hasLineIfEmpty() const
4487 {
4488     if (!node())
4489         return false;
4490 
4491     if (node()->isRootEditableElement())
4492         return true;
4493 
4494     if (node()->isShadowRoot() && toShadowRoot(node())->host()->hasTagName(inputTag))
4495         return true;
4496 
4497     return false;
4498 }
4499 
lineHeight(bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const4500 LayoutUnit RenderBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4501 {
4502     // Inline blocks are replaced elements. Otherwise, just pass off to
4503     // the base class.  If we're being queried as though we're the root line
4504     // box, then the fact that we're an inline-block is irrelevant, and we behave
4505     // just like a block.
4506     if (isReplaced() && linePositionMode == PositionOnContainingLine)
4507         return RenderBox::lineHeight(firstLine, direction, linePositionMode);
4508 
4509     if (firstLine && document().styleEngine()->usesFirstLineRules()) {
4510         RenderStyle* s = style(firstLine);
4511         if (s != style())
4512             return s->computedLineHeight(view());
4513     }
4514 
4515     if (m_lineHeight == -1)
4516         m_lineHeight = style()->computedLineHeight(view());
4517 
4518     return m_lineHeight;
4519 }
4520 
baselinePosition(FontBaseline baselineType,bool firstLine,LineDirectionMode direction,LinePositionMode linePositionMode) const4521 int RenderBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
4522 {
4523     // Inline blocks are replaced elements. Otherwise, just pass off to
4524     // the base class.  If we're being queried as though we're the root line
4525     // box, then the fact that we're an inline-block is irrelevant, and we behave
4526     // just like a block.
4527     if (isReplaced() && linePositionMode == PositionOnContainingLine) {
4528         // For "leaf" theme objects, let the theme decide what the baseline position is.
4529         // FIXME: Might be better to have a custom CSS property instead, so that if the theme
4530         // is turned off, checkboxes/radios will still have decent baselines.
4531         // FIXME: Need to patch form controls to deal with vertical lines.
4532         if (style()->hasAppearance() && !RenderTheme::theme().isControlContainer(style()->appearance()))
4533             return RenderTheme::theme().baselinePosition(this);
4534 
4535         // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
4536         // the normal flow.  We make an exception for marquees, since their baselines are meaningless
4537         // (the content inside them moves).  This matches WinIE as well, which just bottom-aligns them.
4538         // We also give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
4539         // vertically (e.g., an overflow:hidden block that has had scrollTop moved).
4540         bool ignoreBaseline = (layer() && layer()->scrollableArea() && (isMarquee() || (direction == HorizontalLine ? (layer()->scrollableArea()->verticalScrollbar() || layer()->scrollableArea()->scrollYOffset())
4541             : (layer()->scrollableArea()->horizontalScrollbar() || layer()->scrollableArea()->scrollXOffset())))) || (isWritingModeRoot() && !isRubyRun());
4542 
4543         int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction);
4544 
4545         if (isDeprecatedFlexibleBox()) {
4546             // Historically, we did this check for all baselines. But we can't
4547             // remove this code from deprecated flexbox, because it effectively
4548             // breaks -webkit-line-clamp, which is used in the wild -- we would
4549             // calculate the baseline as if -webkit-line-clamp wasn't used.
4550             // For simplicity, we use this for all uses of deprecated flexbox.
4551             LayoutUnit bottomOfContent = direction == HorizontalLine ? borderTop() + paddingTop() + contentHeight() : borderRight() + paddingRight() + contentWidth();
4552             if (baselinePos > bottomOfContent)
4553                 baselinePos = -1;
4554         }
4555         if (baselinePos != -1)
4556             return direction == HorizontalLine ? marginTop() + baselinePos : marginRight() + baselinePos;
4557 
4558         return RenderBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
4559     }
4560 
4561     // If we're not replaced, we'll only get called with PositionOfInteriorLineBoxes.
4562     // Note that inline-block counts as replaced here.
4563     ASSERT(linePositionMode == PositionOfInteriorLineBoxes);
4564 
4565     const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
4566     return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
4567 }
4568 
minLineHeightForReplacedRenderer(bool isFirstLine,LayoutUnit replacedHeight) const4569 LayoutUnit RenderBlock::minLineHeightForReplacedRenderer(bool isFirstLine, LayoutUnit replacedHeight) const
4570 {
4571     if (!document().inNoQuirksMode() && replacedHeight)
4572         return replacedHeight;
4573 
4574     if (!(style(isFirstLine)->lineBoxContain() & LineBoxContainBlock))
4575         return 0;
4576 
4577     return std::max<LayoutUnit>(replacedHeight, lineHeight(isFirstLine, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
4578 }
4579 
firstLineBoxBaseline() const4580 int RenderBlock::firstLineBoxBaseline() const
4581 {
4582     if (isWritingModeRoot() && !isRubyRun())
4583         return -1;
4584 
4585     if (childrenInline()) {
4586         if (firstLineBox())
4587             return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
4588         else
4589             return -1;
4590     }
4591     else {
4592         for (RenderBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
4593             if (!curr->isFloatingOrOutOfFlowPositioned()) {
4594                 int result = curr->firstLineBoxBaseline();
4595                 if (result != -1)
4596                     return curr->logicalTop() + result; // Translate to our coordinate space.
4597             }
4598         }
4599     }
4600 
4601     return -1;
4602 }
4603 
inlineBlockBaseline(LineDirectionMode direction) const4604 int RenderBlock::inlineBlockBaseline(LineDirectionMode direction) const
4605 {
4606     if (style()->overflowY() != OVISIBLE) {
4607         // We are not calling RenderBox::baselinePosition here because the caller should add the margin-top/margin-right, not us.
4608         return direction == HorizontalLine ? height() + m_marginBox.bottom() : width() + m_marginBox.left();
4609     }
4610 
4611     return lastLineBoxBaseline(direction);
4612 }
4613 
lastLineBoxBaseline(LineDirectionMode lineDirection) const4614 int RenderBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const
4615 {
4616     if (isWritingModeRoot() && !isRubyRun())
4617         return -1;
4618 
4619     if (childrenInline()) {
4620         if (!firstLineBox() && hasLineIfEmpty()) {
4621             const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4622             return fontMetrics.ascent()
4623                  + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4624                  + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4625         }
4626         if (lastLineBox())
4627             return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
4628         return -1;
4629     } else {
4630         bool haveNormalFlowChild = false;
4631         for (RenderBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
4632             if (!curr->isFloatingOrOutOfFlowPositioned()) {
4633                 haveNormalFlowChild = true;
4634                 int result = curr->inlineBlockBaseline(lineDirection);
4635                 if (result != -1)
4636                     return curr->logicalTop() + result; // Translate to our coordinate space.
4637             }
4638         }
4639         if (!haveNormalFlowChild && hasLineIfEmpty()) {
4640             const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
4641             return fontMetrics.ascent()
4642                  + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
4643                  + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
4644         }
4645     }
4646 
4647     return -1;
4648 }
4649 
firstLineBlock() const4650 RenderBlock* RenderBlock::firstLineBlock() const
4651 {
4652     RenderBlock* firstLineBlock = const_cast<RenderBlock*>(this);
4653     bool hasPseudo = false;
4654     while (true) {
4655         hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
4656         if (hasPseudo)
4657             break;
4658         RenderObject* parentBlock = firstLineBlock->parent();
4659         // We include isRenderButton in this check because buttons are
4660         // implemented using flex box but should still support first-line. The
4661         // flex box spec requires that flex box does not support first-line,
4662         // though.
4663         // FIXME: Remove when buttons are implemented with align-items instead
4664         // of flexbox.
4665         if (firstLineBlock->isReplaced() || firstLineBlock->isFloating()
4666             || !parentBlock || parentBlock->firstChild() != firstLineBlock
4667             || (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4668             break;
4669         ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isRenderBlock());
4670         firstLineBlock = toRenderBlock(parentBlock);
4671     }
4672 
4673     if (!hasPseudo)
4674         return 0;
4675 
4676     return firstLineBlock;
4677 }
4678 
styleForFirstLetter(RenderObject * firstLetterBlock,RenderObject * firstLetterContainer)4679 static RenderStyle* styleForFirstLetter(RenderObject* firstLetterBlock, RenderObject* firstLetterContainer)
4680 {
4681     RenderStyle* pseudoStyle = firstLetterBlock->getCachedPseudoStyle(FIRST_LETTER, firstLetterContainer->firstLineStyle());
4682     // Force inline display (except for floating first-letters).
4683     pseudoStyle->setDisplay(pseudoStyle->isFloating() ? BLOCK : INLINE);
4684     // CSS2 says first-letter can't be positioned.
4685     pseudoStyle->setPosition(StaticPosition);
4686     return pseudoStyle;
4687 }
4688 
4689 // CSS 2.1 http://www.w3.org/TR/CSS21/selector.html#first-letter
4690 // "Punctuation (i.e, characters defined in Unicode [UNICODE] in the "open" (Ps), "close" (Pe),
4691 // "initial" (Pi). "final" (Pf) and "other" (Po) punctuation classes), that precedes or follows the first letter should be included"
isPunctuationForFirstLetter(UChar c)4692 static inline bool isPunctuationForFirstLetter(UChar c)
4693 {
4694     CharCategory charCategory = category(c);
4695     return charCategory == Punctuation_Open
4696         || charCategory == Punctuation_Close
4697         || charCategory == Punctuation_InitialQuote
4698         || charCategory == Punctuation_FinalQuote
4699         || charCategory == Punctuation_Other;
4700 }
4701 
shouldSkipForFirstLetter(UChar c)4702 static inline bool shouldSkipForFirstLetter(UChar c)
4703 {
4704     return isSpaceOrNewline(c) || c == noBreakSpace || isPunctuationForFirstLetter(c);
4705 }
4706 
findFirstLetterBlock(RenderBlock * start)4707 static inline RenderObject* findFirstLetterBlock(RenderBlock* start)
4708 {
4709     RenderObject* firstLetterBlock = start;
4710     while (true) {
4711         // We include isRenderButton in these two checks because buttons are
4712         // implemented using flex box but should still support first-letter.
4713         // The flex box spec requires that flex box does not support
4714         // first-letter, though.
4715         // FIXME: Remove when buttons are implemented with align-items instead
4716         // of flexbox.
4717         bool canHaveFirstLetterRenderer = firstLetterBlock->style()->hasPseudoStyle(FIRST_LETTER)
4718             && firstLetterBlock->canHaveGeneratedChildren()
4719             && (!firstLetterBlock->isFlexibleBox() || firstLetterBlock->isRenderButton());
4720         if (canHaveFirstLetterRenderer)
4721             return firstLetterBlock;
4722 
4723         RenderObject* parentBlock = firstLetterBlock->parent();
4724         if (firstLetterBlock->isReplaced() || !parentBlock || parentBlock->firstChild() != firstLetterBlock ||
4725             (!parentBlock->isRenderBlockFlow() && !parentBlock->isRenderButton()))
4726             return 0;
4727         firstLetterBlock = parentBlock;
4728     }
4729 
4730     return 0;
4731 }
4732 
updateFirstLetterStyle(RenderObject * firstLetterBlock,RenderObject * currentChild)4733 void RenderBlock::updateFirstLetterStyle(RenderObject* firstLetterBlock, RenderObject* currentChild)
4734 {
4735     RenderObject* firstLetter = currentChild->parent();
4736     RenderObject* firstLetterContainer = firstLetter->parent();
4737     RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4738     ASSERT(firstLetter->isFloating() || firstLetter->isInline());
4739 
4740     if (RenderStyle::compare(firstLetter->style(), pseudoStyle) == Reattach) {
4741         // The first-letter renderer needs to be replaced. Create a new renderer of the right type.
4742         RenderBoxModelObject* newFirstLetter;
4743         if (pseudoStyle->display() == INLINE)
4744             newFirstLetter = RenderInline::createAnonymous(&document());
4745         else
4746             newFirstLetter = RenderBlockFlow::createAnonymous(&document());
4747         newFirstLetter->setStyle(pseudoStyle);
4748 
4749         // Move the first letter into the new renderer.
4750         LayoutStateDisabler layoutStateDisabler(view());
4751         while (RenderObject* child = firstLetter->firstChild()) {
4752             if (child->isText())
4753                 toRenderText(child)->removeAndDestroyTextBoxes();
4754             firstLetter->removeChild(child);
4755             newFirstLetter->addChild(child, 0);
4756         }
4757 
4758         RenderObject* nextSibling = firstLetter->nextSibling();
4759         if (RenderTextFragment* remainingText = toRenderBoxModelObject(firstLetter)->firstLetterRemainingText()) {
4760             ASSERT(remainingText->isAnonymous() || remainingText->node()->renderer() == remainingText);
4761             // Replace the old renderer with the new one.
4762             remainingText->setFirstLetter(newFirstLetter);
4763             newFirstLetter->setFirstLetterRemainingText(remainingText);
4764         }
4765         // To prevent removal of single anonymous block in RenderBlock::removeChild and causing
4766         // |nextSibling| to go stale, we remove the old first letter using removeChildNode first.
4767         firstLetterContainer->virtualChildren()->removeChildNode(firstLetterContainer, firstLetter);
4768         firstLetter->destroy();
4769         firstLetter = newFirstLetter;
4770         firstLetterContainer->addChild(firstLetter, nextSibling);
4771     } else
4772         firstLetter->setStyle(pseudoStyle);
4773 
4774     for (RenderObject* genChild = firstLetter->firstChild(); genChild; genChild = genChild->nextSibling()) {
4775         if (genChild->isText())
4776             genChild->setStyle(pseudoStyle);
4777     }
4778 }
4779 
firstLetterLength(const String & text)4780 static inline unsigned firstLetterLength(const String& text)
4781 {
4782     unsigned length = 0;
4783     bool punctuationOpen = false;
4784 
4785     // Account for leading spaces and punctuation.
4786     while (length < text.length() && shouldSkipForFirstLetter((text)[length])) {
4787         if (isPunctuationForFirstLetter((text)[length]))
4788             punctuationOpen = true;
4789 
4790         length++;
4791     }
4792 
4793     // Bail if we didn't find a letter
4794     if (text.length() && length == text.length())
4795         return 0;
4796 
4797     // Account for first letter.
4798     length++;
4799 
4800     if (!punctuationOpen)
4801         return length;
4802 
4803     // Keep looking for whitespace and allowed punctuation, but avoid
4804     // accumulating just whitespace into the :first-letter.
4805     for (unsigned scanLength = length; scanLength < text.length(); ++scanLength) {
4806         UChar c = (text)[scanLength];
4807 
4808         if (!shouldSkipForFirstLetter(c))
4809             break;
4810 
4811         if (isPunctuationForFirstLetter(c))
4812             length = scanLength + 1;
4813     }
4814 
4815     return length;
4816 }
4817 
createFirstLetterRenderer(RenderObject * firstLetterBlock,RenderObject * currentChild,unsigned length)4818 void RenderBlock::createFirstLetterRenderer(RenderObject* firstLetterBlock, RenderObject* currentChild, unsigned length)
4819 {
4820     ASSERT(length && currentChild->isText());
4821 
4822     RenderObject* firstLetterContainer = currentChild->parent();
4823     RenderStyle* pseudoStyle = styleForFirstLetter(firstLetterBlock, firstLetterContainer);
4824     RenderObject* firstLetter = 0;
4825     if (pseudoStyle->display() == INLINE)
4826         firstLetter = RenderInline::createAnonymous(&document());
4827     else
4828         firstLetter = RenderBlockFlow::createAnonymous(&document());
4829     firstLetter->setStyle(pseudoStyle);
4830     firstLetterContainer->addChild(firstLetter, currentChild);
4831 
4832     RenderText* textObj = toRenderText(currentChild);
4833 
4834     // The original string is going to be either a generated content string or a DOM node's
4835     // string.  We want the original string before it got transformed in case first-letter has
4836     // no text-transform or a different text-transform applied to it.
4837     String oldText = textObj->originalText();
4838     ASSERT(oldText.impl());
4839 
4840     // Construct a text fragment for the text after the first letter.
4841     // This text fragment might be empty.
4842     RenderTextFragment* remainingText =
4843         new RenderTextFragment(textObj->node() ? textObj->node() : &textObj->document(), oldText.impl(), length, oldText.length() - length);
4844     remainingText->setStyle(textObj->style());
4845     if (remainingText->node())
4846         remainingText->node()->setRenderer(remainingText);
4847 
4848     firstLetterContainer->addChild(remainingText, textObj);
4849     firstLetterContainer->removeChild(textObj);
4850     remainingText->setFirstLetter(firstLetter);
4851     toRenderBoxModelObject(firstLetter)->setFirstLetterRemainingText(remainingText);
4852 
4853     // construct text fragment for the first letter
4854     RenderTextFragment* letter =
4855         new RenderTextFragment(remainingText->node() ? remainingText->node() : &remainingText->document(), oldText.impl(), 0, length);
4856     letter->setStyle(pseudoStyle);
4857     firstLetter->addChild(letter);
4858 
4859     textObj->destroy();
4860 }
4861 
updateFirstLetter()4862 void RenderBlock::updateFirstLetter()
4863 {
4864     if (!document().styleEngine()->usesFirstLetterRules())
4865         return;
4866     // Don't recur
4867     if (style()->styleType() == FIRST_LETTER)
4868         return;
4869 
4870     // FIXME: We need to destroy the first-letter object if it is no longer the first child. Need to find
4871     // an efficient way to check for that situation though before implementing anything.
4872     RenderObject* firstLetterBlock = findFirstLetterBlock(this);
4873     if (!firstLetterBlock)
4874         return;
4875 
4876     // Drill into inlines looking for our first text child.
4877     RenderObject* currChild = firstLetterBlock->firstChild();
4878     unsigned length = 0;
4879     while (currChild) {
4880         if (currChild->isText()) {
4881             // FIXME: If there is leading punctuation in a different RenderText than
4882             // the first letter, we'll not apply the correct style to it.
4883             length = firstLetterLength(toRenderText(currChild)->originalText());
4884             if (length)
4885                 break;
4886             currChild = currChild->nextSibling();
4887         } else if (currChild->isListMarker()) {
4888             currChild = currChild->nextSibling();
4889         } else if (currChild->isFloatingOrOutOfFlowPositioned()) {
4890             if (currChild->style()->styleType() == FIRST_LETTER) {
4891                 currChild = currChild->firstChild();
4892                 break;
4893             }
4894             currChild = currChild->nextSibling();
4895         } else if (currChild->isReplaced() || currChild->isRenderButton() || currChild->isMenuList())
4896             break;
4897         else if (currChild->style()->hasPseudoStyle(FIRST_LETTER) && currChild->canHaveGeneratedChildren())  {
4898             // We found a lower-level node with first-letter, which supersedes the higher-level style
4899             firstLetterBlock = currChild;
4900             currChild = currChild->firstChild();
4901         } else
4902             currChild = currChild->firstChild();
4903     }
4904 
4905     if (!currChild)
4906         return;
4907 
4908     // If the child already has style, then it has already been created, so we just want
4909     // to update it.
4910     if (currChild->parent()->style()->styleType() == FIRST_LETTER) {
4911         updateFirstLetterStyle(firstLetterBlock, currChild);
4912         return;
4913     }
4914 
4915     if (!currChild->isText() || currChild->isBR())
4916         return;
4917 
4918     // Our layout state is not valid for the repaints we are going to trigger by
4919     // adding and removing children of firstLetterContainer.
4920     LayoutStateDisabler layoutStateDisabler(view());
4921 
4922     createFirstLetterRenderer(firstLetterBlock, currChild, length);
4923 }
4924 
4925 // Helper methods for obtaining the last line, computing line counts and heights for line counts
4926 // (crawling into blocks).
shouldCheckLines(RenderObject * obj)4927 static bool shouldCheckLines(RenderObject* obj)
4928 {
4929     return !obj->isFloatingOrOutOfFlowPositioned()
4930         && obj->isRenderBlock() && obj->style()->height().isAuto()
4931         && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
4932 }
4933 
getHeightForLineCount(RenderBlock * block,int l,bool includeBottom,int & count)4934 static int getHeightForLineCount(RenderBlock* block, int l, bool includeBottom, int& count)
4935 {
4936     if (block->style()->visibility() == VISIBLE) {
4937         if (block->childrenInline()) {
4938             for (RootInlineBox* box = block->firstRootBox(); box; box = box->nextRootBox()) {
4939                 if (++count == l)
4940                     return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4941             }
4942         }
4943         else {
4944             RenderBox* normalFlowChildWithoutLines = 0;
4945             for (RenderBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
4946                 if (shouldCheckLines(obj)) {
4947                     int result = getHeightForLineCount(toRenderBlock(obj), l, false, count);
4948                     if (result != -1)
4949                         return result + obj->y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
4950                 } else if (!obj->isFloatingOrOutOfFlowPositioned())
4951                     normalFlowChildWithoutLines = obj;
4952             }
4953             if (normalFlowChildWithoutLines && l == 0)
4954                 return normalFlowChildWithoutLines->y() + normalFlowChildWithoutLines->height();
4955         }
4956     }
4957 
4958     return -1;
4959 }
4960 
lineAtIndex(int i) const4961 RootInlineBox* RenderBlock::lineAtIndex(int i) const
4962 {
4963     ASSERT(i >= 0);
4964 
4965     if (style()->visibility() != VISIBLE)
4966         return 0;
4967 
4968     if (childrenInline()) {
4969         for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
4970             if (!i--)
4971                 return box;
4972     } else {
4973         for (RenderObject* child = firstChild(); child; child = child->nextSibling()) {
4974             if (!shouldCheckLines(child))
4975                 continue;
4976             if (RootInlineBox* box = toRenderBlock(child)->lineAtIndex(i))
4977                 return box;
4978         }
4979     }
4980 
4981     return 0;
4982 }
4983 
lineCount(const RootInlineBox * stopRootInlineBox,bool * found) const4984 int RenderBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
4985 {
4986     int count = 0;
4987 
4988     if (style()->visibility() == VISIBLE) {
4989         if (childrenInline())
4990             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
4991                 count++;
4992                 if (box == stopRootInlineBox) {
4993                     if (found)
4994                         *found = true;
4995                     break;
4996                 }
4997             }
4998         else
4999             for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling())
5000                 if (shouldCheckLines(obj)) {
5001                     bool recursiveFound = false;
5002                     count += toRenderBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
5003                     if (recursiveFound) {
5004                         if (found)
5005                             *found = true;
5006                         break;
5007                     }
5008                 }
5009     }
5010     return count;
5011 }
5012 
heightForLineCount(int l)5013 int RenderBlock::heightForLineCount(int l)
5014 {
5015     int count = 0;
5016     return getHeightForLineCount(this, l, true, count);
5017 }
5018 
adjustForBorderFit(LayoutUnit x,LayoutUnit & left,LayoutUnit & right) const5019 void RenderBlock::adjustForBorderFit(LayoutUnit x, LayoutUnit& left, LayoutUnit& right) const
5020 {
5021     // We don't deal with relative positioning.  Our assumption is that you shrink to fit the lines without accounting
5022     // for either overflow or translations via relative positioning.
5023     if (style()->visibility() == VISIBLE) {
5024         if (childrenInline()) {
5025             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
5026                 if (box->firstChild())
5027                     left = min(left, x + static_cast<LayoutUnit>(box->firstChild()->x()));
5028                 if (box->lastChild())
5029                     right = max(right, x + static_cast<LayoutUnit>(ceilf(box->lastChild()->logicalRight())));
5030             }
5031         } else {
5032             for (RenderBox* obj = firstChildBox(); obj; obj = obj->nextSiblingBox()) {
5033                 if (!obj->isFloatingOrOutOfFlowPositioned()) {
5034                     if (obj->isRenderBlockFlow() && !obj->hasOverflowClip())
5035                         toRenderBlock(obj)->adjustForBorderFit(x + obj->x(), left, right);
5036                     else if (obj->style()->visibility() == VISIBLE) {
5037                         // We are a replaced element or some kind of non-block-flow object.
5038                         left = min(left, x + obj->x());
5039                         right = max(right, x + obj->x() + obj->width());
5040                     }
5041                 }
5042             }
5043         }
5044     }
5045 }
5046 
fitBorderToLinesIfNeeded()5047 void RenderBlock::fitBorderToLinesIfNeeded()
5048 {
5049     if (style()->borderFit() == BorderFitBorder || hasOverrideWidth())
5050         return;
5051 
5052     // Walk any normal flow lines to snugly fit.
5053     LayoutUnit left = LayoutUnit::max();
5054     LayoutUnit right = LayoutUnit::min();
5055     LayoutUnit oldWidth = contentWidth();
5056     adjustForBorderFit(0, left, right);
5057 
5058     // Clamp to our existing edges. We can never grow. We only shrink.
5059     LayoutUnit leftEdge = borderLeft() + paddingLeft();
5060     LayoutUnit rightEdge = leftEdge + oldWidth;
5061     left = min(rightEdge, max(leftEdge, left));
5062     right = max(leftEdge, min(rightEdge, right));
5063 
5064     LayoutUnit newContentWidth = right - left;
5065     if (newContentWidth == oldWidth)
5066         return;
5067 
5068     setOverrideLogicalContentWidth(newContentWidth);
5069     layoutBlock(false);
5070     clearOverrideLogicalContentWidth();
5071 }
5072 
clearTruncation()5073 void RenderBlock::clearTruncation()
5074 {
5075     if (style()->visibility() == VISIBLE) {
5076         if (childrenInline() && hasMarkupTruncation()) {
5077             setHasMarkupTruncation(false);
5078             for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
5079                 box->clearTruncation();
5080         } else {
5081             for (RenderObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
5082                 if (shouldCheckLines(obj))
5083                     toRenderBlock(obj)->clearTruncation();
5084             }
5085         }
5086     }
5087 }
5088 
setPaginationStrut(LayoutUnit strut)5089 void RenderBlock::setPaginationStrut(LayoutUnit strut)
5090 {
5091     if (!m_rareData) {
5092         if (!strut)
5093             return;
5094         m_rareData = adoptPtr(new RenderBlockRareData());
5095     }
5096     m_rareData->m_paginationStrut = strut;
5097 }
5098 
setPageLogicalOffset(LayoutUnit logicalOffset)5099 void RenderBlock::setPageLogicalOffset(LayoutUnit logicalOffset)
5100 {
5101     if (!m_rareData) {
5102         if (!logicalOffset)
5103             return;
5104         m_rareData = adoptPtr(new RenderBlockRareData());
5105     }
5106     m_rareData->m_pageLogicalOffset = logicalOffset;
5107 }
5108 
setBreakAtLineToAvoidWidow(int lineToBreak)5109 void RenderBlock::setBreakAtLineToAvoidWidow(int lineToBreak)
5110 {
5111     ASSERT(lineToBreak >= 0);
5112     if (!m_rareData)
5113         m_rareData = adoptPtr(new RenderBlockRareData());
5114 
5115     ASSERT(!m_rareData->m_didBreakAtLineToAvoidWidow);
5116     m_rareData->m_lineBreakToAvoidWidow = lineToBreak;
5117 }
5118 
setDidBreakAtLineToAvoidWidow()5119 void RenderBlock::setDidBreakAtLineToAvoidWidow()
5120 {
5121     ASSERT(!shouldBreakAtLineToAvoidWidow());
5122 
5123     // This function should be called only after a break was applied to avoid widows
5124     // so assert |m_rareData| exists.
5125     ASSERT(m_rareData);
5126 
5127     m_rareData->m_didBreakAtLineToAvoidWidow = true;
5128 }
5129 
clearDidBreakAtLineToAvoidWidow()5130 void RenderBlock::clearDidBreakAtLineToAvoidWidow()
5131 {
5132     if (!m_rareData)
5133         return;
5134 
5135     m_rareData->m_didBreakAtLineToAvoidWidow = false;
5136 }
5137 
clearShouldBreakAtLineToAvoidWidow() const5138 void RenderBlock::clearShouldBreakAtLineToAvoidWidow() const
5139 {
5140     ASSERT(shouldBreakAtLineToAvoidWidow());
5141     if (!m_rareData)
5142         return;
5143 
5144     m_rareData->m_lineBreakToAvoidWidow = -1;
5145 }
5146 
absoluteRects(Vector<IntRect> & rects,const LayoutPoint & accumulatedOffset) const5147 void RenderBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
5148 {
5149     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5150     // inline boxes above and below us (thus getting merged with them to form a single irregular
5151     // shape).
5152     if (isAnonymousBlockContinuation()) {
5153         // FIXME: This is wrong for block-flows that are horizontal.
5154         // https://bugs.webkit.org/show_bug.cgi?id=46781
5155         rects.append(pixelSnappedIntRect(accumulatedOffset.x(), accumulatedOffset.y() - collapsedMarginBefore(),
5156                                 width(), height() + collapsedMarginBefore() + collapsedMarginAfter()));
5157         continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
5158                 inlineElementContinuation()->containingBlock()->location()));
5159     } else
5160         rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
5161 }
5162 
absoluteQuads(Vector<FloatQuad> & quads,bool * wasFixed) const5163 void RenderBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
5164 {
5165     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5166     // inline boxes above and below us (thus getting merged with them to form a single irregular
5167     // shape).
5168     if (isAnonymousBlockContinuation()) {
5169         // FIXME: This is wrong for block-flows that are horizontal.
5170         // https://bugs.webkit.org/show_bug.cgi?id=46781
5171         FloatRect localRect(0, -collapsedMarginBefore(),
5172                             width(), height() + collapsedMarginBefore() + collapsedMarginAfter());
5173         quads.append(localToAbsoluteQuad(localRect, 0 /* mode */, wasFixed));
5174         continuation()->absoluteQuads(quads, wasFixed);
5175     } else
5176         quads.append(RenderBox::localToAbsoluteQuad(FloatRect(0, 0, width(), height()), 0 /* mode */, wasFixed));
5177 }
5178 
rectWithOutlineForRepaint(const RenderLayerModelObject * repaintContainer,LayoutUnit outlineWidth) const5179 LayoutRect RenderBlock::rectWithOutlineForRepaint(const RenderLayerModelObject* repaintContainer, LayoutUnit outlineWidth) const
5180 {
5181     LayoutRect r(RenderBox::rectWithOutlineForRepaint(repaintContainer, outlineWidth));
5182     if (isAnonymousBlockContinuation())
5183         r.inflateY(collapsedMarginBefore()); // FIXME: This is wrong for block-flows that are horizontal.
5184     return r;
5185 }
5186 
hoverAncestor() const5187 RenderObject* RenderBlock::hoverAncestor() const
5188 {
5189     return isAnonymousBlockContinuation() ? continuation() : RenderBox::hoverAncestor();
5190 }
5191 
updateDragState(bool dragOn)5192 void RenderBlock::updateDragState(bool dragOn)
5193 {
5194     RenderBox::updateDragState(dragOn);
5195     if (continuation())
5196         continuation()->updateDragState(dragOn);
5197 }
5198 
outlineStyleForRepaint() const5199 RenderStyle* RenderBlock::outlineStyleForRepaint() const
5200 {
5201     return isAnonymousBlockContinuation() ? continuation()->style() : style();
5202 }
5203 
childBecameNonInline(RenderObject *)5204 void RenderBlock::childBecameNonInline(RenderObject*)
5205 {
5206     makeChildrenNonInline();
5207     if (isAnonymousBlock() && parent() && parent()->isRenderBlock())
5208         toRenderBlock(parent())->removeLeftoverAnonymousBlock(this);
5209     // |this| may be dead here
5210 }
5211 
updateHitTestResult(HitTestResult & result,const LayoutPoint & point)5212 void RenderBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
5213 {
5214     if (result.innerNode())
5215         return;
5216 
5217     if (Node* n = nodeForHitTest()) {
5218         result.setInnerNode(n);
5219         if (!result.innerNonSharedNode())
5220             result.setInnerNonSharedNode(n);
5221         result.setLocalPoint(point);
5222     }
5223 }
5224 
localCaretRect(InlineBox * inlineBox,int caretOffset,LayoutUnit * extraWidthToEndOfLine)5225 LayoutRect RenderBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
5226 {
5227     // Do the normal calculation in most cases.
5228     if (firstChild())
5229         return RenderBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
5230 
5231     LayoutRect caretRect = localCaretRectForEmptyElement(width(), textIndentOffset());
5232 
5233     if (extraWidthToEndOfLine) {
5234         if (isRenderBlock()) {
5235             *extraWidthToEndOfLine = width() - caretRect.maxX();
5236         } else {
5237             // FIXME: This code looks wrong.
5238             // myRight and containerRight are set up, but then clobbered.
5239             // So *extraWidthToEndOfLine will always be 0 here.
5240 
5241             LayoutUnit myRight = caretRect.maxX();
5242             // FIXME: why call localToAbsoluteForContent() twice here, too?
5243             FloatPoint absRightPoint = localToAbsolute(FloatPoint(myRight, 0));
5244 
5245             LayoutUnit containerRight = containingBlock()->x() + containingBlockLogicalWidthForContent();
5246             FloatPoint absContainerPoint = localToAbsolute(FloatPoint(containerRight, 0));
5247 
5248             *extraWidthToEndOfLine = absContainerPoint.x() - absRightPoint.x();
5249         }
5250     }
5251 
5252     return caretRect;
5253 }
5254 
addFocusRingRects(Vector<IntRect> & rects,const LayoutPoint & additionalOffset,const RenderLayerModelObject * paintContainer)5255 void RenderBlock::addFocusRingRects(Vector<IntRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject* paintContainer)
5256 {
5257     // For blocks inside inlines, we go ahead and include margins so that we run right up to the
5258     // inline boxes above and below us (thus getting merged with them to form a single irregular
5259     // shape).
5260     if (inlineElementContinuation()) {
5261         // FIXME: This check really isn't accurate.
5262         bool nextInlineHasLineBox = inlineElementContinuation()->firstLineBox();
5263         // FIXME: This is wrong. The principal renderer may not be the continuation preceding this block.
5264         // FIXME: This is wrong for block-flows that are horizontal.
5265         // https://bugs.webkit.org/show_bug.cgi?id=46781
5266         bool prevInlineHasLineBox = toRenderInline(inlineElementContinuation()->node()->renderer())->firstLineBox();
5267         float topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit();
5268         float bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit();
5269         LayoutRect rect(additionalOffset.x(), additionalOffset.y() - topMargin, width(), height() + topMargin + bottomMargin);
5270         if (!rect.isEmpty())
5271             rects.append(pixelSnappedIntRect(rect));
5272     } else if (width() && height())
5273         rects.append(pixelSnappedIntRect(additionalOffset, size()));
5274 
5275     if (!hasOverflowClip() && !hasControlClip()) {
5276         for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5277             LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5278             LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5279             LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
5280             if (!rect.isEmpty())
5281                 rects.append(pixelSnappedIntRect(rect));
5282         }
5283 
5284         for (RenderObject* curr = firstChild(); curr; curr = curr->nextSibling()) {
5285             if (!curr->isText() && !curr->isListMarker() && curr->isBox()) {
5286                 RenderBox* box = toRenderBox(curr);
5287                 FloatPoint pos;
5288                 // FIXME: This doesn't work correctly with transforms.
5289                 if (box->layer())
5290                     pos = curr->localToContainerPoint(FloatPoint(), paintContainer);
5291                 else
5292                     pos = FloatPoint(additionalOffset.x() + box->x(), additionalOffset.y() + box->y());
5293                 box->addFocusRingRects(rects, flooredLayoutPoint(pos), paintContainer);
5294             }
5295         }
5296     }
5297 
5298     if (inlineElementContinuation())
5299         inlineElementContinuation()->addFocusRingRects(rects, flooredLayoutPoint(additionalOffset + inlineElementContinuation()->containingBlock()->location() - location()), paintContainer);
5300 }
5301 
computeSelfHitTestRects(Vector<LayoutRect> & rects,const LayoutPoint & layerOffset) const5302 void RenderBlock::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
5303 {
5304     RenderBox::computeSelfHitTestRects(rects, layerOffset);
5305 
5306     if (hasHorizontalLayoutOverflow() || hasVerticalLayoutOverflow()) {
5307         for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
5308             LayoutUnit top = max<LayoutUnit>(curr->lineTop(), curr->top());
5309             LayoutUnit bottom = min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
5310             LayoutRect rect(layerOffset.x() + curr->x(), layerOffset.y() + top, curr->width(), bottom - top);
5311             // It's common for this rect to be entirely contained in our box, so exclude that simple case.
5312             if (!rect.isEmpty() && (rects.isEmpty() || !rects[0].contains(rect)))
5313                 rects.append(rect);
5314         }
5315     }
5316 }
5317 
createAnonymousBoxWithSameTypeAs(const RenderObject * parent) const5318 RenderBox* RenderBlock::createAnonymousBoxWithSameTypeAs(const RenderObject* parent) const
5319 {
5320     if (isAnonymousColumnsBlock())
5321         return createAnonymousColumnsWithParentRenderer(parent);
5322     if (isAnonymousColumnSpanBlock())
5323         return createAnonymousColumnSpanWithParentRenderer(parent);
5324     return createAnonymousWithParentRendererAndDisplay(parent, style()->display());
5325 }
5326 
hasNextPage(LayoutUnit logicalOffset,PageBoundaryRule pageBoundaryRule) const5327 bool RenderBlock::hasNextPage(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
5328 {
5329     ASSERT(view()->layoutState() && view()->layoutState()->isPaginated());
5330 
5331     RenderFlowThread* flowThread = flowThreadContainingBlock();
5332     if (!flowThread)
5333         return true; // Printing and multi-column both make new pages to accommodate content.
5334 
5335     // See if we're in the last region.
5336     LayoutUnit pageOffset = offsetFromLogicalTopOfFirstPage() + logicalOffset;
5337     RenderRegion* region = flowThread->regionAtBlockOffset(pageOffset, this);
5338     if (!region)
5339         return false;
5340     if (region->isLastRegion())
5341         return region->isRenderRegionSet() || region->style()->regionFragment() == BreakRegionFragment
5342             || (pageBoundaryRule == IncludePageBoundary && pageOffset == region->logicalTopForFlowThreadContent());
5343     return true;
5344 }
5345 
nextPageLogicalTop(LayoutUnit logicalOffset,PageBoundaryRule pageBoundaryRule) const5346 LayoutUnit RenderBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
5347 {
5348     LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5349     if (!pageLogicalHeight)
5350         return logicalOffset;
5351 
5352     // The logicalOffset is in our coordinate space.  We can add in our pushed offset.
5353     LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset);
5354     if (pageBoundaryRule == ExcludePageBoundary)
5355         return logicalOffset + (remainingLogicalHeight ? remainingLogicalHeight : pageLogicalHeight);
5356     return logicalOffset + remainingLogicalHeight;
5357 }
5358 
paginationUnit() const5359 ColumnInfo::PaginationUnit RenderBlock::paginationUnit() const
5360 {
5361     return ColumnInfo::Column;
5362 }
5363 
pageLogicalTopForOffset(LayoutUnit offset) const5364 LayoutUnit RenderBlock::pageLogicalTopForOffset(LayoutUnit offset) const
5365 {
5366     RenderView* renderView = view();
5367     LayoutUnit firstPageLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_pageOffset.height() : renderView->layoutState()->m_pageOffset.width();
5368     LayoutUnit blockLogicalTop = isHorizontalWritingMode() ? renderView->layoutState()->m_layoutOffset.height() : renderView->layoutState()->m_layoutOffset.width();
5369 
5370     LayoutUnit cumulativeOffset = offset + blockLogicalTop;
5371     RenderFlowThread* flowThread = flowThreadContainingBlock();
5372     if (!flowThread) {
5373         LayoutUnit pageLogicalHeight = renderView->layoutState()->pageLogicalHeight();
5374         if (!pageLogicalHeight)
5375             return 0;
5376         return cumulativeOffset - roundToInt(cumulativeOffset - firstPageLogicalTop) % roundToInt(pageLogicalHeight);
5377     }
5378     return flowThread->pageLogicalTopForOffset(cumulativeOffset);
5379 }
5380 
pageLogicalHeightForOffset(LayoutUnit offset) const5381 LayoutUnit RenderBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
5382 {
5383     RenderView* renderView = view();
5384     RenderFlowThread* flowThread = flowThreadContainingBlock();
5385     if (!flowThread)
5386         return renderView->layoutState()->m_pageLogicalHeight;
5387     return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
5388 }
5389 
pageRemainingLogicalHeightForOffset(LayoutUnit offset,PageBoundaryRule pageBoundaryRule) const5390 LayoutUnit RenderBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
5391 {
5392     RenderView* renderView = view();
5393     offset += offsetFromLogicalTopOfFirstPage();
5394 
5395     RenderFlowThread* flowThread = flowThreadContainingBlock();
5396     if (!flowThread) {
5397         LayoutUnit pageLogicalHeight = renderView->layoutState()->m_pageLogicalHeight;
5398         LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
5399         if (pageBoundaryRule == IncludePageBoundary) {
5400             // If includeBoundaryPoint is true the line exactly on the top edge of a
5401             // column will act as being part of the previous column.
5402             remainingHeight = intMod(remainingHeight, pageLogicalHeight);
5403         }
5404         return remainingHeight;
5405     }
5406 
5407     return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
5408 }
5409 
adjustForUnsplittableChild(RenderBox * child,LayoutUnit logicalOffset,bool includeMargins)5410 LayoutUnit RenderBlock::adjustForUnsplittableChild(RenderBox* child, LayoutUnit logicalOffset, bool includeMargins)
5411 {
5412     bool checkColumnBreaks = view()->layoutState()->isPaginatingColumns();
5413     bool checkPageBreaks = !checkColumnBreaks && view()->layoutState()->m_pageLogicalHeight;
5414     RenderFlowThread* flowThread = flowThreadContainingBlock();
5415     bool checkRegionBreaks = flowThread && flowThread->isRenderNamedFlowThread();
5416     bool isUnsplittable = child->isUnsplittableForPagination() || (checkColumnBreaks && child->style()->columnBreakInside() == PBAVOID)
5417         || (checkPageBreaks && child->style()->pageBreakInside() == PBAVOID)
5418         || (checkRegionBreaks && child->style()->regionBreakInside() == PBAVOID);
5419     if (!isUnsplittable)
5420         return logicalOffset;
5421     LayoutUnit childLogicalHeight = logicalHeightForChild(child) + (includeMargins ? marginBeforeForChild(child) + marginAfterForChild(child) : LayoutUnit());
5422     LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5423     bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
5424     updateMinimumPageHeight(logicalOffset, childLogicalHeight);
5425     if (!pageLogicalHeight || (hasUniformPageLogicalHeight && childLogicalHeight > pageLogicalHeight)
5426         || !hasNextPage(logicalOffset))
5427         return logicalOffset;
5428     LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5429     if (remainingLogicalHeight < childLogicalHeight) {
5430         if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, childLogicalHeight))
5431             return logicalOffset;
5432         return logicalOffset + remainingLogicalHeight;
5433     }
5434     return logicalOffset;
5435 }
5436 
pushToNextPageWithMinimumLogicalHeight(LayoutUnit & adjustment,LayoutUnit logicalOffset,LayoutUnit minimumLogicalHeight) const5437 bool RenderBlock::pushToNextPageWithMinimumLogicalHeight(LayoutUnit& adjustment, LayoutUnit logicalOffset, LayoutUnit minimumLogicalHeight) const
5438 {
5439     bool checkRegion = false;
5440     for (LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment); pageLogicalHeight;
5441         pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset + adjustment)) {
5442         if (minimumLogicalHeight <= pageLogicalHeight)
5443             return true;
5444         if (!hasNextPage(logicalOffset + adjustment))
5445             return false;
5446         adjustment += pageLogicalHeight;
5447         checkRegion = true;
5448     }
5449     return !checkRegion;
5450 }
5451 
setPageBreak(LayoutUnit offset,LayoutUnit spaceShortage)5452 void RenderBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
5453 {
5454     if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5455         flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
5456 }
5457 
updateMinimumPageHeight(LayoutUnit offset,LayoutUnit minHeight)5458 void RenderBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
5459 {
5460     if (RenderFlowThread* flowThread = flowThreadContainingBlock())
5461         flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
5462     else if (ColumnInfo* colInfo = view()->layoutState()->m_columnInfo)
5463         colInfo->updateMinimumColumnHeight(minHeight);
5464 }
5465 
calculateMinimumPageHeight(RenderStyle * renderStyle,RootInlineBox * lastLine,LayoutUnit lineTop,LayoutUnit lineBottom)5466 static inline LayoutUnit calculateMinimumPageHeight(RenderStyle* renderStyle, RootInlineBox* lastLine, LayoutUnit lineTop, LayoutUnit lineBottom)
5467 {
5468     // We may require a certain minimum number of lines per page in order to satisfy
5469     // orphans and widows, and that may affect the minimum page height.
5470     unsigned lineCount = max<unsigned>(renderStyle->hasAutoOrphans() ? 1 : renderStyle->orphans(), renderStyle->hasAutoWidows() ? 1 : renderStyle->widows());
5471     if (lineCount > 1) {
5472         RootInlineBox* line = lastLine;
5473         for (unsigned i = 1; i < lineCount && line->prevRootBox(); i++)
5474             line = line->prevRootBox();
5475 
5476         // FIXME: Paginating using line overflow isn't all fine. See FIXME in
5477         // adjustLinePositionForPagination() for more details.
5478         LayoutRect overflow = line->logicalVisualOverflowRect(line->lineTop(), line->lineBottom());
5479         lineTop = min(line->lineTopWithLeading(), overflow.y());
5480     }
5481     return lineBottom - lineTop;
5482 }
5483 
adjustLinePositionForPagination(RootInlineBox * lineBox,LayoutUnit & delta,RenderFlowThread * flowThread)5484 void RenderBlock::adjustLinePositionForPagination(RootInlineBox* lineBox, LayoutUnit& delta, RenderFlowThread* flowThread)
5485 {
5486     // FIXME: For now we paginate using line overflow.  This ensures that lines don't overlap at all when we
5487     // put a strut between them for pagination purposes.  However, this really isn't the desired rendering, since
5488     // the line on the top of the next page will appear too far down relative to the same kind of line at the top
5489     // of the first column.
5490     //
5491     // The rendering we would like to see is one where the lineTopWithLeading is at the top of the column, and any line overflow
5492     // simply spills out above the top of the column.  This effect would match what happens at the top of the first column.
5493     // We can't achieve this rendering, however, until we stop columns from clipping to the column bounds (thus allowing
5494     // for overflow to occur), and then cache visible overflow for each column rect.
5495     //
5496     // Furthermore, the paint we have to do when a column has overflow has to be special.  We need to exclude
5497     // content that paints in a previous column (and content that paints in the following column).
5498     //
5499     // For now we'll at least honor the lineTopWithLeading when paginating if it is above the logical top overflow. This will
5500     // at least make positive leading work in typical cases.
5501     //
5502     // FIXME: Another problem with simply moving lines is that the available line width may change (because of floats).
5503     // Technically if the location we move the line to has a different line width than our old position, then we need to dirty the
5504     // line and all following lines.
5505     LayoutRect logicalVisualOverflow = lineBox->logicalVisualOverflowRect(lineBox->lineTop(), lineBox->lineBottom());
5506     LayoutUnit logicalOffset = min(lineBox->lineTopWithLeading(), logicalVisualOverflow.y());
5507     LayoutUnit logicalBottom = max(lineBox->lineBottomWithLeading(), logicalVisualOverflow.maxY());
5508     LayoutUnit lineHeight = logicalBottom - logicalOffset;
5509     updateMinimumPageHeight(logicalOffset, calculateMinimumPageHeight(style(), lineBox, logicalOffset, logicalBottom));
5510     logicalOffset += delta;
5511     lineBox->setPaginationStrut(0);
5512     lineBox->setIsFirstAfterPageBreak(false);
5513     LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
5514     bool hasUniformPageLogicalHeight = !flowThread || flowThread->regionsHaveUniformLogicalHeight();
5515     // If lineHeight is greater than pageLogicalHeight, but logicalVisualOverflow.height() still fits, we are
5516     // still going to add a strut, so that the visible overflow fits on a single page.
5517     if (!pageLogicalHeight || (hasUniformPageLogicalHeight && logicalVisualOverflow.height() > pageLogicalHeight)
5518         || !hasNextPage(logicalOffset))
5519         // FIXME: In case the line aligns with the top of the page (or it's slightly shifted downwards) it will not be marked as the first line in the page.
5520         // From here, the fix is not straightforward because it's not easy to always determine when the current line is the first in the page.
5521         return;
5522     LayoutUnit remainingLogicalHeight = pageRemainingLogicalHeightForOffset(logicalOffset, ExcludePageBoundary);
5523 
5524     int lineIndex = lineCount(lineBox);
5525     if (remainingLogicalHeight < lineHeight || (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex)) {
5526         if (shouldBreakAtLineToAvoidWidow() && lineBreakToAvoidWidow() == lineIndex) {
5527             clearShouldBreakAtLineToAvoidWidow();
5528             setDidBreakAtLineToAvoidWidow();
5529         }
5530         // If we have a non-uniform page height, then we have to shift further possibly.
5531         if (!hasUniformPageLogicalHeight && !pushToNextPageWithMinimumLogicalHeight(remainingLogicalHeight, logicalOffset, lineHeight))
5532             return;
5533         if (lineHeight > pageLogicalHeight) {
5534             // Split the top margin in order to avoid splitting the visible part of the line.
5535             remainingLogicalHeight -= min(lineHeight - pageLogicalHeight, max<LayoutUnit>(0, logicalVisualOverflow.y() - lineBox->lineTopWithLeading()));
5536         }
5537         LayoutUnit totalLogicalHeight = lineHeight + max<LayoutUnit>(0, logicalOffset);
5538         LayoutUnit pageLogicalHeightAtNewOffset = hasUniformPageLogicalHeight ? pageLogicalHeight : pageLogicalHeightForOffset(logicalOffset + remainingLogicalHeight);
5539         setPageBreak(logicalOffset, lineHeight - remainingLogicalHeight);
5540         if (((lineBox == firstRootBox() && totalLogicalHeight < pageLogicalHeightAtNewOffset) || (!style()->hasAutoOrphans() && style()->orphans() >= lineIndex))
5541             && !isOutOfFlowPositioned() && !isTableCell())
5542             setPaginationStrut(remainingLogicalHeight + max<LayoutUnit>(0, logicalOffset));
5543         else {
5544             delta += remainingLogicalHeight;
5545             lineBox->setPaginationStrut(remainingLogicalHeight);
5546             lineBox->setIsFirstAfterPageBreak(true);
5547         }
5548     } else if (remainingLogicalHeight == pageLogicalHeight) {
5549         // We're at the very top of a page or column.
5550         if (lineBox != firstRootBox())
5551             lineBox->setIsFirstAfterPageBreak(true);
5552         if (lineBox != firstRootBox() || offsetFromLogicalTopOfFirstPage())
5553             setPageBreak(logicalOffset, lineHeight);
5554     }
5555 }
5556 
updateRegionForLine(RootInlineBox * lineBox) const5557 void RenderBlock::updateRegionForLine(RootInlineBox* lineBox) const
5558 {
5559     ASSERT(lineBox);
5560     lineBox->setContainingRegion(regionAtBlockOffset(lineBox->lineTopWithLeading()));
5561 
5562     RootInlineBox* prevLineBox = lineBox->prevRootBox();
5563     if (!prevLineBox)
5564         return;
5565 
5566     // This check is more accurate than the one in |adjustLinePositionForPagination| because it takes into
5567     // account just the container changes between lines. The before mentioned function doesn't set the flag
5568     // correctly if the line is positioned at the top of the last fragment container.
5569     if (lineBox->containingRegion() != prevLineBox->containingRegion())
5570         lineBox->setIsFirstAfterPageBreak(true);
5571 }
5572 
lineWidthForPaginatedLineChanged(RootInlineBox * rootBox,LayoutUnit lineDelta,RenderFlowThread * flowThread) const5573 bool RenderBlock::lineWidthForPaginatedLineChanged(RootInlineBox* rootBox, LayoutUnit lineDelta, RenderFlowThread* flowThread) const
5574 {
5575     if (!flowThread)
5576         return false;
5577 
5578     RenderRegion* currentRegion = regionAtBlockOffset(rootBox->lineTopWithLeading() + lineDelta);
5579     // Just bail if the region didn't change.
5580     if (rootBox->containingRegion() == currentRegion)
5581         return false;
5582     return rootBox->paginatedLineWidth() != availableLogicalWidthForContent(currentRegion);
5583 }
5584 
offsetFromLogicalTopOfFirstPage() const5585 LayoutUnit RenderBlock::offsetFromLogicalTopOfFirstPage() const
5586 {
5587     LayoutState* layoutState = view()->layoutState();
5588     if (layoutState && !layoutState->isPaginated())
5589         return 0;
5590 
5591     RenderFlowThread* flowThread = flowThreadContainingBlock();
5592     if (flowThread)
5593         return flowThread->offsetFromLogicalTopOfFirstRegion(this);
5594 
5595     if (layoutState) {
5596         ASSERT(layoutState->renderer() == this);
5597 
5598         LayoutSize offsetDelta = layoutState->m_layoutOffset - layoutState->m_pageOffset;
5599         return isHorizontalWritingMode() ? offsetDelta.height() : offsetDelta.width();
5600     }
5601 
5602     ASSERT_NOT_REACHED();
5603     return 0;
5604 }
5605 
regionAtBlockOffset(LayoutUnit blockOffset) const5606 RenderRegion* RenderBlock::regionAtBlockOffset(LayoutUnit blockOffset) const
5607 {
5608     RenderFlowThread* flowThread = flowThreadContainingBlock();
5609     if (!flowThread || !flowThread->hasValidRegionInfo())
5610         return 0;
5611 
5612     return flowThread->regionAtBlockOffset(offsetFromLogicalTopOfFirstPage() + blockOffset, true);
5613 }
5614 
logicalWidthChangedInRegions(RenderFlowThread * flowThread) const5615 bool RenderBlock::logicalWidthChangedInRegions(RenderFlowThread* flowThread) const
5616 {
5617     if (!flowThread || !flowThread->hasValidRegionInfo())
5618         return false;
5619 
5620     return flowThread->logicalWidthChangedInRegionsForBlock(this);
5621 }
5622 
clampToStartAndEndRegions(RenderRegion * region) const5623 RenderRegion* RenderBlock::clampToStartAndEndRegions(RenderRegion* region) const
5624 {
5625     RenderFlowThread* flowThread = flowThreadContainingBlock();
5626 
5627     ASSERT(isRenderView() || (region && flowThread));
5628     if (isRenderView())
5629         return region;
5630 
5631     // We need to clamp to the block, since we want any lines or blocks that overflow out of the
5632     // logical top or logical bottom of the block to size as though the border box in the first and
5633     // last regions extended infinitely. Otherwise the lines are going to size according to the regions
5634     // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
5635     RenderRegion* startRegion;
5636     RenderRegion* endRegion;
5637     flowThread->getRegionRangeForBox(this, startRegion, endRegion);
5638 
5639     if (startRegion && region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
5640         return startRegion;
5641     if (endRegion && region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
5642         return endRegion;
5643 
5644     return region;
5645 }
5646 
collapsedMarginBeforeForChild(const RenderBox * child) const5647 LayoutUnit RenderBlock::collapsedMarginBeforeForChild(const RenderBox* child) const
5648 {
5649     // If the child has the same directionality as we do, then we can just return its
5650     // collapsed margin.
5651     if (!child->isWritingModeRoot())
5652         return child->collapsedMarginBefore();
5653 
5654     // The child has a different directionality.  If the child is parallel, then it's just
5655     // flipped relative to us.  We can use the collapsed margin for the opposite edge.
5656     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5657         return child->collapsedMarginAfter();
5658 
5659     // The child is perpendicular to us, which means its margins don't collapse but are on the
5660     // "logical left/right" sides of the child box.  We can just return the raw margin in this case.
5661     return marginBeforeForChild(child);
5662 }
5663 
collapsedMarginAfterForChild(const RenderBox * child) const5664 LayoutUnit RenderBlock::collapsedMarginAfterForChild(const  RenderBox* child) const
5665 {
5666     // If the child has the same directionality as we do, then we can just return its
5667     // collapsed margin.
5668     if (!child->isWritingModeRoot())
5669         return child->collapsedMarginAfter();
5670 
5671     // The child has a different directionality.  If the child is parallel, then it's just
5672     // flipped relative to us.  We can use the collapsed margin for the opposite edge.
5673     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5674         return child->collapsedMarginBefore();
5675 
5676     // The child is perpendicular to us, which means its margins don't collapse but are on the
5677     // "logical left/right" side of the child box.  We can just return the raw margin in this case.
5678     return marginAfterForChild(child);
5679 }
5680 
hasMarginBeforeQuirk(const RenderBox * child) const5681 bool RenderBlock::hasMarginBeforeQuirk(const RenderBox* child) const
5682 {
5683     // If the child has the same directionality as we do, then we can just return its
5684     // margin quirk.
5685     if (!child->isWritingModeRoot())
5686         return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5687 
5688     // The child has a different directionality. If the child is parallel, then it's just
5689     // flipped relative to us. We can use the opposite edge.
5690     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5691         return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5692 
5693     // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5694     // whether or not authors specified quirky ems, since they're an implementation detail.
5695     return false;
5696 }
5697 
hasMarginAfterQuirk(const RenderBox * child) const5698 bool RenderBlock::hasMarginAfterQuirk(const RenderBox* child) const
5699 {
5700     // If the child has the same directionality as we do, then we can just return its
5701     // margin quirk.
5702     if (!child->isWritingModeRoot())
5703         return child->isRenderBlock() ? toRenderBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
5704 
5705     // The child has a different directionality. If the child is parallel, then it's just
5706     // flipped relative to us. We can use the opposite edge.
5707     if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
5708         return child->isRenderBlock() ? toRenderBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
5709 
5710     // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
5711     // whether or not authors specified quirky ems, since they're an implementation detail.
5712     return false;
5713 }
5714 
renderName() const5715 const char* RenderBlock::renderName() const
5716 {
5717     if (isBody())
5718         return "RenderBody"; // FIXME: Temporary hack until we know that the regression tests pass.
5719 
5720     if (isFloating())
5721         return "RenderBlock (floating)";
5722     if (isOutOfFlowPositioned())
5723         return "RenderBlock (positioned)";
5724     if (isAnonymousColumnsBlock())
5725         return "RenderBlock (anonymous multi-column)";
5726     if (isAnonymousColumnSpanBlock())
5727         return "RenderBlock (anonymous multi-column span)";
5728     if (isAnonymousBlock())
5729         return "RenderBlock (anonymous)";
5730     // FIXME: Temporary hack while the new generated content system is being implemented.
5731     if (isPseudoElement())
5732         return "RenderBlock (generated)";
5733     if (isAnonymous())
5734         return "RenderBlock (generated)";
5735     if (isRelPositioned())
5736         return "RenderBlock (relative positioned)";
5737     if (isStickyPositioned())
5738         return "RenderBlock (sticky positioned)";
5739     return "RenderBlock";
5740 }
5741 
createAnonymousWithParentRendererAndDisplay(const RenderObject * parent,EDisplay display)5742 RenderBlock* RenderBlock::createAnonymousWithParentRendererAndDisplay(const RenderObject* parent, EDisplay display)
5743 {
5744     // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
5745     EDisplay newDisplay;
5746     RenderBlock* newBox = 0;
5747     if (display == BOX || display == INLINE_BOX) {
5748         // FIXME: Remove this case once we have eliminated all internal users of old flexbox
5749         newBox = RenderDeprecatedFlexibleBox::createAnonymous(&parent->document());
5750         newDisplay = BOX;
5751     } else if (display == FLEX || display == INLINE_FLEX) {
5752         newBox = RenderFlexibleBox::createAnonymous(&parent->document());
5753         newDisplay = FLEX;
5754     } else {
5755         newBox = RenderBlockFlow::createAnonymous(&parent->document());
5756         newDisplay = BLOCK;
5757     }
5758 
5759     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), newDisplay);
5760     newBox->setStyle(newStyle.release());
5761     return newBox;
5762 }
5763 
createAnonymousColumnsWithParentRenderer(const RenderObject * parent)5764 RenderBlockFlow* RenderBlock::createAnonymousColumnsWithParentRenderer(const RenderObject* parent)
5765 {
5766     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5767     newStyle->inheritColumnPropertiesFrom(parent->style());
5768 
5769     RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5770     newBox->setStyle(newStyle.release());
5771     return newBox;
5772 }
5773 
createAnonymousColumnSpanWithParentRenderer(const RenderObject * parent)5774 RenderBlockFlow* RenderBlock::createAnonymousColumnSpanWithParentRenderer(const RenderObject* parent)
5775 {
5776     RefPtr<RenderStyle> newStyle = RenderStyle::createAnonymousStyleWithDisplay(parent->style(), BLOCK);
5777     newStyle->setColumnSpan(ColumnSpanAll);
5778 
5779     RenderBlockFlow* newBox = RenderBlockFlow::createAnonymous(&parent->document());
5780     newBox->setStyle(newStyle.release());
5781     return newBox;
5782 }
5783 
5784 #ifndef NDEBUG
checkPositionedObjectsNeedLayout()5785 void RenderBlock::checkPositionedObjectsNeedLayout()
5786 {
5787     if (!gPositionedDescendantsMap)
5788         return;
5789 
5790     if (TrackedRendererListHashSet* positionedDescendantSet = positionedObjects()) {
5791         TrackedRendererListHashSet::const_iterator end = positionedDescendantSet->end();
5792         for (TrackedRendererListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) {
5793             RenderBox* currBox = *it;
5794             ASSERT(!currBox->needsLayout());
5795         }
5796     }
5797 }
5798 
showLineTreeAndMark(const InlineBox * markedBox1,const char * markedLabel1,const InlineBox * markedBox2,const char * markedLabel2,const RenderObject * obj) const5799 void RenderBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const RenderObject* obj) const
5800 {
5801     showRenderObject();
5802     for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
5803         root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
5804 }
5805 
5806 #endif
5807 
5808 } // namespace WebCore
5809