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