Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / third_party / WebKit / Source / core / layout / LayoutBlock.cpp
blobe4fb73ac0da4b56eaa2d6ecf0b41786cbb36f1a9
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.
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.
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.
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.
24 #include "config.h"
25 #include "core/layout/LayoutBlock.h"
27 #include "core/HTMLNames.h"
28 #include "core/dom/AXObjectCache.h"
29 #include "core/dom/Document.h"
30 #include "core/dom/Element.h"
31 #include "core/dom/StyleEngine.h"
32 #include "core/dom/shadow/ShadowRoot.h"
33 #include "core/editing/EditingUtilities.h"
34 #include "core/editing/Editor.h"
35 #include "core/editing/FrameSelection.h"
36 #include "core/fetch/ResourceLoadPriorityOptimizer.h"
37 #include "core/frame/FrameView.h"
38 #include "core/frame/LocalFrame.h"
39 #include "core/frame/Settings.h"
40 #include "core/html/HTMLMarqueeElement.h"
41 #include "core/layout/HitTestLocation.h"
42 #include "core/layout/HitTestResult.h"
43 #include "core/layout/LayoutAnalyzer.h"
44 #include "core/layout/LayoutDeprecatedFlexibleBox.h"
45 #include "core/layout/LayoutFlexibleBox.h"
46 #include "core/layout/LayoutFlowThread.h"
47 #include "core/layout/LayoutGrid.h"
48 #include "core/layout/LayoutInline.h"
49 #include "core/layout/LayoutMultiColumnSpannerPlaceholder.h"
50 #include "core/layout/LayoutObject.h"
51 #include "core/layout/LayoutTableCell.h"
52 #include "core/layout/LayoutTextCombine.h"
53 #include "core/layout/LayoutTextControl.h"
54 #include "core/layout/LayoutTextFragment.h"
55 #include "core/layout/LayoutTheme.h"
56 #include "core/layout/LayoutView.h"
57 #include "core/layout/TextAutosizer.h"
58 #include "core/layout/api/LineLayoutItem.h"
59 #include "core/layout/line/GlyphOverflow.h"
60 #include "core/layout/line/InlineIterator.h"
61 #include "core/layout/line/InlineTextBox.h"
62 #include "core/layout/shapes/ShapeOutsideInfo.h"
63 #include "core/layout/svg/LayoutSVGResourceClipper.h"
64 #include "core/page/Page.h"
65 #include "core/paint/BlockPainter.h"
66 #include "core/paint/BoxPainter.h"
67 #include "core/paint/DeprecatedPaintLayer.h"
68 #include "core/paint/LayoutObjectDrawingRecorder.h"
69 #include "core/style/ComputedStyle.h"
70 #include "core/style/ContentData.h"
71 #include "platform/RuntimeEnabledFeatures.h"
72 #include "platform/geometry/FloatQuad.h"
73 #include "platform/geometry/TransformState.h"
74 #include "wtf/StdLibExtras.h"
75 #include "wtf/TemporaryChange.h"
77 using namespace WTF;
78 using namespace Unicode;
80 namespace blink {
82 using namespace HTMLNames;
84 struct SameSizeAsLayoutBlock : public LayoutBox {
85 LayoutObjectChildList children;
86 LineBoxList lineBoxes;
87 uint32_t bitfields;
90 static_assert(sizeof(LayoutBlock) == sizeof(SameSizeAsLayoutBlock), "LayoutBlock should stay small");
92 // This map keeps track of the positioned objects associated with a containing
93 // block.
95 // This map is populated during layout. It is kept across layouts to handle
96 // that we skip unchanged sub-trees during layout, in such a way that we are
97 // able to lay out deeply nested out-of-flow descendants if their containing
98 // block got laid out. The map could be invalidated during style change but
99 // keeping track of containing blocks at that time is complicated (we are in
100 // the middle of recomputing the style so we can't rely on any of its
101 // information), which is why it's easier to just update it for every layout.
102 static TrackedDescendantsMap* gPositionedDescendantsMap = nullptr;
104 // This map keeps track of the descendants whose 'height' is percentage associated
105 // with a containing block. Like |gPositionedDescendantsMap|, it is also recomputed
106 // for every layout (see the comment above about why).
107 static TrackedDescendantsMap* gPercentHeightDescendantsMap = nullptr;
109 static TrackedContainerMap* gPositionedContainerMap = nullptr;
110 static TrackedContainerMap* gPercentHeightContainerMap = nullptr;
112 struct ScrollInfo {
113 DoubleSize scrollOffset;
114 bool autoHorizontalScrollBarChanged;
115 bool autoVerticalScrollBarChanged;
116 bool hasOffset() const { return scrollOffset != DoubleSize(); }
117 bool scrollBarsChanged() const { return autoHorizontalScrollBarChanged || autoVerticalScrollBarChanged; }
118 void merge(const ScrollInfo& other)
120 // We always keep the first scrollOffset we saw for this block, so don't copy that field.
121 autoHorizontalScrollBarChanged |= other.autoHorizontalScrollBarChanged;
122 autoVerticalScrollBarChanged |= other.autoVerticalScrollBarChanged;
125 typedef WTF::HashMap<LayoutBlock*, ScrollInfo> DelayedUpdateScrollInfoMap;
126 static int gDelayUpdateScrollInfo = 0;
127 static DelayedUpdateScrollInfoMap* gDelayedUpdateScrollInfoMap = nullptr;
129 LayoutBlock::LayoutBlock(ContainerNode* node)
130 : LayoutBox(node)
131 , m_hasMarginBeforeQuirk(false)
132 , m_hasMarginAfterQuirk(false)
133 , m_beingDestroyed(false)
134 , m_hasMarkupTruncation(false)
135 , m_widthAvailableToChildrenChanged(false)
136 , m_hasOnlySelfCollapsingChildren(false)
137 , m_descendantsWithFloatsMarkedForLayout(false)
138 , m_needsRecalcLogicalWidthAfterLayoutChildren(false)
140 // LayoutBlockFlow calls setChildrenInline(true).
141 // By default, subclasses do not have inline children.
144 static void removeBlockFromDescendantAndContainerMaps(LayoutBlock* block, TrackedDescendantsMap*& descendantMap, TrackedContainerMap*& containerMap)
146 if (OwnPtr<TrackedLayoutBoxListHashSet> descendantSet = descendantMap->take(block)) {
147 for (auto& descendant : *descendantSet) {
148 TrackedContainerMap::iterator it = containerMap->find(descendant);
149 ASSERT(it != containerMap->end());
150 if (it == containerMap->end())
151 continue;
152 HashSet<LayoutBlock*>* containerSet = it->value.get();
153 ASSERT(containerSet->contains(block));
154 containerSet->remove(block);
155 if (containerSet->isEmpty())
156 containerMap->remove(it);
161 static void appendImageIfNotNull(Vector<ImageResource*>& imageResources, const StyleImage* styleImage)
163 if (styleImage && styleImage->cachedImage()) {
164 ImageResource* imageResource = styleImage->cachedImage();
165 if (imageResource && !imageResource->isLoaded())
166 imageResources.append(styleImage->cachedImage());
170 static void appendLayers(Vector<ImageResource*>& images, const FillLayer& styleLayer)
172 for (const FillLayer* layer = &styleLayer; layer; layer = layer->next())
173 appendImageIfNotNull(images, layer->image());
176 static void appendImagesFromStyle(Vector<ImageResource*>& images, const ComputedStyle& blockStyle)
178 appendLayers(images, blockStyle.backgroundLayers());
179 appendLayers(images, blockStyle.maskLayers());
181 const ContentData* contentData = blockStyle.contentData();
182 if (contentData && contentData->isImage())
183 appendImageIfNotNull(images, toImageContentData(contentData)->image());
184 if (blockStyle.boxReflect())
185 appendImageIfNotNull(images, blockStyle.boxReflect()->mask().image());
186 appendImageIfNotNull(images, blockStyle.listStyleImage());
187 appendImageIfNotNull(images, blockStyle.borderImageSource());
188 appendImageIfNotNull(images, blockStyle.maskBoxImageSource());
189 if (blockStyle.shapeOutside())
190 appendImageIfNotNull(images, blockStyle.shapeOutside()->image());
193 void LayoutBlock::removeFromGlobalMaps()
195 if (gPercentHeightDescendantsMap)
196 removeBlockFromDescendantAndContainerMaps(this, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
197 if (gPositionedDescendantsMap)
198 removeBlockFromDescendantAndContainerMaps(this, gPositionedDescendantsMap, gPositionedContainerMap);
201 LayoutBlock::~LayoutBlock()
203 removeFromGlobalMaps();
206 void LayoutBlock::willBeDestroyed()
208 // Mark as being destroyed to avoid trouble with merges in removeChild().
209 m_beingDestroyed = true;
211 // Make sure to destroy anonymous children first while they are still connected to the rest of the tree, so that they will
212 // properly dirty line boxes that they are removed from. Effects that do :before/:after only on hover could crash otherwise.
213 children()->destroyLeftoverChildren();
215 // Destroy our continuation before anything other than anonymous children.
216 // The reason we don't destroy it before anonymous children is that they may
217 // have continuations of their own that are anonymous children of our continuation.
218 LayoutBoxModelObject* continuation = this->continuation();
219 if (continuation) {
220 continuation->destroy();
221 setContinuation(nullptr);
224 if (!documentBeingDestroyed()) {
225 if (firstLineBox()) {
226 // We can't wait for LayoutBox::destroy to clear the selection,
227 // because by then we will have nuked the line boxes.
228 // FIXME: The FrameSelection should be responsible for this when it
229 // is notified of DOM mutations.
230 if (isSelectionBorder())
231 view()->clearSelection();
233 // If we are an anonymous block, then our line boxes might have children
234 // that will outlast this block. In the non-anonymous block case those
235 // children will be destroyed by the time we return from this function.
236 if (isAnonymousBlock()) {
237 for (InlineFlowBox* box = firstLineBox(); box; box = box->nextLineBox()) {
238 while (InlineBox* childBox = box->firstChild())
239 childBox->remove();
242 } else if (parent()) {
243 parent()->dirtyLinesFromChangedChild(this);
247 m_lineBoxes.deleteLineBoxes();
249 if (UNLIKELY(gDelayedUpdateScrollInfoMap != 0))
250 gDelayedUpdateScrollInfoMap->remove(this);
252 if (TextAutosizer* textAutosizer = document().textAutosizer())
253 textAutosizer->destroy(this);
255 LayoutBox::willBeDestroyed();
258 void LayoutBlock::styleWillChange(StyleDifference diff, const ComputedStyle& newStyle)
260 const ComputedStyle* oldStyle = style();
262 setReplaced(newStyle.isDisplayInlineType());
264 if (oldStyle && parent()) {
265 bool oldHasTransformRelatedProperty = oldStyle->hasTransformRelatedProperty();
266 bool newHasTransformRelatedProperty = newStyle.hasTransformRelatedProperty();
267 bool oldStyleIsContainer = oldStyle->position() != StaticPosition || oldHasTransformRelatedProperty;
269 if (oldStyleIsContainer && (newStyle.position() == StaticPosition || (oldHasTransformRelatedProperty && !newHasTransformRelatedProperty))) {
270 // Clear our positioned objects list. Our absolutely positioned descendants will be
271 // inserted into our containing block's positioned objects list during layout.
272 removePositionedObjects(0, NewContainingBlock);
273 } else if (!oldStyleIsContainer && (newStyle.position() != StaticPosition || newHasTransformRelatedProperty)) {
274 // Remove our absolutely positioned descendants from their current containing block.
275 // They will be inserted into our positioned objects list during layout.
276 if (LayoutBlock* cb = containingBlockForAbsolutePosition())
277 cb->removePositionedObjects(this, NewContainingBlock);
281 LayoutBox::styleWillChange(diff, newStyle);
284 static bool borderOrPaddingLogicalWidthChanged(const ComputedStyle& oldStyle, const ComputedStyle& newStyle)
286 if (newStyle.isHorizontalWritingMode()) {
287 return oldStyle.borderLeftWidth() != newStyle.borderLeftWidth()
288 || oldStyle.borderRightWidth() != newStyle.borderRightWidth()
289 || oldStyle.paddingLeft() != newStyle.paddingLeft()
290 || oldStyle.paddingRight() != newStyle.paddingRight();
293 return oldStyle.borderTopWidth() != newStyle.borderTopWidth()
294 || oldStyle.borderBottomWidth() != newStyle.borderBottomWidth()
295 || oldStyle.paddingTop() != newStyle.paddingTop()
296 || oldStyle.paddingBottom() != newStyle.paddingBottom();
299 void LayoutBlock::styleDidChange(StyleDifference diff, const ComputedStyle* oldStyle)
301 LayoutBox::styleDidChange(diff, oldStyle);
303 if (isFloatingOrOutOfFlowPositioned() && oldStyle && !oldStyle->isFloating() && !oldStyle->hasOutOfFlowPosition() && parent() && parent()->isLayoutBlockFlow()) {
304 toLayoutBlock(parent())->removeAnonymousWrappersIfRequired();
305 // Reparent to an adjacent anonymous block if one is available.
306 if (previousSibling() && previousSibling()->isAnonymousBlock())
307 toLayoutBlock(parent())->moveChildTo(toLayoutBlock(previousSibling()), this, nullptr, false);
308 else if (nextSibling() && nextSibling()->isAnonymousBlock())
309 toLayoutBlock(parent())->moveChildTo(toLayoutBlock(nextSibling()), this, nextSibling()->slowFirstChild(), false);
312 const ComputedStyle& newStyle = styleRef();
314 if (oldStyle && parent()) {
315 if (oldStyle->position() != newStyle.position() && newStyle.position() != StaticPosition) {
316 // Remove our absolutely positioned descendants from their new containing block,
317 // in case containingBlock() changes by the change to the position property.
318 // See styleWillChange() for other cases.
319 if (LayoutBlock* cb = containingBlock())
320 cb->removePositionedObjects(this, NewContainingBlock);
324 if (TextAutosizer* textAutosizer = document().textAutosizer())
325 textAutosizer->record(this);
327 propagateStyleToAnonymousChildren(true);
329 // It's possible for our border/padding to change, but for the overall logical width of the block to
330 // end up being the same. We keep track of this change so in layoutBlock, we can know to set relayoutChildren=true.
331 m_widthAvailableToChildrenChanged |= oldStyle && diff.needsFullLayout() && needsLayout() && borderOrPaddingLogicalWidthChanged(*oldStyle, newStyle);
333 // If the style has unloaded images, want to notify the ResourceLoadPriorityOptimizer so that
334 // network priorities can be set.
335 Vector<ImageResource*> images;
336 appendImagesFromStyle(images, newStyle);
337 if (images.isEmpty())
338 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->removeLayoutObject(this);
339 else
340 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->addLayoutObject(this);
343 void LayoutBlock::invalidatePaintOfSubtreesIfNeeded(PaintInvalidationState& childPaintInvalidationState)
345 LayoutBox::invalidatePaintOfSubtreesIfNeeded(childPaintInvalidationState);
347 // Take care of positioned objects. This is required as PaintInvalidationState keeps a single clip rect.
348 if (TrackedLayoutBoxListHashSet* positionedObjects = this->positionedObjects()) {
349 for (auto* box : *positionedObjects) {
351 // One of the layoutObjects we're skipping over here may be the child's paint invalidation container,
352 // so we can't pass our own paint invalidation container along.
353 const LayoutBoxModelObject& paintInvalidationContainerForChild = *box->containerForPaintInvalidation();
355 // If it's a new paint invalidation container, we won't have properly accumulated the offset into the
356 // PaintInvalidationState.
357 // FIXME: Teach PaintInvalidationState to handle this case. crbug.com/371485
358 if (paintInvalidationContainerForChild != childPaintInvalidationState.paintInvalidationContainer()) {
359 ForceHorriblySlowRectMapping slowRectMapping(&childPaintInvalidationState);
360 PaintInvalidationState disabledPaintInvalidationState(childPaintInvalidationState, *this, paintInvalidationContainerForChild);
361 box->invalidateTreeIfNeeded(disabledPaintInvalidationState);
362 continue;
365 // If the positioned layoutObject is absolutely positioned and it is inside
366 // a relatively positioned inline element, we need to account for
367 // the inline elements position in PaintInvalidationState.
368 if (box->style()->position() == AbsolutePosition) {
369 LayoutObject* container = box->container(&paintInvalidationContainerForChild, 0);
370 if (container->isInFlowPositioned() && container->isLayoutInline()) {
371 // FIXME: We should be able to use PaintInvalidationState for this.
372 // Currently, we will place absolutely positioned elements inside
373 // relatively positioned inline blocks in the wrong location. crbug.com/371485
374 ForceHorriblySlowRectMapping slowRectMapping(&childPaintInvalidationState);
375 PaintInvalidationState disabledPaintInvalidationState(childPaintInvalidationState, *this, paintInvalidationContainerForChild);
376 box->invalidateTreeIfNeeded(disabledPaintInvalidationState);
377 continue;
381 box->invalidateTreeIfNeeded(childPaintInvalidationState);
386 inline static void invalidateDisplayItemClientForStartOfContinuationsIfNeeded(const LayoutBlock& block)
388 // If the block is a continuation or containing block of an inline continuation, invalidate the
389 // start object of the continuations if it has focus ring because change of continuation may change
390 // the shape of the focus ring.
391 if (!block.isAnonymous())
392 return;
394 LayoutObject* startOfContinuations = nullptr;
395 if (LayoutInline* inlineElementContinuation = block.inlineElementContinuation()) {
396 // This block is an anonymous block continuation.
397 startOfContinuations = inlineElementContinuation->node()->layoutObject();
398 } else if (LayoutObject* firstChild = block.firstChild()) {
399 // This block is the anonymous containing block of an inline element continuation.
400 if (firstChild->isElementContinuation())
401 startOfContinuations = firstChild->node()->layoutObject();
403 if (startOfContinuations && startOfContinuations->styleRef().outlineStyleIsAuto())
404 startOfContinuations->invalidateDisplayItemClient(*startOfContinuations);
407 void LayoutBlock::invalidateDisplayItemClients(const LayoutBoxModelObject& paintInvalidationContainer) const
409 LayoutBox::invalidateDisplayItemClients(paintInvalidationContainer);
410 invalidateDisplayItemClientForStartOfContinuationsIfNeeded(*this);
413 void LayoutBlock::addChildIgnoringContinuation(LayoutObject* newChild, LayoutObject* beforeChild)
415 if (beforeChild && beforeChild->parent() != this) {
416 LayoutObject* beforeChildContainer = beforeChild->parent();
417 while (beforeChildContainer->parent() != this)
418 beforeChildContainer = beforeChildContainer->parent();
419 ASSERT(beforeChildContainer);
421 if (beforeChildContainer->isAnonymous()) {
422 // If the requested beforeChild is not one of our children, then this is because
423 // there is an anonymous container within this object that contains the beforeChild.
424 LayoutObject* beforeChildAnonymousContainer = beforeChildContainer;
425 if (beforeChildAnonymousContainer->isAnonymousBlock()
426 // Full screen layoutObjects and full screen placeholders act as anonymous blocks, not tables:
427 || beforeChildAnonymousContainer->isLayoutFullScreen()
428 || beforeChildAnonymousContainer->isLayoutFullScreenPlaceholder()
430 // Insert the child into the anonymous block box instead of here.
431 if (newChild->isInline() || newChild->isFloatingOrOutOfFlowPositioned() || beforeChild->parent()->slowFirstChild() != beforeChild)
432 beforeChild->parent()->addChild(newChild, beforeChild);
433 else
434 addChild(newChild, beforeChild->parent());
435 return;
438 ASSERT(beforeChildAnonymousContainer->isTable());
439 if (newChild->isTablePart()) {
440 // Insert into the anonymous table.
441 beforeChildAnonymousContainer->addChild(newChild, beforeChild);
442 return;
445 beforeChild = splitAnonymousBoxesAroundChild(beforeChild);
447 ASSERT(beforeChild->parent() == this);
448 if (beforeChild->parent() != this) {
449 // We should never reach here. If we do, we need to use the
450 // safe fallback to use the topmost beforeChild container.
451 beforeChild = beforeChildContainer;
456 bool madeBoxesNonInline = false;
458 // A block has to either have all of its children inline, or all of its children as blocks.
459 // So, if our children are currently inline and a block child has to be inserted, we move all our
460 // inline children into anonymous block boxes.
461 if (childrenInline() && !newChild->isInline() && !newChild->isFloatingOrOutOfFlowPositioned()) {
462 // This is a block with inline content. Wrap the inline content in anonymous blocks.
463 makeChildrenNonInline(beforeChild);
464 madeBoxesNonInline = true;
466 if (beforeChild && beforeChild->parent() != this) {
467 beforeChild = beforeChild->parent();
468 ASSERT(beforeChild->isAnonymousBlock());
469 ASSERT(beforeChild->parent() == this);
471 } else if (!childrenInline() && (newChild->isFloatingOrOutOfFlowPositioned() || newChild->isInline())) {
472 // If we're inserting an inline child but all of our children are blocks, then we have to make sure
473 // it is put into an anomyous block box. We try to use an existing anonymous box if possible, otherwise
474 // a new one is created and inserted into our list of children in the appropriate position.
475 LayoutObject* afterChild = beforeChild ? beforeChild->previousSibling() : lastChild();
477 if (afterChild && afterChild->isAnonymousBlock()) {
478 afterChild->addChild(newChild);
479 return;
482 if (newChild->isInline()) {
483 // No suitable existing anonymous box - create a new one.
484 LayoutBlock* newBox = createAnonymousBlock();
485 LayoutBox::addChild(newBox, beforeChild);
486 // Reparent adjacent floating or out-of-flow siblings to the new box.
487 LayoutObject* child = newBox->previousSibling();
488 while (child && child->isFloatingOrOutOfFlowPositioned()) {
489 LayoutObject* sibling = child->previousSibling();
490 moveChildTo(newBox, child, newBox->firstChild(), false);
491 child = sibling;
493 newBox->addChild(newChild);
494 child = newBox->nextSibling();
495 while (child && child->isFloatingOrOutOfFlowPositioned()) {
496 LayoutObject* sibling = child->nextSibling();
497 moveChildTo(newBox, child, nullptr, false);
498 child = sibling;
500 return;
504 LayoutBox::addChild(newChild, beforeChild);
506 if (madeBoxesNonInline && parent() && isAnonymousBlock() && parent()->isLayoutBlock())
507 toLayoutBlock(parent())->removeLeftoverAnonymousBlock(this);
508 // this object may be dead here
511 void LayoutBlock::addChild(LayoutObject* newChild, LayoutObject* beforeChild)
513 addChildIgnoringContinuation(newChild, beforeChild);
516 static void getInlineRun(LayoutObject* start, LayoutObject* boundary,
517 LayoutObject*& inlineRunStart,
518 LayoutObject*& inlineRunEnd)
520 // Beginning at |start| we find the largest contiguous run of inlines that
521 // we can. We denote the run with start and end points, |inlineRunStart|
522 // and |inlineRunEnd|. Note that these two values may be the same if
523 // we encounter only one inline.
525 // We skip any non-inlines we encounter as long as we haven't found any
526 // inlines yet.
528 // |boundary| indicates a non-inclusive boundary point. Regardless of whether |boundary|
529 // is inline or not, we will not include it in a run with inlines before it. It's as though we encountered
530 // a non-inline.
532 // Start by skipping as many non-inlines as we can.
533 LayoutObject * curr = start;
534 bool sawInline;
535 do {
536 while (curr && !(curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()))
537 curr = curr->nextSibling();
539 inlineRunStart = inlineRunEnd = curr;
541 if (!curr)
542 return; // No more inline children to be found.
544 sawInline = curr->isInline();
546 curr = curr->nextSibling();
547 while (curr && (curr->isInline() || curr->isFloatingOrOutOfFlowPositioned()) && (curr != boundary)) {
548 inlineRunEnd = curr;
549 if (curr->isInline())
550 sawInline = true;
551 curr = curr->nextSibling();
553 } while (!sawInline);
556 void LayoutBlock::deleteLineBoxTree()
558 ASSERT(!m_lineBoxes.firstLineBox());
561 void LayoutBlock::makeChildrenNonInline(LayoutObject *insertionPoint)
563 // makeChildrenNonInline takes a block whose children are *all* inline and it
564 // makes sure that inline children are coalesced under anonymous
565 // blocks. If |insertionPoint| is defined, then it represents the insertion point for
566 // the new block child that is causing us to have to wrap all the inlines. This
567 // means that we cannot coalesce inlines before |insertionPoint| with inlines following
568 // |insertionPoint|, because the new child is going to be inserted in between the inlines,
569 // splitting them.
570 ASSERT(isInlineBlockOrInlineTable() || !isInline());
571 ASSERT(!insertionPoint || insertionPoint->parent() == this);
573 setChildrenInline(false);
575 LayoutObject* child = firstChild();
576 if (!child)
577 return;
579 deleteLineBoxTree();
581 while (child) {
582 LayoutObject* inlineRunStart;
583 LayoutObject* inlineRunEnd;
584 getInlineRun(child, insertionPoint, inlineRunStart, inlineRunEnd);
586 if (!inlineRunStart)
587 break;
589 child = inlineRunEnd->nextSibling();
591 LayoutBlock* block = createAnonymousBlock();
592 children()->insertChildNode(this, block, inlineRunStart);
593 moveChildrenTo(block, inlineRunStart, child);
596 #if ENABLE(ASSERT)
597 for (LayoutObject *c = firstChild(); c; c = c->nextSibling())
598 ASSERT(!c->isInline());
599 #endif
601 setShouldDoFullPaintInvalidation();
604 void LayoutBlock::removeLeftoverAnonymousBlock(LayoutBlock* child)
606 ASSERT(child->isAnonymousBlock());
607 ASSERT(!child->childrenInline());
608 ASSERT(child->parent() == this);
610 if (child->continuation())
611 return;
613 // Promote all the leftover anonymous block's children (to become children of this block
614 // instead). We still want to keep the leftover block in the tree for a moment, for notification
615 // purposes done further below (flow threads and grids).
616 child->moveAllChildrenTo(this, child->nextSibling());
618 // Remove all the information in the flow thread associated with the leftover anonymous block.
619 child->removeFromLayoutFlowThread();
621 // LayoutGrid keeps track of its children, we must notify it about changes in the tree.
622 if (child->parent()->isLayoutGrid())
623 toLayoutGrid(child->parent())->dirtyGrid();
625 // Now remove the leftover anonymous block from the tree, and destroy it. We'll rip it out
626 // manually from the tree before destroying it, because we don't want to trigger any tree
627 // adjustments with regards to anonymous blocks (or any other kind of undesired chain-reaction).
628 children()->removeChildNode(this, child, false);
629 child->destroy();
632 static bool canMergeContiguousAnonymousBlocks(LayoutObject* oldChild, LayoutObject* prev, LayoutObject* next)
634 if (oldChild->documentBeingDestroyed() || oldChild->isInline() || oldChild->virtualContinuation())
635 return false;
637 if ((prev && (!prev->isAnonymousBlock() || toLayoutBlock(prev)->continuation() || toLayoutBlock(prev)->beingDestroyed()))
638 || (next && (!next->isAnonymousBlock() || toLayoutBlock(next)->continuation() || toLayoutBlock(next)->beingDestroyed())))
639 return false;
641 if ((prev && (prev->isRubyRun() || prev->isRubyBase()))
642 || (next && (next->isRubyRun() || next->isRubyBase())))
643 return false;
645 return true;
648 void LayoutBlock::removeAnonymousWrappersIfRequired()
650 ASSERT(isLayoutBlockFlow());
651 Vector<LayoutBox*, 16> blocksToRemove;
652 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
653 if (child->isFloatingOrOutOfFlowPositioned())
654 continue;
656 // There are still block children in the container, so any anonymous wrappers are still needed.
657 if (!child->isAnonymousBlock())
658 return;
659 // We can't remove anonymous wrappers if they contain continuations as this means there are block children present.
660 if (child->isLayoutBlock() && toLayoutBlock(child)->continuation())
661 return;
662 // We are only interested in removing anonymous wrappers if there are inline siblings underneath them.
663 if (!child->childrenInline())
664 return;
666 if (child->isAnonymousBlock())
667 blocksToRemove.append(child);
670 for (size_t i = 0; i < blocksToRemove.size(); i++)
671 collapseAnonymousBlockChild(this, toLayoutBlock(blocksToRemove[i]));
674 void LayoutBlock::collapseAnonymousBlockChild(LayoutBlock* parent, LayoutBlock* child)
676 // It's possible that this block's destruction may have been triggered by the
677 // child's removal. Just bail if the anonymous child block is already being
678 // destroyed. See crbug.com/282088
679 if (child->beingDestroyed())
680 return;
681 parent->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::ChildAnonymousBlockChanged);
682 parent->setChildrenInline(child->childrenInline());
683 LayoutObject* nextSibling = child->nextSibling();
685 parent->children()->removeChildNode(parent, child, child->hasLayer());
686 child->moveAllChildrenTo(parent, nextSibling, child->hasLayer());
687 // Explicitly delete the child's line box tree, or the special anonymous
688 // block handling in willBeDestroyed will cause problems.
689 child->deleteLineBoxTree();
690 child->destroy();
693 static inline bool shouldMakeChildrenInline(const LayoutBlock* block)
695 if (!block->isLayoutBlockFlow())
696 return false;
697 LayoutObject* child = block->firstChild();
698 while (child) {
699 // TODO(rhogan): If we encounter anonymous blocks with inline children we should fold them in here.
700 if (!child->isFloatingOrOutOfFlowPositioned())
701 return false;
702 child = child->nextSibling();
704 return true;
707 void LayoutBlock::removeChild(LayoutObject* oldChild)
709 // No need to waste time in merging or removing empty anonymous blocks.
710 // We can just bail out if our document is getting destroyed.
711 if (documentBeingDestroyed()) {
712 LayoutBox::removeChild(oldChild);
713 return;
716 // If this child is a block, and if our previous and next siblings are
717 // both anonymous blocks with inline content, then we can go ahead and
718 // fold the inline content back together.
719 LayoutObject* prev = oldChild->previousSibling();
720 LayoutObject* next = oldChild->nextSibling();
721 bool canMergeAnonymousBlocks = canMergeContiguousAnonymousBlocks(oldChild, prev, next);
722 if (canMergeAnonymousBlocks && prev && next) {
723 prev->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange);
724 LayoutBlockFlow* nextBlock = toLayoutBlockFlow(next);
725 LayoutBlockFlow* prevBlock = toLayoutBlockFlow(prev);
727 if (prev->childrenInline() != next->childrenInline()) {
728 LayoutBlock* inlineChildrenBlock = prev->childrenInline() ? prevBlock : nextBlock;
729 LayoutBlock* blockChildrenBlock = prev->childrenInline() ? nextBlock : prevBlock;
731 // Place the inline children block inside of the block children block instead of deleting it.
732 ASSERT(!inlineChildrenBlock->continuation());
733 bool inlineChildrenBlockHasLayer = inlineChildrenBlock->hasLayer();
734 children()->removeChildNode(this, inlineChildrenBlock, inlineChildrenBlockHasLayer);
736 // Now just put the inlineChildrenBlock inside the blockChildrenBlock.
737 blockChildrenBlock->children()->insertChildNode(blockChildrenBlock, inlineChildrenBlock, prev == inlineChildrenBlock ? blockChildrenBlock->firstChild() : 0,
738 inlineChildrenBlockHasLayer || blockChildrenBlock->hasLayer());
739 next->setNeedsLayoutAndPrefWidthsRecalcAndFullPaintInvalidation(LayoutInvalidationReason::AnonymousBlockChange);
741 // inlineChildrenBlock got reparented to blockChildrenBlock, so it is no longer a child
742 // of "this". we null out prev or next so that is not used later in the function.
743 if (inlineChildrenBlock == prevBlock)
744 prev = nullptr;
745 else
746 next = nullptr;
747 } else {
748 // Take all the children out of the |next| block and put them in
749 // the |prev| block.
750 nextBlock->moveAllChildrenIncludingFloatsTo(prevBlock, nextBlock->hasLayer() || prevBlock->hasLayer());
752 // Delete the now-empty block's lines and nuke it.
753 nextBlock->deleteLineBoxTree();
754 nextBlock->destroy();
755 next = nullptr;
759 LayoutBox::removeChild(oldChild);
761 LayoutObject* child = prev ? prev : next;
762 if (canMergeAnonymousBlocks && child && !child->previousSibling() && !child->nextSibling() && canCollapseAnonymousBlockChild()) {
763 // The removal has knocked us down to containing only a single anonymous
764 // box. We can go ahead and pull the content right back up into our
765 // box.
766 collapseAnonymousBlockChild(this, toLayoutBlock(child));
767 } else if (((prev && prev->isAnonymousBlock()) || (next && next->isAnonymousBlock())) && canCollapseAnonymousBlockChild()) {
768 // It's possible that the removal has knocked us down to a single anonymous
769 // block with pseudo-style element siblings (e.g. first-letter). If these
770 // are floating, then we need to pull the content up also.
771 LayoutBlock* anonymousBlock = toLayoutBlock((prev && prev->isAnonymousBlock()) ? prev : next);
772 if ((anonymousBlock->previousSibling() || anonymousBlock->nextSibling())
773 && (!anonymousBlock->previousSibling() || (anonymousBlock->previousSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->previousSibling()->isFloating() && !anonymousBlock->previousSibling()->previousSibling()))
774 && (!anonymousBlock->nextSibling() || (anonymousBlock->nextSibling()->style()->styleType() != NOPSEUDO && anonymousBlock->nextSibling()->isFloating() && !anonymousBlock->nextSibling()->nextSibling()))) {
775 collapseAnonymousBlockChild(this, anonymousBlock);
779 if (!firstChild()) {
780 // If this was our last child be sure to clear out our line boxes.
781 if (childrenInline())
782 deleteLineBoxTree();
784 // If we are an empty anonymous block in the continuation chain,
785 // we need to remove ourself and fix the continuation chain.
786 if (!beingDestroyed() && isAnonymousBlockContinuation() && !oldChild->isListMarker()) {
787 LayoutObject* containingBlockIgnoringAnonymous = containingBlock();
788 while (containingBlockIgnoringAnonymous && containingBlockIgnoringAnonymous->isAnonymous())
789 containingBlockIgnoringAnonymous = containingBlockIgnoringAnonymous->containingBlock();
790 for (LayoutObject* curr = this; curr; curr = curr->previousInPreOrder(containingBlockIgnoringAnonymous)) {
791 if (curr->virtualContinuation() != this)
792 continue;
794 // Found our previous continuation. We just need to point it to
795 // |this|'s next continuation.
796 LayoutBoxModelObject* nextContinuation = continuation();
797 if (curr->isLayoutInline())
798 toLayoutInline(curr)->setContinuation(nextContinuation);
799 else if (curr->isLayoutBlock())
800 toLayoutBlock(curr)->setContinuation(nextContinuation);
801 else
802 ASSERT_NOT_REACHED();
804 break;
806 setContinuation(nullptr);
807 destroy();
809 } else if (!beingDestroyed() && !oldChild->isFloatingOrOutOfFlowPositioned() && shouldMakeChildrenInline(this)) {
810 // If the child we're removing means that we can now treat all children as inline without the need for anonymous blocks, then do that.
811 setChildrenInline(true);
815 bool LayoutBlock::isSelfCollapsingBlock() const
817 // We are not self-collapsing if we
818 // (a) have a non-zero height according to layout (an optimization to avoid wasting time)
819 // (b) are a table,
820 // (c) have border/padding,
821 // (d) have a min-height
822 // (e) have specified that one of our margins can't collapse using a CSS extension
823 // (f) establish a new block formatting context.
825 // The early exit must be done before we check for clean layout.
826 // We should be able to give a quick answer if the box is a relayout boundary.
827 // Being a relayout boundary implies a block formatting context, and also
828 // our internal layout shouldn't affect our container in any way.
829 if (createsNewFormattingContext())
830 return false;
832 // Placeholder elements are not laid out until the dimensions of their parent text control are known, so they
833 // don't get layout until their parent has had layout - this is unique in the layout tree and means
834 // when we call isSelfCollapsingBlock on them we find that they still need layout.
835 ASSERT(!needsLayout() || (node() && node()->isElementNode() && toElement(node())->shadowPseudoId() == "-webkit-input-placeholder"));
837 if (logicalHeight() > 0
838 || isTable() || borderAndPaddingLogicalHeight()
839 || style()->logicalMinHeight().isPositive()
840 || style()->marginBeforeCollapse() == MSEPARATE || style()->marginAfterCollapse() == MSEPARATE)
841 return false;
843 Length logicalHeightLength = style()->logicalHeight();
844 bool hasAutoHeight = logicalHeightLength.isAuto();
845 if (logicalHeightLength.hasPercent() && !document().inQuirksMode()) {
846 hasAutoHeight = true;
847 for (LayoutBlock* cb = containingBlock(); !cb->isLayoutView(); cb = cb->containingBlock()) {
848 if (cb->style()->logicalHeight().isFixed() || cb->isTableCell())
849 hasAutoHeight = false;
853 // If the height is 0 or auto, then whether or not we are a self-collapsing block depends
854 // on whether we have content that is all self-collapsing or not.
855 // TODO(alancutter): Make this work correctly for calc lengths.
856 if (hasAutoHeight || ((logicalHeightLength.isFixed() || logicalHeightLength.hasPercent()) && logicalHeightLength.isZero())) {
857 // If the block has inline children, see if we generated any line boxes. If we have any
858 // line boxes, then we can't be self-collapsing, since we have content.
859 if (childrenInline())
860 return !firstLineBox();
862 // Whether or not we collapse is dependent on whether all our normal flow children
863 // are also self-collapsing.
864 if (m_hasOnlySelfCollapsingChildren)
865 return true;
866 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
867 if (child->isFloatingOrOutOfFlowPositioned())
868 continue;
869 if (!child->isSelfCollapsingBlock())
870 return false;
872 return true;
874 return false;
877 void LayoutBlock::startDelayUpdateScrollInfo()
879 if (gDelayUpdateScrollInfo == 0) {
880 ASSERT(!gDelayedUpdateScrollInfoMap);
881 gDelayedUpdateScrollInfoMap = new DelayedUpdateScrollInfoMap;
883 ASSERT(gDelayedUpdateScrollInfoMap);
884 ++gDelayUpdateScrollInfo;
887 void LayoutBlock::finishDelayUpdateScrollInfo()
889 --gDelayUpdateScrollInfo;
890 ASSERT(gDelayUpdateScrollInfo >= 0);
891 if (gDelayUpdateScrollInfo == 0) {
892 ASSERT(gDelayedUpdateScrollInfoMap);
894 OwnPtr<DelayedUpdateScrollInfoMap> infoMap(adoptPtr(gDelayedUpdateScrollInfoMap));
895 gDelayedUpdateScrollInfoMap = nullptr;
897 for (auto block : *infoMap) {
898 if (block.key->hasOverflowClip()) {
899 DeprecatedPaintLayerScrollableArea* scrollableArea = block.key->layer()->scrollableArea();
900 ScrollInfo& scrollInfo = block.value;
901 scrollableArea->finalizeScrollDimensions(scrollInfo.scrollOffset, scrollInfo.autoHorizontalScrollBarChanged, scrollInfo.autoVerticalScrollBarChanged);
907 void LayoutBlock::updateScrollInfoAfterLayout()
909 if (hasOverflowClip()) {
910 if (style()->isFlippedBlocksWritingMode()) {
911 // FIXME: https://bugs.webkit.org/show_bug.cgi?id=97937
912 // Workaround for now. We cannot delay the scroll info for overflow
913 // for items with opposite writing directions, as the contents needs
914 // to overflow in that direction
915 layer()->scrollableArea()->updateAfterLayout();
916 return;
919 if (gDelayUpdateScrollInfo) {
920 LayoutUnit logicalWidthExcludingScrollbar = logicalWidth() - scrollbarLogicalWidth();
921 LayoutUnit logicalHeightExcludingScrollbar = logicalHeight() - scrollbarLogicalHeight();
922 ScrollInfo scrollInfo;
923 layer()->scrollableArea()->updateScrollDimensions(scrollInfo.scrollOffset, scrollInfo.autoHorizontalScrollBarChanged, scrollInfo.autoVerticalScrollBarChanged);
924 DelayedUpdateScrollInfoMap::AddResult scrollInfoIterator = gDelayedUpdateScrollInfoMap->add(this, scrollInfo);
925 if (!scrollInfoIterator.isNewEntry)
926 scrollInfoIterator.storedValue->value.merge(scrollInfo);
927 if (scrollInfo.autoHorizontalScrollBarChanged)
928 setLogicalHeight(logicalHeightExcludingScrollbar + scrollbarLogicalHeight());
929 if (scrollInfo.autoVerticalScrollBarChanged)
930 setLogicalWidth(logicalWidthExcludingScrollbar + scrollbarLogicalWidth());
931 } else {
932 layer()->scrollableArea()->updateAfterLayout();
937 void LayoutBlock::layout()
939 LayoutAnalyzer::Scope analyzer(*this);
941 // Table cells call layoutBlock directly, so don't add any logic here. Put code into
942 // layoutBlock().
943 layoutBlock(false);
945 // It's safe to check for control clip here, since controls can never be table cells.
946 // If we have a lightweight clip, there can never be any overflow from children.
947 if (hasControlClip() && m_overflow)
948 clearLayoutOverflow();
950 invalidateBackgroundObscurationStatus();
953 bool LayoutBlock::updateImageLoadingPriorities()
955 Vector<ImageResource*> images;
956 appendImagesFromStyle(images, styleRef());
958 if (images.isEmpty())
959 return false;
961 LayoutRect viewBounds = viewRect();
962 LayoutRect objectBounds(absoluteContentBox());
963 // The object bounds might be empty right now, so intersects will fail since it doesn't deal
964 // with empty rects. Use LayoutRect::contains in that case.
965 bool isVisible;
966 if (!objectBounds.isEmpty())
967 isVisible = viewBounds.intersects(objectBounds);
968 else
969 isVisible = viewBounds.contains(objectBounds);
971 ResourceLoadPriorityOptimizer::VisibilityStatus status = isVisible ?
972 ResourceLoadPriorityOptimizer::Visible : ResourceLoadPriorityOptimizer::NotVisible;
974 LayoutRect screenArea;
975 if (!objectBounds.isEmpty()) {
976 screenArea = viewBounds;
977 screenArea.intersect(objectBounds);
980 for (auto* imageResource : images)
981 ResourceLoadPriorityOptimizer::resourceLoadPriorityOptimizer()->notifyImageResourceVisibility(imageResource, status, screenArea);
983 return true;
986 bool LayoutBlock::widthAvailableToChildrenHasChanged()
988 bool widthAvailableToChildrenHasChanged = m_widthAvailableToChildrenChanged;
989 m_widthAvailableToChildrenChanged = false;
991 // If we use border-box sizing, have percentage padding, and our parent has changed width then the width available to our children has changed even
992 // though our own width has remained the same.
993 widthAvailableToChildrenHasChanged |= style()->boxSizing() == BORDER_BOX && needsPreferredWidthsRecalculation() && view()->layoutState()->containingBlockLogicalWidthChanged();
995 return widthAvailableToChildrenHasChanged;
998 bool LayoutBlock::updateLogicalWidthAndColumnWidth()
1000 LayoutUnit oldWidth = logicalWidth();
1001 updateLogicalWidth();
1002 return oldWidth != logicalWidth() || widthAvailableToChildrenHasChanged();
1005 void LayoutBlock::layoutBlock(bool)
1007 ASSERT_NOT_REACHED();
1008 clearNeedsLayout();
1011 void LayoutBlock::addOverflowFromChildren()
1013 if (childrenInline())
1014 toLayoutBlockFlow(this)->addOverflowFromInlineChildren();
1015 else
1016 addOverflowFromBlockChildren();
1019 void LayoutBlock::computeOverflow(LayoutUnit oldClientAfterEdge)
1021 m_overflow.clear();
1023 // Add overflow from children.
1024 addOverflowFromChildren();
1026 // Add in the overflow from positioned objects.
1027 addOverflowFromPositionedObjects();
1029 if (hasOverflowClip()) {
1030 // When we have overflow clip, propagate the original spillout since it will include collapsed bottom margins
1031 // and bottom padding. Set the axis we don't care about to be 1, since we want this overflow to always
1032 // be considered reachable.
1033 LayoutRect clientRect(noOverflowRect());
1034 LayoutRect rectToApply;
1035 if (isHorizontalWritingMode())
1036 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), 1, std::max<LayoutUnit>(0, oldClientAfterEdge - clientRect.y()));
1037 else
1038 rectToApply = LayoutRect(clientRect.x(), clientRect.y(), std::max<LayoutUnit>(0, oldClientAfterEdge - clientRect.x()), 1);
1039 addLayoutOverflow(rectToApply);
1040 if (hasOverflowModel())
1041 m_overflow->setLayoutClientAfterEdge(oldClientAfterEdge);
1044 addVisualEffectOverflow();
1046 addVisualOverflowFromTheme();
1049 void LayoutBlock::addOverflowFromBlockChildren()
1051 for (LayoutBox* child = firstChildBox(); child; child = child->nextSiblingBox()) {
1052 if (!child->isFloatingOrOutOfFlowPositioned() && !child->isColumnSpanAll())
1053 addOverflowFromChild(child);
1057 void LayoutBlock::addOverflowFromPositionedObjects()
1059 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects();
1060 if (!positionedDescendants)
1061 return;
1063 for (auto* positionedObject : *positionedDescendants) {
1064 // Fixed positioned elements don't contribute to layout overflow, since they don't scroll with the content.
1065 if (positionedObject->style()->position() != FixedPosition)
1066 addOverflowFromChild(positionedObject, toLayoutSize(positionedObject->location()));
1070 void LayoutBlock::addVisualOverflowFromTheme()
1072 if (!style()->hasAppearance())
1073 return;
1075 IntRect inflatedRect = pixelSnappedBorderBoxRect();
1076 LayoutTheme::theme().addVisualOverflow(*this, inflatedRect);
1077 addVisualOverflow(LayoutRect(inflatedRect));
1080 bool LayoutBlock::createsNewFormattingContext() const
1082 return isInlineBlockOrInlineTable() || isFloatingOrOutOfFlowPositioned() || hasOverflowClip() || isFlexItemIncludingDeprecated()
1083 || style()->specifiesColumns() || isLayoutFlowThread() || isTableCell() || isTableCaption() || isFieldset() || isWritingModeRoot()
1084 || isDocumentElement() || isColumnSpanAll() || isGridItem();
1087 void LayoutBlock::updateBlockChildDirtyBitsBeforeLayout(bool relayoutChildren, LayoutBox& child)
1089 if (child.isOutOfFlowPositioned()) {
1090 // It's rather useless to mark out-of-flow children at this point. We may not be their
1091 // containing block (and if we are, it's just pure luck), so this would be the wrong place
1092 // for it. Furthermore, it would cause trouble for out-of-flow descendants of column
1093 // spanners, if the containing block is outside the spanner but inside the multicol container.
1094 return;
1096 // FIXME: Technically percentage height objects only need a relayout if their percentage isn't going to be turned into
1097 // an auto value. Add a method to determine this, so that we can avoid the relayout.
1098 bool hasRelativeLogicalHeight = child.hasRelativeLogicalHeight()
1099 || (child.isAnonymous() && this->hasRelativeLogicalHeight())
1100 || child.stretchesToViewport();
1101 if (relayoutChildren || (hasRelativeLogicalHeight && !isLayoutView()))
1102 child.setChildNeedsLayout(MarkOnlyThis);
1104 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1105 if (relayoutChildren && child.needsPreferredWidthsRecalculation())
1106 child.setPreferredLogicalWidthsDirty(MarkOnlyThis);
1109 void LayoutBlock::simplifiedNormalFlowLayout()
1111 if (childrenInline()) {
1112 ListHashSet<RootInlineBox*> lineBoxes;
1113 ASSERT_WITH_SECURITY_IMPLICATION(isLayoutBlockFlow());
1114 for (InlineWalker walker(toLayoutBlockFlow(this)); !walker.atEnd(); walker.advance()) {
1115 LayoutObject* o = walker.current();
1116 if (!o->isOutOfFlowPositioned() && (o->isReplaced() || o->isFloating())) {
1117 o->layoutIfNeeded();
1118 if (toLayoutBox(o)->inlineBoxWrapper()) {
1119 RootInlineBox& box = toLayoutBox(o)->inlineBoxWrapper()->root();
1120 lineBoxes.add(&box);
1122 } else if (o->isText() || (o->isLayoutInline() && !walker.atEndOfInline())) {
1123 o->clearNeedsLayout();
1127 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
1128 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
1129 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
1130 RootInlineBox* box = *it;
1131 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
1133 } else {
1134 for (LayoutBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
1135 if (!box->isOutOfFlowPositioned()) {
1136 if (box->isLayoutMultiColumnSpannerPlaceholder())
1137 toLayoutMultiColumnSpannerPlaceholder(box)->markForLayoutIfObjectInFlowThreadNeedsLayout();
1138 box->layoutIfNeeded();
1144 bool LayoutBlock::simplifiedLayout()
1146 // Check if we need to do a full layout.
1147 if (normalChildNeedsLayout() || selfNeedsLayout())
1148 return false;
1150 // Check that we actually need to do a simplified layout.
1151 if (!posChildNeedsLayout() && !(needsSimplifiedNormalFlowLayout() || needsPositionedMovementLayout()))
1152 return false;
1156 // LayoutState needs this deliberate scope to pop before paint invalidation.
1157 LayoutState state(*this, locationOffset());
1159 if (needsPositionedMovementLayout() && !tryLayoutDoingPositionedMovementOnly())
1160 return false;
1162 TextAutosizer::LayoutScope textAutosizerLayoutScope(this);
1164 // Lay out positioned descendants or objects that just need to recompute overflow.
1165 if (needsSimplifiedNormalFlowLayout())
1166 simplifiedNormalFlowLayout();
1168 // Lay out our positioned objects if our positioned child bit is set.
1169 // Also, if an absolute position element inside a relative positioned container moves, and the absolute element has a fixed position
1170 // child, neither the fixed element nor its container learn of the movement since posChildNeedsLayout() is only marked as far as the
1171 // relative positioned container. So if we can have fixed pos objects in our positioned objects list check if any of them
1172 // are statically positioned and thus need to move with their absolute ancestors.
1173 bool canContainFixedPosObjects = canContainFixedPositionObjects();
1174 if (posChildNeedsLayout() || needsPositionedMovementLayout() || canContainFixedPosObjects)
1175 layoutPositionedObjects(false, needsPositionedMovementLayout() ? ForcedLayoutAfterContainingBlockMoved : (!posChildNeedsLayout() && canContainFixedPosObjects ? LayoutOnlyFixedPositionedObjects : DefaultLayout));
1177 // Recompute our overflow information.
1178 // FIXME: We could do better here by computing a temporary overflow object from layoutPositionedObjects and only
1179 // updating our overflow if we either used to have overflow or if the new temporary object has overflow.
1180 // For now just always recompute overflow. This is no worse performance-wise than the old code that called rightmostPosition and
1181 // lowestPosition on every relayout so it's not a regression.
1182 // computeOverflow expects the bottom edge before we clamp our height. Since this information isn't available during
1183 // simplifiedLayout, we cache the value in m_overflow.
1184 LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
1185 computeOverflow(oldClientAfterEdge);
1188 updateLayerTransformAfterLayout();
1190 updateScrollInfoAfterLayout();
1192 clearNeedsLayout();
1194 if (LayoutAnalyzer* analyzer = frameView()->layoutAnalyzer())
1195 analyzer->increment(LayoutAnalyzer::LayoutObjectsThatNeedSimplifiedLayout);
1197 return true;
1200 void LayoutBlock::markFixedPositionObjectForLayoutIfNeeded(LayoutObject* child, SubtreeLayoutScope& layoutScope)
1202 if (child->style()->position() != FixedPosition)
1203 return;
1205 bool hasStaticBlockPosition = child->style()->hasStaticBlockPosition(isHorizontalWritingMode());
1206 bool hasStaticInlinePosition = child->style()->hasStaticInlinePosition(isHorizontalWritingMode());
1207 if (!hasStaticBlockPosition && !hasStaticInlinePosition)
1208 return;
1210 LayoutObject* o = child->parent();
1211 while (o && !o->isLayoutView() && o->style()->position() != AbsolutePosition)
1212 o = o->parent();
1213 if (o->style()->position() != AbsolutePosition)
1214 return;
1216 LayoutBox* box = toLayoutBox(child);
1217 if (hasStaticInlinePosition) {
1218 LogicalExtentComputedValues computedValues;
1219 box->computeLogicalWidth(computedValues);
1220 LayoutUnit newLeft = computedValues.m_position;
1221 if (newLeft != box->logicalLeft())
1222 layoutScope.setChildNeedsLayout(child);
1223 } else if (hasStaticBlockPosition) {
1224 LayoutUnit oldTop = box->logicalTop();
1225 box->updateLogicalHeight();
1226 if (box->logicalTop() != oldTop)
1227 layoutScope.setChildNeedsLayout(child);
1231 LayoutUnit LayoutBlock::marginIntrinsicLogicalWidthForChild(LayoutBox& child) const
1233 // A margin has three types: fixed, percentage, and auto (variable).
1234 // Auto and percentage margins become 0 when computing min/max width.
1235 // Fixed margins can be added in as is.
1236 Length marginLeft = child.style()->marginStartUsing(style());
1237 Length marginRight = child.style()->marginEndUsing(style());
1238 LayoutUnit margin = 0;
1239 if (marginLeft.isFixed())
1240 margin += marginLeft.value();
1241 if (marginRight.isFixed())
1242 margin += marginRight.value();
1243 return margin;
1246 static bool needsLayoutDueToStaticPosition(LayoutBox* child)
1248 // When a non-positioned block element moves, it may have positioned children that are
1249 // implicitly positioned relative to the non-positioned block.
1250 const ComputedStyle* style = child->style();
1251 bool isHorizontal = style->isHorizontalWritingMode();
1252 if (style->hasStaticBlockPosition(isHorizontal)) {
1253 LayoutBox::LogicalExtentComputedValues computedValues;
1254 LayoutUnit currentLogicalTop = child->logicalTop();
1255 LayoutUnit currentLogicalHeight = child->logicalHeight();
1256 child->computeLogicalHeight(currentLogicalHeight, currentLogicalTop, computedValues);
1257 if (computedValues.m_position != currentLogicalTop || computedValues.m_extent != currentLogicalHeight)
1258 return true;
1260 if (style->hasStaticInlinePosition(isHorizontal)) {
1261 LayoutBox::LogicalExtentComputedValues computedValues;
1262 LayoutUnit currentLogicalLeft = child->logicalLeft();
1263 LayoutUnit currentLogicalWidth = child->logicalWidth();
1264 child->computeLogicalWidth(computedValues);
1265 if (computedValues.m_position != currentLogicalLeft || computedValues.m_extent != currentLogicalWidth)
1266 return true;
1268 return false;
1271 void LayoutBlock::layoutPositionedObjects(bool relayoutChildren, PositionedLayoutBehavior info)
1273 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects();
1274 if (!positionedDescendants)
1275 return;
1277 for (auto* positionedObject : *positionedDescendants) {
1278 positionedObject->setMayNeedPaintInvalidation();
1280 SubtreeLayoutScope layoutScope(*positionedObject);
1281 // A fixed position element with an absolute positioned ancestor has no way of knowing if the latter has changed position. So
1282 // 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.
1283 // it has static position.
1284 markFixedPositionObjectForLayoutIfNeeded(positionedObject, layoutScope);
1285 if (info == LayoutOnlyFixedPositionedObjects) {
1286 positionedObject->layoutIfNeeded();
1287 continue;
1290 if (!positionedObject->normalChildNeedsLayout() && (relayoutChildren || needsLayoutDueToStaticPosition(positionedObject)))
1291 layoutScope.setChildNeedsLayout(positionedObject);
1293 // If relayoutChildren is set and the child has percentage padding or an embedded content box, we also need to invalidate the childs pref widths.
1294 if (relayoutChildren && positionedObject->needsPreferredWidthsRecalculation())
1295 positionedObject->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1297 if (!positionedObject->needsLayout())
1298 positionedObject->markForPaginationRelayoutIfNeeded(layoutScope);
1300 // FIXME: We should be able to do a r->setNeedsPositionedMovementLayout() here instead of a full layout. Need
1301 // to investigate why it does not trigger the correct invalidations in that case. crbug.com/350756
1302 if (info == ForcedLayoutAfterContainingBlockMoved)
1303 positionedObject->setNeedsLayout(LayoutInvalidationReason::AncestorMoved, MarkOnlyThis);
1305 positionedObject->layoutIfNeeded();
1309 void LayoutBlock::markPositionedObjectsForLayout()
1311 if (TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects()) {
1312 for (auto* descendant : *positionedDescendants)
1313 descendant->setChildNeedsLayout();
1317 void LayoutBlock::markForPaginationRelayoutIfNeeded(SubtreeLayoutScope& layoutScope)
1319 ASSERT(!needsLayout());
1320 if (needsLayout())
1321 return;
1323 if (view()->layoutState()->pageLogicalHeightChanged() || (view()->layoutState()->pageLogicalHeight() && view()->layoutState()->pageLogicalOffset(*this, logicalTop()) != pageLogicalOffset()))
1324 layoutScope.setChildNeedsLayout(this);
1327 void LayoutBlock::paint(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1329 BlockPainter(*this).paint(paintInfo, paintOffset);
1332 void LayoutBlock::paintChildren(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1334 BlockPainter(*this).paintChildren(paintInfo, paintOffset);
1337 void LayoutBlock::paintObject(const PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1339 BlockPainter(*this).paintObject(paintInfo, paintOffset);
1342 LayoutInline* LayoutBlock::inlineElementContinuation() const
1344 LayoutBoxModelObject* continuation = this->continuation();
1345 return continuation && continuation->isInline() ? toLayoutInline(continuation) : 0;
1348 bool LayoutBlock::isSelectionRoot() const
1350 if (isPseudoElement())
1351 return false;
1352 ASSERT(node() || isAnonymous());
1354 // FIXME: Eventually tables should have to learn how to fill gaps between cells, at least in simple non-spanning cases.
1355 if (isTable())
1356 return false;
1358 if (isBody() || isDocumentElement() || hasOverflowClip()
1359 || isPositioned() || isFloating()
1360 || isTableCell() || isInlineBlockOrInlineTable()
1361 || hasTransformRelatedProperty() || hasReflection() || hasMask() || isWritingModeRoot()
1362 || isLayoutFlowThread() || isFlexItemIncludingDeprecated())
1363 return true;
1365 if (view() && view()->selectionStart()) {
1366 Node* startElement = view()->selectionStart()->node();
1367 if (startElement && startElement->rootEditableElement() == node())
1368 return true;
1371 return false;
1374 LayoutUnit LayoutBlock::blockDirectionOffset(const LayoutSize& offsetFromBlock) const
1376 return isHorizontalWritingMode() ? offsetFromBlock.height() : offsetFromBlock.width();
1379 LayoutUnit LayoutBlock::inlineDirectionOffset(const LayoutSize& offsetFromBlock) const
1381 return isHorizontalWritingMode() ? offsetFromBlock.width() : offsetFromBlock.height();
1384 LayoutRect LayoutBlock::logicalRectToPhysicalRect(const LayoutPoint& rootBlockPhysicalPosition, const LayoutRect& logicalRect) const
1386 LayoutRect result;
1387 if (isHorizontalWritingMode())
1388 result = logicalRect;
1389 else
1390 result = LayoutRect(logicalRect.y(), logicalRect.x(), logicalRect.height(), logicalRect.width());
1391 flipForWritingMode(result);
1392 result.moveBy(rootBlockPhysicalPosition);
1393 return result;
1396 LayoutUnit LayoutBlock::logicalLeftSelectionOffset(const LayoutBlock* rootBlock, LayoutUnit position) const
1398 // The border can potentially be further extended by our containingBlock().
1399 if (rootBlock != this)
1400 return containingBlock()->logicalLeftSelectionOffset(rootBlock, position + logicalTop());
1401 return logicalLeftOffsetForContent();
1404 LayoutUnit LayoutBlock::logicalRightSelectionOffset(const LayoutBlock* rootBlock, LayoutUnit position) const
1406 // The border can potentially be further extended by our containingBlock().
1407 if (rootBlock != this)
1408 return containingBlock()->logicalRightSelectionOffset(rootBlock, position + logicalTop());
1409 return logicalRightOffsetForContent();
1412 LayoutBlock* LayoutBlock::blockBeforeWithinSelectionRoot(LayoutSize& offset) const
1414 if (isSelectionRoot())
1415 return nullptr;
1417 const LayoutObject* object = this;
1418 LayoutObject* sibling;
1419 do {
1420 sibling = object->previousSibling();
1421 while (sibling && (!sibling->isLayoutBlock() || toLayoutBlock(sibling)->isSelectionRoot()))
1422 sibling = sibling->previousSibling();
1424 offset -= LayoutSize(toLayoutBlock(object)->logicalLeft(), toLayoutBlock(object)->logicalTop());
1425 object = object->parent();
1426 } while (!sibling && object && object->isLayoutBlock() && !toLayoutBlock(object)->isSelectionRoot());
1428 if (!sibling)
1429 return nullptr;
1431 LayoutBlock* beforeBlock = toLayoutBlock(sibling);
1433 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
1435 LayoutObject* child = beforeBlock->lastChild();
1436 while (child && child->isLayoutBlock()) {
1437 beforeBlock = toLayoutBlock(child);
1438 offset += LayoutSize(beforeBlock->logicalLeft(), beforeBlock->logicalTop());
1439 child = beforeBlock->lastChild();
1441 return beforeBlock;
1444 void LayoutBlock::setSelectionState(SelectionState state)
1446 LayoutBox::setSelectionState(state);
1448 if (inlineBoxWrapper() && canUpdateSelectionOnRootLineBoxes())
1449 inlineBoxWrapper()->root().setHasSelectedChildren(state != SelectionNone);
1452 void LayoutBlock::insertIntoTrackedLayoutBoxMaps(LayoutBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
1454 if (!descendantsMap) {
1455 descendantsMap = new TrackedDescendantsMap;
1456 containerMap = new TrackedContainerMap;
1459 TrackedLayoutBoxListHashSet* descendantSet = descendantsMap->get(this);
1460 if (!descendantSet) {
1461 descendantSet = new TrackedLayoutBoxListHashSet;
1462 descendantsMap->set(this, adoptPtr(descendantSet));
1464 bool added = descendantSet->add(descendant).isNewEntry;
1465 if (!added) {
1466 ASSERT(containerMap->get(descendant));
1467 ASSERT(containerMap->get(descendant)->contains(this));
1468 return;
1471 HashSet<LayoutBlock*>* containerSet = containerMap->get(descendant);
1472 if (!containerSet) {
1473 containerSet = new HashSet<LayoutBlock*>;
1474 containerMap->set(descendant, adoptPtr(containerSet));
1476 ASSERT(!containerSet->contains(this));
1477 containerSet->add(this);
1480 void LayoutBlock::removeFromTrackedLayoutBoxMaps(LayoutBox* descendant, TrackedDescendantsMap*& descendantsMap, TrackedContainerMap*& containerMap)
1482 if (!descendantsMap)
1483 return;
1485 OwnPtr<HashSet<LayoutBlock*>> containerSet = containerMap->take(descendant);
1486 if (!containerSet)
1487 return;
1489 for (auto* container : *containerSet) {
1490 // FIXME: Disabling this assert temporarily until we fix the layout
1491 // bugs associated with positioned objects not properly cleared from
1492 // their ancestor chain before being moved. See webkit bug 93766.
1493 // ASSERT(descendant->isDescendantOf(container));
1495 TrackedDescendantsMap::iterator descendantsMapIterator = descendantsMap->find(container);
1496 ASSERT(descendantsMapIterator != descendantsMap->end());
1497 if (descendantsMapIterator == descendantsMap->end())
1498 continue;
1499 TrackedLayoutBoxListHashSet* descendantSet = descendantsMapIterator->value.get();
1500 ASSERT(descendantSet->contains(descendant));
1501 descendantSet->remove(descendant);
1502 if (descendantSet->isEmpty())
1503 descendantsMap->remove(descendantsMapIterator);
1507 TrackedLayoutBoxListHashSet* LayoutBlock::positionedObjects() const
1509 if (gPositionedDescendantsMap)
1510 return gPositionedDescendantsMap->get(this);
1511 return nullptr;
1514 void LayoutBlock::insertPositionedObject(LayoutBox* o)
1516 ASSERT(!isAnonymousBlock());
1517 insertIntoTrackedLayoutBoxMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
1520 void LayoutBlock::removePositionedObject(LayoutBox* o)
1522 removeFromTrackedLayoutBoxMaps(o, gPositionedDescendantsMap, gPositionedContainerMap);
1525 void LayoutBlock::removePositionedObjects(LayoutBlock* o, ContainingBlockState containingBlockState)
1527 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects();
1528 if (!positionedDescendants)
1529 return;
1531 Vector<LayoutBox*, 16> deadObjects;
1532 for (auto* positionedObject : *positionedDescendants) {
1533 if (!o || positionedObject->isDescendantOf(o)) {
1534 if (containingBlockState == NewContainingBlock) {
1535 positionedObject->setChildNeedsLayout(MarkOnlyThis);
1536 if (positionedObject->needsPreferredWidthsRecalculation())
1537 positionedObject->setPreferredLogicalWidthsDirty(MarkOnlyThis);
1540 // It is parent blocks job to add positioned child to positioned objects list of its containing block
1541 // Parent layout needs to be invalidated to ensure this happens.
1542 LayoutObject* p = positionedObject->parent();
1543 while (p && !p->isLayoutBlock())
1544 p = p->parent();
1545 if (p)
1546 p->setChildNeedsLayout();
1548 deadObjects.append(positionedObject);
1552 for (unsigned i = 0; i < deadObjects.size(); i++)
1553 removePositionedObject(deadObjects.at(i));
1556 void LayoutBlock::addPercentHeightDescendant(LayoutBox* descendant)
1558 insertIntoTrackedLayoutBoxMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
1561 void LayoutBlock::removePercentHeightDescendant(LayoutBox* descendant)
1563 removeFromTrackedLayoutBoxMaps(descendant, gPercentHeightDescendantsMap, gPercentHeightContainerMap);
1566 TrackedLayoutBoxListHashSet* LayoutBlock::percentHeightDescendants() const
1568 return gPercentHeightDescendantsMap ? gPercentHeightDescendantsMap->get(this) : 0;
1571 bool LayoutBlock::hasPercentHeightContainerMap()
1573 return gPercentHeightContainerMap;
1576 bool LayoutBlock::hasPercentHeightDescendant(LayoutBox* descendant)
1578 // We don't null check gPercentHeightContainerMap since the caller
1579 // already ensures this and we need to call this function on every
1580 // descendant in clearPercentHeightDescendantsFrom().
1581 ASSERT(gPercentHeightContainerMap);
1582 return gPercentHeightContainerMap->contains(descendant);
1585 void LayoutBlock::dirtyForLayoutFromPercentageHeightDescendants(SubtreeLayoutScope& layoutScope)
1587 if (!gPercentHeightDescendantsMap)
1588 return;
1590 TrackedLayoutBoxListHashSet* descendants = gPercentHeightDescendantsMap->get(this);
1591 if (!descendants)
1592 return;
1594 for (auto* box : *descendants) {
1595 while (box != this) {
1596 if (box->normalChildNeedsLayout())
1597 break;
1598 layoutScope.setChildNeedsLayout(box);
1599 box = box->containingBlock();
1600 ASSERT(box);
1601 if (!box)
1602 break;
1607 void LayoutBlock::removePercentHeightDescendantIfNeeded(LayoutBox* descendant)
1609 // We query the map directly, rather than looking at style's
1610 // logicalHeight()/logicalMinHeight()/logicalMaxHeight() since those
1611 // can change with writing mode/directional changes.
1612 if (!hasPercentHeightContainerMap())
1613 return;
1615 if (!hasPercentHeightDescendant(descendant))
1616 return;
1618 removePercentHeightDescendant(descendant);
1621 void LayoutBlock::clearPercentHeightDescendantsFrom(LayoutBox* parent)
1623 ASSERT(gPercentHeightContainerMap);
1624 for (LayoutObject* curr = parent->slowFirstChild(); curr; curr = curr->nextInPreOrder(parent)) {
1625 if (!curr->isBox())
1626 continue;
1628 LayoutBox* box = toLayoutBox(curr);
1629 if (!hasPercentHeightDescendant(box))
1630 continue;
1632 removePercentHeightDescendant(box);
1636 LayoutUnit LayoutBlock::textIndentOffset() const
1638 LayoutUnit cw = 0;
1639 if (style()->textIndent().hasPercent())
1640 cw = containingBlock()->availableLogicalWidth();
1641 return minimumValueForLength(style()->textIndent(), cw);
1644 void LayoutBlock::markLinesDirtyInBlockRange(LayoutUnit logicalTop, LayoutUnit logicalBottom, RootInlineBox* highest)
1646 if (logicalTop >= logicalBottom)
1647 return;
1649 RootInlineBox* lowestDirtyLine = lastRootBox();
1650 RootInlineBox* afterLowest = lowestDirtyLine;
1651 while (lowestDirtyLine && lowestDirtyLine->lineBottomWithLeading() >= logicalBottom && logicalBottom < LayoutUnit::max()) {
1652 afterLowest = lowestDirtyLine;
1653 lowestDirtyLine = lowestDirtyLine->prevRootBox();
1656 while (afterLowest && afterLowest != highest && (afterLowest->lineBottomWithLeading() >= logicalTop || afterLowest->lineBottomWithLeading() < 0)) {
1657 afterLowest->markDirty();
1658 afterLowest = afterLowest->prevRootBox();
1662 bool LayoutBlock::isPointInOverflowControl(HitTestResult& result, const LayoutPoint& locationInContainer, const LayoutPoint& accumulatedOffset)
1664 if (!scrollsOverflow())
1665 return false;
1667 return layer()->scrollableArea()->hitTestOverflowControls(result, roundedIntPoint(locationInContainer - toLayoutSize(accumulatedOffset)));
1670 Node* LayoutBlock::nodeForHitTest() const
1672 // If we are in the margins of block elements that are part of a
1673 // continuation we're actually still inside the enclosing element
1674 // that was split. Use the appropriate inner node.
1675 return isAnonymousBlockContinuation() ? continuation()->node() : node();
1678 bool LayoutBlock::nodeAtPoint(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
1680 LayoutPoint adjustedLocation(accumulatedOffset + location());
1681 LayoutSize localOffset = toLayoutSize(adjustedLocation);
1683 if (!isLayoutView()) {
1684 // Check if we need to do anything at all.
1685 // If we have clipping, then we can't have any spillout.
1686 LayoutRect overflowBox = hasOverflowClip() ? borderBoxRect() : visualOverflowRect();
1687 flipForWritingMode(overflowBox);
1688 overflowBox.moveBy(adjustedLocation);
1689 if (!locationInContainer.intersects(overflowBox))
1690 return false;
1693 if ((hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground)
1694 && visibleToHitTestRequest(result.hitTestRequest())
1695 && isPointInOverflowControl(result, locationInContainer.point(), adjustedLocation)) {
1696 updateHitTestResult(result, locationInContainer.point() - localOffset);
1697 // FIXME: isPointInOverflowControl() doesn't handle rect-based tests yet.
1698 if (!result.addNodeToListBasedTestResult(nodeForHitTest(), locationInContainer))
1699 return true;
1702 if (style()->clipPath()) {
1703 switch (style()->clipPath()->type()) {
1704 case ClipPathOperation::SHAPE: {
1705 ShapeClipPathOperation* clipPath = toShapeClipPathOperation(style()->clipPath());
1706 // FIXME: handle marginBox etc.
1707 if (!clipPath->path(FloatRect(borderBoxRect())).contains(FloatPoint(locationInContainer.point() - localOffset), clipPath->windRule()))
1708 return false;
1709 break;
1711 case ClipPathOperation::REFERENCE:
1712 ReferenceClipPathOperation* referenceClipPathOperation = toReferenceClipPathOperation(style()->clipPath());
1713 Element* element = document().getElementById(referenceClipPathOperation->fragment());
1714 if (isSVGClipPathElement(element) && element->layoutObject()) {
1715 LayoutSVGResourceClipper* clipper = toLayoutSVGResourceClipper(toLayoutSVGResourceContainer(element->layoutObject()));
1716 if (!clipper->hitTestClipContent(FloatRect(borderBoxRect()), FloatPoint(locationInContainer.point() - localOffset)))
1717 return false;
1719 break;
1723 // If we have clipping, then we can't have any spillout.
1724 bool useOverflowClip = hasOverflowClip() && !hasSelfPaintingLayer();
1725 bool useClip = (hasControlClip() || useOverflowClip);
1726 bool checkChildren = !useClip;
1727 if (!checkChildren) {
1728 if (hasControlClip()) {
1729 checkChildren = locationInContainer.intersects(controlClipRect(adjustedLocation));
1730 } else {
1731 LayoutRect clipRect = overflowClipRect(adjustedLocation, IncludeOverlayScrollbarSize);
1732 if (style()->hasBorderRadius())
1733 checkChildren = locationInContainer.intersects(style()->getRoundedBorderFor(clipRect));
1734 else
1735 checkChildren = locationInContainer.intersects(clipRect);
1738 if (checkChildren) {
1739 // Hit test descendants first.
1740 LayoutSize scrolledOffset(localOffset);
1741 if (hasOverflowClip())
1742 scrolledOffset -= scrolledContentOffset();
1744 // Hit test contents
1745 if (hitTestContents(result, locationInContainer, toLayoutPoint(scrolledOffset), hitTestAction)) {
1746 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
1747 return true;
1749 if (hitTestAction == HitTestFloat && hitTestFloats(result, locationInContainer, toLayoutPoint(scrolledOffset)))
1750 return true;
1753 // Check if the point is outside radii.
1754 if (style()->hasBorderRadius()) {
1755 LayoutRect borderRect = borderBoxRect();
1756 borderRect.moveBy(adjustedLocation);
1757 FloatRoundedRect border = style()->getRoundedBorderFor(borderRect);
1758 if (!locationInContainer.intersects(border))
1759 return false;
1762 // Now hit test our background
1763 if (hitTestAction == HitTestBlockBackground || hitTestAction == HitTestChildBlockBackground) {
1764 LayoutRect boundsRect(adjustedLocation, size());
1765 if (visibleToHitTestRequest(result.hitTestRequest()) && locationInContainer.intersects(boundsRect)) {
1766 updateHitTestResult(result, flipForWritingMode(locationInContainer.point() - localOffset));
1767 if (!result.addNodeToListBasedTestResult(nodeForHitTest(), locationInContainer, boundsRect))
1768 return true;
1772 return false;
1775 bool LayoutBlock::hitTestContents(HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction hitTestAction)
1777 if (childrenInline() && !isTable()) {
1778 // We have to hit-test our line boxes.
1779 if (m_lineBoxes.hitTest(LineLayoutBoxModel(this), result, locationInContainer, accumulatedOffset, hitTestAction))
1780 return true;
1781 } else {
1782 // Hit test our children.
1783 HitTestAction childHitTest = hitTestAction;
1784 if (hitTestAction == HitTestChildBlockBackgrounds)
1785 childHitTest = HitTestChildBlockBackground;
1786 for (LayoutBox* child = lastChildBox(); child; child = child->previousSiblingBox()) {
1787 LayoutPoint childPoint = flipForWritingModeForChild(child, accumulatedOffset);
1788 if (!child->hasSelfPaintingLayer() && !child->isFloating() && !child->isColumnSpanAll() && child->nodeAtPoint(result, locationInContainer, childPoint, childHitTest))
1789 return true;
1793 return false;
1796 Position LayoutBlock::positionForBox(InlineBox *box, bool start) const
1798 if (!box)
1799 return Position();
1801 if (!box->lineLayoutItem().nonPseudoNode())
1802 return Position::editingPositionOf(nonPseudoNode(), start ? caretMinOffset() : caretMaxOffset());
1804 if (!box->isInlineTextBox())
1805 return Position::editingPositionOf(box->lineLayoutItem().nonPseudoNode(), start ? box->lineLayoutItem().caretMinOffset() : box->lineLayoutItem().caretMaxOffset());
1807 InlineTextBox* textBox = toInlineTextBox(box);
1808 return Position::editingPositionOf(box->lineLayoutItem().nonPseudoNode(), start ? textBox->start() : textBox->start() + textBox->len());
1811 static inline bool isEditingBoundary(LayoutObject* ancestor, LayoutObject* child)
1813 ASSERT(!ancestor || ancestor->nonPseudoNode());
1814 ASSERT(child && child->nonPseudoNode());
1815 return !ancestor || !ancestor->parent() || (ancestor->hasLayer() && ancestor->parent()->isLayoutView())
1816 || ancestor->nonPseudoNode()->hasEditableStyle() == child->nonPseudoNode()->hasEditableStyle();
1819 // FIXME: This function should go on LayoutObject as an instance method. Then
1820 // all cases in which positionForPoint recurs could call this instead to
1821 // prevent crossing editable boundaries. This would require many tests.
1822 static PositionWithAffinity positionForPointRespectingEditingBoundaries(LayoutBlock* parent, LayoutBox* child, const LayoutPoint& pointInParentCoordinates)
1824 LayoutPoint childLocation = child->location();
1825 if (child->isInFlowPositioned())
1826 childLocation += child->offsetForInFlowPosition();
1828 // FIXME: This is wrong if the child's writing-mode is different from the parent's.
1829 LayoutPoint pointInChildCoordinates(toLayoutPoint(pointInParentCoordinates - childLocation));
1831 // If this is an anonymous layoutObject, we just recur normally
1832 Node* childNode = child->nonPseudoNode();
1833 if (!childNode)
1834 return child->positionForPoint(pointInChildCoordinates);
1836 // Otherwise, first make sure that the editability of the parent and child agree.
1837 // If they don't agree, then we return a visible position just before or after the child
1838 LayoutObject* ancestor = parent;
1839 while (ancestor && !ancestor->nonPseudoNode())
1840 ancestor = ancestor->parent();
1842 // If we can't find an ancestor to check editability on, or editability is unchanged, we recur like normal
1843 if (isEditingBoundary(ancestor, child))
1844 return child->positionForPoint(pointInChildCoordinates);
1846 // Otherwise return before or after the child, depending on if the click was to the logical left or logical right of the child
1847 LayoutUnit childMiddle = parent->logicalWidthForChild(*child) / 2;
1848 LayoutUnit logicalLeft = parent->isHorizontalWritingMode() ? pointInChildCoordinates.x() : pointInChildCoordinates.y();
1849 if (logicalLeft < childMiddle)
1850 return ancestor->createPositionWithAffinity(childNode->nodeIndex());
1851 return ancestor->createPositionWithAffinity(childNode->nodeIndex() + 1, TextAffinity::Upstream);
1854 PositionWithAffinity LayoutBlock::positionForPointWithInlineChildren(const LayoutPoint& pointInLogicalContents)
1856 ASSERT(childrenInline());
1858 if (!firstRootBox())
1859 return createPositionWithAffinity(0);
1861 bool linesAreFlipped = style()->isFlippedLinesWritingMode();
1862 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
1864 // look for the closest line box in the root box which is at the passed-in y coordinate
1865 InlineBox* closestBox = nullptr;
1866 RootInlineBox* firstRootBoxWithChildren = nullptr;
1867 RootInlineBox* lastRootBoxWithChildren = nullptr;
1868 for (RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox()) {
1869 if (!root->firstLeafChild())
1870 continue;
1871 if (!firstRootBoxWithChildren)
1872 firstRootBoxWithChildren = root;
1874 if (!linesAreFlipped && root->isFirstAfterPageBreak() && (pointInLogicalContents.y() < root->lineTopWithLeading()
1875 || (blocksAreFlipped && pointInLogicalContents.y() == root->lineTopWithLeading())))
1876 break;
1878 lastRootBoxWithChildren = root;
1880 // check if this root line box is located at this y coordinate
1881 if (pointInLogicalContents.y() < root->selectionBottom() || (blocksAreFlipped && pointInLogicalContents.y() == root->selectionBottom())) {
1882 if (linesAreFlipped) {
1883 RootInlineBox* nextRootBoxWithChildren = root->nextRootBox();
1884 while (nextRootBoxWithChildren && !nextRootBoxWithChildren->firstLeafChild())
1885 nextRootBoxWithChildren = nextRootBoxWithChildren->nextRootBox();
1887 if (nextRootBoxWithChildren && nextRootBoxWithChildren->isFirstAfterPageBreak() && (pointInLogicalContents.y() > nextRootBoxWithChildren->lineTopWithLeading()
1888 || (!blocksAreFlipped && pointInLogicalContents.y() == nextRootBoxWithChildren->lineTopWithLeading())))
1889 continue;
1891 closestBox = root->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
1892 if (closestBox)
1893 break;
1897 bool moveCaretToBoundary = document().frame()->editor().behavior().shouldMoveCaretToHorizontalBoundaryWhenPastTopOrBottom();
1899 if (!moveCaretToBoundary && !closestBox && lastRootBoxWithChildren) {
1900 // y coordinate is below last root line box, pretend we hit it
1901 closestBox = lastRootBoxWithChildren->closestLeafChildForLogicalLeftPosition(pointInLogicalContents.x());
1904 if (closestBox) {
1905 if (moveCaretToBoundary) {
1906 LayoutUnit firstRootBoxWithChildrenTop = std::min<LayoutUnit>(firstRootBoxWithChildren->selectionTop(), firstRootBoxWithChildren->logicalTop());
1907 if (pointInLogicalContents.y() < firstRootBoxWithChildrenTop
1908 || (blocksAreFlipped && pointInLogicalContents.y() == firstRootBoxWithChildrenTop)) {
1909 InlineBox* box = firstRootBoxWithChildren->firstLeafChild();
1910 if (box->isLineBreak()) {
1911 if (InlineBox* newBox = box->nextLeafChildIgnoringLineBreak())
1912 box = newBox;
1914 // y coordinate is above first root line box, so return the start of the first
1915 return PositionWithAffinity(positionForBox(box, true));
1919 // pass the box a top position that is inside it
1920 LayoutPoint point(pointInLogicalContents.x(), closestBox->root().blockDirectionPointInLine());
1921 if (!isHorizontalWritingMode())
1922 point = point.transposedPoint();
1923 if (closestBox->lineLayoutItem().isReplaced())
1924 return positionForPointRespectingEditingBoundaries(this, &toLayoutBox(closestBox->layoutObject()), point);
1925 return closestBox->lineLayoutItem().positionForPoint(point);
1928 if (lastRootBoxWithChildren) {
1929 // We hit this case for Mac behavior when the Y coordinate is below the last box.
1930 ASSERT(moveCaretToBoundary);
1931 InlineBox* logicallyLastBox;
1932 if (lastRootBoxWithChildren->getLogicalEndBoxWithNode(logicallyLastBox))
1933 return PositionWithAffinity(positionForBox(logicallyLastBox, false));
1936 // Can't reach this. We have a root line box, but it has no kids.
1937 // FIXME: This should ASSERT_NOT_REACHED(), but clicking on placeholder text
1938 // seems to hit this code path.
1939 return createPositionWithAffinity(0);
1942 static inline bool isChildHitTestCandidate(LayoutBox* box)
1944 return box->size().height() && box->style()->visibility() == VISIBLE && !box->isFloatingOrOutOfFlowPositioned() && !box->isLayoutFlowThread();
1947 PositionWithAffinity LayoutBlock::positionForPoint(const LayoutPoint& point)
1949 if (isTable())
1950 return LayoutBox::positionForPoint(point);
1952 if (isReplaced()) {
1953 // FIXME: This seems wrong when the object's writing-mode doesn't match the line's writing-mode.
1954 LayoutUnit pointLogicalLeft = isHorizontalWritingMode() ? point.x() : point.y();
1955 LayoutUnit pointLogicalTop = isHorizontalWritingMode() ? point.y() : point.x();
1957 if (pointLogicalLeft < 0)
1958 return createPositionWithAffinity(caretMinOffset());
1959 if (pointLogicalLeft >= logicalWidth())
1960 return createPositionWithAffinity(caretMaxOffset());
1961 if (pointLogicalTop < 0)
1962 return createPositionWithAffinity(caretMinOffset());
1963 if (pointLogicalTop >= logicalHeight())
1964 return createPositionWithAffinity(caretMaxOffset());
1967 LayoutPoint pointInContents = point;
1968 offsetForContents(pointInContents);
1969 LayoutPoint pointInLogicalContents(pointInContents);
1970 if (!isHorizontalWritingMode())
1971 pointInLogicalContents = pointInLogicalContents.transposedPoint();
1973 if (childrenInline())
1974 return positionForPointWithInlineChildren(pointInLogicalContents);
1976 LayoutBox* lastCandidateBox = lastChildBox();
1977 while (lastCandidateBox && !isChildHitTestCandidate(lastCandidateBox))
1978 lastCandidateBox = lastCandidateBox->previousSiblingBox();
1980 bool blocksAreFlipped = style()->isFlippedBlocksWritingMode();
1981 if (lastCandidateBox) {
1982 if (pointInLogicalContents.y() > logicalTopForChild(*lastCandidateBox)
1983 || (!blocksAreFlipped && pointInLogicalContents.y() == logicalTopForChild(*lastCandidateBox)))
1984 return positionForPointRespectingEditingBoundaries(this, lastCandidateBox, pointInContents);
1986 for (LayoutBox* childBox = firstChildBox(); childBox; childBox = childBox->nextSiblingBox()) {
1987 if (!isChildHitTestCandidate(childBox))
1988 continue;
1989 LayoutUnit childLogicalBottom = logicalTopForChild(*childBox) + logicalHeightForChild(*childBox);
1990 // We hit child if our click is above the bottom of its padding box (like IE6/7 and FF3).
1991 if (isChildHitTestCandidate(childBox) && (pointInLogicalContents.y() < childLogicalBottom
1992 || (blocksAreFlipped && pointInLogicalContents.y() == childLogicalBottom)))
1993 return positionForPointRespectingEditingBoundaries(this, childBox, pointInContents);
1997 // We only get here if there are no hit test candidate children below the click.
1998 return LayoutBox::positionForPoint(point);
2001 void LayoutBlock::offsetForContents(LayoutPoint& offset) const
2003 offset = flipForWritingMode(offset);
2005 if (hasOverflowClip())
2006 offset += LayoutSize(scrolledContentOffset());
2008 offset = flipForWritingMode(offset);
2011 int LayoutBlock::columnGap() const
2013 if (style()->hasNormalColumnGap())
2014 return style()->fontDescription().computedPixelSize(); // "1em" is recommended as the normal gap setting. Matches <p> margins.
2015 return static_cast<int>(style()->columnGap());
2018 void LayoutBlock::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
2020 if (childrenInline()) {
2021 // FIXME: Remove this const_cast.
2022 toLayoutBlockFlow(const_cast<LayoutBlock*>(this))->computeInlinePreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
2023 } else {
2024 computeBlockPreferredLogicalWidths(minLogicalWidth, maxLogicalWidth);
2027 maxLogicalWidth = std::max(minLogicalWidth, maxLogicalWidth);
2029 if (isHTMLMarqueeElement(node()) && toHTMLMarqueeElement(node())->isHorizontal())
2030 minLogicalWidth = LayoutUnit();
2032 if (isTableCell()) {
2033 Length tableCellWidth = toLayoutTableCell(this)->styleOrColLogicalWidth();
2034 if (tableCellWidth.isFixed() && tableCellWidth.value() > 0)
2035 maxLogicalWidth = std::max(minLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(tableCellWidth.value()));
2038 int scrollbarWidth = intrinsicScrollbarLogicalWidth();
2039 maxLogicalWidth += scrollbarWidth;
2040 minLogicalWidth += scrollbarWidth;
2043 void LayoutBlock::computePreferredLogicalWidths()
2045 ASSERT(preferredLogicalWidthsDirty());
2047 m_minPreferredLogicalWidth = 0;
2048 m_maxPreferredLogicalWidth = 0;
2050 // FIXME: The isFixed() calls here should probably be checking for isSpecified since you
2051 // should be able to use percentage, calc or viewport relative values for width.
2052 const ComputedStyle& styleToUse = styleRef();
2053 if (!isTableCell() && styleToUse.logicalWidth().isFixed() && styleToUse.logicalWidth().value() >= 0
2054 && !(isDeprecatedFlexItem() && !styleToUse.logicalWidth().intValue()))
2055 m_minPreferredLogicalWidth = m_maxPreferredLogicalWidth = adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalWidth().value());
2056 else
2057 computeIntrinsicLogicalWidths(m_minPreferredLogicalWidth, m_maxPreferredLogicalWidth);
2059 if (styleToUse.logicalMinWidth().isFixed() && styleToUse.logicalMinWidth().value() > 0) {
2060 m_maxPreferredLogicalWidth = std::max(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
2061 m_minPreferredLogicalWidth = std::max(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMinWidth().value()));
2064 if (styleToUse.logicalMaxWidth().isFixed()) {
2065 m_maxPreferredLogicalWidth = std::min(m_maxPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
2066 m_minPreferredLogicalWidth = std::min(m_minPreferredLogicalWidth, adjustContentBoxLogicalWidthForBoxSizing(styleToUse.logicalMaxWidth().value()));
2069 // Table layout uses integers, ceil the preferred widths to ensure that they can contain the contents.
2070 if (isTableCell()) {
2071 m_minPreferredLogicalWidth = m_minPreferredLogicalWidth.ceil();
2072 m_maxPreferredLogicalWidth = m_maxPreferredLogicalWidth.ceil();
2075 LayoutUnit borderAndPadding = borderAndPaddingLogicalWidth();
2076 m_minPreferredLogicalWidth += borderAndPadding;
2077 m_maxPreferredLogicalWidth += borderAndPadding;
2079 clearPreferredLogicalWidthsDirty();
2082 void LayoutBlock::computeBlockPreferredLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
2084 const ComputedStyle& styleToUse = styleRef();
2085 bool nowrap = styleToUse.whiteSpace() == NOWRAP;
2087 LayoutObject* child = firstChild();
2088 LayoutBlock* containingBlock = this->containingBlock();
2089 LayoutUnit floatLeftWidth = 0, floatRightWidth = 0;
2090 while (child) {
2091 // Positioned children don't affect the min/max width. Spanners only affect the min/max
2092 // width of the multicol container, not the flow thread.
2093 if (child->isOutOfFlowPositioned() || child->isColumnSpanAll()) {
2094 child = child->nextSibling();
2095 continue;
2098 RefPtr<ComputedStyle> childStyle = child->mutableStyle();
2099 if (child->isFloating() || (child->isBox() && toLayoutBox(child)->avoidsFloats())) {
2100 LayoutUnit floatTotalWidth = floatLeftWidth + floatRightWidth;
2101 if (childStyle->clear() & CLEFT) {
2102 maxLogicalWidth = std::max(floatTotalWidth, maxLogicalWidth);
2103 floatLeftWidth = 0;
2105 if (childStyle->clear() & CRIGHT) {
2106 maxLogicalWidth = std::max(floatTotalWidth, maxLogicalWidth);
2107 floatRightWidth = 0;
2111 // A margin basically has three types: fixed, percentage, and auto (variable).
2112 // Auto and percentage margins simply become 0 when computing min/max width.
2113 // Fixed margins can be added in as is.
2114 Length startMarginLength = childStyle->marginStartUsing(&styleToUse);
2115 Length endMarginLength = childStyle->marginEndUsing(&styleToUse);
2116 LayoutUnit margin = 0;
2117 LayoutUnit marginStart = 0;
2118 LayoutUnit marginEnd = 0;
2119 if (startMarginLength.isFixed())
2120 marginStart += startMarginLength.value();
2121 if (endMarginLength.isFixed())
2122 marginEnd += endMarginLength.value();
2123 margin = marginStart + marginEnd;
2125 LayoutUnit childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth;
2126 computeChildPreferredLogicalWidths(*child, childMinPreferredLogicalWidth, childMaxPreferredLogicalWidth);
2128 LayoutUnit w = childMinPreferredLogicalWidth + margin;
2129 minLogicalWidth = std::max(w, minLogicalWidth);
2131 // IE ignores tables for calculation of nowrap. Makes some sense.
2132 if (nowrap && !child->isTable())
2133 maxLogicalWidth = std::max(w, maxLogicalWidth);
2135 w = childMaxPreferredLogicalWidth + margin;
2137 if (!child->isFloating()) {
2138 if (child->isBox() && toLayoutBox(child)->avoidsFloats()) {
2139 // Determine a left and right max value based off whether or not the floats can fit in the
2140 // margins of the object. For negative margins, we will attempt to overlap the float if the negative margin
2141 // is smaller than the float width.
2142 bool ltr = containingBlock ? containingBlock->style()->isLeftToRightDirection() : styleToUse.isLeftToRightDirection();
2143 LayoutUnit marginLogicalLeft = ltr ? marginStart : marginEnd;
2144 LayoutUnit marginLogicalRight = ltr ? marginEnd : marginStart;
2145 LayoutUnit maxLeft = marginLogicalLeft > 0 ? std::max(floatLeftWidth, marginLogicalLeft) : floatLeftWidth + marginLogicalLeft;
2146 LayoutUnit maxRight = marginLogicalRight > 0 ? std::max(floatRightWidth, marginLogicalRight) : floatRightWidth + marginLogicalRight;
2147 w = childMaxPreferredLogicalWidth + maxLeft + maxRight;
2148 w = std::max(w, floatLeftWidth + floatRightWidth);
2149 } else {
2150 maxLogicalWidth = std::max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
2152 floatLeftWidth = floatRightWidth = 0;
2155 if (child->isFloating()) {
2156 if (childStyle->floating() == LeftFloat)
2157 floatLeftWidth += w;
2158 else
2159 floatRightWidth += w;
2160 } else {
2161 maxLogicalWidth = std::max(w, maxLogicalWidth);
2164 child = child->nextSibling();
2167 // Always make sure these values are non-negative.
2168 minLogicalWidth = std::max<LayoutUnit>(0, minLogicalWidth);
2169 maxLogicalWidth = std::max<LayoutUnit>(0, maxLogicalWidth);
2171 maxLogicalWidth = std::max(floatLeftWidth + floatRightWidth, maxLogicalWidth);
2174 void LayoutBlock::computeChildPreferredLogicalWidths(LayoutObject& child, LayoutUnit& minPreferredLogicalWidth, LayoutUnit& maxPreferredLogicalWidth) const
2176 if (child.isBox() && child.isHorizontalWritingMode() != isHorizontalWritingMode()) {
2177 // If the child is an orthogonal flow, child's height determines the width, but the height is not available until layout.
2178 // http://dev.w3.org/csswg/css-writing-modes-3/#orthogonal-shrink-to-fit
2179 if (!child.needsLayout()) {
2180 minPreferredLogicalWidth = maxPreferredLogicalWidth = toLayoutBox(child).logicalHeight();
2181 return;
2183 m_needsRecalcLogicalWidthAfterLayoutChildren = true;
2184 minPreferredLogicalWidth = maxPreferredLogicalWidth = toLayoutBox(child).computeLogicalHeightWithoutLayout();
2185 return;
2187 minPreferredLogicalWidth = child.minPreferredLogicalWidth();
2188 maxPreferredLogicalWidth = child.maxPreferredLogicalWidth();
2189 if (child.isLayoutBlock() && toLayoutBlock(child).needsRecalcLogicalWidthAfterLayoutChildren())
2190 m_needsRecalcLogicalWidthAfterLayoutChildren = true;
2193 bool LayoutBlock::hasLineIfEmpty() const
2195 if (!node())
2196 return false;
2198 if (node()->isRootEditableElement())
2199 return true;
2201 if (node()->isShadowRoot() && isHTMLInputElement(*toShadowRoot(node())->host()))
2202 return true;
2204 return false;
2207 LayoutUnit LayoutBlock::lineHeight(bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
2209 // Inline blocks are replaced elements. Otherwise, just pass off to
2210 // the base class. If we're being queried as though we're the root line
2211 // box, then the fact that we're an inline-block is irrelevant, and we behave
2212 // just like a block.
2213 if (isReplaced() && linePositionMode == PositionOnContainingLine)
2214 return LayoutBox::lineHeight(firstLine, direction, linePositionMode);
2216 const ComputedStyle& style = styleRef(firstLine && document().styleEngine().usesFirstLineRules());
2217 return style.computedLineHeight();
2220 int LayoutBlock::beforeMarginInLineDirection(LineDirectionMode direction) const
2222 return direction == HorizontalLine ? marginTop() : marginRight();
2225 int LayoutBlock::baselinePosition(FontBaseline baselineType, bool firstLine, LineDirectionMode direction, LinePositionMode linePositionMode) const
2227 // Inline blocks are replaced elements. Otherwise, just pass off to
2228 // the base class. If we're being queried as though we're the root line
2229 // box, then the fact that we're an inline-block is irrelevant, and we behave
2230 // just like a block.
2231 if (isInline() && linePositionMode == PositionOnContainingLine) {
2232 // For "leaf" theme objects, let the theme decide what the baseline position is.
2233 // FIXME: Might be better to have a custom CSS property instead, so that if the theme
2234 // is turned off, checkboxes/radios will still have decent baselines.
2235 // FIXME: Need to patch form controls to deal with vertical lines.
2236 if (style()->hasAppearance() && !LayoutTheme::theme().isControlContainer(style()->appearance()))
2237 return LayoutTheme::theme().baselinePosition(this);
2239 // CSS2.1 states that the baseline of an inline block is the baseline of the last line box in
2240 // the normal flow.
2241 // We give up on finding a baseline if we have a vertical scrollbar, or if we are scrolled
2242 // vertically (e.g., an overflow:hidden block that has had scrollTop moved).
2243 bool ignoreBaseline = (layer() && layer()->scrollableArea()
2244 && (direction == HorizontalLine
2245 ? (layer()->scrollableArea()->verticalScrollbar() || layer()->scrollableArea()->scrollYOffset())
2246 : (layer()->scrollableArea()->horizontalScrollbar() || layer()->scrollableArea()->scrollXOffset())))
2247 || (isWritingModeRoot() && !isRubyRun());
2249 int baselinePos = ignoreBaseline ? -1 : inlineBlockBaseline(direction);
2251 if (isDeprecatedFlexibleBox()) {
2252 // Historically, we did this check for all baselines. But we can't
2253 // remove this code from deprecated flexbox, because it effectively
2254 // breaks -webkit-line-clamp, which is used in the wild -- we would
2255 // calculate the baseline as if -webkit-line-clamp wasn't used.
2256 // For simplicity, we use this for all uses of deprecated flexbox.
2257 LayoutUnit bottomOfContent = direction == HorizontalLine ? size().height() - borderBottom() - paddingBottom() - horizontalScrollbarHeight() : size().width() - borderLeft() - paddingLeft() - verticalScrollbarWidth();
2258 if (baselinePos > bottomOfContent)
2259 baselinePos = -1;
2261 if (baselinePos != -1)
2262 return beforeMarginInLineDirection(direction) + baselinePos;
2264 return LayoutBox::baselinePosition(baselineType, firstLine, direction, linePositionMode);
2267 // If we're not replaced, we'll only get called with PositionOfInteriorLineBoxes.
2268 // Note that inline-block counts as replaced here.
2269 ASSERT(linePositionMode == PositionOfInteriorLineBoxes);
2271 const FontMetrics& fontMetrics = style(firstLine)->fontMetrics();
2272 return fontMetrics.ascent(baselineType) + (lineHeight(firstLine, direction, linePositionMode) - fontMetrics.height()) / 2;
2275 LayoutUnit LayoutBlock::minLineHeightForReplacedObject(bool isFirstLine, LayoutUnit replacedHeight) const
2277 if (!document().inNoQuirksMode() && replacedHeight)
2278 return replacedHeight;
2280 return std::max<LayoutUnit>(replacedHeight, lineHeight(isFirstLine, isHorizontalWritingMode() ? HorizontalLine : VerticalLine, PositionOfInteriorLineBoxes));
2283 int LayoutBlock::firstLineBoxBaseline() const
2285 if (isWritingModeRoot() && !isRubyRun())
2286 return -1;
2288 if (childrenInline()) {
2289 if (firstLineBox())
2290 return firstLineBox()->logicalTop() + style(true)->fontMetrics().ascent(firstRootBox()->baselineType());
2291 return -1;
2293 for (LayoutBox* curr = firstChildBox(); curr; curr = curr->nextSiblingBox()) {
2294 if (!curr->isFloatingOrOutOfFlowPositioned()) {
2295 int result = curr->firstLineBoxBaseline();
2296 if (result != -1)
2297 return curr->logicalTop() + result; // Translate to our coordinate space.
2300 return -1;
2303 int LayoutBlock::inlineBlockBaseline(LineDirectionMode direction) const
2305 if (!style()->isOverflowVisible()) {
2306 // We are not calling LayoutBox::baselinePosition here because the caller should add the margin-top/margin-right, not us.
2307 return direction == HorizontalLine ? size().height() + marginBottom() : size().width() + marginLeft();
2310 return lastLineBoxBaseline(direction);
2313 int LayoutBlock::lastLineBoxBaseline(LineDirectionMode lineDirection) const
2315 if (isWritingModeRoot() && !isRubyRun())
2316 return -1;
2318 if (childrenInline()) {
2319 if (!firstLineBox() && hasLineIfEmpty()) {
2320 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
2321 return fontMetrics.ascent()
2322 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
2323 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
2325 if (lastLineBox())
2326 return lastLineBox()->logicalTop() + style(lastLineBox() == firstLineBox())->fontMetrics().ascent(lastRootBox()->baselineType());
2327 return -1;
2330 bool haveNormalFlowChild = false;
2331 for (LayoutBox* curr = lastChildBox(); curr; curr = curr->previousSiblingBox()) {
2332 if (!curr->isFloatingOrOutOfFlowPositioned()) {
2333 haveNormalFlowChild = true;
2334 int result = curr->inlineBlockBaseline(lineDirection);
2335 if (result != -1)
2336 return curr->logicalTop() + result; // Translate to our coordinate space.
2339 if (!haveNormalFlowChild && hasLineIfEmpty()) {
2340 const FontMetrics& fontMetrics = firstLineStyle()->fontMetrics();
2341 return fontMetrics.ascent()
2342 + (lineHeight(true, lineDirection, PositionOfInteriorLineBoxes) - fontMetrics.height()) / 2
2343 + (lineDirection == HorizontalLine ? borderTop() + paddingTop() : borderRight() + paddingRight());
2345 return -1;
2348 static inline bool isLayoutBlockFlowOrLayoutButton(LayoutObject* layoutObject)
2350 // We include isLayoutButton in this check because buttons are implemented
2351 // using flex box but should still support first-line|first-letter.
2352 // The flex box and grid specs require that flex box and grid do not
2353 // support first-line|first-letter, though.
2354 // FIXME: Remove when buttons are implemented with align-items instead
2355 // of flex box.
2356 return layoutObject->isLayoutBlockFlow() || layoutObject->isLayoutButton();
2359 LayoutBlock* LayoutBlock::firstLineBlock() const
2361 LayoutBlock* firstLineBlock = const_cast<LayoutBlock*>(this);
2362 bool hasPseudo = false;
2363 while (true) {
2364 hasPseudo = firstLineBlock->style()->hasPseudoStyle(FIRST_LINE);
2365 if (hasPseudo)
2366 break;
2367 LayoutObject* parentBlock = firstLineBlock->parent();
2368 if (firstLineBlock->isReplaced() || firstLineBlock->isFloatingOrOutOfFlowPositioned()
2369 || !parentBlock
2370 || !isLayoutBlockFlowOrLayoutButton(parentBlock))
2371 break;
2372 ASSERT_WITH_SECURITY_IMPLICATION(parentBlock->isLayoutBlock());
2373 if (toLayoutBlock(parentBlock)->firstChild() != firstLineBlock)
2374 break;
2375 firstLineBlock = toLayoutBlock(parentBlock);
2378 if (!hasPseudo)
2379 return nullptr;
2381 return firstLineBlock;
2384 // Helper methods for obtaining the last line, computing line counts and heights for line counts
2385 // (crawling into blocks).
2386 static bool shouldCheckLines(LayoutObject* obj)
2388 return !obj->isFloatingOrOutOfFlowPositioned()
2389 && obj->isLayoutBlock() && obj->style()->height().isAuto()
2390 && (!obj->isDeprecatedFlexibleBox() || obj->style()->boxOrient() == VERTICAL);
2393 static int getHeightForLineCount(LayoutBlock* block, int l, bool includeBottom, int& count)
2395 if (block->style()->visibility() == VISIBLE) {
2396 if (block->isLayoutBlockFlow() && block->childrenInline()) {
2397 for (RootInlineBox* box = toLayoutBlockFlow(block)->firstRootBox(); box; box = box->nextRootBox()) {
2398 if (++count == l)
2399 return box->lineBottom() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
2401 } else {
2402 LayoutBox* normalFlowChildWithoutLines = nullptr;
2403 for (LayoutBox* obj = block->firstChildBox(); obj; obj = obj->nextSiblingBox()) {
2404 if (shouldCheckLines(obj)) {
2405 int result = getHeightForLineCount(toLayoutBlock(obj), l, false, count);
2406 if (result != -1)
2407 return result + obj->location().y() + (includeBottom ? (block->borderBottom() + block->paddingBottom()) : LayoutUnit());
2408 } else if (!obj->isFloatingOrOutOfFlowPositioned()) {
2409 normalFlowChildWithoutLines = obj;
2412 if (normalFlowChildWithoutLines && l == 0)
2413 return normalFlowChildWithoutLines->location().y() + normalFlowChildWithoutLines->size().height();
2417 return -1;
2420 RootInlineBox* LayoutBlock::lineAtIndex(int i) const
2422 ASSERT(i >= 0);
2424 if (style()->visibility() != VISIBLE)
2425 return nullptr;
2427 if (childrenInline()) {
2428 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
2429 if (!i--)
2430 return box;
2432 } else {
2433 for (LayoutObject* child = firstChild(); child; child = child->nextSibling()) {
2434 if (!shouldCheckLines(child))
2435 continue;
2436 if (RootInlineBox* box = toLayoutBlock(child)->lineAtIndex(i))
2437 return box;
2441 return nullptr;
2444 int LayoutBlock::lineCount(const RootInlineBox* stopRootInlineBox, bool* found) const
2446 int count = 0;
2448 if (style()->visibility() == VISIBLE) {
2449 if (childrenInline()) {
2450 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox()) {
2451 count++;
2452 if (box == stopRootInlineBox) {
2453 if (found)
2454 *found = true;
2455 break;
2458 } else {
2459 for (LayoutObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
2460 if (shouldCheckLines(obj)) {
2461 bool recursiveFound = false;
2462 count += toLayoutBlock(obj)->lineCount(stopRootInlineBox, &recursiveFound);
2463 if (recursiveFound) {
2464 if (found)
2465 *found = true;
2466 break;
2472 return count;
2475 int LayoutBlock::heightForLineCount(int l)
2477 int count = 0;
2478 return getHeightForLineCount(this, l, true, count);
2481 void LayoutBlock::clearTruncation()
2483 if (style()->visibility() == VISIBLE) {
2484 if (childrenInline() && hasMarkupTruncation()) {
2485 setHasMarkupTruncation(false);
2486 for (RootInlineBox* box = firstRootBox(); box; box = box->nextRootBox())
2487 box->clearTruncation();
2488 } else {
2489 for (LayoutObject* obj = firstChild(); obj; obj = obj->nextSibling()) {
2490 if (shouldCheckLines(obj))
2491 toLayoutBlock(obj)->clearTruncation();
2497 void LayoutBlock::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
2499 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
2500 // inline boxes above and below us (thus getting merged with them to form a single irregular
2501 // shape).
2502 if (isAnonymousBlockContinuation()) {
2503 // FIXME: This is wrong for vertical writing-modes.
2504 // https://bugs.webkit.org/show_bug.cgi?id=46781
2505 LayoutRect rect(accumulatedOffset, size());
2506 rect.expand(collapsedMarginBoxLogicalOutsets());
2507 rects.append(pixelSnappedIntRect(rect));
2508 continuation()->absoluteRects(rects, accumulatedOffset - toLayoutSize(location() +
2509 inlineElementContinuation()->containingBlock()->location()));
2510 } else {
2511 rects.append(pixelSnappedIntRect(accumulatedOffset, size()));
2515 void LayoutBlock::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
2517 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
2518 // inline boxes above and below us (thus getting merged with them to form a single irregular
2519 // shape).
2520 if (isAnonymousBlockContinuation()) {
2521 // FIXME: This is wrong for vertical writing-modes.
2522 // https://bugs.webkit.org/show_bug.cgi?id=46781
2523 LayoutRect localRect(LayoutPoint(), size());
2524 localRect.expand(collapsedMarginBoxLogicalOutsets());
2525 quads.append(localToAbsoluteQuad(FloatRect(localRect), 0 /* mode */, wasFixed));
2526 continuation()->absoluteQuads(quads, wasFixed);
2527 } else {
2528 quads.append(LayoutBox::localToAbsoluteQuad(FloatRect(0, 0, size().width().toFloat(), size().height().toFloat()), 0 /* mode */, wasFixed));
2532 LayoutObject* LayoutBlock::hoverAncestor() const
2534 return isAnonymousBlockContinuation() ? continuation() : LayoutBox::hoverAncestor();
2537 void LayoutBlock::updateDragState(bool dragOn)
2539 LayoutBox::updateDragState(dragOn);
2540 if (LayoutBoxModelObject* continuation = this->continuation())
2541 continuation->updateDragState(dragOn);
2544 void LayoutBlock::childBecameNonInline(LayoutObject*)
2546 makeChildrenNonInline();
2547 if (isAnonymousBlock() && parent() && parent()->isLayoutBlock())
2548 toLayoutBlock(parent())->removeLeftoverAnonymousBlock(this);
2549 // |this| may be dead here
2552 void LayoutBlock::updateHitTestResult(HitTestResult& result, const LayoutPoint& point)
2554 if (result.innerNode())
2555 return;
2557 if (Node* n = nodeForHitTest())
2558 result.setNodeAndPosition(n, point);
2561 // An inline-block uses its inlineBox as the inlineBoxWrapper,
2562 // so the firstChild() is nullptr if the only child is an empty inline-block.
2563 inline bool LayoutBlock::isInlineBoxWrapperActuallyChild() const
2565 return isInlineBlockOrInlineTable() && !size().isEmpty() && node() && editingIgnoresContent(node());
2568 LayoutRect LayoutBlock::localCaretRect(InlineBox* inlineBox, int caretOffset, LayoutUnit* extraWidthToEndOfLine)
2570 // Do the normal calculation in most cases.
2571 if (firstChild() || isInlineBoxWrapperActuallyChild())
2572 return LayoutBox::localCaretRect(inlineBox, caretOffset, extraWidthToEndOfLine);
2574 LayoutRect caretRect = localCaretRectForEmptyElement(size().width(), textIndentOffset());
2576 if (extraWidthToEndOfLine)
2577 *extraWidthToEndOfLine = size().width() - caretRect.maxX();
2579 return caretRect;
2582 void LayoutBlock::addOutlineRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, IncludeBlockVisualOverflowOrNot includeBlockOverflows) const
2584 // For blocks inside inlines, we go ahead and include margins so that we run right up to the
2585 // inline boxes above and below us (thus getting merged with them to form a single irregular
2586 // shape).
2587 const LayoutInline* inlineElementContinuation = this->inlineElementContinuation();
2588 if (inlineElementContinuation) {
2589 // FIXME: This check really isn't accurate.
2590 bool nextInlineHasLineBox = inlineElementContinuation->firstLineBox();
2591 // FIXME: This is wrong. The principal layoutObject may not be the continuation preceding this block.
2592 // FIXME: This is wrong for vertical writing-modes.
2593 // https://bugs.webkit.org/show_bug.cgi?id=46781
2594 bool prevInlineHasLineBox = toLayoutInline(inlineElementContinuation->node()->layoutObject())->firstLineBox();
2595 LayoutUnit topMargin = prevInlineHasLineBox ? collapsedMarginBefore() : LayoutUnit();
2596 LayoutUnit bottomMargin = nextInlineHasLineBox ? collapsedMarginAfter() : LayoutUnit();
2597 if (topMargin || bottomMargin) {
2598 LayoutRect rect(additionalOffset, size());
2599 rect.expandEdges(topMargin, 0, bottomMargin, 0);
2600 rects.append(rect);
2602 } else if (!isAnonymous()) { // For anonymous blocks, the children add outline rects.
2603 rects.append(LayoutRect(additionalOffset, size()));
2606 if (includeBlockOverflows == IncludeBlockVisualOverflow && !hasOverflowClip() && !hasControlClip()) {
2607 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2608 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
2609 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
2610 LayoutRect rect(additionalOffset.x() + curr->x(), additionalOffset.y() + top, curr->width(), bottom - top);
2611 if (!rect.isEmpty())
2612 rects.append(rect);
2615 addOutlineRectsForNormalChildren(rects, additionalOffset, includeBlockOverflows);
2616 if (TrackedLayoutBoxListHashSet* positionedObjects = this->positionedObjects()) {
2617 for (auto* box : *positionedObjects)
2618 addOutlineRectsForDescendant(*box, rects, additionalOffset, includeBlockOverflows);
2622 if (inlineElementContinuation)
2623 inlineElementContinuation->addOutlineRects(rects, additionalOffset + (inlineElementContinuation->containingBlock()->location() - location()), includeBlockOverflows);
2626 void LayoutBlock::computeSelfHitTestRects(Vector<LayoutRect>& rects, const LayoutPoint& layerOffset) const
2628 LayoutBox::computeSelfHitTestRects(rects, layerOffset);
2630 if (hasHorizontalLayoutOverflow() || hasVerticalLayoutOverflow()) {
2631 for (RootInlineBox* curr = firstRootBox(); curr; curr = curr->nextRootBox()) {
2632 LayoutUnit top = std::max<LayoutUnit>(curr->lineTop(), curr->top());
2633 LayoutUnit bottom = std::min<LayoutUnit>(curr->lineBottom(), curr->top() + curr->height());
2634 LayoutRect rect(layerOffset.x() + curr->x(), layerOffset.y() + top, curr->width(), bottom - top);
2635 // It's common for this rect to be entirely contained in our box, so exclude that simple case.
2636 if (!rect.isEmpty() && (rects.isEmpty() || !rects[0].contains(rect)))
2637 rects.append(rect);
2642 LayoutBox* LayoutBlock::createAnonymousBoxWithSameTypeAs(const LayoutObject* parent) const
2644 return createAnonymousWithParentAndDisplay(parent, style()->display());
2647 LayoutUnit LayoutBlock::nextPageLogicalTop(LayoutUnit logicalOffset, PageBoundaryRule pageBoundaryRule) const
2649 LayoutUnit pageLogicalHeight = pageLogicalHeightForOffset(logicalOffset);
2650 if (!pageLogicalHeight)
2651 return logicalOffset;
2653 return logicalOffset + pageRemainingLogicalHeightForOffset(logicalOffset, pageBoundaryRule);
2656 LayoutUnit LayoutBlock::pageLogicalHeightForOffset(LayoutUnit offset) const
2658 LayoutView* layoutView = view();
2659 LayoutFlowThread* flowThread = flowThreadContainingBlock();
2660 if (!flowThread)
2661 return layoutView->layoutState()->pageLogicalHeight();
2662 return flowThread->pageLogicalHeightForOffset(offset + offsetFromLogicalTopOfFirstPage());
2665 LayoutUnit LayoutBlock::pageRemainingLogicalHeightForOffset(LayoutUnit offset, PageBoundaryRule pageBoundaryRule) const
2667 LayoutView* layoutView = view();
2668 offset += offsetFromLogicalTopOfFirstPage();
2670 LayoutFlowThread* flowThread = flowThreadContainingBlock();
2671 if (!flowThread) {
2672 LayoutUnit pageLogicalHeight = layoutView->layoutState()->pageLogicalHeight();
2673 LayoutUnit remainingHeight = pageLogicalHeight - intMod(offset, pageLogicalHeight);
2674 if (pageBoundaryRule == AssociateWithFormerPage) {
2675 // An offset exactly at a page boundary will act as being part of the former page in
2676 // question (i.e. no remaining space), rather than being part of the latter (i.e. one
2677 // whole page length of remaining space).
2678 remainingHeight = intMod(remainingHeight, pageLogicalHeight);
2680 return remainingHeight;
2683 return flowThread->pageRemainingLogicalHeightForOffset(offset, pageBoundaryRule);
2686 void LayoutBlock::setPageBreak(LayoutUnit offset, LayoutUnit spaceShortage)
2688 if (LayoutFlowThread* flowThread = flowThreadContainingBlock())
2689 flowThread->setPageBreak(offsetFromLogicalTopOfFirstPage() + offset, spaceShortage);
2692 void LayoutBlock::updateMinimumPageHeight(LayoutUnit offset, LayoutUnit minHeight)
2694 if (LayoutFlowThread* flowThread = flowThreadContainingBlock())
2695 flowThread->updateMinimumPageHeight(offsetFromLogicalTopOfFirstPage() + offset, minHeight);
2698 LayoutUnit LayoutBlock::collapsedMarginBeforeForChild(const LayoutBox& child) const
2700 // If the child has the same directionality as we do, then we can just return its
2701 // collapsed margin.
2702 if (!child.isWritingModeRoot())
2703 return child.collapsedMarginBefore();
2705 // The child has a different directionality. If the child is parallel, then it's just
2706 // flipped relative to us. We can use the collapsed margin for the opposite edge.
2707 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
2708 return child.collapsedMarginAfter();
2710 // The child is perpendicular to us, which means its margins don't collapse but are on the
2711 // "logical left/right" sides of the child box. We can just return the raw margin in this case.
2712 return marginBeforeForChild(child);
2715 LayoutUnit LayoutBlock::collapsedMarginAfterForChild(const LayoutBox& child) const
2717 // If the child has the same directionality as we do, then we can just return its
2718 // collapsed margin.
2719 if (!child.isWritingModeRoot())
2720 return child.collapsedMarginAfter();
2722 // The child has a different directionality. If the child is parallel, then it's just
2723 // flipped relative to us. We can use the collapsed margin for the opposite edge.
2724 if (child.isHorizontalWritingMode() == isHorizontalWritingMode())
2725 return child.collapsedMarginBefore();
2727 // The child is perpendicular to us, which means its margins don't collapse but are on the
2728 // "logical left/right" side of the child box. We can just return the raw margin in this case.
2729 return marginAfterForChild(child);
2732 bool LayoutBlock::hasMarginBeforeQuirk(const LayoutBox* child) const
2734 // If the child has the same directionality as we do, then we can just return its
2735 // margin quirk.
2736 if (!child->isWritingModeRoot())
2737 return child->isLayoutBlock() ? toLayoutBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
2739 // The child has a different directionality. If the child is parallel, then it's just
2740 // flipped relative to us. We can use the opposite edge.
2741 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
2742 return child->isLayoutBlock() ? toLayoutBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
2744 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
2745 // whether or not authors specified quirky ems, since they're an implementation detail.
2746 return false;
2749 bool LayoutBlock::hasMarginAfterQuirk(const LayoutBox* child) const
2751 // If the child has the same directionality as we do, then we can just return its
2752 // margin quirk.
2753 if (!child->isWritingModeRoot())
2754 return child->isLayoutBlock() ? toLayoutBlock(child)->hasMarginAfterQuirk() : child->style()->hasMarginAfterQuirk();
2756 // The child has a different directionality. If the child is parallel, then it's just
2757 // flipped relative to us. We can use the opposite edge.
2758 if (child->isHorizontalWritingMode() == isHorizontalWritingMode())
2759 return child->isLayoutBlock() ? toLayoutBlock(child)->hasMarginBeforeQuirk() : child->style()->hasMarginBeforeQuirk();
2761 // The child is perpendicular to us and box sides are never quirky in html.css, and we don't really care about
2762 // whether or not authors specified quirky ems, since they're an implementation detail.
2763 return false;
2766 const char* LayoutBlock::name() const
2768 ASSERT_NOT_REACHED();
2769 return "LayoutBlock";
2772 LayoutBlock* LayoutBlock::createAnonymousWithParentAndDisplay(const LayoutObject* parent, EDisplay display)
2774 // FIXME: Do we need to convert all our inline displays to block-type in the anonymous logic ?
2775 EDisplay newDisplay;
2776 LayoutBlock* newBox = nullptr;
2777 if (display == FLEX || display == INLINE_FLEX) {
2778 newBox = LayoutFlexibleBox::createAnonymous(&parent->document());
2779 newDisplay = FLEX;
2780 } else {
2781 newBox = LayoutBlockFlow::createAnonymous(&parent->document());
2782 newDisplay = BLOCK;
2785 RefPtr<ComputedStyle> newStyle = ComputedStyle::createAnonymousStyleWithDisplay(parent->styleRef(), newDisplay);
2786 parent->updateAnonymousChildStyle(*newBox, *newStyle);
2787 newBox->setStyle(newStyle.release());
2788 return newBox;
2791 static bool recalcNormalFlowChildOverflowIfNeeded(LayoutObject* layoutObject)
2793 if (layoutObject->isOutOfFlowPositioned() || !layoutObject->needsOverflowRecalcAfterStyleChange())
2794 return false;
2796 ASSERT(layoutObject->isLayoutBlock());
2797 return toLayoutBlock(layoutObject)->recalcOverflowAfterStyleChange();
2800 bool LayoutBlock::recalcChildOverflowAfterStyleChange()
2802 ASSERT(childNeedsOverflowRecalcAfterStyleChange());
2803 clearChildNeedsOverflowRecalcAfterStyleChange();
2805 bool childrenOverflowChanged = false;
2807 if (childrenInline()) {
2808 ListHashSet<RootInlineBox*> lineBoxes;
2809 ASSERT_WITH_SECURITY_IMPLICATION(isLayoutBlockFlow());
2810 for (InlineWalker walker(toLayoutBlockFlow(this)); !walker.atEnd(); walker.advance()) {
2811 LayoutObject* layoutObject = walker.current();
2812 if (recalcNormalFlowChildOverflowIfNeeded(layoutObject)) {
2813 childrenOverflowChanged = true;
2814 if (InlineBox* inlineBoxWrapper = toLayoutBlock(layoutObject)->inlineBoxWrapper())
2815 lineBoxes.add(&inlineBoxWrapper->root());
2819 // FIXME: Glyph overflow will get lost in this case, but not really a big deal.
2820 GlyphOverflowAndFallbackFontsMap textBoxDataMap;
2821 for (ListHashSet<RootInlineBox*>::const_iterator it = lineBoxes.begin(); it != lineBoxes.end(); ++it) {
2822 RootInlineBox* box = *it;
2823 box->computeOverflow(box->lineTop(), box->lineBottom(), textBoxDataMap);
2825 } else {
2826 for (LayoutBox* box = firstChildBox(); box; box = box->nextSiblingBox()) {
2827 if (recalcNormalFlowChildOverflowIfNeeded(box))
2828 childrenOverflowChanged = true;
2832 TrackedLayoutBoxListHashSet* positionedDescendants = positionedObjects();
2833 if (!positionedDescendants)
2834 return childrenOverflowChanged;
2836 for (auto* box : *positionedDescendants) {
2837 if (!box->needsOverflowRecalcAfterStyleChange())
2838 continue;
2839 LayoutBlock* block = toLayoutBlock(box);
2840 if (!block->recalcOverflowAfterStyleChange() || box->style()->position() == FixedPosition)
2841 continue;
2843 childrenOverflowChanged = true;
2845 return childrenOverflowChanged;
2848 bool LayoutBlock::recalcOverflowAfterStyleChange()
2850 ASSERT(needsOverflowRecalcAfterStyleChange());
2852 bool childrenOverflowChanged = false;
2853 if (childNeedsOverflowRecalcAfterStyleChange())
2854 childrenOverflowChanged = recalcChildOverflowAfterStyleChange();
2856 if (!selfNeedsOverflowRecalcAfterStyleChange() && !childrenOverflowChanged)
2857 return false;
2859 clearSelfNeedsOverflowRecalcAfterStyleChange();
2860 // If the current block needs layout, overflow will be recalculated during
2861 // layout time anyway. We can safely exit here.
2862 if (needsLayout())
2863 return false;
2865 LayoutUnit oldClientAfterEdge = hasOverflowModel() ? m_overflow->layoutClientAfterEdge() : clientLogicalBottom();
2866 computeOverflow(oldClientAfterEdge);
2868 if (hasOverflowClip())
2869 layer()->scrollableArea()->updateAfterOverflowRecalc();
2871 return !hasOverflowClip();
2874 // Called when a positioned object moves but doesn't necessarily change size. A simplified layout is attempted
2875 // that just updates the object's position. If the size does change, the object remains dirty.
2876 bool LayoutBlock::tryLayoutDoingPositionedMovementOnly()
2878 LayoutUnit oldWidth = logicalWidth();
2879 LogicalExtentComputedValues computedValues;
2880 logicalExtentAfterUpdatingLogicalWidth(logicalTop(), computedValues);
2881 // If we shrink to fit our width may have changed, so we still need full layout.
2882 if (oldWidth != computedValues.m_extent)
2883 return false;
2884 setLogicalWidth(computedValues.m_extent);
2885 setLogicalLeft(computedValues.m_position);
2886 setMarginStart(computedValues.m_margins.m_start);
2887 setMarginEnd(computedValues.m_margins.m_end);
2889 LayoutUnit oldHeight = logicalHeight();
2890 LayoutUnit oldIntrinsicContentLogicalHeight = intrinsicContentLogicalHeight();
2892 setIntrinsicContentLogicalHeight(contentLogicalHeight());
2893 computeLogicalHeight(oldHeight, logicalTop(), computedValues);
2895 if (hasPercentHeightDescendants() && oldHeight != computedValues.m_extent) {
2896 setIntrinsicContentLogicalHeight(oldIntrinsicContentLogicalHeight);
2897 return false;
2900 setLogicalHeight(computedValues.m_extent);
2901 setLogicalTop(computedValues.m_position);
2902 setMarginBefore(computedValues.m_margins.m_before);
2903 setMarginAfter(computedValues.m_margins.m_after);
2905 return true;
2908 #if ENABLE(ASSERT)
2909 void LayoutBlock::checkPositionedObjectsNeedLayout()
2911 if (!gPositionedDescendantsMap)
2912 return;
2914 if (TrackedLayoutBoxListHashSet* positionedDescendantSet = positionedObjects()) {
2915 TrackedLayoutBoxListHashSet::const_iterator end = positionedDescendantSet->end();
2916 for (TrackedLayoutBoxListHashSet::const_iterator it = positionedDescendantSet->begin(); it != end; ++it) {
2917 LayoutBox* currBox = *it;
2918 ASSERT(!currBox->needsLayout());
2923 #endif
2925 #ifndef NDEBUG
2927 void LayoutBlock::showLineTreeAndMark(const InlineBox* markedBox1, const char* markedLabel1, const InlineBox* markedBox2, const char* markedLabel2, const LayoutObject* obj) const
2929 showLayoutObject();
2930 for (const RootInlineBox* root = firstRootBox(); root; root = root->nextRootBox())
2931 root->showLineTreeAndMark(markedBox1, markedLabel1, markedBox2, markedLabel2, obj, 1);
2934 #endif
2936 } // namespace blink