Remove some obsolete WebKitVersionChecks.
[WebKit-https.git] / Source / WebCore / rendering / RenderBox.cpp
1 /*
2  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
4  *           (C) 2005 Allan Sandfeld Jensen (kde@carewolf.com)
5  *           (C) 2005, 2006 Samuel Weinig (sam.weinig@gmail.com)
6  * Copyright (C) 2005-2010, 2015 Apple Inc. All rights reserved.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Library General Public
10  * License as published by the Free Software Foundation; either
11  * version 2 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Library General Public License for more details.
17  *
18  * You should have received a copy of the GNU Library General Public License
19  * along with this library; see the file COPYING.LIB.  If not, write to
20  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21  * Boston, MA 02110-1301, USA.
22  *
23  */
24
25 #include "config.h"
26 #include "RenderBox.h"
27
28 #include "CSSFontSelector.h"
29 #include "ControlStates.h"
30 #include "Document.h"
31 #include "Editing.h"
32 #include "EventHandler.h"
33 #include "FloatQuad.h"
34 #include "FloatRoundedRect.h"
35 #include "Frame.h"
36 #include "FrameView.h"
37 #include "GraphicsContext.h"
38 #include "HTMLBodyElement.h"
39 #include "HTMLButtonElement.h"
40 #include "HTMLFrameOwnerElement.h"
41 #include "HTMLHtmlElement.h"
42 #include "HTMLImageElement.h"
43 #include "HTMLInputElement.h"
44 #include "HTMLLegendElement.h"
45 #include "HTMLNames.h"
46 #include "HTMLSelectElement.h"
47 #include "HTMLTextAreaElement.h"
48 #include "HitTestResult.h"
49 #include "InlineElementBox.h"
50 #include "MainFrame.h"
51 #include "Page.h"
52 #include "PaintInfo.h"
53 #include "RenderBoxRegionInfo.h"
54 #include "RenderChildIterator.h"
55 #include "RenderDeprecatedFlexibleBox.h"
56 #include "RenderFlexibleBox.h"
57 #include "RenderGeometryMap.h"
58 #include "RenderInline.h"
59 #include "RenderIterator.h"
60 #include "RenderLayer.h"
61 #include "RenderLayerCompositor.h"
62 #include "RenderMultiColumnFlowThread.h"
63 #include "RenderNamedFlowFragment.h"
64 #include "RenderNamedFlowThread.h"
65 #include "RenderTableCell.h"
66 #include "RenderTheme.h"
67 #include "RenderView.h"
68 #include "RuntimeApplicationChecks.h"
69 #include "ScrollAnimator.h"
70 #include "ScrollbarTheme.h"
71 #include "StyleScrollSnapPoints.h"
72 #include "TransformState.h"
73 #include <algorithm>
74 #include <math.h>
75 #include <wtf/StackStats.h>
76
77 #include "RenderGrid.h"
78
79 #if PLATFORM(IOS)
80 #include "Settings.h"
81 #endif
82
83 namespace WebCore {
84
85 struct SameSizeAsRenderBox : public RenderBoxModelObject {
86     virtual ~SameSizeAsRenderBox() { }
87     LayoutRect frameRect;
88     LayoutBoxExtent marginBox;
89     LayoutUnit preferredLogicalWidths[2];
90     void* pointers[2];
91 };
92
93 COMPILE_ASSERT(sizeof(RenderBox) == sizeof(SameSizeAsRenderBox), RenderBox_should_stay_small);
94
95 using namespace HTMLNames;
96
97 // Used by flexible boxes when flexing this element and by table cells.
98 typedef WTF::HashMap<const RenderBox*, LayoutUnit> OverrideSizeMap;
99 static OverrideSizeMap* gOverrideHeightMap = nullptr;
100 static OverrideSizeMap* gOverrideWidthMap = nullptr;
101
102 // Used by grid elements to properly size their grid items.
103 typedef WTF::HashMap<const RenderBox*, std::optional<LayoutUnit>> OverrideOptionalSizeMap;
104 static OverrideOptionalSizeMap* gOverrideContainingBlockLogicalHeightMap = nullptr;
105 static OverrideOptionalSizeMap* gOverrideContainingBlockLogicalWidthMap = nullptr;
106
107 // Size of border belt for autoscroll. When mouse pointer in border belt,
108 // autoscroll is started.
109 static const int autoscrollBeltSize = 20;
110 static const unsigned backgroundObscurationTestMaxDepth = 4;
111
112 using ControlStatesRendererMap = HashMap<const RenderObject*, std::unique_ptr<ControlStates>>;
113 static ControlStatesRendererMap& controlStatesRendererMap()
114 {
115     static NeverDestroyed<ControlStatesRendererMap> map;
116     return map;
117 }
118
119 static ControlStates* controlStatesForRenderer(const RenderBox& renderer)
120 {
121     return controlStatesRendererMap().ensure(&renderer, [] {
122         return std::make_unique<ControlStates>();
123     }).iterator->value.get();
124 }
125
126 static void removeControlStatesForRenderer(const RenderBox& renderer)
127 {
128     controlStatesRendererMap().remove(&renderer);
129 }
130
131 bool RenderBox::s_hadOverflowClip = false;
132
133 RenderBox::RenderBox(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
134     : RenderBoxModelObject(element, WTFMove(style), baseTypeFlags)
135 {
136     setIsBox();
137 }
138
139 RenderBox::RenderBox(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
140     : RenderBoxModelObject(document, WTFMove(style), baseTypeFlags)
141 {
142     setIsBox();
143 }
144
145 RenderBox::~RenderBox()
146 {
147     // Do not add any code here. Add it to willBeDestroyed() instead.
148 }
149
150 void RenderBox::willBeDestroyed()
151 {
152     if (frame().eventHandler().autoscrollRenderer() == this)
153         frame().eventHandler().stopAutoscrollTimer(true);
154
155     clearOverrideSize();
156     clearContainingBlockOverrideSize();
157
158     RenderBlock::removePercentHeightDescendantIfNeeded(*this);
159
160     ShapeOutsideInfo::removeInfo(*this);
161
162     view().unscheduleLazyRepaint(*this);
163     removeControlStatesForRenderer(*this);
164     
165     RenderBoxModelObject::willBeDestroyed();
166 }
167
168 RenderRegion* RenderBox::clampToStartAndEndRegions(RenderRegion* region) const
169 {
170     RenderFlowThread* flowThread = flowThreadContainingBlock();
171
172     ASSERT(isRenderView() || (region && flowThread));
173     if (isRenderView())
174         return region;
175
176     // We need to clamp to the block, since we want any lines or blocks that overflow out of the
177     // logical top or logical bottom of the block to size as though the border box in the first and
178     // last regions extended infinitely. Otherwise the lines are going to size according to the regions
179     // they overflow into, which makes no sense when this block doesn't exist in |region| at all.
180     RenderRegion* startRegion = nullptr;
181     RenderRegion* endRegion = nullptr;
182     if (!flowThread->getRegionRangeForBox(this, startRegion, endRegion))
183         return region;
184
185     if (region->logicalTopForFlowThreadContent() < startRegion->logicalTopForFlowThreadContent())
186         return startRegion;
187     if (region->logicalTopForFlowThreadContent() > endRegion->logicalTopForFlowThreadContent())
188         return endRegion;
189
190     return region;
191 }
192
193 bool RenderBox::hasRegionRangeInFlowThread() const
194 {
195     RenderFlowThread* flowThread = flowThreadContainingBlock();
196     if (!flowThread || !flowThread->hasValidRegionInfo())
197         return false;
198
199     return flowThread->hasCachedRegionRangeForBox(*this);
200 }
201
202 LayoutRect RenderBox::clientBoxRectInRegion(RenderRegion* region) const
203 {
204     if (!region)
205         return clientBoxRect();
206
207     LayoutRect clientBox = borderBoxRectInRegion(region);
208     clientBox.setLocation(clientBox.location() + LayoutSize(borderLeft(), borderTop()));
209     clientBox.setSize(clientBox.size() - LayoutSize(borderLeft() + borderRight() + verticalScrollbarWidth(), borderTop() + borderBottom() + horizontalScrollbarHeight()));
210
211     return clientBox;
212 }
213
214 LayoutRect RenderBox::borderBoxRectInRegion(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
215 {
216     if (!region)
217         return borderBoxRect();
218
219     auto* flowThread = flowThreadContainingBlock();
220     if (!is<RenderNamedFlowThread>(flowThread))
221         return borderBoxRect();
222
223     RenderRegion* startRegion = nullptr;
224     RenderRegion* endRegion = nullptr;
225     if (!flowThread->getRegionRangeForBox(this, startRegion, endRegion)) {
226         // FIXME: In a perfect world this condition should never happen.
227         return borderBoxRect();
228     }
229
230     ASSERT(flowThread->regionInRange(region, startRegion, endRegion));
231
232     // Compute the logical width and placement in this region.
233     RenderBoxRegionInfo* boxInfo = renderBoxRegionInfo(region, cacheFlag);
234     if (!boxInfo)
235         return borderBoxRect();
236
237     // We have cached insets.
238     LayoutUnit logicalWidth = boxInfo->logicalWidth();
239     LayoutUnit logicalLeft = boxInfo->logicalLeft();
240
241     // Now apply the parent inset since it is cumulative whenever anything in the containing block chain shifts.
242     // FIXME: Doesn't work right with perpendicular writing modes.
243     const RenderBlock* currentBox = containingBlock();
244     RenderBoxRegionInfo* currentBoxInfo = isRenderFlowThread() ? nullptr : currentBox->renderBoxRegionInfo(region);
245     while (currentBoxInfo && currentBoxInfo->isShifted()) {
246         if (currentBox->style().direction() == LTR)
247             logicalLeft += currentBoxInfo->logicalLeft();
248         else
249             logicalLeft -= (currentBox->logicalWidth() - currentBoxInfo->logicalWidth()) - currentBoxInfo->logicalLeft();
250
251         // Once we reach the fragmentation container we should stop.
252         if (currentBox->isRenderFlowThread())
253             break;
254
255         currentBox = currentBox->containingBlock();
256         if (!currentBox)
257             break;
258         region = currentBox->clampToStartAndEndRegions(region);
259         currentBoxInfo = currentBox->renderBoxRegionInfo(region);
260     }
261
262     if (cacheFlag == DoNotCacheRenderBoxRegionInfo)
263         delete boxInfo;
264
265     if (isHorizontalWritingMode())
266         return LayoutRect(logicalLeft, 0, logicalWidth, height());
267     return LayoutRect(0, logicalLeft, width(), logicalWidth);
268 }
269
270 static RenderBlockFlow* outermostBlockContainingFloatingObject(RenderBox& box)
271 {
272     ASSERT(box.isFloating());
273     RenderBlockFlow* parentBlock = nullptr;
274     for (auto& ancestor : ancestorsOfType<RenderBlockFlow>(box)) {
275         if (ancestor.isRenderView())
276             break;
277         if (!parentBlock || ancestor.containsFloat(box))
278             parentBlock = &ancestor;
279     }
280     return parentBlock;
281 }
282
283 void RenderBox::removeFloatingOrPositionedChildFromBlockLists()
284 {
285     ASSERT(isFloatingOrOutOfFlowPositioned());
286
287     if (renderTreeBeingDestroyed())
288         return;
289
290     if (isFloating()) {
291         if (RenderBlockFlow* parentBlock = outermostBlockContainingFloatingObject(*this)) {
292             parentBlock->markSiblingsWithFloatsForLayout(this);
293             parentBlock->markAllDescendantsWithFloatsForLayout(this, false);
294         }
295     }
296
297     if (isOutOfFlowPositioned())
298         RenderBlock::removePositionedObject(*this);
299 }
300
301 void RenderBox::styleWillChange(StyleDifference diff, const RenderStyle& newStyle)
302 {
303     s_hadOverflowClip = hasOverflowClip();
304
305     const RenderStyle* oldStyle = hasInitializedStyle() ? &style() : nullptr;
306     if (oldStyle) {
307         // The background of the root element or the body element could propagate up to
308         // the canvas. Issue full repaint, when our style changes substantially.
309         if (diff >= StyleDifferenceRepaint && (isDocumentElementRenderer() || isBody())) {
310             view().repaintRootContents();
311             if (oldStyle->hasEntirelyFixedBackground() != newStyle.hasEntirelyFixedBackground())
312                 view().compositor().rootFixedBackgroundsChanged();
313         }
314         
315         // When a layout hint happens and an object's position style changes, we have to do a layout
316         // to dirty the render tree using the old position value now.
317         if (diff == StyleDifferenceLayout && parent() && oldStyle->position() != newStyle.position()) {
318             markContainingBlocksForLayout();
319             if (oldStyle->position() == StaticPosition)
320                 repaint();
321             else if (newStyle.hasOutOfFlowPosition())
322                 parent()->setChildNeedsLayout();
323             if (isFloating() && !isOutOfFlowPositioned() && newStyle.hasOutOfFlowPosition())
324                 removeFloatingOrPositionedChildFromBlockLists();
325         }
326     } else if (isBody())
327         view().repaintRootContents();
328
329 #if ENABLE(CSS_SCROLL_SNAP)
330     bool boxContributesSnapPositions = newStyle.scrollSnapArea().hasSnapPosition();
331     if (boxContributesSnapPositions || (oldStyle && oldStyle->scrollSnapArea().hasSnapPosition())) {
332         if (boxContributesSnapPositions)
333             view().registerBoxWithScrollSnapPositions(*this);
334         else
335             view().unregisterBoxWithScrollSnapPositions(*this);
336     }
337 #endif
338
339     RenderBoxModelObject::styleWillChange(diff, newStyle);
340 }
341
342 void RenderBox::styleDidChange(StyleDifference diff, const RenderStyle* oldStyle)
343 {
344     // Horizontal writing mode definition is updated in RenderBoxModelObject::updateFromStyle,
345     // (as part of the RenderBoxModelObject::styleDidChange call below). So, we can safely cache the horizontal
346     // writing mode value before style change here.
347     bool oldHorizontalWritingMode = isHorizontalWritingMode();
348
349     RenderBoxModelObject::styleDidChange(diff, oldStyle);
350
351     const RenderStyle& newStyle = style();
352     if (needsLayout() && oldStyle) {
353         RenderBlock::removePercentHeightDescendantIfNeeded(*this);
354
355         // Normally we can do optimized positioning layout for absolute/fixed positioned objects. There is one special case, however, which is
356         // when the positioned object's margin-before is changed. In this case the parent has to get a layout in order to run margin collapsing
357         // to determine the new static position.
358         if (isOutOfFlowPositioned() && newStyle.hasStaticBlockPosition(isHorizontalWritingMode()) && oldStyle->marginBefore() != newStyle.marginBefore()
359             && parent() && !parent()->normalChildNeedsLayout())
360             parent()->setChildNeedsLayout();
361     }
362
363     if (RenderBlock::hasPercentHeightContainerMap() && firstChild()
364         && oldHorizontalWritingMode != isHorizontalWritingMode())
365         RenderBlock::clearPercentHeightDescendantsFrom(*this);
366
367     // If our zoom factor changes and we have a defined scrollLeft/Top, we need to adjust that value into the
368     // new zoomed coordinate space.
369     if (hasOverflowClip() && layer() && oldStyle && oldStyle->effectiveZoom() != newStyle.effectiveZoom()) {
370         if (int left = layer()->scrollOffset().x()) {
371             left = (left / oldStyle->effectiveZoom()) * newStyle.effectiveZoom();
372             layer()->scrollToXOffset(left);
373         }
374         if (int top = layer()->scrollOffset().y()) {
375             top = (top / oldStyle->effectiveZoom()) * newStyle.effectiveZoom();
376             layer()->scrollToYOffset(top);
377         }
378     }
379
380     // Our opaqueness might have changed without triggering layout.
381     if (diff >= StyleDifferenceRepaint && diff <= StyleDifferenceRepaintLayer) {
382         auto parentToInvalidate = parent();
383         for (unsigned i = 0; i < backgroundObscurationTestMaxDepth && parentToInvalidate; ++i) {
384             parentToInvalidate->invalidateBackgroundObscurationStatus();
385             parentToInvalidate = parentToInvalidate->parent();
386         }
387     }
388
389     bool isBodyRenderer = isBody();
390     bool isDocElementRenderer = isDocumentElementRenderer();
391
392     if (isDocElementRenderer || isBodyRenderer) {
393         // Propagate the new writing mode and direction up to the RenderView.
394         auto* documentElementRenderer = document().documentElement()->renderer();
395         auto& viewStyle = view().mutableStyle();
396         bool rootStyleChanged = false;
397         bool viewDirectionOrWritingModeChanged = false;
398         auto* rootRenderer = isBodyRenderer ? documentElementRenderer : nullptr;
399         if (viewStyle.direction() != newStyle.direction() && (isDocElementRenderer || !documentElementRenderer->style().hasExplicitlySetDirection())) {
400             viewStyle.setDirection(newStyle.direction());
401             viewDirectionOrWritingModeChanged = true;
402             if (isBodyRenderer) {
403                 rootRenderer->mutableStyle().setDirection(newStyle.direction());
404                 rootStyleChanged = true;
405             }
406             setNeedsLayoutAndPrefWidthsRecalc();
407
408             view().frameView().topContentDirectionDidChange();
409         }
410
411         if (viewStyle.writingMode() != newStyle.writingMode() && (isDocElementRenderer || !documentElementRenderer->style().hasExplicitlySetWritingMode())) {
412             viewStyle.setWritingMode(newStyle.writingMode());
413             viewDirectionOrWritingModeChanged = true;
414             view().setHorizontalWritingMode(newStyle.isHorizontalWritingMode());
415             view().markAllDescendantsWithFloatsForLayout();
416             if (isBodyRenderer) {
417                 rootStyleChanged = true;
418                 rootRenderer->mutableStyle().setWritingMode(newStyle.writingMode());
419                 rootRenderer->setHorizontalWritingMode(newStyle.isHorizontalWritingMode());
420             }
421             setNeedsLayoutAndPrefWidthsRecalc();
422         }
423
424         view().frameView().recalculateScrollbarOverlayStyle();
425         
426         const Pagination& pagination = view().frameView().pagination();
427         if (viewDirectionOrWritingModeChanged && pagination.mode != Pagination::Unpaginated) {
428             viewStyle.setColumnStylesFromPaginationMode(pagination.mode);
429             if (view().multiColumnFlowThread())
430                 view().updateColumnProgressionFromStyle(viewStyle);
431         }
432         
433         if (viewDirectionOrWritingModeChanged && view().multiColumnFlowThread())
434             view().updateStylesForColumnChildren();
435         
436         if (rootStyleChanged && is<RenderBlockFlow>(rootRenderer) && downcast<RenderBlockFlow>(*rootRenderer).multiColumnFlowThread())
437             downcast<RenderBlockFlow>(*rootRenderer).updateStylesForColumnChildren();
438         
439         if (isBodyRenderer && pagination.mode != Pagination::Unpaginated && page().paginationLineGridEnabled()) {
440             // Propagate the body font back up to the RenderView and use it as
441             // the basis of the grid.
442             if (newStyle.fontDescription() != view().style().fontDescription()) {
443                 view().mutableStyle().setFontDescription(newStyle.fontDescription());
444                 view().mutableStyle().fontCascade().update(&document().fontSelector());
445             }
446         }
447
448         if (diff != StyleDifferenceEqual)
449             view().compositor().rootOrBodyStyleChanged(*this, oldStyle);
450     }
451
452     if ((oldStyle && oldStyle->shapeOutside()) || style().shapeOutside())
453         updateShapeOutsideInfoAfterStyleChange(style(), oldStyle);
454     updateGridPositionAfterStyleChange(style(), oldStyle);
455 }
456
457 void RenderBox::willBeRemovedFromTree()
458 {
459 #if ENABLE(CSS_SCROLL_SNAP)
460     if (hasInitializedStyle() && style().scrollSnapArea().hasSnapPosition())
461         view().unregisterBoxWithScrollSnapPositions(*this);
462 #endif
463     
464     RenderBoxModelObject::willBeRemovedFromTree();
465 }
466     
467
468 void RenderBox::updateGridPositionAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
469 {
470     if (!oldStyle || !is<RenderGrid>(parent()))
471         return;
472
473     if (oldStyle->gridItemColumnStart() == style.gridItemColumnStart()
474         && oldStyle->gridItemColumnEnd() == style.gridItemColumnEnd()
475         && oldStyle->gridItemRowStart() == style.gridItemRowStart()
476         && oldStyle->gridItemRowEnd() == style.gridItemRowEnd()
477         && oldStyle->order() == style.order()
478         && oldStyle->hasOutOfFlowPosition() == style.hasOutOfFlowPosition())
479         return;
480
481     // Positioned items don't participate on the layout of the grid,
482     // so we don't need to mark the grid as dirty if they change positions.
483     if (oldStyle->hasOutOfFlowPosition() && style.hasOutOfFlowPosition())
484         return;
485
486     // It should be possible to not dirty the grid in some cases (like moving an
487     // explicitly placed grid item).
488     // For now, it's more simple to just always recompute the grid.
489     downcast<RenderGrid>(*parent()).dirtyGrid();
490 }
491
492 void RenderBox::updateShapeOutsideInfoAfterStyleChange(const RenderStyle& style, const RenderStyle* oldStyle)
493 {
494     const ShapeValue* shapeOutside = style.shapeOutside();
495     const ShapeValue* oldShapeOutside = oldStyle ? oldStyle->shapeOutside() : nullptr;
496
497     Length shapeMargin = style.shapeMargin();
498     Length oldShapeMargin = oldStyle ? oldStyle->shapeMargin() : RenderStyle::initialShapeMargin();
499
500     float shapeImageThreshold = style.shapeImageThreshold();
501     float oldShapeImageThreshold = oldStyle ? oldStyle->shapeImageThreshold() : RenderStyle::initialShapeImageThreshold();
502
503     // FIXME: A future optimization would do a deep comparison for equality. (bug 100811)
504     if (shapeOutside == oldShapeOutside && shapeMargin == oldShapeMargin && shapeImageThreshold == oldShapeImageThreshold)
505         return;
506
507     if (!shapeOutside)
508         ShapeOutsideInfo::removeInfo(*this);
509     else
510         ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
511
512     if (shapeOutside || shapeOutside != oldShapeOutside)
513         markShapeOutsideDependentsForLayout();
514 }
515
516 void RenderBox::updateFromStyle()
517 {
518     RenderBoxModelObject::updateFromStyle();
519
520     const RenderStyle& styleToUse = style();
521     bool isDocElementRenderer = isDocumentElementRenderer();
522     bool isViewObject = isRenderView();
523
524     // The root and the RenderView always paint their backgrounds/borders.
525     if (isDocElementRenderer || isViewObject)
526         setHasVisibleBoxDecorations(true);
527
528     setFloating(!isOutOfFlowPositioned() && styleToUse.isFloating());
529
530     // We also handle <body> and <html>, whose overflow applies to the viewport.
531     if (styleToUse.overflowX() != OVISIBLE && !isDocElementRenderer && isRenderBlock()) {
532         bool boxHasOverflowClip = true;
533         if (isBody()) {
534             // Overflow on the body can propagate to the viewport under the following conditions.
535             // (1) The root element is <html>.
536             // (2) We are the primary <body> (can be checked by looking at document.body).
537             // (3) The root element has visible overflow.
538             if (is<HTMLHtmlElement>(*document().documentElement())
539                 && document().body() == element()
540                 && document().documentElement()->renderer()->style().overflowX() == OVISIBLE) {
541                 boxHasOverflowClip = false;
542             }
543         }
544         // Check for overflow clip.
545         // It's sufficient to just check one direction, since it's illegal to have visible on only one overflow value.
546         if (boxHasOverflowClip) {
547             if (!s_hadOverflowClip && hasRenderOverflow()) {
548                 // Erase the overflow.
549                 // Overflow changes have to result in immediate repaints of the entire layout overflow area because
550                 // repaints issued by removal of descendants get clipped using the updated style when they shouldn't.
551                 repaintRectangle(visualOverflowRect());
552                 repaintRectangle(layoutOverflowRect());
553             }
554             setHasOverflowClip();
555         }
556     }
557     setHasTransformRelatedProperty(styleToUse.hasTransformRelatedProperty());
558     setHasReflection(styleToUse.boxReflect());
559 }
560
561 void RenderBox::layout()
562 {
563     StackStats::LayoutCheckPoint layoutCheckPoint;
564     ASSERT(needsLayout());
565
566     RenderObject* child = firstChild();
567     if (!child) {
568         clearNeedsLayout();
569         return;
570     }
571
572     LayoutStateMaintainer statePusher(view(), *this, locationOffset(), style().isFlippedBlocksWritingMode());
573     while (child) {
574         if (child->needsLayout())
575             downcast<RenderElement>(*child).layout();
576         ASSERT(!child->needsLayout());
577         child = child->nextSibling();
578     }
579     statePusher.pop();
580     invalidateBackgroundObscurationStatus();
581     clearNeedsLayout();
582 }
583
584 // More IE extensions.  clientWidth and clientHeight represent the interior of an object
585 // excluding border and scrollbar.
586 LayoutUnit RenderBox::clientWidth() const
587 {
588     return width() - borderLeft() - borderRight() - verticalScrollbarWidth();
589 }
590
591 LayoutUnit RenderBox::clientHeight() const
592 {
593     return height() - borderTop() - borderBottom() - horizontalScrollbarHeight();
594 }
595
596 int RenderBox::scrollWidth() const
597 {
598     if (hasOverflowClip() && layer())
599         return layer()->scrollWidth();
600     // For objects with visible overflow, this matches IE.
601     // FIXME: Need to work right with writing modes.
602     if (style().isLeftToRightDirection()) {
603         // FIXME: This should use snappedIntSize() instead with absolute coordinates.
604         return roundToInt(std::max(clientWidth(), layoutOverflowRect().maxX() - borderLeft()));
605     }
606     return roundToInt(clientWidth() - std::min<LayoutUnit>(0, layoutOverflowRect().x() - borderLeft()));
607 }
608
609 int RenderBox::scrollHeight() const
610 {
611     if (hasOverflowClip() && layer())
612         return layer()->scrollHeight();
613     // For objects with visible overflow, this matches IE.
614     // FIXME: Need to work right with writing modes.
615     // FIXME: This should use snappedIntSize() instead with absolute coordinates.
616     return roundToInt(std::max(clientHeight(), layoutOverflowRect().maxY() - borderTop()));
617 }
618
619 int RenderBox::scrollLeft() const
620 {
621     return hasOverflowClip() && layer() ? layer()->scrollPosition().x() : 0;
622 }
623
624 int RenderBox::scrollTop() const
625 {
626     return hasOverflowClip() && layer() ? layer()->scrollPosition().y() : 0;
627 }
628
629 static void setupWheelEventTestTrigger(RenderLayer& layer)
630 {
631     Page& page = layer.renderer().page();
632     if (!page.expectsWheelEventTriggers())
633         return;
634     layer.scrollAnimator().setWheelEventTestTrigger(page.testTrigger());
635 }
636
637 void RenderBox::setScrollLeft(int newLeft)
638 {
639     if (!hasOverflowClip() || !layer())
640         return;
641     setupWheelEventTestTrigger(*layer());
642     layer()->scrollToXPosition(newLeft, RenderLayer::ScrollOffsetClamped);
643 }
644
645 void RenderBox::setScrollTop(int newTop)
646 {
647     if (!hasOverflowClip() || !layer())
648         return;
649     setupWheelEventTestTrigger(*layer());
650     layer()->scrollToYPosition(newTop, RenderLayer::ScrollOffsetClamped);
651 }
652
653 void RenderBox::absoluteRects(Vector<IntRect>& rects, const LayoutPoint& accumulatedOffset) const
654 {
655     rects.append(snappedIntRect(accumulatedOffset, size()));
656 }
657
658 void RenderBox::absoluteQuads(Vector<FloatQuad>& quads, bool* wasFixed) const
659 {
660     FloatRect localRect(0, 0, width(), height());
661
662     RenderFlowThread* flowThread = flowThreadContainingBlock();
663     if (flowThread && flowThread->absoluteQuadsForBox(quads, wasFixed, this, localRect.y(), localRect.maxY()))
664         return;
665
666     quads.append(localToAbsoluteQuad(localRect, UseTransforms, wasFixed));
667 }
668
669 void RenderBox::updateLayerTransform()
670 {
671     // Transform-origin depends on box size, so we need to update the layer transform after layout.
672     if (hasLayer())
673         layer()->updateTransform();
674 }
675
676 LayoutUnit RenderBox::constrainLogicalWidthInRegionByMinMax(LayoutUnit logicalWidth, LayoutUnit availableWidth, RenderBlock& cb, RenderRegion* region) const
677 {
678     const RenderStyle& styleToUse = style();
679     if (!styleToUse.logicalMaxWidth().isUndefined())
680         logicalWidth = std::min(logicalWidth, computeLogicalWidthInRegionUsing(MaxSize, styleToUse.logicalMaxWidth(), availableWidth, cb, region));
681     return std::max(logicalWidth, computeLogicalWidthInRegionUsing(MinSize, styleToUse.logicalMinWidth(), availableWidth, cb, region));
682 }
683
684 LayoutUnit RenderBox::constrainLogicalHeightByMinMax(LayoutUnit logicalHeight, std::optional<LayoutUnit> intrinsicContentHeight) const
685 {
686     const RenderStyle& styleToUse = style();
687     if (!styleToUse.logicalMaxHeight().isUndefined()) {
688         if (std::optional<LayoutUnit> maxH = computeLogicalHeightUsing(MaxSize, styleToUse.logicalMaxHeight(), intrinsicContentHeight))
689             logicalHeight = std::min(logicalHeight, maxH.value());
690     }
691     if (std::optional<LayoutUnit> computedLogicalHeight = computeLogicalHeightUsing(MinSize, styleToUse.logicalMinHeight(), intrinsicContentHeight))
692         return std::max(logicalHeight, computedLogicalHeight.value());
693     return logicalHeight;
694 }
695
696 LayoutUnit RenderBox::constrainContentBoxLogicalHeightByMinMax(LayoutUnit logicalHeight, std::optional<LayoutUnit> intrinsicContentHeight) const
697 {
698     const RenderStyle& styleToUse = style();
699     if (!styleToUse.logicalMaxHeight().isUndefined()) {
700         if (std::optional<LayoutUnit> maxH = computeContentLogicalHeight(MaxSize, styleToUse.logicalMaxHeight(), intrinsicContentHeight))
701             logicalHeight = std::min(logicalHeight, maxH.value());
702     }
703     if (std::optional<LayoutUnit> computedContentLogicalHeight = computeContentLogicalHeight(MinSize, styleToUse.logicalMinHeight(), intrinsicContentHeight))
704         return std::max(logicalHeight, computedContentLogicalHeight.value());
705     return logicalHeight;
706 }
707
708 RoundedRect::Radii RenderBox::borderRadii() const
709 {
710     auto& style = this->style();
711     LayoutRect bounds = frameRect();
712
713     unsigned borderLeft = style.borderLeftWidth();
714     unsigned borderTop = style.borderTopWidth();
715     bounds.moveBy(LayoutPoint(borderLeft, borderTop));
716     bounds.contract(borderLeft + style.borderRightWidth(), borderTop + style.borderBottomWidth());
717     return style.getRoundedBorderFor(bounds).radii();
718 }
719
720 LayoutRect RenderBox::contentBoxRect() const
721 {
722     LayoutUnit x = borderLeft() + paddingLeft();
723     if (shouldPlaceBlockDirectionScrollbarOnLeft())
724         x += verticalScrollbarWidth();
725     LayoutUnit y = borderTop() + paddingTop();
726     return LayoutRect(x, y, contentWidth(), contentHeight());
727 }
728
729 IntRect RenderBox::absoluteContentBox() const
730 {
731     // This is wrong with transforms and flipped writing modes.
732     IntRect rect = snappedIntRect(contentBoxRect());
733     FloatPoint absPos = localToAbsolute();
734     rect.move(absPos.x(), absPos.y());
735     return rect;
736 }
737
738 FloatQuad RenderBox::absoluteContentQuad() const
739 {
740     LayoutRect rect = contentBoxRect();
741     return localToAbsoluteQuad(FloatRect(rect));
742 }
743
744 LayoutRect RenderBox::outlineBoundsForRepaint(const RenderLayerModelObject* repaintContainer, const RenderGeometryMap* geometryMap) const
745 {
746     LayoutRect box = borderBoundingBox();
747     adjustRectForOutlineAndShadow(box);
748
749     if (repaintContainer != this) {
750         FloatQuad containerRelativeQuad;
751         if (geometryMap)
752             containerRelativeQuad = geometryMap->mapToContainer(box, repaintContainer);
753         else
754             containerRelativeQuad = localToContainerQuad(FloatRect(box), repaintContainer);
755
756         box = LayoutRect(containerRelativeQuad.boundingBox());
757     }
758     
759     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
760     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
761     box.move(view().layoutDelta());
762
763     return LayoutRect(snapRectToDevicePixels(box, document().deviceScaleFactor()));
764 }
765
766 void RenderBox::addFocusRingRects(Vector<LayoutRect>& rects, const LayoutPoint& additionalOffset, const RenderLayerModelObject*)
767 {
768     if (!size().isEmpty())
769         rects.append(LayoutRect(additionalOffset, size()));
770 }
771
772 int RenderBox::reflectionOffset() const
773 {
774     if (!style().boxReflect())
775         return 0;
776     if (style().boxReflect()->direction() == ReflectionLeft || style().boxReflect()->direction() == ReflectionRight)
777         return valueForLength(style().boxReflect()->offset(), borderBoxRect().width());
778     return valueForLength(style().boxReflect()->offset(), borderBoxRect().height());
779 }
780
781 LayoutRect RenderBox::reflectedRect(const LayoutRect& r) const
782 {
783     if (!style().boxReflect())
784         return LayoutRect();
785
786     LayoutRect box = borderBoxRect();
787     LayoutRect result = r;
788     switch (style().boxReflect()->direction()) {
789         case ReflectionBelow:
790             result.setY(box.maxY() + reflectionOffset() + (box.maxY() - r.maxY()));
791             break;
792         case ReflectionAbove:
793             result.setY(box.y() - reflectionOffset() - box.height() + (box.maxY() - r.maxY()));
794             break;
795         case ReflectionLeft:
796             result.setX(box.x() - reflectionOffset() - box.width() + (box.maxX() - r.maxX()));
797             break;
798         case ReflectionRight:
799             result.setX(box.maxX() + reflectionOffset() + (box.maxX() - r.maxX()));
800             break;
801     }
802     return result;
803 }
804
805 bool RenderBox::fixedElementLaysOutRelativeToFrame(const FrameView& frameView) const
806 {
807     return style().position() == FixedPosition && container()->isRenderView() && frameView.fixedElementsLayoutRelativeToFrame();
808 }
809
810 bool RenderBox::includeVerticalScrollbarSize() const
811 {
812     return hasOverflowClip() && layer() && !layer()->hasOverlayScrollbars()
813         && (style().overflowY() == OSCROLL || style().overflowY() == OAUTO);
814 }
815
816 bool RenderBox::includeHorizontalScrollbarSize() const
817 {
818     return hasOverflowClip() && layer() && !layer()->hasOverlayScrollbars()
819         && (style().overflowX() == OSCROLL || style().overflowX() == OAUTO);
820 }
821
822 int RenderBox::verticalScrollbarWidth() const
823 {
824     return includeVerticalScrollbarSize() ? layer()->verticalScrollbarWidth() : 0;
825 }
826
827 int RenderBox::horizontalScrollbarHeight() const
828 {
829     return includeHorizontalScrollbarSize() ? layer()->horizontalScrollbarHeight() : 0;
830 }
831
832 int RenderBox::intrinsicScrollbarLogicalWidth() const
833 {
834     if (!hasOverflowClip())
835         return 0;
836
837     if (isHorizontalWritingMode() && (style().overflowY() == OSCROLL && !hasVerticalScrollbarWithAutoBehavior())) {
838         ASSERT(layer() && layer()->hasVerticalScrollbar());
839         return verticalScrollbarWidth();
840     }
841
842     if (!isHorizontalWritingMode() && (style().overflowX() == OSCROLL && !hasHorizontalScrollbarWithAutoBehavior())) {
843         ASSERT(layer() && layer()->hasHorizontalScrollbar());
844         return horizontalScrollbarHeight();
845     }
846
847     return 0;
848 }
849
850 bool RenderBox::scrollLayer(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement)
851 {
852     RenderLayer* boxLayer = layer();
853     if (boxLayer && boxLayer->scroll(direction, granularity, multiplier)) {
854         if (stopElement)
855             *stopElement = element();
856
857         return true;
858     }
859
860     return false;
861 }
862
863 bool RenderBox::scroll(ScrollDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement, RenderBox* startBox, const IntPoint& wheelEventAbsolutePoint)
864 {
865     if (scrollLayer(direction, granularity, multiplier, stopElement))
866         return true;
867
868     if (stopElement && *stopElement && *stopElement == element())
869         return true;
870
871     RenderBlock* nextScrollBlock = containingBlock();
872     if (is<RenderNamedFlowThread>(nextScrollBlock)) {
873         ASSERT(startBox);
874         nextScrollBlock = downcast<RenderNamedFlowThread>(*nextScrollBlock).fragmentFromAbsolutePointAndBox(wheelEventAbsolutePoint, *startBox);
875     }
876
877     if (nextScrollBlock && !nextScrollBlock->isRenderView())
878         return nextScrollBlock->scroll(direction, granularity, multiplier, stopElement, startBox, wheelEventAbsolutePoint);
879
880     return false;
881 }
882
883 bool RenderBox::logicalScroll(ScrollLogicalDirection direction, ScrollGranularity granularity, float multiplier, Element** stopElement)
884 {
885     bool scrolled = false;
886     
887     RenderLayer* l = layer();
888     if (l) {
889 #if PLATFORM(COCOA)
890         // On Mac only we reset the inline direction position when doing a document scroll (e.g., hitting Home/End).
891         if (granularity == ScrollByDocument)
892             scrolled = l->scroll(logicalToPhysical(ScrollInlineDirectionBackward, isHorizontalWritingMode(), style().isFlippedBlocksWritingMode()), ScrollByDocument, multiplier);
893 #endif
894         if (l->scroll(logicalToPhysical(direction, isHorizontalWritingMode(), style().isFlippedBlocksWritingMode()), granularity, multiplier))
895             scrolled = true;
896         
897         if (scrolled) {
898             if (stopElement)
899                 *stopElement = element();
900             return true;
901         }
902     }
903
904     if (stopElement && *stopElement && *stopElement == element())
905         return true;
906
907     RenderBlock* b = containingBlock();
908     if (b && !b->isRenderView())
909         return b->logicalScroll(direction, granularity, multiplier, stopElement);
910     return false;
911 }
912
913 bool RenderBox::canBeScrolledAndHasScrollableArea() const
914 {
915     return canBeProgramaticallyScrolled() && (hasHorizontalOverflow() || hasVerticalOverflow());
916 }
917
918 bool RenderBox::isScrollableOrRubberbandableBox() const
919 {
920     return canBeScrolledAndHasScrollableArea();
921 }
922
923 // FIXME: This is badly named. overflow:hidden can be programmatically scrolled, yet this returns false in that case.
924 bool RenderBox::canBeProgramaticallyScrolled() const
925 {
926     if (isRenderView())
927         return true;
928
929     if (!hasOverflowClip())
930         return false;
931
932     if (hasScrollableOverflowX() || hasScrollableOverflowY())
933         return true;
934
935     return element() && element()->hasEditableStyle();
936 }
937
938 bool RenderBox::usesCompositedScrolling() const
939 {
940     return hasOverflowClip() && hasLayer() && layer()->usesCompositedScrolling();
941 }
942
943 void RenderBox::autoscroll(const IntPoint& position)
944 {
945     if (layer())
946         layer()->autoscroll(position);
947 }
948
949 // There are two kinds of renderer that can autoscroll.
950 bool RenderBox::canAutoscroll() const
951 {
952     if (isRenderView())
953         return view().frameView().isScrollable();
954
955     // Check for a box that can be scrolled in its own right.
956     if (canBeScrolledAndHasScrollableArea())
957         return true;
958
959     return false;
960 }
961
962 // If specified point is in border belt, returned offset denotes direction of
963 // scrolling.
964 IntSize RenderBox::calculateAutoscrollDirection(const IntPoint& windowPoint) const
965 {
966     IntRect box(absoluteBoundingBoxRect());
967     box.moveBy(view().frameView().scrollPosition());
968     IntRect windowBox = view().frameView().contentsToWindow(box);
969
970     IntPoint windowAutoscrollPoint = windowPoint;
971
972     if (windowAutoscrollPoint.x() < windowBox.x() + autoscrollBeltSize)
973         windowAutoscrollPoint.move(-autoscrollBeltSize, 0);
974     else if (windowAutoscrollPoint.x() > windowBox.maxX() - autoscrollBeltSize)
975         windowAutoscrollPoint.move(autoscrollBeltSize, 0);
976
977     if (windowAutoscrollPoint.y() < windowBox.y() + autoscrollBeltSize)
978         windowAutoscrollPoint.move(0, -autoscrollBeltSize);
979     else if (windowAutoscrollPoint.y() > windowBox.maxY() - autoscrollBeltSize)
980         windowAutoscrollPoint.move(0, autoscrollBeltSize);
981
982     return windowAutoscrollPoint - windowPoint;
983 }
984
985 RenderBox* RenderBox::findAutoscrollable(RenderObject* renderer)
986 {
987     while (renderer && !(is<RenderBox>(*renderer) && downcast<RenderBox>(*renderer).canAutoscroll())) {
988         if (is<RenderView>(*renderer) && renderer->document().ownerElement())
989             renderer = renderer->document().ownerElement()->renderer();
990         else
991             renderer = renderer->parent();
992     }
993
994     return is<RenderBox>(renderer) ? downcast<RenderBox>(renderer) : nullptr;
995 }
996
997 void RenderBox::panScroll(const IntPoint& source)
998 {
999     if (layer())
1000         layer()->panScrollFromPoint(source);
1001 }
1002
1003 bool RenderBox::hasVerticalScrollbarWithAutoBehavior() const
1004 {
1005     bool overflowScrollActsLikeAuto = style().overflowY() == OSCROLL && !style().hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
1006     return hasOverflowClip() && (style().overflowY() == OAUTO || style().overflowY() == OOVERLAY || overflowScrollActsLikeAuto);
1007 }
1008
1009 bool RenderBox::hasHorizontalScrollbarWithAutoBehavior() const
1010 {
1011     bool overflowScrollActsLikeAuto = style().overflowX() == OSCROLL && !style().hasPseudoStyle(SCROLLBAR) && ScrollbarTheme::theme().usesOverlayScrollbars();
1012     return hasOverflowClip() && (style().overflowX() == OAUTO || style().overflowX() == OOVERLAY || overflowScrollActsLikeAuto);
1013 }
1014
1015 bool RenderBox::needsPreferredWidthsRecalculation() const
1016 {
1017     return style().paddingStart().isPercentOrCalculated() || style().paddingEnd().isPercentOrCalculated();
1018 }
1019
1020 ScrollPosition RenderBox::scrollPosition() const
1021 {
1022     if (!hasOverflowClip())
1023         return { 0, 0 };
1024
1025     ASSERT(hasLayer());
1026     return layer()->scrollPosition();
1027 }
1028
1029 LayoutSize RenderBox::cachedSizeForOverflowClip() const
1030 {
1031     ASSERT(hasOverflowClip());
1032     ASSERT(hasLayer());
1033     return layer()->size();
1034 }
1035
1036 void RenderBox::applyCachedClipAndScrollPositionForRepaint(LayoutRect& paintRect) const
1037 {
1038     flipForWritingMode(paintRect);
1039     paintRect.moveBy(-scrollPosition()); // For overflow:auto/scroll/hidden.
1040
1041     // Do not clip scroll layer contents to reduce the number of repaints while scrolling.
1042     if (usesCompositedScrolling()) {
1043         flipForWritingMode(paintRect);
1044         return;
1045     }
1046
1047     // height() is inaccurate if we're in the middle of a layout of this RenderBox, so use the
1048     // layer's size instead. Even if the layer's size is wrong, the layer itself will repaint
1049     // anyway if its size does change.
1050     LayoutRect clipRect(LayoutPoint(), cachedSizeForOverflowClip());
1051     paintRect = intersection(paintRect, clipRect);
1052     flipForWritingMode(paintRect);
1053 }
1054
1055 void RenderBox::computeIntrinsicLogicalWidths(LayoutUnit& minLogicalWidth, LayoutUnit& maxLogicalWidth) const
1056 {
1057     minLogicalWidth = minPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1058     maxLogicalWidth = maxPreferredLogicalWidth() - borderAndPaddingLogicalWidth();
1059 }
1060
1061 LayoutUnit RenderBox::minPreferredLogicalWidth() const
1062 {
1063     if (preferredLogicalWidthsDirty()) {
1064 #ifndef NDEBUG
1065         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
1066 #endif
1067         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
1068     }
1069         
1070     return m_minPreferredLogicalWidth;
1071 }
1072
1073 LayoutUnit RenderBox::maxPreferredLogicalWidth() const
1074 {
1075     if (preferredLogicalWidthsDirty()) {
1076 #ifndef NDEBUG
1077         SetLayoutNeededForbiddenScope layoutForbiddenScope(const_cast<RenderBox*>(this));
1078 #endif
1079         const_cast<RenderBox*>(this)->computePreferredLogicalWidths();
1080     }
1081         
1082     return m_maxPreferredLogicalWidth;
1083 }
1084
1085 bool RenderBox::hasOverrideLogicalContentHeight() const
1086 {
1087     return gOverrideHeightMap && gOverrideHeightMap->contains(this);
1088 }
1089
1090 bool RenderBox::hasOverrideLogicalContentWidth() const
1091 {
1092     return gOverrideWidthMap && gOverrideWidthMap->contains(this);
1093 }
1094
1095 void RenderBox::setOverrideLogicalContentHeight(LayoutUnit height)
1096 {
1097     if (!gOverrideHeightMap)
1098         gOverrideHeightMap = new OverrideSizeMap();
1099     gOverrideHeightMap->set(this, height);
1100 }
1101
1102 void RenderBox::setOverrideLogicalContentWidth(LayoutUnit width)
1103 {
1104     if (!gOverrideWidthMap)
1105         gOverrideWidthMap = new OverrideSizeMap();
1106     gOverrideWidthMap->set(this, width);
1107 }
1108
1109 void RenderBox::clearOverrideLogicalContentHeight()
1110 {
1111     if (gOverrideHeightMap)
1112         gOverrideHeightMap->remove(this);
1113 }
1114
1115 void RenderBox::clearOverrideLogicalContentWidth()
1116 {
1117     if (gOverrideWidthMap)
1118         gOverrideWidthMap->remove(this);
1119 }
1120
1121 void RenderBox::clearOverrideSize()
1122 {
1123     clearOverrideLogicalContentHeight();
1124     clearOverrideLogicalContentWidth();
1125 }
1126
1127 LayoutUnit RenderBox::overrideLogicalContentWidth() const
1128 {
1129     ASSERT(hasOverrideLogicalContentWidth());
1130     return gOverrideWidthMap->get(this);
1131 }
1132
1133 LayoutUnit RenderBox::overrideLogicalContentHeight() const
1134 {
1135     ASSERT(hasOverrideLogicalContentHeight());
1136     return gOverrideHeightMap->get(this);
1137 }
1138
1139 std::optional<LayoutUnit> RenderBox::overrideContainingBlockContentLogicalWidth() const
1140 {
1141     ASSERT(hasOverrideContainingBlockLogicalWidth());
1142     return gOverrideContainingBlockLogicalWidthMap->get(this);
1143 }
1144
1145 std::optional<LayoutUnit> RenderBox::overrideContainingBlockContentLogicalHeight() const
1146 {
1147     ASSERT(hasOverrideContainingBlockLogicalHeight());
1148     return gOverrideContainingBlockLogicalHeightMap->get(this);
1149 }
1150
1151 bool RenderBox::hasOverrideContainingBlockLogicalWidth() const
1152 {
1153     return gOverrideContainingBlockLogicalWidthMap && gOverrideContainingBlockLogicalWidthMap->contains(this);
1154 }
1155
1156 bool RenderBox::hasOverrideContainingBlockLogicalHeight() const
1157 {
1158     return gOverrideContainingBlockLogicalHeightMap && gOverrideContainingBlockLogicalHeightMap->contains(this);
1159 }
1160
1161 void RenderBox::setOverrideContainingBlockContentLogicalWidth(std::optional<LayoutUnit> logicalWidth)
1162 {
1163     if (!gOverrideContainingBlockLogicalWidthMap)
1164         gOverrideContainingBlockLogicalWidthMap = new OverrideOptionalSizeMap;
1165     gOverrideContainingBlockLogicalWidthMap->set(this, logicalWidth);
1166 }
1167
1168 void RenderBox::setOverrideContainingBlockContentLogicalHeight(std::optional<LayoutUnit> logicalHeight)
1169 {
1170     if (!gOverrideContainingBlockLogicalHeightMap)
1171         gOverrideContainingBlockLogicalHeightMap = new OverrideOptionalSizeMap;
1172     gOverrideContainingBlockLogicalHeightMap->set(this, logicalHeight);
1173 }
1174
1175 void RenderBox::clearContainingBlockOverrideSize()
1176 {
1177     if (gOverrideContainingBlockLogicalWidthMap)
1178         gOverrideContainingBlockLogicalWidthMap->remove(this);
1179     clearOverrideContainingBlockContentLogicalHeight();
1180 }
1181
1182 void RenderBox::clearOverrideContainingBlockContentLogicalHeight()
1183 {
1184     if (gOverrideContainingBlockLogicalHeightMap)
1185         gOverrideContainingBlockLogicalHeightMap->remove(this);
1186 }
1187
1188 LayoutUnit RenderBox::adjustBorderBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1189 {
1190     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
1191     if (style().boxSizing() == CONTENT_BOX)
1192         return width + bordersPlusPadding;
1193     return std::max(width, bordersPlusPadding);
1194 }
1195
1196 LayoutUnit RenderBox::adjustBorderBoxLogicalHeightForBoxSizing(LayoutUnit height) const
1197 {
1198     LayoutUnit bordersPlusPadding = borderAndPaddingLogicalHeight();
1199     if (style().boxSizing() == CONTENT_BOX)
1200         return height + bordersPlusPadding;
1201     return std::max(height, bordersPlusPadding);
1202 }
1203
1204 LayoutUnit RenderBox::adjustContentBoxLogicalWidthForBoxSizing(LayoutUnit width) const
1205 {
1206     if (style().boxSizing() == BORDER_BOX)
1207         width -= borderAndPaddingLogicalWidth();
1208     return std::max<LayoutUnit>(0, width);
1209 }
1210
1211 LayoutUnit RenderBox::adjustContentBoxLogicalHeightForBoxSizing(std::optional<LayoutUnit> height) const
1212 {
1213     if (!height)
1214         return 0;
1215     LayoutUnit result = height.value();
1216     if (style().boxSizing() == BORDER_BOX)
1217         result -= borderAndPaddingLogicalHeight();
1218     return std::max(LayoutUnit(), result);
1219 }
1220
1221 // Hit Testing
1222 bool RenderBox::nodeAtPoint(const HitTestRequest& request, HitTestResult& result, const HitTestLocation& locationInContainer, const LayoutPoint& accumulatedOffset, HitTestAction action)
1223 {
1224     LayoutPoint adjustedLocation = accumulatedOffset + location();
1225
1226     // Check kids first.
1227     for (RenderObject* child = lastChild(); child; child = child->previousSibling()) {
1228         if (!child->hasLayer() && child->nodeAtPoint(request, result, locationInContainer, adjustedLocation, action)) {
1229             updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1230             return true;
1231         }
1232     }
1233
1234     RenderFlowThread* flowThread = flowThreadContainingBlock();
1235     RenderRegion* regionToUse = flowThread ? downcast<RenderNamedFlowFragment>(flowThread->currentRegion()) : nullptr;
1236
1237     // If the box is not contained by this region there's no point in going further.
1238     if (regionToUse && !flowThread->objectShouldFragmentInFlowRegion(this, regionToUse))
1239         return false;
1240
1241     // Check our bounds next. For this purpose always assume that we can only be hit in the
1242     // foreground phase (which is true for replaced elements like images).
1243     LayoutRect boundsRect = borderBoxRectInRegion(regionToUse);
1244     boundsRect.moveBy(adjustedLocation);
1245     if (visibleToHitTesting() && action == HitTestForeground && locationInContainer.intersects(boundsRect)) {
1246         updateHitTestResult(result, locationInContainer.point() - toLayoutSize(adjustedLocation));
1247         if (!result.addNodeToRectBasedTestResult(element(), request, locationInContainer, boundsRect))
1248             return true;
1249     }
1250
1251     return false;
1252 }
1253
1254 // --------------------- painting stuff -------------------------------
1255
1256 void RenderBox::paintRootBoxFillLayers(const PaintInfo& paintInfo)
1257 {
1258     ASSERT(isDocumentElementRenderer());
1259     if (paintInfo.skipRootBackground())
1260         return;
1261
1262     auto* rootBackgroundRenderer = view().rendererForRootBackground();
1263     if (!rootBackgroundRenderer)
1264         return;
1265
1266     auto& style = rootBackgroundRenderer->style();
1267     auto color = style.visitedDependentColor(CSSPropertyBackgroundColor);
1268     paintFillLayers(paintInfo, color, style.backgroundLayers(), view().backgroundRect(), BackgroundBleedNone, CompositeSourceOver, rootBackgroundRenderer);
1269 }
1270
1271 BackgroundBleedAvoidance RenderBox::determineBackgroundBleedAvoidance(GraphicsContext& context) const
1272 {
1273     if (context.paintingDisabled())
1274         return BackgroundBleedNone;
1275
1276     const RenderStyle& style = this->style();
1277
1278     if (!style.hasBackground() || !style.hasBorder() || !style.hasBorderRadius() || borderImageIsLoadedAndCanBeRendered())
1279         return BackgroundBleedNone;
1280
1281     AffineTransform ctm = context.getCTM();
1282     FloatSize contextScaling(static_cast<float>(ctm.xScale()), static_cast<float>(ctm.yScale()));
1283
1284     // Because RoundedRect uses IntRect internally the inset applied by the 
1285     // BackgroundBleedShrinkBackground strategy cannot be less than one integer
1286     // layout coordinate, even with subpixel layout enabled. To take that into
1287     // account, we clamp the contextScaling to 1.0 for the following test so
1288     // that borderObscuresBackgroundEdge can only return true if the border
1289     // widths are greater than 2 in both layout coordinates and screen
1290     // coordinates.
1291     // This precaution will become obsolete if RoundedRect is ever promoted to
1292     // a sub-pixel representation.
1293     if (contextScaling.width() > 1) 
1294         contextScaling.setWidth(1);
1295     if (contextScaling.height() > 1) 
1296         contextScaling.setHeight(1);
1297
1298     if (borderObscuresBackgroundEdge(contextScaling))
1299         return BackgroundBleedShrinkBackground;
1300     if (!style.hasAppearance() && borderObscuresBackground() && backgroundHasOpaqueTopLayer())
1301         return BackgroundBleedBackgroundOverBorder;
1302
1303     return BackgroundBleedUseTransparencyLayer;
1304 }
1305
1306 void RenderBox::paintBoxDecorations(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1307 {
1308     if (!paintInfo.shouldPaintWithinRoot(*this))
1309         return;
1310
1311     LayoutRect paintRect = borderBoxRectInRegion(currentRenderNamedFlowFragment());
1312     paintRect.moveBy(paintOffset);
1313     adjustBorderBoxRectForPainting(paintRect);
1314
1315 #if PLATFORM(IOS)
1316     // Workaround for <rdar://problem/6209763>. Force the painting bounds of checkboxes and radio controls to be square.
1317     if (style().appearance() == CheckboxPart || style().appearance() == RadioPart) {
1318         int width = std::min(paintRect.width(), paintRect.height());
1319         int height = width;
1320         paintRect = IntRect(paintRect.x(), paintRect.y() + (this->height() - height) / 2, width, height); // Vertically center the checkbox, like on desktop
1321     }
1322 #endif
1323     BackgroundBleedAvoidance bleedAvoidance = determineBackgroundBleedAvoidance(paintInfo.context());
1324
1325     // FIXME: Should eventually give the theme control over whether the box shadow should paint, since controls could have
1326     // custom shadows of their own.
1327     if (!boxShadowShouldBeAppliedToBackground(paintRect.location(), bleedAvoidance))
1328         paintBoxShadow(paintInfo, paintRect, style(), Normal);
1329
1330     GraphicsContextStateSaver stateSaver(paintInfo.context(), false);
1331     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
1332         // To avoid the background color bleeding out behind the border, we'll render background and border
1333         // into a transparency layer, and then clip that in one go (which requires setting up the clip before
1334         // beginning the layer).
1335         stateSaver.save();
1336         paintInfo.context().clipRoundedRect(style().getRoundedBorderFor(paintRect).pixelSnappedRoundedRectForPainting(document().deviceScaleFactor()));
1337         paintInfo.context().beginTransparencyLayer(1);
1338     }
1339
1340     // If we have a native theme appearance, paint that before painting our background.
1341     // The theme will tell us whether or not we should also paint the CSS background.
1342     bool borderOrBackgroundPaintingIsNeeded = true;
1343     if (style().hasAppearance()) {
1344         ControlStates* controlStates = controlStatesForRenderer(*this);
1345         borderOrBackgroundPaintingIsNeeded = theme().paint(*this, *controlStates, paintInfo, paintRect);
1346         if (controlStates->needsRepaint())
1347             view().scheduleLazyRepaint(*this);
1348     }
1349
1350     if (borderOrBackgroundPaintingIsNeeded) {
1351         if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
1352             paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1353
1354         paintBackground(paintInfo, paintRect, bleedAvoidance);
1355
1356         if (style().hasAppearance())
1357             theme().paintDecorations(*this, paintInfo, paintRect);
1358     }
1359     paintBoxShadow(paintInfo, paintRect, style(), Inset);
1360
1361     // The theme will tell us whether or not we should also paint the CSS border.
1362     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder && (!style().hasAppearance() || (borderOrBackgroundPaintingIsNeeded && theme().paintBorderOnly(*this, paintInfo, paintRect))) && style().hasVisibleBorderDecoration())
1363         paintBorder(paintInfo, paintRect, style(), bleedAvoidance);
1364
1365     if (bleedAvoidance == BackgroundBleedUseTransparencyLayer)
1366         paintInfo.context().endTransparencyLayer();
1367 }
1368
1369 bool RenderBox::paintsOwnBackground() const
1370 {
1371     if (isBody()) {
1372         // The <body> only paints its background if the root element has defined a background independent of the body,
1373         // or if the <body>'s parent is not the document element's renderer (e.g. inside SVG foreignObject).
1374         auto documentElementRenderer = document().documentElement()->renderer();
1375         return !documentElementRenderer
1376             || documentElementRenderer->hasBackground()
1377             || (documentElementRenderer != parent());
1378     }
1379     
1380     return true;
1381 }
1382
1383 void RenderBox::paintBackground(const PaintInfo& paintInfo, const LayoutRect& paintRect, BackgroundBleedAvoidance bleedAvoidance)
1384 {
1385     if (isDocumentElementRenderer()) {
1386         paintRootBoxFillLayers(paintInfo);
1387         return;
1388     }
1389
1390     if (!paintsOwnBackground())
1391         return;
1392
1393     if (backgroundIsKnownToBeObscured(paintRect.location()) && !boxShadowShouldBeAppliedToBackground(paintRect.location(), bleedAvoidance))
1394         return;
1395
1396     paintFillLayers(paintInfo, style().visitedDependentColor(CSSPropertyBackgroundColor), style().backgroundLayers(), paintRect, bleedAvoidance);
1397 }
1398
1399 bool RenderBox::getBackgroundPaintedExtent(const LayoutPoint& paintOffset, LayoutRect& paintedExtent) const
1400 {
1401     ASSERT(hasBackground());
1402     LayoutRect backgroundRect = snappedIntRect(borderBoxRect());
1403
1404     Color backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
1405     if (backgroundColor.isVisible()) {
1406         paintedExtent = backgroundRect;
1407         return true;
1408     }
1409
1410     auto& layers = style().backgroundLayers();
1411     if (!layers.image() || layers.next()) {
1412         paintedExtent =  backgroundRect;
1413         return true;
1414     }
1415
1416     auto geometry = calculateBackgroundImageGeometry(nullptr, layers, paintOffset, backgroundRect);
1417     paintedExtent = geometry.destRect();
1418     return !geometry.hasNonLocalGeometry();
1419 }
1420
1421 bool RenderBox::backgroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect) const
1422 {
1423     if (!paintsOwnBackground())
1424         return false;
1425
1426     Color backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
1427     if (!backgroundColor.isOpaque())
1428         return false;
1429
1430     // If the element has appearance, it might be painted by theme.
1431     // We cannot be sure if theme paints the background opaque.
1432     // In this case it is safe to not assume opaqueness.
1433     // FIXME: May be ask theme if it paints opaque.
1434     if (style().hasAppearance())
1435         return false;
1436     // FIXME: Check the opaqueness of background images.
1437
1438     if (hasClip() || hasClipPath())
1439         return false;
1440
1441     // FIXME: Use rounded rect if border radius is present.
1442     if (style().hasBorderRadius())
1443         return false;
1444     
1445     // FIXME: The background color clip is defined by the last layer.
1446     if (style().backgroundLayers().next())
1447         return false;
1448     LayoutRect backgroundRect;
1449     switch (style().backgroundClip()) {
1450     case BorderFillBox:
1451         backgroundRect = borderBoxRect();
1452         break;
1453     case PaddingFillBox:
1454         backgroundRect = paddingBoxRect();
1455         break;
1456     case ContentFillBox:
1457         backgroundRect = contentBoxRect();
1458         break;
1459     default:
1460         break;
1461     }
1462     return backgroundRect.contains(localRect);
1463 }
1464
1465 static bool isCandidateForOpaquenessTest(const RenderBox& childBox)
1466 {
1467     const RenderStyle& childStyle = childBox.style();
1468     if (childStyle.position() != StaticPosition && childBox.containingBlock() != childBox.parent())
1469         return false;
1470     if (childStyle.visibility() != VISIBLE)
1471         return false;
1472     if (childStyle.shapeOutside())
1473         return false;
1474     if (!childBox.width() || !childBox.height())
1475         return false;
1476     if (RenderLayer* childLayer = childBox.layer()) {
1477         if (childLayer->isComposited())
1478             return false;
1479         // FIXME: Deal with z-index.
1480         if (!childStyle.hasAutoZIndex())
1481             return false;
1482         if (childLayer->hasTransform() || childLayer->isTransparent() || childLayer->hasFilter())
1483             return false;
1484         if (!childBox.scrollPosition().isZero())
1485             return false;
1486     }
1487     return true;
1488 }
1489
1490 bool RenderBox::foregroundIsKnownToBeOpaqueInRect(const LayoutRect& localRect, unsigned maxDepthToTest) const
1491 {
1492     if (!maxDepthToTest)
1493         return false;
1494     for (auto& childBox : childrenOfType<RenderBox>(*this)) {
1495         if (!isCandidateForOpaquenessTest(childBox))
1496             continue;
1497         LayoutPoint childLocation = childBox.location();
1498         if (childBox.isRelPositioned())
1499             childLocation.move(childBox.relativePositionOffset());
1500         LayoutRect childLocalRect = localRect;
1501         childLocalRect.moveBy(-childLocation);
1502         if (childLocalRect.y() < 0 || childLocalRect.x() < 0) {
1503             // If there is unobscured area above/left of a static positioned box then the rect is probably not covered.
1504             if (childBox.style().position() == StaticPosition)
1505                 return false;
1506             continue;
1507         }
1508         if (childLocalRect.maxY() > childBox.height() || childLocalRect.maxX() > childBox.width())
1509             continue;
1510         if (childBox.backgroundIsKnownToBeOpaqueInRect(childLocalRect))
1511             return true;
1512         if (childBox.foregroundIsKnownToBeOpaqueInRect(childLocalRect, maxDepthToTest - 1))
1513             return true;
1514     }
1515     return false;
1516 }
1517
1518 bool RenderBox::computeBackgroundIsKnownToBeObscured(const LayoutPoint& paintOffset)
1519 {
1520     // Test to see if the children trivially obscure the background.
1521     // FIXME: This test can be much more comprehensive.
1522     if (!hasBackground())
1523         return false;
1524     // Table and root background painting is special.
1525     if (isTable() || isDocumentElementRenderer())
1526         return false;
1527
1528     LayoutRect backgroundRect;
1529     if (!getBackgroundPaintedExtent(paintOffset, backgroundRect))
1530         return false;
1531     return foregroundIsKnownToBeOpaqueInRect(backgroundRect, backgroundObscurationTestMaxDepth);
1532 }
1533
1534 bool RenderBox::backgroundHasOpaqueTopLayer() const
1535 {
1536     auto& fillLayer = style().backgroundLayers();
1537     if (fillLayer.clip() != BorderFillBox)
1538         return false;
1539
1540     // Clipped with local scrolling
1541     if (hasOverflowClip() && fillLayer.attachment() == LocalBackgroundAttachment)
1542         return false;
1543
1544     if (fillLayer.hasOpaqueImage(*this) && fillLayer.hasRepeatXY() && fillLayer.image()->canRender(this, style().effectiveZoom()))
1545         return true;
1546
1547     // If there is only one layer and no image, check whether the background color is opaque.
1548     if (!fillLayer.next() && !fillLayer.hasImage()) {
1549         Color bgColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
1550         if (bgColor.isOpaque())
1551             return true;
1552     }
1553
1554     return false;
1555 }
1556
1557 void RenderBox::paintMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1558 {
1559     if (!paintInfo.shouldPaintWithinRoot(*this) || style().visibility() != VISIBLE || paintInfo.phase != PaintPhaseMask || paintInfo.context().paintingDisabled())
1560         return;
1561
1562     LayoutRect paintRect = LayoutRect(paintOffset, size());
1563     adjustBorderBoxRectForPainting(paintRect);
1564     paintMaskImages(paintInfo, paintRect);
1565 }
1566
1567 void RenderBox::paintClippingMask(PaintInfo& paintInfo, const LayoutPoint& paintOffset)
1568 {
1569     if (!paintInfo.shouldPaintWithinRoot(*this) || style().visibility() != VISIBLE || paintInfo.phase != PaintPhaseClippingMask || paintInfo.context().paintingDisabled())
1570         return;
1571
1572     LayoutRect paintRect = LayoutRect(paintOffset, size());
1573     paintInfo.context().fillRect(snappedIntRect(paintRect), Color::black);
1574 }
1575
1576 void RenderBox::paintMaskImages(const PaintInfo& paintInfo, const LayoutRect& paintRect)
1577 {
1578     // Figure out if we need to push a transparency layer to render our mask.
1579     bool pushTransparencyLayer = false;
1580     bool compositedMask = hasLayer() && layer()->hasCompositedMask();
1581     bool flattenCompositingLayers = paintInfo.paintBehavior & PaintBehaviorFlattenCompositingLayers;
1582     CompositeOperator compositeOp = CompositeSourceOver;
1583
1584     bool allMaskImagesLoaded = true;
1585     
1586     if (!compositedMask || flattenCompositingLayers) {
1587         pushTransparencyLayer = true;
1588
1589         // Don't render a masked element until all the mask images have loaded, to prevent a flash of unmasked content.
1590         if (auto* maskBoxImage = style().maskBoxImage().image())
1591             allMaskImagesLoaded &= maskBoxImage->isLoaded();
1592
1593         allMaskImagesLoaded &= style().maskLayers().imagesAreLoaded();
1594
1595         paintInfo.context().setCompositeOperation(CompositeDestinationIn);
1596         paintInfo.context().beginTransparencyLayer(1);
1597         compositeOp = CompositeSourceOver;
1598     }
1599
1600     if (allMaskImagesLoaded) {
1601         paintFillLayers(paintInfo, Color(), style().maskLayers(), paintRect, BackgroundBleedNone, compositeOp);
1602         paintNinePieceImage(paintInfo.context(), paintRect, style(), style().maskBoxImage(), compositeOp);
1603     }
1604     
1605     if (pushTransparencyLayer)
1606         paintInfo.context().endTransparencyLayer();
1607 }
1608
1609 LayoutRect RenderBox::maskClipRect(const LayoutPoint& paintOffset)
1610 {
1611     const NinePieceImage& maskBoxImage = style().maskBoxImage();
1612     if (maskBoxImage.image()) {
1613         LayoutRect borderImageRect = borderBoxRect();
1614         
1615         // Apply outsets to the border box.
1616         borderImageRect.expand(style().maskBoxImageOutsets());
1617         return borderImageRect;
1618     }
1619     
1620     LayoutRect result;
1621     LayoutRect borderBox = borderBoxRect();
1622     for (auto* maskLayer = &style().maskLayers(); maskLayer; maskLayer = maskLayer->next()) {
1623         if (maskLayer->image()) {
1624             // Masks should never have fixed attachment, so it's OK for paintContainer to be null.
1625             result.unite(calculateBackgroundImageGeometry(nullptr, *maskLayer, paintOffset, borderBox).destRect());
1626         }
1627     }
1628     return result;
1629 }
1630
1631 void RenderBox::paintFillLayers(const PaintInfo& paintInfo, const Color& color, const FillLayer& fillLayer, const LayoutRect& rect,
1632     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderElement* backgroundObject)
1633 {
1634     Vector<const FillLayer*, 8> layers;
1635     bool shouldDrawBackgroundInSeparateBuffer = false;
1636
1637     for (auto* layer = &fillLayer; layer; layer = layer->next()) {
1638         layers.append(layer);
1639
1640         if (layer->blendMode() != BlendModeNormal)
1641             shouldDrawBackgroundInSeparateBuffer = true;
1642
1643         // Stop traversal when an opaque layer is encountered.
1644         // FIXME: It would be possible for the following occlusion culling test to be more aggressive
1645         // on layers with no repeat by testing whether the image covers the layout rect.
1646         // Testing that here would imply duplicating a lot of calculations that are currently done in
1647         // RenderBoxModelObject::paintFillLayerExtended. A more efficient solution might be to move
1648         // the layer recursion into paintFillLayerExtended, or to compute the layer geometry here
1649         // and pass it down.
1650
1651         // The clipOccludesNextLayers condition must be evaluated first to avoid short-circuiting.
1652         if (layer->clipOccludesNextLayers(layer == &fillLayer) && layer->hasOpaqueImage(*this) && layer->image()->canRender(this, style().effectiveZoom()) && layer->hasRepeatXY() && layer->blendMode() == BlendModeNormal)
1653             break;
1654     }
1655
1656     auto& context = paintInfo.context();
1657     auto baseBgColorUsage = BaseBackgroundColorUse;
1658
1659     if (shouldDrawBackgroundInSeparateBuffer) {
1660         paintFillLayer(paintInfo, color, *layers.last(), rect, bleedAvoidance, op, backgroundObject, BaseBackgroundColorOnly);
1661         baseBgColorUsage = BaseBackgroundColorSkip;
1662         context.beginTransparencyLayer(1);
1663     }
1664
1665     auto topLayer = layers.rend();
1666     for (auto it = layers.rbegin(); it != topLayer; ++it)
1667         paintFillLayer(paintInfo, color, **it, rect, bleedAvoidance, op, backgroundObject, baseBgColorUsage);
1668
1669     if (shouldDrawBackgroundInSeparateBuffer)
1670         context.endTransparencyLayer();
1671 }
1672
1673 void RenderBox::paintFillLayer(const PaintInfo& paintInfo, const Color& c, const FillLayer& fillLayer, const LayoutRect& rect,
1674     BackgroundBleedAvoidance bleedAvoidance, CompositeOperator op, RenderElement* backgroundObject, BaseBackgroundColorUsage baseBgColorUsage)
1675 {
1676     paintFillLayerExtended(paintInfo, c, fillLayer, rect, bleedAvoidance, nullptr, LayoutSize(), op, backgroundObject, baseBgColorUsage);
1677 }
1678
1679 static bool layersUseImage(WrappedImagePtr image, const FillLayer& layers)
1680 {
1681     for (auto* layer = &layers; layer; layer = layer->next()) {
1682         if (layer->image() && image == layer->image()->data())
1683             return true;
1684     }
1685     return false;
1686 }
1687
1688 void RenderBox::imageChanged(WrappedImagePtr image, const IntRect*)
1689 {
1690     if (!parent())
1691         return;
1692
1693     if ((style().borderImage().image() && style().borderImage().image()->data() == image) ||
1694         (style().maskBoxImage().image() && style().maskBoxImage().image()->data() == image)) {
1695         repaint();
1696         return;
1697     }
1698
1699     ShapeValue* shapeOutsideValue = style().shapeOutside();
1700     if (!view().frameView().isInRenderTreeLayout() && isFloating() && shapeOutsideValue && shapeOutsideValue->image() && shapeOutsideValue->image()->data() == image) {
1701         ShapeOutsideInfo::ensureInfo(*this).markShapeAsDirty();
1702         markShapeOutsideDependentsForLayout();
1703     }
1704
1705     bool didFullRepaint = repaintLayerRectsForImage(image, style().backgroundLayers(), true);
1706     if (!didFullRepaint)
1707         repaintLayerRectsForImage(image, style().maskLayers(), false);
1708
1709     if (!isComposited())
1710         return;
1711
1712     if (layer()->hasCompositedMask() && layersUseImage(image, style().maskLayers()))
1713         layer()->contentChanged(MaskImageChanged);
1714     if (layersUseImage(image, style().backgroundLayers()))
1715         layer()->contentChanged(BackgroundImageChanged);
1716 }
1717
1718 bool RenderBox::repaintLayerRectsForImage(WrappedImagePtr image, const FillLayer& layers, bool drawingBackground)
1719 {
1720     LayoutRect rendererRect;
1721     RenderBox* layerRenderer = nullptr;
1722
1723     for (auto* layer = &layers; layer; layer = layer->next()) {
1724         if (layer->image() && image == layer->image()->data() && layer->image()->canRender(this, style().effectiveZoom())) {
1725             // Now that we know this image is being used, compute the renderer and the rect if we haven't already.
1726             bool drawingRootBackground = drawingBackground && (isDocumentElementRenderer() || (isBody() && !document().documentElement()->renderer()->hasBackground()));
1727             if (!layerRenderer) {
1728                 if (drawingRootBackground) {
1729                     layerRenderer = &view();
1730
1731                     LayoutUnit rw = downcast<RenderView>(*layerRenderer).frameView().contentsWidth();
1732                     LayoutUnit rh = downcast<RenderView>(*layerRenderer).frameView().contentsHeight();
1733
1734                     rendererRect = LayoutRect(-layerRenderer->marginLeft(),
1735                         -layerRenderer->marginTop(),
1736                         std::max(layerRenderer->width() + layerRenderer->horizontalMarginExtent() + layerRenderer->borderLeft() + layerRenderer->borderRight(), rw),
1737                         std::max(layerRenderer->height() + layerRenderer->verticalMarginExtent() + layerRenderer->borderTop() + layerRenderer->borderBottom(), rh));
1738                 } else {
1739                     layerRenderer = this;
1740                     rendererRect = borderBoxRect();
1741                 }
1742             }
1743             // FIXME: Figure out how to pass absolute position to calculateBackgroundImageGeometry (for pixel snapping)
1744             BackgroundImageGeometry geometry = layerRenderer->calculateBackgroundImageGeometry(nullptr, *layer, LayoutPoint(), rendererRect);
1745             if (geometry.hasNonLocalGeometry()) {
1746                 // Rather than incur the costs of computing the paintContainer for renderers with fixed backgrounds
1747                 // in order to get the right destRect, just repaint the entire renderer.
1748                 layerRenderer->repaint();
1749                 return true;
1750             }
1751             
1752             LayoutRect rectToRepaint = geometry.destRect();
1753             bool shouldClipToLayer = true;
1754
1755             // If this is the root background layer, we may need to extend the repaintRect if the FrameView has an
1756             // extendedBackground. We should only extend the rect if it is already extending the full width or height
1757             // of the rendererRect.
1758             if (drawingRootBackground && view().frameView().hasExtendedBackgroundRectForPainting()) {
1759                 shouldClipToLayer = false;
1760                 IntRect extendedBackgroundRect = view().frameView().extendedBackgroundRectForPainting();
1761                 if (rectToRepaint.width() == rendererRect.width()) {
1762                     rectToRepaint.move(extendedBackgroundRect.x(), 0);
1763                     rectToRepaint.setWidth(extendedBackgroundRect.width());
1764                 }
1765                 if (rectToRepaint.height() == rendererRect.height()) {
1766                     rectToRepaint.move(0, extendedBackgroundRect.y());
1767                     rectToRepaint.setHeight(extendedBackgroundRect.height());
1768                 }
1769             }
1770
1771             layerRenderer->repaintRectangle(rectToRepaint, shouldClipToLayer);
1772             if (geometry.destRect() == rendererRect)
1773                 return true;
1774         }
1775     }
1776     return false;
1777 }
1778
1779 bool RenderBox::pushContentsClip(PaintInfo& paintInfo, const LayoutPoint& accumulatedOffset)
1780 {
1781     if (paintInfo.phase == PaintPhaseBlockBackground || paintInfo.phase == PaintPhaseSelfOutline || paintInfo.phase == PaintPhaseMask)
1782         return false;
1783         
1784     bool isControlClip = hasControlClip();
1785     bool isOverflowClip = hasOverflowClip() && !layer()->isSelfPaintingLayer();
1786     
1787     if (!isControlClip && !isOverflowClip)
1788         return false;
1789     
1790     if (paintInfo.phase == PaintPhaseOutline)
1791         paintInfo.phase = PaintPhaseChildOutlines;
1792     else if (paintInfo.phase == PaintPhaseChildBlockBackground) {
1793         paintInfo.phase = PaintPhaseBlockBackground;
1794         paintObject(paintInfo, accumulatedOffset);
1795         paintInfo.phase = PaintPhaseChildBlockBackgrounds;
1796     }
1797     float deviceScaleFactor = document().deviceScaleFactor();
1798     FloatRect clipRect = snapRectToDevicePixels((isControlClip ? controlClipRect(accumulatedOffset) : overflowClipRect(accumulatedOffset, currentRenderNamedFlowFragment(), IgnoreOverlayScrollbarSize, paintInfo.phase)), deviceScaleFactor);
1799     paintInfo.context().save();
1800     if (style().hasBorderRadius())
1801         paintInfo.context().clipRoundedRect(style().getRoundedInnerBorderFor(LayoutRect(accumulatedOffset, size())).pixelSnappedRoundedRectForPainting(deviceScaleFactor));
1802     paintInfo.context().clip(clipRect);
1803     return true;
1804 }
1805
1806 void RenderBox::popContentsClip(PaintInfo& paintInfo, PaintPhase originalPhase, const LayoutPoint& accumulatedOffset)
1807 {
1808     ASSERT(hasControlClip() || (hasOverflowClip() && !layer()->isSelfPaintingLayer()));
1809
1810     paintInfo.context().restore();
1811     if (originalPhase == PaintPhaseOutline) {
1812         paintInfo.phase = PaintPhaseSelfOutline;
1813         paintObject(paintInfo, accumulatedOffset);
1814         paintInfo.phase = originalPhase;
1815     } else if (originalPhase == PaintPhaseChildBlockBackground)
1816         paintInfo.phase = originalPhase;
1817 }
1818
1819 LayoutRect RenderBox::overflowClipRect(const LayoutPoint& location, RenderRegion* region, OverlayScrollbarSizeRelevancy relevancy, PaintPhase)
1820 {
1821     // FIXME: When overflow-clip (CSS3) is implemented, we'll obtain the property
1822     // here.
1823     LayoutRect clipRect = borderBoxRectInRegion(region);
1824     clipRect.setLocation(location + clipRect.location() + LayoutSize(borderLeft(), borderTop()));
1825     clipRect.setSize(clipRect.size() - LayoutSize(borderLeft() + borderRight(), borderTop() + borderBottom()));
1826
1827     // Subtract out scrollbars if we have them.
1828     if (layer()) {
1829         if (shouldPlaceBlockDirectionScrollbarOnLeft())
1830             clipRect.move(layer()->verticalScrollbarWidth(relevancy), 0);
1831         clipRect.contract(layer()->verticalScrollbarWidth(relevancy), layer()->horizontalScrollbarHeight(relevancy));
1832     }
1833
1834     return clipRect;
1835 }
1836
1837 LayoutRect RenderBox::clipRect(const LayoutPoint& location, RenderRegion* region)
1838 {
1839     LayoutRect borderBoxRect = borderBoxRectInRegion(region);
1840     LayoutRect clipRect = LayoutRect(borderBoxRect.location() + location, borderBoxRect.size());
1841
1842     if (!style().clipLeft().isAuto()) {
1843         LayoutUnit c = valueForLength(style().clipLeft(), borderBoxRect.width());
1844         clipRect.move(c, 0);
1845         clipRect.contract(c, 0);
1846     }
1847
1848     // We don't use the region-specific border box's width and height since clip offsets are (stupidly) specified
1849     // from the left and top edges. Therefore it's better to avoid constraining to smaller widths and heights.
1850
1851     if (!style().clipRight().isAuto())
1852         clipRect.contract(width() - valueForLength(style().clipRight(), width()), 0);
1853
1854     if (!style().clipTop().isAuto()) {
1855         LayoutUnit c = valueForLength(style().clipTop(), borderBoxRect.height());
1856         clipRect.move(0, c);
1857         clipRect.contract(0, c);
1858     }
1859
1860     if (!style().clipBottom().isAuto())
1861         clipRect.contract(0, height() - valueForLength(style().clipBottom(), height()));
1862
1863     return clipRect;
1864 }
1865
1866 LayoutUnit RenderBox::shrinkLogicalWidthToAvoidFloats(LayoutUnit childMarginStart, LayoutUnit childMarginEnd, const RenderBlock& cb, RenderRegion* region) const
1867 {    
1868     RenderRegion* containingBlockRegion = nullptr;
1869     LayoutUnit logicalTopPosition = logicalTop();
1870     if (region) {
1871         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1872         logicalTopPosition = std::max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1873         containingBlockRegion = cb.clampToStartAndEndRegions(region);
1874     }
1875
1876     LayoutUnit logicalHeight = cb.logicalHeightForChild(*this);
1877     LayoutUnit result = cb.availableLogicalWidthForLineInRegion(logicalTopPosition, DoNotIndentText, containingBlockRegion, logicalHeight) - childMarginStart - childMarginEnd;
1878
1879     // We need to see if margins on either the start side or the end side can contain the floats in question. If they can,
1880     // then just using the line width is inaccurate. In the case where a float completely fits, we don't need to use the line
1881     // offset at all, but can instead push all the way to the content edge of the containing block. In the case where the float
1882     // doesn't fit, we can use the line offset, but we need to grow it by the margin to reflect the fact that the margin was
1883     // "consumed" by the float. Negative margins aren't consumed by the float, and so we ignore them.
1884     if (childMarginStart > 0) {
1885         LayoutUnit startContentSide = cb.startOffsetForContent(containingBlockRegion);
1886         LayoutUnit startContentSideWithMargin = startContentSide + childMarginStart;
1887         LayoutUnit startOffset = cb.startOffsetForLineInRegion(logicalTopPosition, DoNotIndentText, containingBlockRegion, logicalHeight);
1888         if (startOffset > startContentSideWithMargin)
1889             result += childMarginStart;
1890         else
1891             result += startOffset - startContentSide;
1892     }
1893     
1894     if (childMarginEnd > 0) {
1895         LayoutUnit endContentSide = cb.endOffsetForContent(containingBlockRegion);
1896         LayoutUnit endContentSideWithMargin = endContentSide + childMarginEnd;
1897         LayoutUnit endOffset = cb.endOffsetForLineInRegion(logicalTopPosition, DoNotIndentText, containingBlockRegion, logicalHeight);
1898         if (endOffset > endContentSideWithMargin)
1899             result += childMarginEnd;
1900         else
1901             result += endOffset - endContentSide;
1902     }
1903
1904     return result;
1905 }
1906
1907 LayoutUnit RenderBox::containingBlockLogicalWidthForContent() const
1908 {
1909     if (hasOverrideContainingBlockLogicalWidth()) {
1910         if (auto overrideLogicalWidth = overrideContainingBlockContentLogicalWidth())
1911             return overrideLogicalWidth.value();
1912     }
1913
1914     if (RenderBlock* cb = containingBlock())
1915         return cb->availableLogicalWidth();
1916     return LayoutUnit();
1917 }
1918
1919 LayoutUnit RenderBox::containingBlockLogicalHeightForContent(AvailableLogicalHeightType heightType) const
1920 {
1921     if (hasOverrideContainingBlockLogicalHeight()) {
1922         if (auto overrideLogicalHeight = overrideContainingBlockContentLogicalHeight())
1923             return overrideLogicalHeight.value();
1924     }
1925
1926     if (RenderBlock* cb = containingBlock())
1927         return cb->availableLogicalHeight(heightType);
1928     return LayoutUnit();
1929 }
1930
1931 LayoutUnit RenderBox::containingBlockLogicalWidthForContentInRegion(RenderRegion* region) const
1932 {
1933     if (!region)
1934         return containingBlockLogicalWidthForContent();
1935
1936     RenderBlock* cb = containingBlock();
1937     RenderRegion* containingBlockRegion = cb->clampToStartAndEndRegions(region);
1938     // FIXME: It's unclear if a region's content should use the containing block's override logical width.
1939     // If it should, the following line should call containingBlockLogicalWidthForContent.
1940     LayoutUnit result = cb->availableLogicalWidth();
1941     RenderBoxRegionInfo* boxInfo = cb->renderBoxRegionInfo(containingBlockRegion);
1942     if (!boxInfo)
1943         return result;
1944     return std::max<LayoutUnit>(0, result - (cb->logicalWidth() - boxInfo->logicalWidth()));
1945 }
1946
1947 LayoutUnit RenderBox::containingBlockAvailableLineWidthInRegion(RenderRegion* region) const
1948 {
1949     RenderBlock* cb = containingBlock();
1950     RenderRegion* containingBlockRegion = nullptr;
1951     LayoutUnit logicalTopPosition = logicalTop();
1952     if (region) {
1953         LayoutUnit offsetFromLogicalTopOfRegion = region ? region->logicalTopForFlowThreadContent() - offsetFromLogicalTopOfFirstPage() : LayoutUnit();
1954         logicalTopPosition = std::max(logicalTopPosition, logicalTopPosition + offsetFromLogicalTopOfRegion);
1955         containingBlockRegion = cb->clampToStartAndEndRegions(region);
1956     }
1957     return cb->availableLogicalWidthForLineInRegion(logicalTopPosition, DoNotIndentText, containingBlockRegion, availableLogicalHeight(IncludeMarginBorderPadding));
1958 }
1959
1960 LayoutUnit RenderBox::perpendicularContainingBlockLogicalHeight() const
1961 {
1962     if (hasOverrideContainingBlockLogicalHeight()) {
1963         if (auto overrideLogicalHeight = overrideContainingBlockContentLogicalHeight())
1964             return overrideLogicalHeight.value();
1965     }
1966
1967     RenderBlock* cb = containingBlock();
1968     if (cb->hasOverrideLogicalContentHeight())
1969         return cb->overrideLogicalContentHeight();
1970
1971     const RenderStyle& containingBlockStyle = cb->style();
1972     Length logicalHeightLength = containingBlockStyle.logicalHeight();
1973
1974     // FIXME: For now just support fixed heights.  Eventually should support percentage heights as well.
1975     if (!logicalHeightLength.isFixed()) {
1976         LayoutUnit fillFallbackExtent = containingBlockStyle.isHorizontalWritingMode() ? view().frameView().visibleHeight() : view().frameView().visibleWidth();
1977         LayoutUnit fillAvailableExtent = containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding);
1978         view().addPercentHeightDescendant(const_cast<RenderBox&>(*this));
1979         // FIXME: https://bugs.webkit.org/show_bug.cgi?id=158286 We also need to perform the same percentHeightDescendant treatment to the element which dictates the return value for containingBlock()->availableLogicalHeight() above.
1980         return std::min(fillAvailableExtent, fillFallbackExtent);
1981     }
1982
1983     // Use the content box logical height as specified by the style.
1984     return cb->adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit(logicalHeightLength.value()));
1985 }
1986
1987 void RenderBox::mapLocalToContainer(const RenderLayerModelObject* repaintContainer, TransformState& transformState, MapCoordinatesFlags mode, bool* wasFixed) const
1988 {
1989     if (repaintContainer == this)
1990         return;
1991
1992     if (view().layoutStateEnabled() && !repaintContainer) {
1993         LayoutState* layoutState = view().layoutState();
1994         LayoutSize offset = layoutState->m_paintOffset + locationOffset();
1995         if (style().hasInFlowPosition() && layer())
1996             offset += layer()->offsetForInFlowPosition();
1997         transformState.move(offset);
1998         return;
1999     }
2000
2001     bool containerSkipped;
2002     RenderElement* container = this->container(repaintContainer, containerSkipped);
2003     if (!container)
2004         return;
2005
2006     bool isFixedPos = style().position() == FixedPosition;
2007     // If this box has a transform, it acts as a fixed position container for fixed descendants,
2008     // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
2009     if (hasTransform() && !isFixedPos)
2010         mode &= ~IsFixed;
2011     else if (isFixedPos)
2012         mode |= IsFixed;
2013
2014     if (wasFixed)
2015         *wasFixed = mode & IsFixed;
2016     
2017     LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(transformState.mappedPoint()));
2018     
2019     bool preserve3D = mode & UseTransforms && (container->style().preserves3D() || style().preserves3D());
2020     if (mode & UseTransforms && shouldUseTransformFromContainer(container)) {
2021         TransformationMatrix t;
2022         getTransformFromContainer(container, containerOffset, t);
2023         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2024     } else
2025         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2026
2027     if (containerSkipped) {
2028         // There can't be a transform between repaintContainer and o, because transforms create containers, so it should be safe
2029         // to just subtract the delta between the repaintContainer and o.
2030         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container);
2031         transformState.move(-containerOffset.width(), -containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2032         return;
2033     }
2034
2035     mode &= ~ApplyContainerFlip;
2036
2037     // For fixed positioned elements inside out-of-flow named flows, we do not want to
2038     // map their position further to regions based on their coordinates inside the named flows.
2039     if (!container->isOutOfFlowRenderFlowThread() || !fixedPositionedWithNamedFlowContainingBlock())
2040         container->mapLocalToContainer(repaintContainer, transformState, mode, wasFixed);
2041     else
2042         container->mapLocalToContainer(downcast<RenderLayerModelObject>(container), transformState, mode, wasFixed);
2043 }
2044
2045 const RenderObject* RenderBox::pushMappingToContainer(const RenderLayerModelObject* ancestorToStopAt, RenderGeometryMap& geometryMap) const
2046 {
2047     ASSERT(ancestorToStopAt != this);
2048
2049     bool ancestorSkipped;
2050     RenderElement* container = this->container(ancestorToStopAt, ancestorSkipped);
2051     if (!container)
2052         return nullptr;
2053
2054     bool isFixedPos = style().position() == FixedPosition;
2055     LayoutSize adjustmentForSkippedAncestor;
2056     if (ancestorSkipped) {
2057         // There can't be a transform between repaintContainer and container, because transforms create containers, so it should be safe
2058         // to just subtract the delta between the ancestor and container.
2059         adjustmentForSkippedAncestor = -ancestorToStopAt->offsetFromAncestorContainer(*container);
2060     }
2061
2062     bool offsetDependsOnPoint = false;
2063     LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint(), &offsetDependsOnPoint);
2064
2065     bool preserve3D = container->style().preserves3D() || style().preserves3D();
2066     if (shouldUseTransformFromContainer(container) && (geometryMap.mapCoordinatesFlags() & UseTransforms)) {
2067         TransformationMatrix t;
2068         getTransformFromContainer(container, containerOffset, t);
2069         t.translateRight(adjustmentForSkippedAncestor.width(), adjustmentForSkippedAncestor.height());
2070         
2071         geometryMap.push(this, t, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform());
2072     } else {
2073         containerOffset += adjustmentForSkippedAncestor;
2074         geometryMap.push(this, containerOffset, preserve3D, offsetDependsOnPoint, isFixedPos, hasTransform());
2075     }
2076     
2077     return ancestorSkipped ? ancestorToStopAt : container;
2078 }
2079
2080 void RenderBox::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
2081 {
2082     bool isFixedPos = style().position() == FixedPosition;
2083     if (hasTransform() && !isFixedPos) {
2084         // If this box has a transform, it acts as a fixed position container for fixed descendants,
2085         // and may itself also be fixed position. So propagate 'fixed' up only if this box is fixed position.
2086         mode &= ~IsFixed;
2087     } else if (isFixedPos)
2088         mode |= IsFixed;
2089
2090     RenderBoxModelObject::mapAbsoluteToLocalPoint(mode, transformState);
2091 }
2092
2093 LayoutSize RenderBox::offsetFromContainer(RenderElement& renderer, const LayoutPoint&, bool* offsetDependsOnPoint) const
2094 {
2095     // A region "has" boxes inside it without being their container. 
2096     ASSERT(&renderer == container() || is<RenderRegion>(renderer));
2097
2098     LayoutSize offset;    
2099     if (isInFlowPositioned())
2100         offset += offsetForInFlowPosition();
2101
2102     if (!isInline() || isReplaced())
2103         offset += topLeftLocationOffset();
2104
2105     if (is<RenderBox>(renderer))
2106         offset -= toLayoutSize(downcast<RenderBox>(renderer).scrollPosition());
2107
2108     if (style().position() == AbsolutePosition && renderer.isInFlowPositioned() && is<RenderInline>(renderer))
2109         offset += downcast<RenderInline>(renderer).offsetForInFlowPositionedInline(this);
2110
2111     if (offsetDependsOnPoint)
2112         *offsetDependsOnPoint |= is<RenderFlowThread>(renderer);
2113
2114     return offset;
2115 }
2116
2117 std::unique_ptr<InlineElementBox> RenderBox::createInlineBox()
2118 {
2119     return std::make_unique<InlineElementBox>(*this);
2120 }
2121
2122 void RenderBox::dirtyLineBoxes(bool fullLayout)
2123 {
2124     if (!m_inlineBoxWrapper)
2125         return;
2126     
2127     if (fullLayout) {
2128         delete m_inlineBoxWrapper;
2129         m_inlineBoxWrapper = nullptr;
2130     } else
2131         m_inlineBoxWrapper->dirtyLineBoxes();
2132 }
2133
2134 void RenderBox::positionLineBox(InlineElementBox& box)
2135 {
2136     if (isOutOfFlowPositioned()) {
2137         // Cache the x position only if we were an INLINE type originally.
2138         bool wasInline = style().isOriginalDisplayInlineType();
2139         if (wasInline) {
2140             // The value is cached in the xPos of the box.  We only need this value if
2141             // our object was inline originally, since otherwise it would have ended up underneath
2142             // the inlines.
2143             RootInlineBox& rootBox = box.root();
2144             rootBox.blockFlow().setStaticInlinePositionForChild(*this, rootBox.lineTopWithLeading(), LayoutUnit::fromFloatRound(box.logicalLeft()));
2145             if (style().hasStaticInlinePosition(box.isHorizontal()))
2146                 setChildNeedsLayout(MarkOnlyThis); // Just mark the positioned object as needing layout, so it will update its position properly.
2147         } else {
2148             // Our object was a block originally, so we make our normal flow position be
2149             // just below the line box (as though all the inlines that came before us got
2150             // wrapped in an anonymous block, which is what would have happened had we been
2151             // in flow).  This value was cached in the y() of the box.
2152             layer()->setStaticBlockPosition(box.logicalTop());
2153             if (style().hasStaticBlockPosition(box.isHorizontal()))
2154                 setChildNeedsLayout(MarkOnlyThis); // Just mark the positioned object as needing layout, so it will update its position properly.
2155         }
2156         return;
2157     }
2158
2159     if (isReplaced()) {
2160         setLocation(LayoutPoint(box.topLeft()));
2161         setInlineBoxWrapper(&box);
2162     }
2163 }
2164
2165 void RenderBox::deleteLineBoxWrapper()
2166 {
2167     if (!m_inlineBoxWrapper)
2168         return;
2169     
2170     if (!renderTreeBeingDestroyed())
2171         m_inlineBoxWrapper->removeFromParent();
2172     delete m_inlineBoxWrapper;
2173     m_inlineBoxWrapper = nullptr;
2174 }
2175
2176 LayoutRect RenderBox::clippedOverflowRectForRepaint(const RenderLayerModelObject* repaintContainer) const
2177 {
2178     if (style().visibility() != VISIBLE && !enclosingLayer()->hasVisibleContent())
2179         return LayoutRect();
2180     LayoutRect r = visualOverflowRect();
2181     // FIXME: layoutDelta needs to be applied in parts before/after transforms and
2182     // repaint containers. https://bugs.webkit.org/show_bug.cgi?id=23308
2183     r.move(view().layoutDelta());
2184     return computeRectForRepaint(r, repaintContainer);
2185 }
2186
2187 bool RenderBox::shouldApplyClipAndScrollPositionForRepaint(const RenderLayerModelObject* repaintContainer) const
2188 {
2189 #if PLATFORM(IOS)
2190     if (!repaintContainer || repaintContainer != this)
2191         return true;
2192
2193     return !hasLayer() || !layer()->usesCompositedScrolling();
2194 #else
2195     UNUSED_PARAM(repaintContainer);
2196     return true;
2197 #endif
2198 }
2199
2200 LayoutRect RenderBox::computeRectForRepaint(const LayoutRect& rect, const RenderLayerModelObject* repaintContainer, RepaintContext context) const
2201 {
2202     // The rect we compute at each step is shifted by our x/y offset in the parent container's coordinate space.
2203     // Only when we cross a writing mode boundary will we have to possibly flipForWritingMode (to convert into a more appropriate
2204     // offset corner for the enclosing container).  This allows for a fully RL or BT document to repaint
2205     // properly even during layout, since the rect remains flipped all the way until the end.
2206     //
2207     // RenderView::computeRectForRepaint then converts the rect to physical coordinates.  We also convert to
2208     // physical when we hit a repaintContainer boundary.  Therefore the final rect returned is always in the
2209     // physical coordinate space of the repaintContainer.
2210     LayoutRect adjustedRect = rect;
2211     const RenderStyle& styleToUse = style();
2212     // LayoutState is only valid for root-relative, non-fixed position repainting
2213     if (view().layoutStateEnabled() && !repaintContainer && styleToUse.position() != FixedPosition) {
2214         LayoutState* layoutState = view().layoutState();
2215
2216         if (layer() && layer()->transform())
2217             adjustedRect = LayoutRect(encloseRectToDevicePixels(layer()->transform()->mapRect(adjustedRect), document().deviceScaleFactor()));
2218
2219         // We can't trust the bits on RenderObject, because this might be called while re-resolving style.
2220         if (styleToUse.hasInFlowPosition() && layer())
2221             adjustedRect.move(layer()->offsetForInFlowPosition());
2222
2223         adjustedRect.moveBy(location());
2224         adjustedRect.move(layoutState->m_paintOffset);
2225         if (layoutState->m_clipped)
2226             adjustedRect.intersect(layoutState->m_clipRect);
2227         return adjustedRect;
2228     }
2229
2230     if (hasReflection())
2231         adjustedRect.unite(reflectedRect(adjustedRect));
2232
2233     if (repaintContainer == this) {
2234         if (repaintContainer->style().isFlippedBlocksWritingMode())
2235             flipForWritingMode(adjustedRect);
2236         return adjustedRect;
2237     }
2238
2239     bool repaintContainerIsSkipped;
2240     auto* container = this->container(repaintContainer, repaintContainerIsSkipped);
2241     if (!container)
2242         return adjustedRect;
2243     
2244     // This code isn't necessary for in-flow RenderFlowThreads.
2245     // Don't add the location of the region in the flow thread for absolute positioned
2246     // elements because their absolute position already pushes them down through
2247     // the regions so adding this here and then adding the topLeft again would cause
2248     // us to add the height twice.
2249     // The same logic applies for elements flowed directly into the flow thread. Their topLeft member
2250     // will already contain the portion rect of the region.
2251     EPosition position = styleToUse.position();
2252     if (container->isOutOfFlowRenderFlowThread() && position != AbsolutePosition && containingBlock() != flowThreadContainingBlock()) {
2253         RenderRegion* firstRegion = nullptr;
2254         RenderRegion* lastRegion = nullptr;
2255         if (downcast<RenderFlowThread>(*container).getRegionRangeForBox(this, firstRegion, lastRegion))
2256             adjustedRect.moveBy(firstRegion->flowThreadPortionRect().location());
2257     }
2258
2259     if (isWritingModeRoot()) {
2260         if (!isOutOfFlowPositioned() || !context.m_dirtyRectIsFlipped) {
2261             flipForWritingMode(adjustedRect);
2262             context.m_dirtyRectIsFlipped = true;
2263         }
2264     }
2265
2266     LayoutSize locationOffset = this->locationOffset();
2267     // FIXME: This is needed as long as RenderWidget snaps to integral size/position.
2268     if (isRenderReplaced() && isWidget()) {
2269         LayoutSize flooredLocationOffset = toIntSize(flooredIntPoint(locationOffset));
2270         adjustedRect.expand(locationOffset - flooredLocationOffset);
2271         locationOffset = flooredLocationOffset;
2272     }
2273
2274     if (is<RenderMultiColumnFlowThread>(this)) {
2275         // We won't normally run this code. Only when the repaintContainer is null (i.e., we're trying
2276         // to get the rect in view coordinates) will we come in here, since normally repaintContainer
2277         // will be set and we'll stop at the flow thread. This case is mainly hit by the check for whether
2278         // or not images should animate.
2279         // FIXME: Just as with offsetFromContainer, we aren't really handling objects that span
2280         // multiple columns properly.
2281         LayoutPoint physicalPoint(flipForWritingMode(adjustedRect.location()));
2282         if (auto* region = downcast<RenderMultiColumnFlowThread>(*this).physicalTranslationFromFlowToRegion((physicalPoint))) {
2283             adjustedRect.setLocation(region->flipForWritingMode(physicalPoint));
2284             return region->computeRectForRepaint(adjustedRect, repaintContainer, context);
2285         }
2286     }
2287
2288     LayoutPoint topLeft = adjustedRect.location();
2289     topLeft.move(locationOffset);
2290
2291     // We are now in our parent container's coordinate space. Apply our transform to obtain a bounding box
2292     // in the parent's coordinate space that encloses us.
2293     if (hasLayer() && layer()->transform()) {
2294         context.m_hasPositionFixedDescendant = position == FixedPosition;
2295         adjustedRect = LayoutRect(encloseRectToDevicePixels(layer()->transform()->mapRect(adjustedRect), document().deviceScaleFactor()));
2296         topLeft = adjustedRect.location();
2297         topLeft.move(locationOffset);
2298     } else if (position == FixedPosition)
2299         context.m_hasPositionFixedDescendant = true;
2300
2301     if (position == AbsolutePosition && container->isInFlowPositioned() && is<RenderInline>(*container))
2302         topLeft += downcast<RenderInline>(*container).offsetForInFlowPositionedInline(this);
2303     else if (styleToUse.hasInFlowPosition() && layer()) {
2304         // Apply the relative position offset when invalidating a rectangle.  The layer
2305         // is translated, but the render box isn't, so we need to do this to get the
2306         // right dirty rect.  Since this is called from RenderObject::setStyle, the relative position
2307         // flag on the RenderObject has been cleared, so use the one on the style().
2308         topLeft += layer()->offsetForInFlowPosition();
2309     }
2310
2311     // FIXME: We ignore the lightweight clipping rect that controls use, since if |o| is in mid-layout,
2312     // its controlClipRect will be wrong. For overflow clip we use the values cached by the layer.
2313     adjustedRect.setLocation(topLeft);
2314     if (container->hasOverflowClip()) {
2315         RenderBox& containerBox = downcast<RenderBox>(*container);
2316         if (containerBox.shouldApplyClipAndScrollPositionForRepaint(repaintContainer)) {
2317             containerBox.applyCachedClipAndScrollPositionForRepaint(adjustedRect);
2318             if (adjustedRect.isEmpty())
2319                 return adjustedRect;
2320         }
2321     }
2322
2323     if (repaintContainerIsSkipped) {
2324         // If the repaintContainer is below container, then we need to map the rect into repaintContainer's coordinates.
2325         LayoutSize containerOffset = repaintContainer->offsetFromAncestorContainer(*container);
2326         adjustedRect.move(-containerOffset);
2327         return adjustedRect;
2328     }
2329     return container->computeRectForRepaint(adjustedRect, repaintContainer, context);
2330 }
2331
2332 void RenderBox::repaintDuringLayoutIfMoved(const LayoutRect& oldRect)
2333 {
2334     if (oldRect.location() != m_frameRect.location()) {
2335         LayoutRect newRect = m_frameRect;
2336         // The child moved.  Invalidate the object's old and new positions.  We have to do this
2337         // since the object may not have gotten a layout.
2338         m_frameRect = oldRect;
2339         repaint();
2340         repaintOverhangingFloats(true);
2341         m_frameRect = newRect;
2342         repaint();
2343         repaintOverhangingFloats(true);
2344     }
2345 }
2346
2347 void RenderBox::repaintOverhangingFloats(bool)
2348 {
2349 }
2350
2351 void RenderBox::updateLogicalWidth()
2352 {
2353     LogicalExtentComputedValues computedValues;
2354     computeLogicalWidthInRegion(computedValues);
2355
2356     setLogicalWidth(computedValues.m_extent);
2357     setLogicalLeft(computedValues.m_position);
2358     setMarginStart(computedValues.m_margins.m_start);
2359     setMarginEnd(computedValues.m_margins.m_end);
2360 }
2361
2362 void RenderBox::computeLogicalWidthInRegion(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
2363 {
2364     computedValues.m_extent = logicalWidth();
2365     computedValues.m_position = logicalLeft();
2366     computedValues.m_margins.m_start = marginStart();
2367     computedValues.m_margins.m_end = marginEnd();
2368
2369     if (isOutOfFlowPositioned()) {
2370         // FIXME: This calculation is not patched for block-flow yet.
2371         // https://bugs.webkit.org/show_bug.cgi?id=46500
2372         computePositionedLogicalWidth(computedValues, region);
2373         return;
2374     }
2375
2376     // If layout is limited to a subtree, the subtree root's logical width does not change.
2377     if (element() && !view().frameView().layoutPending() && view().frameView().layoutRoot() == this)
2378         return;
2379
2380     // The parent box is flexing us, so it has increased or decreased our
2381     // width.  Use the width from the style context.
2382     // FIXME: Account for block-flow in flexible boxes.
2383     // https://bugs.webkit.org/show_bug.cgi?id=46418
2384     if (hasOverrideLogicalContentWidth() && (isRubyRun() || style().borderFit() == BorderFitLines || (parent()->isFlexibleBoxIncludingDeprecated()))) {
2385         computedValues.m_extent = overrideLogicalContentWidth() + borderAndPaddingLogicalWidth();
2386         return;
2387     }
2388
2389     // FIXME: Account for block-flow in flexible boxes.
2390     // https://bugs.webkit.org/show_bug.cgi?id=46418
2391     bool inVerticalBox = parent()->isDeprecatedFlexibleBox() && (parent()->style().boxOrient() == VERTICAL);
2392     bool stretching = (parent()->style().boxAlign() == BSTRETCH);
2393     // FIXME: Stretching is the only reason why we don't want the box to be treated as a replaced element, so we could perhaps
2394     // refactor all this logic, not only for flex and grid since alignment is intended to be applied to any block.
2395     bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inVerticalBox || !stretching);
2396     treatAsReplaced = treatAsReplaced && (!isGridItem() || !hasStretchedLogicalWidth());
2397
2398     const RenderStyle& styleToUse = style();
2399     Length logicalWidthLength = treatAsReplaced ? Length(computeReplacedLogicalWidth(), Fixed) : styleToUse.logicalWidth();
2400
2401     RenderBlock& cb = *containingBlock();
2402     LayoutUnit containerLogicalWidth = std::max<LayoutUnit>(0, containingBlockLogicalWidthForContentInRegion(region));
2403     bool hasPerpendicularContainingBlock = cb.isHorizontalWritingMode() != isHorizontalWritingMode();
2404
2405     if (isInline() && !isInlineBlockOrInlineTable()) {
2406         // just calculate margins
2407         computedValues.m_margins.m_start = minimumValueForLength(styleToUse.marginStart(), containerLogicalWidth);
2408         computedValues.m_margins.m_end = minimumValueForLength(styleToUse.marginEnd(), containerLogicalWidth);
2409         if (treatAsReplaced)
2410             computedValues.m_extent = std::max<LayoutUnit>(floatValueForLength(logicalWidthLength, 0) + borderAndPaddingLogicalWidth(), minPreferredLogicalWidth());
2411         return;
2412     }
2413
2414     LayoutUnit containerWidthInInlineDirection = containerLogicalWidth;
2415     if (hasPerpendicularContainingBlock)
2416         containerWidthInInlineDirection = perpendicularContainingBlockLogicalHeight();
2417
2418     // Width calculations
2419     if (treatAsReplaced) {
2420         computedValues.m_extent = logicalWidthLength.value() + borderAndPaddingLogicalWidth();
2421     } else {
2422         LayoutUnit preferredWidth = computeLogicalWidthInRegionUsing(MainOrPreferredSize, styleToUse.logicalWidth(), containerWidthInInlineDirection, cb, region);
2423         computedValues.m_extent = constrainLogicalWidthInRegionByMinMax(preferredWidth, containerWidthInInlineDirection, cb, region);
2424     }
2425
2426     // Margin calculations.
2427     if (hasPerpendicularContainingBlock || isFloating() || isInline()) {
2428         computedValues.m_margins.m_start = minimumValueForLength(styleToUse.marginStart(), containerLogicalWidth);
2429         computedValues.m_margins.m_end = minimumValueForLength(styleToUse.marginEnd(), containerLogicalWidth);
2430     } else {
2431         LayoutUnit containerLogicalWidthForAutoMargins = containerLogicalWidth;
2432         if (avoidsFloats() && cb.containsFloats())
2433             containerLogicalWidthForAutoMargins = containingBlockAvailableLineWidthInRegion(region);
2434         bool hasInvertedDirection = cb.style().isLeftToRightDirection() != style().isLeftToRightDirection();
2435         computeInlineDirectionMargins(cb, containerLogicalWidthForAutoMargins, computedValues.m_extent,
2436             hasInvertedDirection ? computedValues.m_margins.m_end : computedValues.m_margins.m_start,
2437             hasInvertedDirection ? computedValues.m_margins.m_start : computedValues.m_margins.m_end);
2438     }
2439     
2440     if (!hasPerpendicularContainingBlock && containerLogicalWidth && containerLogicalWidth != (computedValues.m_extent + computedValues.m_margins.m_start + computedValues.m_margins.m_end)
2441         && !isFloating() && !isInline() && !cb.isFlexibleBoxIncludingDeprecated()
2442 #if ENABLE(MATHML)
2443         // RenderMathMLBlocks take the size of their content so we must not adjust the margin to fill the container size.
2444         && !cb.isRenderMathMLBlock()
2445 #endif
2446         && !cb.isRenderGrid()
2447         ) {
2448         LayoutUnit newMargin = containerLogicalWidth - computedValues.m_extent - cb.marginStartForChild(*this);
2449         bool hasInvertedDirection = cb.style().isLeftToRightDirection() != style().isLeftToRightDirection();
2450         if (hasInvertedDirection)
2451             computedValues.m_margins.m_start = newMargin;
2452         else
2453             computedValues.m_margins.m_end = newMargin;
2454     }
2455 }
2456
2457 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth) const
2458 {
2459     LayoutUnit marginStart = 0;
2460     LayoutUnit marginEnd = 0;
2461     return fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2462 }
2463
2464 LayoutUnit RenderBox::fillAvailableMeasure(LayoutUnit availableLogicalWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2465 {
2466     marginStart = minimumValueForLength(style().marginStart(), availableLogicalWidth);
2467     marginEnd = minimumValueForLength(style().marginEnd(), availableLogicalWidth);
2468     return availableLogicalWidth - marginStart - marginEnd;
2469 }
2470
2471 LayoutUnit RenderBox::computeIntrinsicLogicalWidthUsing(Length logicalWidthLength, LayoutUnit availableLogicalWidth, LayoutUnit borderAndPadding) const
2472 {
2473     if (logicalWidthLength.type() == FillAvailable)
2474         return std::max(borderAndPadding, fillAvailableMeasure(availableLogicalWidth));
2475
2476     LayoutUnit minLogicalWidth = 0;
2477     LayoutUnit maxLogicalWidth = 0;
2478     computeIntrinsicLogicalWidths(minLogicalWidth, maxLogicalWidth);
2479
2480     if (logicalWidthLength.type() == MinContent)
2481         return minLogicalWidth + borderAndPadding;
2482
2483     if (logicalWidthLength.type() == MaxContent)
2484         return maxLogicalWidth + borderAndPadding;
2485
2486     if (logicalWidthLength.type() == FitContent) {
2487         minLogicalWidth += borderAndPadding;
2488         maxLogicalWidth += borderAndPadding;
2489         return std::max(minLogicalWidth, std::min(maxLogicalWidth, fillAvailableMeasure(availableLogicalWidth)));
2490     }
2491
2492     ASSERT_NOT_REACHED();
2493     return 0;
2494 }
2495
2496 LayoutUnit RenderBox::computeLogicalWidthInRegionUsing(SizeType widthType, Length logicalWidth, LayoutUnit availableLogicalWidth,
2497     const RenderBlock& cb, RenderRegion* region) const
2498 {
2499     ASSERT(widthType == MinSize || widthType == MainOrPreferredSize || !logicalWidth.isAuto());
2500     if (widthType == MinSize && logicalWidth.isAuto())
2501         return adjustBorderBoxLogicalWidthForBoxSizing(0);
2502
2503     if (!logicalWidth.isIntrinsicOrAuto()) {
2504         // FIXME: If the containing block flow is perpendicular to our direction we need to use the available logical height instead.
2505         return adjustBorderBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, availableLogicalWidth));
2506     }
2507
2508     if (logicalWidth.isIntrinsic())
2509         return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth());
2510
2511     LayoutUnit marginStart = 0;
2512     LayoutUnit marginEnd = 0;
2513     LayoutUnit logicalWidthResult = fillAvailableMeasure(availableLogicalWidth, marginStart, marginEnd);
2514
2515     if (shrinkToAvoidFloats() && cb.containsFloats())
2516         logicalWidthResult = std::min(logicalWidthResult, shrinkLogicalWidthToAvoidFloats(marginStart, marginEnd, cb, region));
2517
2518     if (widthType == MainOrPreferredSize && sizesLogicalWidthToFitContent(widthType))
2519         return std::max(minPreferredLogicalWidth(), std::min(maxPreferredLogicalWidth(), logicalWidthResult));
2520     return logicalWidthResult;
2521 }
2522
2523 bool RenderBox::columnFlexItemHasStretchAlignment() const
2524 {
2525     // auto margins mean we don't stretch. Note that this function will only be
2526     // used for widths, so we don't have to check marginBefore/marginAfter.
2527     const auto& parentStyle = parent()->style();
2528     ASSERT(parentStyle.isColumnFlexDirection());
2529     if (style().marginStart().isAuto() || style().marginEnd().isAuto())
2530         return false;
2531     return style().resolvedAlignSelf(isAnonymous() ? &parentStyle : nullptr, containingBlock()->selfAlignmentNormalBehavior()).position() == ItemPositionStretch;
2532 }
2533
2534 bool RenderBox::isStretchingColumnFlexItem() const
2535 {
2536     if (parent()->isDeprecatedFlexibleBox() && parent()->style().boxOrient() == VERTICAL && parent()->style().boxAlign() == BSTRETCH)
2537         return true;
2538
2539     // We don't stretch multiline flexboxes because they need to apply line spacing (align-content) first.
2540     if (parent()->isFlexibleBox() && parent()->style().flexWrap() == FlexNoWrap && parent()->style().isColumnFlexDirection() && columnFlexItemHasStretchAlignment())
2541         return true;
2542     return false;
2543 }
2544
2545 // FIXME: Can/Should we move this inside specific layout classes (flex. grid)? Can we refactor columnFlexItemHasStretchAlignment logic?
2546 bool RenderBox::hasStretchedLogicalWidth() const
2547 {
2548     auto& style = this->style();
2549     if (!style.logicalWidth().isAuto() || style.marginStart().isAuto() || style.marginEnd().isAuto())
2550         return false;
2551     RenderBlock* containingBlock = this->containingBlock();
2552     if (!containingBlock) {
2553         // We are evaluating align-self/justify-self, which default to 'normal' for the root element.
2554         // The 'normal' value behaves like 'start' except for Flexbox Items, which obviously should have a container.
2555         return false;
2556     }
2557     const auto* parentStyle = isAnonymous() ? &containingBlock->style() : nullptr;
2558     if (containingBlock->isHorizontalWritingMode() != isHorizontalWritingMode())
2559         return style.resolvedAlignSelf(parentStyle, containingBlock->selfAlignmentNormalBehavior(this)).position() == ItemPositionStretch;
2560     return style.resolvedJustifySelf(parentStyle, containingBlock->selfAlignmentNormalBehavior(this)).position() == ItemPositionStretch;
2561 }
2562
2563 bool RenderBox::sizesLogicalWidthToFitContent(SizeType widthType) const
2564 {
2565     // Anonymous inline blocks always fill the width of their containing block.
2566     if (isAnonymousInlineBlock())
2567         return false;
2568
2569     // Marquees in WinIE are like a mixture of blocks and inline-blocks.  They size as though they're blocks,
2570     // but they allow text to sit on the same line as the marquee.
2571     if (isFloating() || (isInlineBlockOrInlineTable() && !isHTMLMarquee()))
2572         return true;
2573
2574     if (isGridItem())
2575         return !hasStretchedLogicalWidth();
2576
2577     // This code may look a bit strange.  Basically width:intrinsic should clamp the size when testing both
2578     // min-width and width.  max-width is only clamped if it is also intrinsic.
2579     Length logicalWidth = (widthType == MaxSize) ? style().logicalMaxWidth() : style().logicalWidth();
2580     if (logicalWidth.type() == Intrinsic)
2581         return true;
2582
2583     // Children of a horizontal marquee do not fill the container by default.
2584     // FIXME: Need to deal with MAUTO value properly.  It could be vertical.
2585     // FIXME: Think about block-flow here.  Need to find out how marquee direction relates to
2586     // block-flow (as well as how marquee overflow should relate to block flow).
2587     // https://bugs.webkit.org/show_bug.cgi?id=46472
2588     if (parent()->isHTMLMarquee()) {
2589         EMarqueeDirection dir = parent()->style().marqueeDirection();
2590         if (dir == MAUTO || dir == MFORWARD || dir == MBACKWARD || dir == MLEFT || dir == MRIGHT)
2591             return true;
2592     }
2593
2594 #if ENABLE(MATHML)
2595     // RenderMathMLBlocks take the size of their content, not of their container.
2596     if (parent()->isRenderMathMLBlock())
2597         return true;
2598 #endif
2599
2600     // Flexible box items should shrink wrap, so we lay them out at their intrinsic widths.
2601     // In the case of columns that have a stretch alignment, we layout at the stretched size
2602     // to avoid an extra layout when applying alignment.
2603     if (parent()->isFlexibleBox()) {
2604         // For multiline columns, we need to apply align-content first, so we can't stretch now.
2605         if (!parent()->style().isColumnFlexDirection() || parent()->style().flexWrap() != FlexNoWrap)
2606             return true;
2607         if (!columnFlexItemHasStretchAlignment())
2608             return true;
2609     }
2610
2611     // Flexible horizontal boxes lay out children at their intrinsic widths.  Also vertical boxes
2612     // that don't stretch their kids lay out their children at their intrinsic widths.
2613     // FIXME: Think about block-flow here.
2614     // https://bugs.webkit.org/show_bug.cgi?id=46473
2615     if (parent()->isDeprecatedFlexibleBox() && (parent()->style().boxOrient() == HORIZONTAL || parent()->style().boxAlign() != BSTRETCH))
2616         return true;
2617
2618     // Button, input, select, textarea, and legend treat width value of 'auto' as 'intrinsic' unless it's in a
2619     // stretching column flexbox.
2620     // FIXME: Think about block-flow here.
2621     // https://bugs.webkit.org/show_bug.cgi?id=46473
2622     if (logicalWidth.type() == Auto && !isStretchingColumnFlexItem() && element() && (is<HTMLInputElement>(*element()) || is<HTMLSelectElement>(*element()) || is<HTMLButtonElement>(*element()) || is<HTMLTextAreaElement>(*element()) || is<HTMLLegendElement>(*element())))
2623         return true;
2624
2625     if (isHorizontalWritingMode() != containingBlock()->isHorizontalWritingMode())
2626         return true;
2627
2628     return false;
2629 }
2630
2631 void RenderBox::computeInlineDirectionMargins(const RenderBlock& containingBlock, LayoutUnit containerWidth, LayoutUnit childWidth, LayoutUnit& marginStart, LayoutUnit& marginEnd) const
2632 {
2633     
2634     const RenderStyle& containingBlockStyle = containingBlock.style();
2635     Length marginStartLength = style().marginStartUsing(&containingBlockStyle);
2636     Length marginEndLength = style().marginEndUsing(&containingBlockStyle);
2637
2638     if (isFloating() || isInline()) {
2639         // Inline blocks/tables and floats don't have their margins increased.
2640         marginStart = minimumValueForLength(marginStartLength, containerWidth);
2641         marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2642         return;
2643     }
2644
2645     if (containingBlock.isFlexibleBox()) {
2646         // We need to let flexbox handle the margin adjustment - otherwise, flexbox
2647         // will think we're wider than we actually are and calculate line sizes
2648         // wrong. See also http://dev.w3.org/csswg/css-flexbox/#auto-margins
2649         if (marginStartLength.isAuto())
2650             marginStartLength = Length(0, Fixed);
2651         if (marginEndLength.isAuto())
2652             marginEndLength = Length(0, Fixed);
2653     }
2654
2655     // Case One: The object is being centered in the containing block's available logical width.
2656     if ((marginStartLength.isAuto() && marginEndLength.isAuto() && childWidth < containerWidth)
2657         || (!marginStartLength.isAuto() && !marginEndLength.isAuto() && containingBlock.style().textAlign() == WEBKIT_CENTER)) {
2658         // Other browsers center the margin box for align=center elements so we match them here.
2659         LayoutUnit marginStartWidth = minimumValueForLength(marginStartLength, containerWidth);
2660         LayoutUnit marginEndWidth = minimumValueForLength(marginEndLength, containerWidth);
2661         LayoutUnit centeredMarginBoxStart = std::max<LayoutUnit>(0, (containerWidth - childWidth - marginStartWidth - marginEndWidth) / 2);
2662         marginStart = centeredMarginBoxStart + marginStartWidth;
2663         marginEnd = containerWidth - childWidth - marginStart + marginEndWidth;
2664         return;
2665     } 
2666     
2667     // Case Two: The object is being pushed to the start of the containing block's available logical width.
2668     if (marginEndLength.isAuto() && childWidth < containerWidth) {
2669         marginStart = valueForLength(marginStartLength, containerWidth);
2670         marginEnd = containerWidth - childWidth - marginStart;
2671         return;
2672     } 
2673     
2674     // Case Three: The object is being pushed to the end of the containing block's available logical width.
2675     bool pushToEndFromTextAlign = !marginEndLength.isAuto() && ((!containingBlockStyle.isLeftToRightDirection() && containingBlockStyle.textAlign() == WEBKIT_LEFT)
2676         || (containingBlockStyle.isLeftToRightDirection() && containingBlockStyle.textAlign() == WEBKIT_RIGHT));
2677     if ((marginStartLength.isAuto() || pushToEndFromTextAlign) && childWidth < containerWidth) {
2678         marginEnd = valueForLength(marginEndLength, containerWidth);
2679         marginStart = containerWidth - childWidth - marginEnd;
2680         return;
2681     } 
2682     
2683     // Case Four: Either no auto margins, or our width is >= the container width (css2.1, 10.3.3).  In that case
2684     // auto margins will just turn into 0.
2685     marginStart = minimumValueForLength(marginStartLength, containerWidth);
2686     marginEnd = minimumValueForLength(marginEndLength, containerWidth);
2687 }
2688
2689 RenderBoxRegionInfo* RenderBox::renderBoxRegionInfo(RenderRegion* region, RenderBoxRegionInfoFlags cacheFlag) const
2690 {
2691     // Make sure nobody is trying to call this with a null region.
2692     if (!region)
2693         return nullptr;
2694
2695     // If we have computed our width in this region already, it will be cached, and we can
2696     // just return it.
2697     RenderBoxRegionInfo* boxInfo = region->renderBoxRegionInfo(this);
2698     if (boxInfo && cacheFlag == CacheRenderBoxRegionInfo)
2699         return boxInfo;
2700
2701     // No cached value was found, so we have to compute our insets in this region.
2702     // FIXME: For now we limit this computation to normal RenderBlocks. Future patches will expand
2703     // support to cover all boxes.
2704     RenderFlowThread* flowThread = flowThreadContainingBlock();
2705     if (isRenderFlowThread() || !is<RenderNamedFlowThread>(flowThread) || !canHaveBoxInfoInRegion() || flowThread->style().writingMode() != style().writingMode())
2706         return nullptr;
2707
2708     LogicalExtentComputedValues computedValues;
2709     computeLogicalWidthInRegion(computedValues, region);
2710
2711     // Now determine the insets based off where this object is supposed to be positioned.
2712     RenderBlock& cb = *containingBlock();
2713     RenderRegion* clampedContainingBlockRegion = cb.clampToStartAndEndRegions(region);
2714     RenderBoxRegionInfo* containingBlockInfo = cb.renderBoxRegionInfo(clampedContainingBlockRegion);
2715     LayoutUnit containingBlockLogicalWidth = cb.logicalWidth();
2716     LayoutUnit containingBlockLogicalWidthInRegion = containingBlockInfo ? containingBlockInfo->logicalWidth() : containingBlockLogicalWidth;
2717     
2718     LayoutUnit marginStartInRegion = computedValues.m_margins.m_start;
2719     LayoutUnit startMarginDelta = marginStartInRegion - marginStart();
2720     LayoutUnit logicalWidthInRegion = computedValues.m_extent;
2721     LayoutUnit logicalLeftInRegion = computedValues.m_position;
2722     LayoutUnit widthDelta = logicalWidthInRegion - logicalWidth();
2723     LayoutUnit logicalLeftDelta = isOutOfFlowPositioned() ? logicalLeftInRegion - logicalLeft() : startMarginDelta;
2724     LayoutUnit logicalRightInRegion = containingBlockLogicalWidthInRegion - (logicalLeftInRegion + logicalWidthInRegion);
2725     LayoutUnit oldLogicalRight = containingBlockLogicalWidth - (logicalLeft() + logicalWidth());
2726     LayoutUnit logicalRightDelta = isOutOfFlowPositioned() ? logicalRightInRegion - oldLogicalRight : startMarginDelta;
2727
2728     LayoutUnit logicalLeftOffset = 0;
2729     
2730     if (!isOutOfFlowPositioned() && avoidsFloats() && cb.containsFloats()) {
2731         LayoutUnit startPositionDelta = cb.computeStartPositionDeltaForChildAvoidingFloats(*this, marginStartInRegion, region);
2732         if (cb.style().isLeftToRightDirection())
2733             logicalLeftDelta += startPositionDelta;
2734         else
2735             logicalRightDelta += startPositionDelta;
2736     }
2737
2738     if (cb.style().isLeftToRightDirection())
2739         logicalLeftOffset += logicalLeftDelta;
2740     else
2741         logicalLeftOffset -= (widthDelta + logicalRightDelta);
2742     
2743     LayoutUnit logicalRightOffset = logicalWidth() - (logicalLeftOffset + logicalWidthInRegion);
2744     bool isShifted = (containingBlockInfo && containingBlockInfo->isShifted())
2745             || (style().isLeftToRightDirection() && logicalLeftOffset)
2746             || (!style().isLeftToRightDirection() && logicalRightOffset);
2747
2748     // FIXME: Although it's unlikely, these boxes can go outside our bounds, and so we will need to incorporate them into overflow.
2749     if (cacheFlag == CacheRenderBoxRegionInfo)
2750         return region->setRenderBoxRegionInfo(this, logicalLeftOffset, logicalWidthInRegion, isShifted);
2751     return new RenderBoxRegionInfo(logicalLeftOffset, logicalWidthInRegion, isShifted);
2752 }
2753
2754 static bool shouldFlipBeforeAfterMargins(const RenderStyle& containingBlockStyle, const RenderStyle* childStyle)
2755 {
2756     ASSERT(containingBlockStyle.isHorizontalWritingMode() != childStyle->isHorizontalWritingMode());
2757     WritingMode childWritingMode = childStyle->writingMode();
2758     bool shouldFlip = false;
2759     switch (containingBlockStyle.writingMode()) {
2760     case TopToBottomWritingMode:
2761         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2762         break;
2763     case BottomToTopWritingMode:
2764         shouldFlip = (childWritingMode == RightToLeftWritingMode);
2765         break;
2766     case RightToLeftWritingMode:
2767         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2768         break;
2769     case LeftToRightWritingMode:
2770         shouldFlip = (childWritingMode == BottomToTopWritingMode);
2771         break;
2772     }
2773
2774     if (!containingBlockStyle.isLeftToRightDirection())
2775         shouldFlip = !shouldFlip;
2776
2777     return shouldFlip;
2778 }
2779
2780 void RenderBox::cacheIntrinsicContentLogicalHeightForFlexItem(LayoutUnit height) const
2781 {
2782     if (isFloatingOrOutOfFlowPositioned() || !parent() || !parent()->isFlexibleBox())
2783         return;
2784     downcast<RenderFlexibleBox>(parent())->setCachedChildIntrinsicContentLogicalHeight(*this, height);
2785 }
2786
2787 void RenderBox::updateLogicalHeight()
2788 {
2789     cacheIntrinsicContentLogicalHeightForFlexItem(contentLogicalHeight());
2790     auto computedValues = computeLogicalHeight(logicalHeight(), logicalTop());
2791     setLogicalHeight(computedValues.m_extent);
2792     setLogicalTop(computedValues.m_position);
2793     setMarginBefore(computedValues.m_margins.m_before);
2794     setMarginAfter(computedValues.m_margins.m_after);
2795 }
2796
2797 RenderBox::LogicalExtentComputedValues RenderBox::computeLogicalHeight(LayoutUnit logicalHeight, LayoutUnit logicalTop) const
2798 {
2799     LogicalExtentComputedValues computedValues;
2800     computedValues.m_extent = logicalHeight;
2801     computedValues.m_position = logicalTop;
2802
2803     // Cell height is managed by the table and inline non-replaced elements do not support a height property.
2804     if (isTableCell() || (isInline() && !isReplaced()))
2805         return computedValues;
2806
2807     Length h;
2808     if (isOutOfFlowPositioned())
2809         computePositionedLogicalHeight(computedValues);
2810     else {
2811         RenderBlock& cb = *containingBlock();
2812         bool hasPerpendicularContainingBlock = cb.isHorizontalWritingMode() != isHorizontalWritingMode();
2813     
2814         if (!hasPerpendicularContainingBlock) {
2815             bool shouldFlipBeforeAfter = cb.style().writingMode() != style().writingMode();
2816             computeBlockDirectionMargins(cb,
2817                 shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2818                 shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2819         }
2820
2821         // For tables, calculate margins only.
2822         if (isTable()) {
2823             if (hasPerpendicularContainingBlock) {
2824                 bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb.style(), &style());
2825                 computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), computedValues.m_extent,
2826                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2827                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2828             }
2829             return computedValues;
2830         }
2831
2832         // FIXME: Account for block-flow in flexible boxes.
2833         // https://bugs.webkit.org/show_bug.cgi?id=46418
2834         bool inHorizontalBox = parent()->isDeprecatedFlexibleBox() && parent()->style().boxOrient() == HORIZONTAL;
2835         bool stretching = parent()->style().boxAlign() == BSTRETCH;
2836         bool treatAsReplaced = shouldComputeSizeAsReplaced() && (!inHorizontalBox || !stretching);
2837         bool checkMinMaxHeight = false;
2838
2839         // The parent box is flexing us, so it has increased or decreased our height.  We have to
2840         // grab our cached flexible height.
2841         // FIXME: Account for block-flow in flexible boxes.
2842         // https://bugs.webkit.org/show_bug.cgi?id=46418
2843         if (hasOverrideLogicalContentHeight() && (parent()->isFlexibleBoxIncludingDeprecated() || parent()->isRenderGrid())) {
2844             h = Length(overrideLogicalContentHeight(), Fixed);
2845         } else if (treatAsReplaced)
2846             h = Length(computeReplacedLogicalHeight(), Fixed);
2847         else {
2848             h = style().logicalHeight();
2849             checkMinMaxHeight = true;
2850         }
2851
2852         // Block children of horizontal flexible boxes fill the height of the box.
2853         // FIXME: Account for block-flow in flexible boxes.
2854         // https://bugs.webkit.org/show_bug.cgi?id=46418
2855         if (h.isAuto() && is<RenderDeprecatedFlexibleBox>(*parent()) && parent()->style().boxOrient() == HORIZONTAL
2856                 && downcast<RenderDeprecatedFlexibleBox>(*parent()).isStretchingChildren()) {
2857             h = Length(parentBox()->contentLogicalHeight() - marginBefore() - marginAfter() - borderAndPaddingLogicalHeight(), Fixed);
2858             checkMinMaxHeight = false;
2859         }
2860
2861         LayoutUnit heightResult;
2862         if (checkMinMaxHeight) {
2863             LayoutUnit intrinsicHeight = computedValues.m_extent - borderAndPaddingLogicalHeight();
2864             heightResult = computeLogicalHeightUsing(MainOrPreferredSize, style().logicalHeight(), intrinsicHeight).value_or(computedValues.m_extent);
2865             heightResult = constrainLogicalHeightByMinMax(heightResult, intrinsicHeight);
2866         } else {
2867             // The only times we don't check min/max height are when a fixed length has
2868             // been given as an override.  Just use that.  The value has already been adjusted
2869             // for box-sizing.
2870             ASSERT(h.isFixed());
2871             heightResult = h.value() + borderAndPaddingLogicalHeight();
2872         }
2873
2874         computedValues.m_extent = heightResult;
2875
2876         if (hasPerpendicularContainingBlock) {
2877             bool shouldFlipBeforeAfter = shouldFlipBeforeAfterMargins(cb.style(), &style());
2878             computeInlineDirectionMargins(cb, containingBlockLogicalWidthForContent(), heightResult,
2879                     shouldFlipBeforeAfter ? computedValues.m_margins.m_after : computedValues.m_margins.m_before,
2880                     shouldFlipBeforeAfter ? computedValues.m_margins.m_before : computedValues.m_margins.m_after);
2881         }
2882     }
2883
2884     // WinIE quirk: The <html> block always fills the entire canvas in quirks mode.  The <body> always fills the
2885     // <html> block in quirks mode.  Only apply this quirk if the block is normal flow and no height
2886     // is specified. When we're printing, we also need this quirk if the body or root has a percentage 
2887     // height since we don't set a height in RenderView when we're printing. So without this quirk, the 
2888     // height has nothing to be a percentage of, and it ends up being 0. That is bad.
2889     bool paginatedContentNeedsBaseHeight = document().printing() && h.isPercentOrCalculated()
2890         && (isDocumentElementRenderer() || (isBody() && document().documentElement()->renderer()->style().logicalHeight().isPercentOrCalculated())) && !isInline();
2891     if (stretchesToViewport() || paginatedContentNeedsBaseHeight) {
2892         LayoutUnit margins = collapsedMarginBefore() + collapsedMarginAfter();
2893         LayoutUnit visibleHeight = view().pageOrViewLogicalHeight();
2894         if (isDocumentElementRenderer())
2895             computedValues.m_extent = std::max(computedValues.m_extent, visibleHeight - margins);
2896         else {
2897             LayoutUnit marginsBordersPadding = margins + parentBox()->marginBefore() + parentBox()->marginAfter() + parentBox()->borderAndPaddingLogicalHeight();
2898             computedValues.m_extent = std::max(computedValues.m_extent, visibleHeight - marginsBordersPadding);
2899         }
2900     }
2901     return computedValues;
2902 }
2903
2904 LayoutUnit RenderBox::computeLogicalHeightWithoutLayout() const
2905 {
2906     // FIXME:: We should probably return something other than just
2907     // border + padding, but for now we have no good way to do anything else
2908     // without layout, so we just use that.
2909     LogicalExtentComputedValues computedValues = computeLogicalHeight(borderAndPaddingLogicalHeight(), LayoutUnit());
2910     return computedValues.m_extent;
2911 }
2912
2913 std::optional<LayoutUnit> RenderBox::computeLogicalHeightUsing(SizeType heightType, const Length& height, std::optional<LayoutUnit> intrinsicContentHeight) const
2914 {
2915     if (std::optional<LayoutUnit> logicalHeight = computeContentAndScrollbarLogicalHeightUsing(heightType, height, intrinsicContentHeight))
2916         return adjustBorderBoxLogicalHeightForBoxSizing(logicalHeight.value());
2917     return std::nullopt;
2918 }
2919
2920 std::optional<LayoutUnit> RenderBox::computeContentLogicalHeight(SizeType heightType, const Length& height, std::optional<LayoutUnit> intrinsicContentHeight) const
2921 {
2922     if (std::optional<LayoutUnit> heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(heightType, height, intrinsicContentHeight))
2923         return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
2924     return std::nullopt;
2925 }
2926
2927 std::optional<LayoutUnit> RenderBox::computeIntrinsicLogicalContentHeightUsing(Length logicalHeightLength, std::optional<LayoutUnit> intrinsicContentHeight, LayoutUnit borderAndPadding) const
2928 {
2929     // FIXME: The CSS sizing spec is considering changing what min-content/max-content should resolve to.
2930     // If that happens, this code will have to change.
2931     if (logicalHeightLength.isMinContent() || logicalHeightLength.isMaxContent() || logicalHeightLength.isFitContent()) {
2932         if (!intrinsicContentHeight)
2933             return intrinsicContentHeight;
2934         if (style().boxSizing() == BORDER_BOX)
2935             return intrinsicContentHeight.value() + borderAndPaddingLogicalHeight();
2936         return intrinsicContentHeight;
2937     }
2938     if (logicalHeightLength.isFillAvailable())
2939         return containingBlock()->availableLogicalHeight(ExcludeMarginBorderPadding) - borderAndPadding;
2940     ASSERT_NOT_REACHED();
2941     return LayoutUnit(0);
2942 }
2943
2944 std::optional<LayoutUnit> RenderBox::computeContentAndScrollbarLogicalHeightUsing(SizeType heightType, const Length& height, std::optional<LayoutUnit> intrinsicContentHeight) const
2945 {
2946     if (height.isAuto())
2947         return heightType == MinSize ? std::optional<LayoutUnit>(0) : std::nullopt;
2948     // FIXME: The CSS sizing spec is considering changing what min-content/max-content should resolve to.
2949     // If that happens, this code will have to change.
2950     if (height.isIntrinsic())
2951         return computeIntrinsicLogicalContentHeightUsing(height, intrinsicContentHeight, borderAndPaddingLogicalHeight());
2952     if (height.isFixed())
2953         return LayoutUnit(height.value());
2954     if (height.isPercentOrCalculated())
2955         return computePercentageLogicalHeight(height);
2956     return std::nullopt;
2957 }
2958
2959 bool RenderBox::skipContainingBlockForPercentHeightCalculation(const RenderBox& containingBlock, bool isPerpendicularWritingMode) const
2960 {
2961     // Flow threads for multicol or paged overflow should be skipped. They are invisible to the DOM,
2962     // and percent heights of children should be resolved against the multicol or paged container.
2963     if (containingBlock.isInFlowRenderFlowThread() && !isPerpendicularWritingMode)
2964         return true;
2965
2966     // Render view is not considered auto height.
2967     if (is<RenderView>(containingBlock))
2968         return false;
2969
2970     // If the writing mode of the containing block is orthogonal to ours, it means
2971     // that we shouldn't skip anything, since we're going to resolve the
2972     // percentage height against a containing block *width*.
2973     if (isPerpendicularWritingMode)
2974         return false;
2975     
2976     // Anonymous blocks should not impede percentage resolution on a child.
2977     // Examples of such anonymous blocks are blocks wrapped around inlines that
2978     // have block siblings (from the CSS spec) and multicol flow threads (an
2979     // implementation detail). Another implementation detail, ruby runs, create
2980     // anonymous inline-blocks, so skip those too. All other types of anonymous
2981     // objects, such as table-cells and flexboxes, will be treated as if they were
2982     // non-anonymous.
2983     if (containingBlock.isAnonymous())
2984         return containingBlock.style().display() == BLOCK || containingBlock.style().display() == INLINE_BLOCK;
2985     
2986     // For quirks mode, we skip most auto-height containing blocks when computing
2987     // percentages.
2988     return document().inQuirksMode() && !containingBlock.isTableCell() && !containingBlock.isOutOfFlowPositioned() && !containingBlock.isRenderGrid() && containingBlock.style().logicalHeight().isAuto();
2989 }
2990
2991 bool RenderBox::shouldTreatChildAsReplacedInTableCells() const
2992 {
2993     if (isReplaced())
2994         return true;
2995     return element() && (element()->isFormControlElement() || is<HTMLImageElement>(element()));
2996 }
2997
2998 static bool tableCellShouldHaveZeroInitialSize(const RenderBlock& block, const RenderBox& child, bool scrollsOverflowY)
2999 {
3000     // Normally we would let the cell size intrinsically, but scrolling overflow has to be
3001     // treated differently, since WinIE lets scrolled overflow regions shrink as needed.
3002     // While we can't get all cases right, we can at least detect when the cell has a specified
3003     // height or when the table has a specified height. In these cases we want to initially have
3004     // no size and allow the flexing of the table or the cell to its specified height to cause us
3005     // to grow to fill the space. This could end up being wrong in some cases, but it is
3006     // preferable to the alternative (sizing intrinsically and making the row end up too big).
3007     const RenderTableCell& cell = downcast<RenderTableCell>(block);
3008     return scrollsOverflowY && !child.shouldTreatChildAsReplacedInTableCells() && (!cell.style().logicalHeight().isAuto() || !cell.table()->style().logicalHeight().isAuto());
3009 }
3010
3011 std::optional<LayoutUnit> RenderBox::computePercentageLogicalHeight(const Length& height) const
3012 {
3013     std::optional<LayoutUnit> availableHeight;
3014
3015     bool skippedAutoHeightContainingBlock = false;
3016     RenderBlock* cb = containingBlock();
3017     const RenderBox* containingBlockChild = this;
3018     LayoutUnit rootMarginBorderPaddingHeight = 0;
3019     bool isHorizontal = isHorizontalWritingMode();
3020     while (cb && !is<RenderView>(*cb) && skipContainingBlockForPercentHeightCalculation(*cb, isHorizontal != cb->isHorizontalWritingMode())) {
3021         if (cb->isBody() || cb->isDocumentElementRenderer())
3022             rootMarginBorderPaddingHeight += cb->marginBefore() + cb->marginAfter() + cb->borderAndPaddingLogicalHeight();
3023         skippedAutoHeightContainingBlock = true;
3024         containingBlockChild = cb;
3025         cb = cb->containingBlock();
3026     }
3027     cb->addPercentHeightDescendant(const_cast<RenderBox&>(*this));
3028
3029     if (isHorizontal != cb->isHorizontalWritingMode())
3030         availableHeight = containingBlockChild->containingBlockLogicalWidthForContent();
3031     else if (hasOverrideContainingBlockLogicalHeight())
3032         availableHeight = overrideContainingBlockContentLogicalHeight();
3033     else if (is<RenderTableCell>(*cb)) {
3034         if (!skippedAutoHeightContainingBlock) {
3035             // Table cells violate what the CSS spec says to do with heights. Basically we
3036             // don't care if the cell specified a height or not. We just always make ourselves
3037             // be a percentage of the cell's current content height.
3038             if (!cb->hasOverrideLogicalContentHeight())
3039                 return tableCellShouldHaveZeroInitialSize(*cb, *this, scrollsOverflowY()) ? std::optional<LayoutUnit>(0) : std::nullopt;
3040
3041             availableHeight = cb->overrideLogicalContentHeight();
3042         }
3043     } else
3044         availableHeight = cb->availableLogicalHeightForPercentageComputation();
3045     
3046     if (!availableHeight)
3047         return availableHeight;
3048
3049     LayoutUnit result = valueForLength(height, availableHeight.value() - rootMarginBorderPaddingHeight + (isTable() && isOutOfFlowPositioned() ? cb->paddingBefore() + cb->paddingAfter() : LayoutUnit()));
3050     
3051     // |overrideLogicalContentHeight| is the maximum height made available by the
3052     // cell to its percent height children when we decide they can determine the
3053     // height of the cell. If the percent height child is box-sizing:content-box
3054     // then we must subtract the border and padding from the cell's
3055     // |availableHeight| (given by |overrideLogicalContentHeight|) to arrive
3056     // at the child's computed height.
3057     bool subtractBorderAndPadding = isTable() || (is<RenderTableCell>(*cb) && !skippedAutoHeightContainingBlock && cb->hasOverrideLogicalContentHeight());
3058     if (subtractBorderAndPadding) {
3059         result -= borderAndPaddingLogicalHeight();
3060         return std::max(LayoutUnit(), result);
3061     }
3062     return result;
3063 }
3064
3065 LayoutUnit RenderBox::computeReplacedLogicalWidth(ShouldComputePreferred shouldComputePreferred) const
3066 {
3067     return computeReplacedLogicalWidthRespectingMinMaxWidth(computeReplacedLogicalWidthUsing(MainOrPreferredSize, style().logicalWidth()), shouldComputePreferred);
3068 }
3069
3070 LayoutUnit RenderBox::computeReplacedLogicalWidthRespectingMinMaxWidth(LayoutUnit logicalWidth, ShouldComputePreferred shouldComputePreferred) const
3071 {
3072     auto& logicalMinWidth = style().logicalMinWidth();
3073     auto& logicalMaxWidth = style().logicalMaxWidth();
3074     bool useLogicalWidthForMinWidth = (shouldComputePreferred == ComputePreferred && logicalMinWidth.isPercentOrCalculated()) || logicalMinWidth.isUndefined();
3075     bool useLogicalWidthForMaxWidth = (shouldComputePreferred == ComputePreferred && logicalMaxWidth.isPercentOrCalculated()) || logicalMaxWidth.isUndefined();
3076     auto minLogicalWidth =  useLogicalWidthForMinWidth ? logicalWidth : computeReplacedLogicalWidthUsing(MinSize, logicalMinWidth);
3077     auto maxLogicalWidth =  useLogicalWidthForMaxWidth ? logicalWidth : computeReplacedLogicalWidthUsing(MaxSize, logicalMaxWidth);
3078     return std::max(minLogicalWidth, std::min(logicalWidth, maxLogicalWidth));
3079 }
3080
3081 LayoutUnit RenderBox::computeReplacedLogicalWidthUsing(SizeType widthType, Length logicalWidth) const
3082 {
3083     ASSERT(widthType == MinSize || widthType == MainOrPreferredSize || !logicalWidth.isAuto());
3084     if (widthType == MinSize && logicalWidth.isAuto())
3085         return adjustContentBoxLogicalWidthForBoxSizing(0);
3086
3087     switch (logicalWidth.type()) {
3088         case Fixed:
3089             return adjustContentBoxLogicalWidthForBoxSizing(logicalWidth.value());
3090         case MinContent:
3091         case MaxContent: {
3092             // MinContent/MaxContent don't need the availableLogicalWidth argument.
3093             LayoutUnit availableLogicalWidth = 0;
3094             return computeIntrinsicLogicalWidthUsing(logicalWidth, availableLogicalWidth, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
3095         }
3096         case FitContent:
3097         case FillAvailable:
3098         case Percent: 
3099         case Calculated: {
3100             // FIXME: containingBlockLogicalWidthForContent() is wrong if the replaced element's block-flow is perpendicular to the
3101             // containing block's block-flow.
3102             // https://bugs.webkit.org/show_bug.cgi?id=46496
3103             const LayoutUnit cw = isOutOfFlowPositioned() ? containingBlockLogicalWidthForPositioned(downcast<RenderBoxModelObject>(*container())) : containingBlockLogicalWidthForContent();
3104             Length containerLogicalWidth = containingBlock()->style().logicalWidth();
3105             // FIXME: Handle cases when containing block width is calculated or viewport percent.
3106             // https://bugs.webkit.org/show_bug.cgi?id=91071
3107             if (logicalWidth.isIntrinsic())
3108                 return computeIntrinsicLogicalWidthUsing(logicalWidth, cw, borderAndPaddingLogicalWidth()) - borderAndPaddingLogicalWidth();
3109             if (cw > 0 || (!cw && (containerLogicalWidth.isFixed() || containerLogicalWidth.isPercentOrCalculated())))
3110                 return adjustContentBoxLogicalWidthForBoxSizing(minimumValueForLength(logicalWidth, cw));
3111         }
3112         FALLTHROUGH;
3113         case Intrinsic:
3114         case MinIntrinsic:
3115         case Auto:
3116         case Relative:
3117         case Undefined:
3118             return intrinsicLogicalWidth();
3119     }
3120
3121     ASSERT_NOT_REACHED();
3122     return 0;
3123 }
3124
3125 LayoutUnit RenderBox::computeReplacedLogicalHeight(std::optional<LayoutUnit>) const
3126 {
3127     return computeReplacedLogicalHeightRespectingMinMaxHeight(computeReplacedLogicalHeightUsing(MainOrPreferredSize, style().logicalHeight()));
3128 }
3129
3130 static bool allowMinMaxPercentagesInAutoHeightBlocksQuirk()
3131 {
3132 #if PLATFORM(MAC)
3133     return MacApplication::isIBooks();
3134 #elif PLATFORM(IOS)
3135     return IOSApplication::isIBooks();
3136 #endif
3137     return false;
3138 }
3139
3140 bool RenderBox::replacedMinMaxLogicalHeightComputesAsNone(SizeType sizeType) const
3141 {
3142     ASSERT(sizeType == MinSize || sizeType == MaxSize);
3143     
3144     auto logicalHeight = sizeType == MinSize ? style().logicalMinHeight() : style().logicalMaxHeight();
3145     auto initialLogicalHeight = sizeType == MinSize ? RenderStyle::initialMinSize() : RenderStyle::initialMaxSize();
3146     
3147     if (logicalHeight == initialLogicalHeight)
3148         return true;
3149     
3150     // Make sure % min-height and % max-height resolve to none if the containing block has auto height.
3151     // Note that the "height" case for replaced elements was handled by hasReplacedLogicalHeight, which is why
3152     // min and max-height are the only ones handled here.
3153     // FIXME: For now we put in a quirk for iBooks until we can move them to viewport units.
3154     if (auto* cb = containingBlockForAutoHeightDetection(logicalHeight))
3155         return allowMinMaxPercentagesInAutoHeightBlocksQuirk() ? false : cb->hasAutoHeightOrContainingBlockWithAutoHeight();
3156
3157     return false;
3158 }
3159
3160 LayoutUnit RenderBox::computeReplacedLogicalHeightRespectingMinMaxHeight(LayoutUnit logicalHeight) const
3161 {
3162     LayoutUnit minLogicalHeight;
3163     if (!replacedMinMaxLogicalHeightComputesAsNone(MinSize))
3164         minLogicalHeight = computeReplacedLogicalHeightUsing(MinSize, style().logicalMinHeight());
3165     LayoutUnit maxLogicalHeight = logicalHeight;
3166     if (!replacedMinMaxLogicalHeightComputesAsNone(MaxSize))
3167         maxLogicalHeight = computeReplacedLogicalHeightUsing(MaxSize, style().logicalMaxHeight());
3168     return std::max(minLogicalHeight, std::min(logicalHeight, maxLogicalHeight));
3169 }
3170
3171 LayoutUnit RenderBox::computeReplacedLogicalHeightUsing(SizeType heightType, Length logicalHeight) const
3172 {
3173     ASSERT(heightType == MinSize || heightType == MainOrPreferredSize || !logicalHeight.isAuto());
3174     if (heightType == MinSize && logicalHeight.isAuto())
3175         return adjustContentBoxLogicalHeightForBoxSizing(std::optional<LayoutUnit>(0));
3176
3177     switch (logicalHeight.type()) {
3178         case Fixed:
3179             return adjustContentBoxLogicalHeightForBoxSizing(LayoutUnit(logicalHeight.value()));
3180         case Percent:
3181         case Calculated:
3182         {
3183             auto* container = isOutOfFlowPositioned() ? this->container() : containingBlock();
3184             while (container && container->isAnonymous()) {
3185                 // Stop at rendering context root.
3186                 if (is<RenderView>(*container) || is<RenderNamedFlowThread>(*container))
3187                     break;
3188                 container = container->containingBlock();
3189             }
3190             std::optional<LayoutUnit> stretchedHeight;
3191             if (is<RenderBlock>(container)) {
3192                 auto* block = downcast<RenderBlock>(container);
3193                 block->addPercentHeightDescendant(*const_cast<RenderBox*>(this));
3194                 if (block->isFlexItem())
3195                     stretchedHeight = downcast<RenderFlexibleBox>(block->parent())->childLogicalHeightForPercentageResolution(*block);
3196                 else if (block->isGridItem() && block->hasOverrideLogicalContentHeight())
3197                     stretchedHeight = block->overrideLogicalContentHeight();
3198             }
3199
3200             // FIXME: This calculation is not patched for block-flow yet.
3201             // https://bugs.webkit.org/show_bug.cgi?id=46500
3202             if (container->isOutOfFlowPositioned()
3203                 && container->style().height().isAuto()
3204                 && !(container->style().top().isAuto() || container->style().bottom().isAuto())) {
3205                 ASSERT_WITH_SECURITY_IMPLICATION(container->isRenderBlock());
3206                 auto& block = downcast<RenderBlock>(*container);
3207                 auto computedValues = block.computeLogicalHeight(block.logicalHeight(), 0);
3208                 LayoutUnit newContentHeight = computedValues.m_extent - block.borderAndPaddingLogicalHeight() - block.scrollbarLogicalHeight();
3209                 LayoutUnit newHeight = block.adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
3210                 return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, newHeight));
3211             }
3212             
3213             // FIXME: availableLogicalHeight() is wrong if the replaced element's block-flow is perpendicular to the
3214             // containing block's block-flow.
3215             // https://bugs.webkit.org/show_bug.cgi?id=46496
3216             LayoutUnit availableHeight;
3217             if (isOutOfFlowPositioned())
3218                 availableHeight = containingBlockLogicalHeightForPositioned(downcast<RenderBoxModelObject>(*container));
3219             else if (stretchedHeight)
3220                 availableHeight = stretchedHeight.value();
3221             else {
3222                 availableHeight = containingBlockLogicalHeightForContent(IncludeMarginBorderPadding);
3223                 // It is necessary to use the border-box to match WinIE's broken
3224                 // box model.  This is essential for sizing inside
3225                 // table cells using percentage heights.
3226                 // FIXME: This needs to be made block-flow-aware.  If the cell and image are perpendicular block-flows, this isn't right.
3227                 // https://bugs.webkit.org/show_bug.cgi?id=46997
3228                 while (container && !is<RenderView>(*container)
3229                     && (container->style().logicalHeight().isAuto() || container->style().logicalHeight().isPercentOrCalculated())) {
3230                     if (container->isTableCell()) {
3231                         // Don't let table cells squeeze percent-height replaced elements
3232                         // <http://bugs.webkit.org/show_bug.cgi?id=15359>
3233                         availableHeight = std::max(availableHeight, intrinsicLogicalHeight());
3234                         return valueForLength(logicalHeight, availableHeight - borderAndPaddingLogicalHeight());
3235                     }
3236                     downcast<RenderBlock>(*container).addPercentHeightDescendant(const_cast<RenderBox&>(*this));
3237                     container = container->containingBlock();
3238                 }
3239             }
3240             return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(logicalHeight, availableHeight));
3241         }
3242         case MinContent:
3243         case MaxContent:
3244         case FitContent:
3245         case FillAvailable:
3246             return adjustContentBoxLogicalHeightForBoxSizing(computeIntrinsicLogicalContentHeightUsing(logicalHeight, intrinsicLogicalHeight(), borderAndPaddingLogicalHeight()));
3247         default:
3248             return intrinsicLogicalHeight();
3249     }
3250 }
3251
3252 LayoutUnit RenderBox::availableLogicalHeight(AvailableLogicalHeightType heightType) const
3253 {
3254     return constrainLogicalHeightByMinMax(availableLogicalHeightUsing(style().logicalHeight(), heightType), std::nullopt);
3255 }
3256
3257 LayoutUnit RenderBox::availableLogicalHeightUsing(const Length& h, AvailableLogicalHeightType heightType) const
3258 {
3259     // We need to stop here, since we don't want to increase the height of the table
3260     // artificially.  We're going to rely on this cell getting expanded to some new
3261     // height, and then when we lay out again we'll use the calculation below.
3262     if (isTableCell() && (h.isAuto() || h.isPercentOrCalculated())) {
3263         if (hasOverrideLogicalContentHeight())
3264             return overrideLogicalContentHeight();
3265         return logicalHeight() - borderAndPaddingLogicalHeight();
3266     }
3267
3268     if (isFlexItem()) {
3269         auto& flexBox = downcast<RenderFlexibleBox>(*parent());
3270         auto stretchedHeight = flexBox.childLogicalHeightForPercentageResolution(*this);
3271         if (stretchedHeight)
3272             return stretchedHeight.value();
3273     }
3274
3275     if (h.isPercentOrCalculated() && isOutOfFlowPositioned() && !isRenderFlowThread()) {
3276         // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
3277         LayoutUnit availableHeight = containingBlockLogicalHeightForPositioned(*containingBlock());
3278         return adjustContentBoxLogicalHeightForBoxSizing(valueForLength(h, availableHeight));
3279     }
3280
3281     if (std::optional<LayoutUnit> heightIncludingScrollbar = computeContentAndScrollbarLogicalHeightUsing(MainOrPreferredSize, h, std::nullopt))
3282         return std::max<LayoutUnit>(0, adjustContentBoxLogicalHeightForBoxSizing(heightIncludingScrollbar) - scrollbarLogicalHeight());
3283
3284     // FIXME: Check logicalTop/logicalBottom here to correctly handle vertical writing-mode.
3285     // https://bugs.webkit.org/show_bug.cgi?id=46500
3286     if (is<RenderBlock>(*this) && isOutOfFlowPositioned() && style().height().isAuto() && !(style().top().isAuto() || style().bottom().isAuto())) {
3287         RenderBlock& block = const_cast<RenderBlock&>(downcast<RenderBlock>(*this));
3288         auto computedValues = block.computeLogicalHeight(block.logicalHeight(), 0);
3289         LayoutUnit newContentHeight = computedValues.m_extent - block.borderAndPaddingLogicalHeight() - block.scrollbarLogicalHeight();
3290         return adjustContentBoxLogicalHeightForBoxSizing(newContentHeight);
3291     }
3292
3293     // FIXME: This is wrong if the containingBlock has a perpendicular writing mode.
3294     LayoutUnit availableHeight = containingBlockLogicalHeightForContent(heightType);
3295     if (heightType == ExcludeMarginBorderPadding) {
3296         // FIXME: Margin collapsing hasn't happened yet, so this incorrectly removes collapsed margins.
3297         availableHeight -= marginBefore() + marginAfter() + borderAndPaddingLogicalHeight();
3298     }
3299     return availableHeight;
3300 }
3301
3302 void RenderBox::computeBlockDirectionMargins(const RenderBlock& containingBlock, LayoutUnit& marginBefore, LayoutUnit& marginAfter) const
3303 {
3304     if (isTableCell()) {
3305         // FIXME: Not right if we allow cells to have different directionality than the table.  If we do allow this, though,
3306         // we may just do it with an extra anonymous block inside the cell.
3307         marginBefore = 0;
3308         marginAfter = 0;
3309         return;
3310     }
3311
3312     // Margins are calculated with respect to the logical width of
3313     // the containing block (8.3)
3314     LayoutUnit cw = containingBlockLogicalWidthForContent();
3315     const RenderStyle& containingBlockStyle = containingBlock.style();
3316     marginBefore = minimumValueForLength(style().marginBeforeUsing(&containingBlockStyle), cw);
3317     marginAfter = minimumValueForLength(style().marginAfterUsing(&containingBlockStyle), cw);
3318 }
3319
3320 void RenderBox::computeAndSetBlockDirectionMargins(const RenderBlock& containingBlock)
3321 {
3322     LayoutUnit marginBefore;
3323     LayoutUnit marginAfter;
3324     computeBlockDirectionMargins(containingBlock, marginBefore, marginAfter);
3325     containingBlock.setMarginBeforeForChild(*this, marginBefore);
3326     containingBlock.setMarginAfterForChild(*this, marginAfter);
3327 }
3328
3329 LayoutUnit RenderBox::containingBlockLogicalWidthForPositioned(const RenderBoxModelObject& containingBlock, RenderRegion* region, bool checkForPerpendicularWritingMode) const
3330 {
3331     if (checkForPerpendicularWritingMode && containingBlock.isHorizontalWritingMode() != isHorizontalWritingMode())
3332         return containingBlockLogicalHeightForPositioned(containingBlock, false);
3333
3334     if (hasOverrideContainingBlockLogicalWidth()) {
3335         if (auto overrideLogicalWidth = overrideContainingBlockContentLogicalWidth())
3336             return overrideLogicalWidth.value();
3337     }
3338
3339     if (is<RenderBox>(containingBlock)) {
3340         bool isFixedPosition = style().position() == FixedPosition;
3341
3342         RenderFlowThread* flowThread = flowThreadContainingBlock();
3343         if (!flowThread) {
3344             if (isFixedPosition && is<RenderView>(containingBlock))
3345                 return downcast<RenderView>(containingBlock).clientLogicalWidthForFixedPosition();
3346
3347             return downcast<RenderBox>(containingBlock).clientLogicalWidth();
3348         }
3349
3350         if (isFixedPosition && is<RenderNamedFlowThread>(containingBlock))
3351             return containingBlock.view().clientLogicalWidth();
3352
3353         if (!is<RenderBlock>(containingBlock))
3354             return downcast<RenderBox>(containingBlock).clientLogicalWidth();
3355
3356         const RenderBlock& cb = downcast<RenderBlock>(containingBlock);
3357         RenderBoxRegionInfo* boxInfo = nullptr;
3358         if (!region) {
3359             if (is<RenderFlowThread>(containingBlock) && !checkForPerpendicularWritingMode)
3360                 return downcast<RenderFlowThread>(containingBlock).contentLogicalWidthOfFirstRegion();
3361             if (isWritingModeRoot()) {
3362                 LayoutUnit cbPageOffset = cb.offsetFromLogicalTopOfFirstPage();
3363                 RenderRegion* cbRegion = cb.regionAtBlockOffset(cbPageOffset);
3364                 if (cbRegion)
3365                     boxInfo = cb.renderBoxRegionInfo(cbRegion);
3366             }
3367         } else if (flowThread->isHorizontalWritingMode() == containingBlock.isHorizontalWritingMode()) {
3368             RenderRegion* containingBlockRegion = cb.clampToStartAndEndRegions(region);
3369             boxInfo = cb.renderBoxRegionInfo(containingBlockRegion);
3370         }
3371         return (boxInfo) ? std::max<LayoutUnit>(0, cb.clientLogicalWidth() - (cb.logicalWidth() - boxInfo->logicalWidth())) : cb.clientLogicalWidth();
3372     }
3373
3374     ASSERT(containingBlock.isInFlowPositioned());
3375
3376     const auto& flow = downcast<RenderInline>(containingBlock);
3377     InlineFlowBox* first = flow.firstLineBox();
3378     InlineFlowBox* last = flow.lastLineBox();
3379
3380     // If the containing block is empty, return a width of 0.
3381     if (!first || !last)
3382         return 0;
3383
3384     LayoutUnit fromLeft;
3385     LayoutUnit fromRight;
3386     if (containingBlock.style().isLeftToRightDirection()) {
3387         fromLeft = first->logicalLeft() + first->borderLogicalLeft();
3388         fromRight = last->logicalLeft() + last->logicalWidth() - last->borderLogicalRight();
3389     } else {
3390         fromRight = first->logicalLeft() + first->logicalWidth() - first->borderLogicalRight();
3391         fromLeft = last->logicalLeft() + last->borderLogicalLeft();
3392     }
3393
3394     return std::max<LayoutUnit>(0, fromRight - fromLeft);
3395 }
3396
3397 LayoutUnit RenderBox::containingBlockLogicalHeightForPositioned(const RenderBoxModelObject& containingBlock, bool checkForPerpendicularWritingMode) const
3398 {
3399     if (checkForPerpendicularWritingMode && containingBlock.isHorizontalWritingMode() != isHorizontalWritingMode())
3400         return containingBlockLogicalWidthForPositioned(containingBlock, nullptr, false);
3401
3402     if (hasOverrideContainingBlockLogicalHeight()) {
3403         if (auto overrideLogicalHeight = overrideContainingBlockContentLogicalHeight())
3404             return overrideLogicalHeight.value();
3405     }
3406
3407     if (containingBlock.isBox()) {
3408         bool isFixedPosition = style().position() == FixedPosition;
3409
3410         if (isFixedPosition && is<RenderView>(containingBlock))
3411             return downcast<RenderView>(containingBlock).clientLogicalHeightForFixedPosition();
3412
3413         const RenderBlock& cb = is<RenderBlock>(containingBlock) ? downcast<RenderBlock>(containingBlock) : *containingBlock.containingBlock();
3414         LayoutUnit result = cb.clientLogicalHeight();
3415         RenderFlowThread* flowThread = flowThreadContainingBlock();
3416         if (flowThread && is<RenderFlowThread>(containingBlock) && flowThread->isHorizontalWritingMode() == containingBlock.isHorizontalWritingMode()) {
3417             if (is<RenderNamedFlowThread>(containingBlock) && isFixedPosition)
3418                 return containingBlock.view().clientLogicalHeight();
3419             return downcast<RenderFlowThread>(containingBlock).contentLogicalHeightOfFirstRegion();
3420         }
3421         return result;
3422     }
3423         
3424     ASSERT(containingBlock.isInFlowPositioned());
3425
3426     const auto& flow = downcast<RenderInline>(containingBlock);
3427     InlineFlowBox* first = flow.firstLineBox();
3428     InlineFlowBox* last = flow.lastLineBox();
3429
3430     // If the containing block is empty, return a height of 0.
3431     if (!first || !last)
3432         return 0;
3433
3434     LayoutUnit heightResult;
3435     LayoutRect boundingBox = flow.linesBoundingBox();
3436     if (containingBlock.isHorizontalWritingMode())
3437         heightResult = boundingBox.height();
3438     else
3439         heightResult = boundingBox.width();
3440     heightResult -= (containingBlock.borderBefore() + containingBlock.borderAfter());
3441     return heightResult;
3442 }
3443
3444 static void computeInlineStaticDistance(Length& logicalLeft, Length& logicalRight, const RenderBox* child, const RenderBoxModelObject& containerBlock, LayoutUnit containerLogicalWidth, RenderRegion* region)
3445 {
3446     if (!logicalLeft.isAuto() || !logicalRight.isAuto())
3447         return;
3448
3449     RenderObject* parent = child->parent();
3450     TextDirection parentDirection = parent->style().direction();
3451
3452     // This method is using enclosingBox() which is wrong for absolutely
3453     // positioned grid items, as they rely on the grid area. So for grid items if
3454     // both "left" and "right" properties are "auto", we can consider that one of
3455     // them (depending on the direction) is simply "0".
3456     if (parent->isRenderGrid() && parent == child->containingBlock()) {
3457         if (parentDirection == LTR)
3458             logicalLeft.setValue(Fixed, 0);
3459         else
3460             logicalRight.setValue(Fixed, 0);
3461         return;
3462     }
3463
3464     // FIXME: The static distance computation has not been patched for mixed writing modes yet.
3465     if (parentDirection == LTR) {
3466         LayoutUnit staticPosition = child->layer()->staticInlinePosition() - containerBlock.borderLogicalLeft();
3467         for (auto* current = parent; current && current != &containerBlock; current = current->container()) {
3468             if (!is<RenderBox>(*current))
3469                 continue;
3470             const auto& renderBox = downcast<RenderBox>(*current);
3471             staticPosition += renderBox.logicalLeft();
3472             if (renderBox.isInFlowPositioned())
3473                 staticPosition += renderBox.isHorizontalWritingMode() ? renderBox.offsetForInFlowPosition().width() : renderBox.offsetForInFlowPosition().height();
3474             if (region && is<RenderBlock>(*current)) {
3475                 const RenderBlock& currentBlock = downcast<RenderBlock>(*current);
3476                 region = currentBlock.clampToStartAndEndRegions(region);
3477                 RenderBoxRegionInfo* boxInfo = currentBlock.renderBoxRegionInfo(region);
3478                 if (boxInfo)
3479                     staticPosition += boxInfo->logicalLeft();
3480             }
3481         }
3482         logicalLeft.setValue(Fixed, staticPosition);
3483     } else {
3484         LayoutUnit staticPosition = child->layer()->staticInlinePosition() + containerLogicalWidth + containerBlock.borderLogicalLeft();
3485         auto& enclosingBox = parent->enclosingBox();
3486         if (&enclosingBox != &containerBlock && containerBlock.isDescendantOf(&enclosingBox)) {
3487             logicalRight.setValue(Fixed, staticPosition);
3488             return;
3489         }
3490
3491         staticPosition -= enclosingBox.logicalWidth();
3492         for (const RenderElement* current = &enclosingBox; current; current = current->container()) {
3493             if (!is<RenderBox>(*current))
3494                 continue;
3495
3496             if (current != &containerBlock) {
3497                 auto& renderBox = downcast<RenderBox>(*current);
3498                 staticPosition -= renderBox.logicalLeft();
3499                 if (renderBox.isInFlowPositioned())
3500                     staticPosition -= renderBox.isHorizontalWritingMode() ? renderBox.offsetForInFlowPosition().width() : renderBox.offsetForInFlowPosition().height();
3501             }
3502             if (region && is<RenderBlock>(*current)) {
3503                 auto& currentBlock = downcast<RenderBlock>(*current);
3504                 region = currentBlock.clampToStartAndEndRegions(region);
3505                 RenderBoxRegionInfo* boxInfo = currentBlock.renderBoxRegionInfo(region);
3506                 if (boxInfo) {
3507                     if (current != &containerBlock)
3508                         staticPosition -= currentBlock.logicalWidth() - (boxInfo->logicalLeft() + boxInfo->logicalWidth());
3509                     if (current == &enclosingBox)
3510                         staticPosition += enclosingBox.logicalWidth() - boxInfo->logicalWidth();
3511                 }
3512             }
3513             if (current == &containerBlock)
3514                 break;
3515         }
3516         logicalRight.setValue(Fixed, staticPosition);
3517     }
3518 }
3519
3520 void RenderBox::computePositionedLogicalWidth(LogicalExtentComputedValues& computedValues, RenderRegion* region) const
3521 {
3522     if (isReplaced()) {
3523         // FIXME: Positioned replaced elements inside a flow thread are not working properly
3524         // with variable width regions (see https://bugs.webkit.org/show_bug.cgi?id=69896 ).
3525         computePositionedLogicalWidthReplaced(computedValues);
3526         return;
3527     }
3528
3529     // QUESTIONS
3530     // FIXME 1: Should we still deal with these the cases of 'left' or 'right' having
3531     // the type 'static' in determining whether to calculate the static distance?
3532     // NOTE: 'static' is not a legal value for 'left' or 'right' as of CSS 2.1.
3533
3534     // FIXME 2: Can perhaps optimize out cases when max-width/min-width are greater
3535     // than or less than the computed width().  Be careful of box-sizing and
3536     // percentage issues.
3537
3538     // The following is based off of the W3C Working Draft from April 11, 2006 of
3539     // CSS 2.1: Section 10.3.7 "Absolutely positioned, non-replaced elements"
3540     // <http://www.w3.org/TR/CSS21/visudet.html#abs-non-replaced-width>
3541     // (block-style-comments in this function and in computePositionedLogicalWidthUsing()
3542     // correspond to text from the spec)
3543
3544
3545     // We don't use containingBlock(), since we may be positioned by an enclosing
3546     // relative positioned inline.
3547     const RenderBoxModelObject& containerBlock = downcast<RenderBoxModelObject>(*container());
3548     
3549     const LayoutUnit containerLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, region);
3550
3551     // Use the container block's direction except when calculating the static distance
3552     // This conforms with the reference results for abspos-replaced-width-margin-000.htm
3553     // of the CSS 2.1 test suite
3554     TextDirection containerDirection = containerBlock.style().direction();
3555
3556     bool isHorizontal = isHorizontalWritingMode();
3557     const LayoutUnit bordersPlusPadding = borderAndPaddingLogicalWidth();
3558     const Length marginLogicalLeft = isHorizontal ? style().marginLeft() : style().marginTop();
3559     const Length marginLogicalRight = isHorizontal ? style().marginRight() : style().marginBottom();
3560
3561     Length logicalLeftLength = style().logicalLeft();
3562     Length logicalRightLength = style().logicalRight();
3563
3564     /*---------------------------------------------------------------------------*\
3565      * For the purposes of this section and the next, the term "static position"
3566      * (of an element) refers, roughly, to the position an element would have had
3567      * in the normal flow. More precisely:
3568      *
3569      * * The static position for 'left' is the distance from the left edge of the
3570      *   containing block to the left margin edge of a hypothetical box that would
3571      *   have been the first box of the element if its 'position' property had
3572      *   been 'static' and 'float' had been 'none'. The value is negative if the
3573      *   hypothetical box is to the left of the containing block.
3574      * * The static position for 'right' is the distance from the right edge of the
3575      *   containing block to the right margin edge of the same hypothetical box as
3576      *   above. The value is positive if the hypothetical box is to the left of the
3577      *   containing block's edge.
3578      *
3579      * But rather than actually calculating the dimensions of that hypothetical box,
3580      * user agents are free to make a guess at its probable position.
3581      *
3582      * For the purposes of calculating the static position, the containing block of
3583      * fixed positioned elements is the initial containing block instead of the
3584      * viewport, and all scrollable boxes should be assumed to be scrolled to their
3585      * origin.
3586     \*---------------------------------------------------------------------------*/
3587
3588     // see FIXME 1
3589     // Calculate the static distance if needed.
3590     computeInlineStaticDistance(logicalLeftLength, logicalRightLength, this, containerBlock, containerLogicalWidth, region);
3591     
3592     // Calculate constraint equation values for 'width' case.
3593     computePositionedLogicalWidthUsing(MainOrPreferredSize, style().logicalWidth(), containerBlock, containerDirection,
3594                                        containerLogicalWidth, bordersPlusPadding,
3595                                        logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3596                                        computedValues);
3597
3598     // Calculate constraint equation values for 'max-width' case.
3599     if (!style().logicalMaxWidth().isUndefined()) {
3600         LogicalExtentComputedValues maxValues;
3601
3602         computePositionedLogicalWidthUsing(MaxSize, style().logicalMaxWidth(), containerBlock, containerDirection,
3603                                            containerLogicalWidth, bordersPlusPadding,
3604                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3605                                            maxValues);
3606
3607         if (computedValues.m_extent > maxValues.m_extent) {
3608             computedValues.m_extent = maxValues.m_extent;
3609             computedValues.m_position = maxValues.m_position;
3610             computedValues.m_margins.m_start = maxValues.m_margins.m_start;
3611             computedValues.m_margins.m_end = maxValues.m_margins.m_end;
3612         }
3613     }
3614
3615     // Calculate constraint equation values for 'min-width' case.
3616     if (!style().logicalMinWidth().isZero() || style().logicalMinWidth().isIntrinsic()) {
3617         LogicalExtentComputedValues minValues;
3618
3619         computePositionedLogicalWidthUsing(MinSize, style().logicalMinWidth(), containerBlock, containerDirection,
3620                                            containerLogicalWidth, bordersPlusPadding,
3621                                            logicalLeftLength, logicalRightLength, marginLogicalLeft, marginLogicalRight,
3622                                            minValues);
3623
3624         if (computedValues.m_extent < minValues.m_extent) {
3625             computedValues.m_extent = minValues.m_extent;
3626             computedValues.m_position = minValues.m_position;
3627             computedValues.m_margins.m_start = minValues.m_margins.m_start;
3628             computedValues.m_margins.m_end = minValues.m_margins.m_end;
3629         }
3630     }
3631
3632     computedValues.m_extent += bordersPlusPadding;
3633     if (is<RenderBox>(containerBlock)) {
3634         auto& containingBox = downcast<RenderBox>(containerBlock);
3635         if (containingBox.shouldPlaceBlockDirectionScrollbarOnLeft())
3636             computedValues.m_position += containingBox.verticalScrollbarWidth();
3637     }
3638     
3639     // Adjust logicalLeft if we need to for the flipped version of our writing mode in regions.
3640     // FIXME: Add support for other types of objects as containerBlock, not only RenderBlock.
3641     RenderFlowThread* flowThread = flowThreadContainingBlock();
3642     if (flowThread && !region && isWritingModeRoot() && isHorizontalWritingMode() == containerBlock.isHorizontalWritingMode() && is<RenderBlock>(containerBlock)) {
3643         ASSERT(containerBlock.canHaveBoxInfoInRegion());
3644         LayoutUnit logicalLeftPos = computedValues.m_position;
3645         const RenderBlock& renderBlock = downcast<RenderBlock>(containerBlock);
3646         LayoutUnit cbPageOffset = renderBlock.offsetFromLogicalTopOfFirstPage();
3647         RenderRegion* cbRegion = renderBlock.regionAtBlockOffset(cbPageOffset);
3648         if (cbRegion) {
3649             RenderBoxRegionInfo* boxInfo = renderBlock.renderBoxRegionInfo(cbRegion);
3650             if (boxInfo) {
3651                 logicalLeftPos += boxInfo->logicalLeft();
3652                 computedValues.m_position = logicalLeftPos;
3653             }
3654         }
3655     }
3656 }
3657
3658 static void computeLogicalLeftPositionedOffset(LayoutUnit& logicalLeftPos, const RenderBox* child, LayoutUnit logicalWidthValue, const RenderBoxModelObject& containerBlock, LayoutUnit containerLogicalWidth)
3659 {
3660     // Deal with differing writing modes here.  Our offset needs to be in the containing block's coordinate space. If the containing block is flipped
3661     // along this axis, then we need to flip the coordinate.  This can only happen if the containing block is both a flipped mode and perpendicular to us.
3662     if (containerBlock.isHorizontalWritingMode() != child->isHorizontalWritingMode() && containerBlock.style().isFlippedBlocksWritingMode()) {
3663         logicalLeftPos = containerLogicalWidth - logicalWidthValue - logicalLeftPos;
3664         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock.borderRight() : containerBlock.borderBottom());
3665     } else
3666         logicalLeftPos += (child->isHorizontalWritingMode() ? containerBlock.borderLeft() : containerBlock.borderTop());
3667 }
3668
3669 void RenderBox::computePositionedLogicalWidthUsing(SizeType widthType, Length logicalWidth, const RenderBoxModelObject& containerBlock, TextDirection containerDirection,
3670                                                    LayoutUnit containerLogicalWidth, LayoutUnit bordersPlusPadding,
3671                                                    Length logicalLeft, Length logicalRight, Length marginLogicalLeft, Length marginLogicalRight,
3672                                                    LogicalExtentComputedValues& computedValues) const
3673 {
3674     ASSERT(widthType == MinSize || widthType == MainOrPreferredSize || !logicalWidth.isAuto());
3675     if (widthType == MinSize && logicalWidth.isAuto())
3676         logicalWidth = Length(0, Fixed);
3677     else if (logicalWidth.isIntrinsic())
3678         logicalWidth = Length(computeIntrinsicLogicalWidthUsing(logicalWidth, containerLogicalWidth, bordersPlusPadding) - bordersPlusPadding, Fixed);
3679
3680     // 'left' and 'right' cannot both be 'auto' because one would of been
3681     // converted to the static position already
3682     ASSERT(!(logicalLeft.isAuto() && logicalRight.isAuto()));
3683
3684     LayoutUnit logicalLeftValue = 0;
3685
3686     const LayoutUnit containerRelativeLogicalWidth = containingBlockLogicalWidthForPositioned(containerBlock, nullptr, false);
3687
3688     bool logicalWidthIsAuto = logicalWidth.isIntrinsicOrAuto();
3689     bool logicalLeftIsAuto = logicalLeft.isAuto();
3690     bool logicalRightIsAuto = logicalRight.isAuto();
3691     LayoutUnit& marginLogicalLeftValue = style().isLeftToRightDirection() ? computedValues.m_margins.m_start : computedValues.m_margins.m_end;
3692     LayoutUnit& marginLogicalRightValue = style().isLeftToRightDirection() ? computedValues.m_margins.m_end : computedValues.m_margins.m_start;
3693
3694     if (!logicalLeftIsAuto && !logicalWidthIsAuto && !logicalRightIsAuto) {
3695         /*-----------------------------------------------------------------------*\
3696          * If none of the three is 'auto': If both 'margin-left' and 'margin-
3697          * right' are 'auto', solve the equation under the extra constraint that
3698          * the two margins get equal values, unless this would make them negative,
3699          * in which case when direction of the containing block is 'ltr' ('rtl'),
3700          * set 'margin-left' ('margin-right') to zero and solve for 'margin-right'
3701          * ('margin-left'). If one of 'margin-left' or 'margin-right' is 'auto',
3702          * solve the equation for that value. If the values are over-constrained,
3703          * ignore the value for 'left' (in case the 'direction' property of the
3704          * containing block is 'rtl') or 'right' (in case 'direction' is 'ltr')
3705          * and solve for that value.
3706         \*-----------------------------------------------------------------------*/
3707         // NOTE:  It is not necessary to solve for 'right' in the over constrained
3708         // case because the value is not used for any further calculations.
3709
3710         logicalLeftValue = valueForLength(logicalLeft, containerLogicalWidth);
3711         computedValues.m_extent = adjustContentBoxLogicalWidthForBoxSizing(valueForLength(logicalWidth, containerLogicalWidth));
3712
3713         const LayoutUnit availableSpace = containerLogicalWidth - (logicalLeftValue + computedValues.m_extent + valueForLength(logicalRight, containerLogicalWidth) + bordersPlusPadding);
3714
3715         // Margins are now the only unknown
3716         if (marginLogicalLeft.isAuto() && marginLogicalRight.isAuto()) {
3717             // Both margins auto, solve for equality
3718             if (availableSpace >= 0) {
3719                 marginLogicalLeftValue = availableSpace / 2; // split the difference
3720                 marginLogicalRightValue = availableSpace - marginLogicalLeftValue; // account for odd valued differences
3721             } else {
3722                 // Use the containing block's direction rather than the parent block's
3723                 // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3724                 if (containerDirection == LTR) {
3725                     marginLogicalLeftValue = 0;
3726                     marginLogicalRightValue = availableSpace; // will be negative
3727                 } else {
3728                     marginLogicalLeftValue = availableSpace; // will be negative
3729                     marginLogicalRightValue = 0;
3730                 }
3731             }
3732         } else if (marginLogicalLeft.isAuto()) {
3733             // Solve for left margin
3734             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3735             marginLogicalLeftValue = availableSpace - marginLogicalRightValue;
3736         } else if (marginLogicalRight.isAuto()) {
3737             // Solve for right margin
3738             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3739             marginLogicalRightValue = availableSpace - marginLogicalLeftValue;
3740         } else {
3741             // Over-constrained, solve for left if direction is RTL
3742             marginLogicalLeftValue = valueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3743             marginLogicalRightValue = valueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3744
3745             // Use the containing block's direction rather than the parent block's
3746             // per CSS 2.1 reference test abspos-non-replaced-width-margin-000.
3747             if (containerDirection == RTL)
3748                 logicalLeftValue = (availableSpace + logicalLeftValue) - marginLogicalLeftValue - marginLogicalRightValue;
3749         }
3750     } else {
3751         /*--------------------------------------------------------------------*\
3752          * Otherwise, set 'auto' values for 'margin-left' and 'margin-right'
3753          * to 0, and pick the one of the following six rules that applies.
3754          *
3755          * 1. 'left' and 'width' are 'auto' and 'right' is not 'auto', then the
3756          *    width is shrink-to-fit. Then solve for 'left'
3757          *
3758          *              OMIT RULE 2 AS IT SHOULD NEVER BE HIT
3759          * ------------------------------------------------------------------
3760          * 2. 'left' and 'right' are 'auto' and 'width' is not 'auto', then if
3761          *    the 'direction' property of the containing block is 'ltr' set
3762          *    'left' to the static position, otherwise set 'right' to the
3763          *    static position. Then solve for 'left' (if 'direction is 'rtl')
3764          *    or 'right' (if 'direction' is 'ltr').
3765          * ------------------------------------------------------------------
3766          *
3767          * 3. 'width' and 'right' are 'auto' and 'left' is not 'auto', then the
3768          *    width is shrink-to-fit . Then solve for 'right'
3769          * 4. 'left' is 'auto', 'width' and 'right' are not 'auto', then solve
3770          *    for 'left'
3771          * 5. 'width' is 'auto', 'left' and 'right' are not 'auto', then solve
3772          *    for 'width'
3773          * 6. 'right' is 'auto', 'left' and 'width' are not 'auto', then solve
3774          *    for 'right'
3775          *
3776          * Calculation of the shrink-to-fit width is similar to calculating the
3777          * width of a table cell using the automatic table layout algorithm.
3778          * Roughly: calculate the preferred width by formatting the content
3779          * without breaking lines other than where explicit line breaks occur,
3780          * and also calculate the preferred minimum width, e.g., by trying all
3781          * possible line breaks. CSS 2.1 does not define the exact algorithm.
3782          * Thirdly, calculate the available width: this is found by solving
3783          * for 'width' after setting 'left' (in case 1) or 'right' (in case 3)
3784          * to 0.
3785          *
3786          * Then the shrink-to-fit width is:
3787          * min(max(preferred minimum width, available width), preferred width).
3788         \*--------------------------------------------------------------------*/
3789         // NOTE: For rules 3 and 6 it is not necessary to solve for 'right'
3790         // because the value is not used for any further calculations.
3791
3792         // Calculate margins, 'auto' margins are ignored.
3793         marginLogicalLeftValue = minimumValueForLength(marginLogicalLeft, containerRelativeLogicalWidth);
3794         marginLogicalRightValue = minimumValueForLength(marginLogicalRight, containerRelativeLogicalWidth);
3795
3796         const LayoutUnit availableSpace = containerLogicalWidth - (marginLogicalLeftValue + marginLogicalRightValue + bordersPlusPadding);
3797
3798         // FIXME: Is there a faster way to find the correct case?
3799         // Use rule/case that applies.
3800         if (logicalLeftIsAuto && logicalWidthIsAuto && !logicalRightIsAuto) {
3801             // RULE 1: (use shrink-to-fit for width, and solve of left)
3802             LayoutUnit logicalRightValue = valueForLength(logicalRight, containerLogicalWidth);
3803
3804             // FIXME: would it be better to have shrink-to-fit in one step?
3805             LayoutUnit preferredWidth = maxPreferredLogicalWidth() - bordersPlusPadding;
3806             LayoutUnit preferredMinWidth = minPreferredLogicalWidth() - bordersPlusPadding;
3807             LayoutUnit availableWidth = availableSpace - logicalRightValue;