REGRESSION(r219045): A partially loaded image may not be repainted when its complete...
[WebKit-https.git] / Source / WebCore / rendering / RenderBoxModelObject.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, 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
7  * Copyright (C) 2010 Google Inc. All rights reserved.
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public License
20  * along with this library; see the file COPYING.LIB.  If not, write to
21  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  *
24  */
25
26 #include "config.h"
27 #include "RenderBoxModelObject.h"
28
29 #include "BitmapImage.h"
30 #include "BorderEdge.h"
31 #include "CachedImage.h"
32 #include "FloatRoundedRect.h"
33 #include "Frame.h"
34 #include "FrameView.h"
35 #include "GeometryUtilities.h"
36 #include "GraphicsContext.h"
37 #include "HTMLFrameOwnerElement.h"
38 #include "HTMLFrameSetElement.h"
39 #include "HTMLNames.h"
40 #include "ImageBuffer.h"
41 #include "ImageQualityController.h"
42 #include "Path.h"
43 #include "RenderBlock.h"
44 #include "RenderFlexibleBox.h"
45 #include "RenderInline.h"
46 #include "RenderLayer.h"
47 #include "RenderLayerBacking.h"
48 #include "RenderLayerCompositor.h"
49 #include "RenderMultiColumnFlowThread.h"
50 #include "RenderNamedFlowFragment.h"
51 #include "RenderNamedFlowThread.h"
52 #include "RenderRegion.h"
53 #include "RenderTable.h"
54 #include "RenderTableRow.h"
55 #include "RenderText.h"
56 #include "RenderTextFragment.h"
57 #include "RenderView.h"
58 #include "ScrollingConstraints.h"
59 #include "Settings.h"
60 #include "TransformState.h"
61 #include <wtf/NeverDestroyed.h>
62 #if !ASSERT_DISABLED
63 #include <wtf/SetForScope.h>
64 #endif
65
66 #if PLATFORM(IOS)
67 #include "RuntimeApplicationChecks.h"
68 #endif
69
70 namespace WebCore {
71
72 using namespace HTMLNames;
73
74 // The HashMap for storing continuation pointers.
75 // An inline can be split with blocks occuring in between the inline content.
76 // When this occurs we need a pointer to the next object. We can basically be
77 // split into a sequence of inlines and blocks. The continuation will either be
78 // an anonymous block (that houses other blocks) or it will be an inline flow.
79 // <b><i><p>Hello</p></i></b>. In this example the <i> will have a block as
80 // its continuation but the <b> will just have an inline as its continuation.
81 typedef HashMap<const RenderBoxModelObject*, RenderBoxModelObject*> ContinuationMap;
82 static ContinuationMap& continuationMap()
83 {
84     static NeverDestroyed<ContinuationMap> map;
85     return map;
86 }
87
88 // This HashMap is similar to the continuation map, but connects first-letter
89 // renderers to their remaining text fragments.
90 typedef HashMap<const RenderBoxModelObject*, RenderTextFragment*> FirstLetterRemainingTextMap;
91 static FirstLetterRemainingTextMap* firstLetterRemainingTextMap = nullptr;
92
93 void RenderBoxModelObject::setSelectionState(SelectionState state)
94 {
95     if (state == SelectionInside && selectionState() != SelectionNone)
96         return;
97
98     if ((state == SelectionStart && selectionState() == SelectionEnd)
99         || (state == SelectionEnd && selectionState() == SelectionStart))
100         RenderLayerModelObject::setSelectionState(SelectionBoth);
101     else
102         RenderLayerModelObject::setSelectionState(state);
103
104     // FIXME: We should consider whether it is OK propagating to ancestor RenderInlines.
105     // This is a workaround for http://webkit.org/b/32123
106     // The containing block can be null in case of an orphaned tree.
107     RenderBlock* containingBlock = this->containingBlock();
108     if (containingBlock && !containingBlock->isRenderView())
109         containingBlock->setSelectionState(state);
110 }
111
112 void RenderBoxModelObject::contentChanged(ContentChangeType changeType)
113 {
114     if (!hasLayer())
115         return;
116
117     layer()->contentChanged(changeType);
118 }
119
120 bool RenderBoxModelObject::hasAcceleratedCompositing() const
121 {
122     return view().compositor().hasAcceleratedCompositing();
123 }
124
125 bool RenderBoxModelObject::startTransition(double timeOffset, CSSPropertyID propertyId, const RenderStyle* fromStyle, const RenderStyle* toStyle)
126 {
127     ASSERT(hasLayer());
128     ASSERT(isComposited());
129     return layer()->backing()->startTransition(timeOffset, propertyId, fromStyle, toStyle);
130 }
131
132 void RenderBoxModelObject::transitionPaused(double timeOffset, CSSPropertyID propertyId)
133 {
134     ASSERT(hasLayer());
135     ASSERT(isComposited());
136     layer()->backing()->transitionPaused(timeOffset, propertyId);
137 }
138
139 void RenderBoxModelObject::transitionFinished(CSSPropertyID propertyId)
140 {
141     ASSERT(hasLayer());
142     ASSERT(isComposited());
143     layer()->backing()->transitionFinished(propertyId);
144 }
145
146 bool RenderBoxModelObject::startAnimation(double timeOffset, const Animation* animation, const KeyframeList& keyframes)
147 {
148     ASSERT(hasLayer());
149     ASSERT(isComposited());
150     return layer()->backing()->startAnimation(timeOffset, animation, keyframes);
151 }
152
153 void RenderBoxModelObject::animationPaused(double timeOffset, const String& name)
154 {
155     ASSERT(hasLayer());
156     ASSERT(isComposited());
157     layer()->backing()->animationPaused(timeOffset, name);
158 }
159
160 void RenderBoxModelObject::animationFinished(const String& name)
161 {
162     ASSERT(hasLayer());
163     ASSERT(isComposited());
164     layer()->backing()->animationFinished(name);
165 }
166
167 void RenderBoxModelObject::suspendAnimations(double time)
168 {
169     ASSERT(hasLayer());
170     ASSERT(isComposited());
171     layer()->backing()->suspendAnimations(time);
172 }
173
174 RenderBoxModelObject::RenderBoxModelObject(Element& element, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
175     : RenderLayerModelObject(element, WTFMove(style), baseTypeFlags | RenderBoxModelObjectFlag)
176 {
177 }
178
179 RenderBoxModelObject::RenderBoxModelObject(Document& document, RenderStyle&& style, BaseTypeFlags baseTypeFlags)
180     : RenderLayerModelObject(document, WTFMove(style), baseTypeFlags | RenderBoxModelObjectFlag)
181 {
182 }
183
184 RenderBoxModelObject::~RenderBoxModelObject()
185 {
186     // Do not add any code here. Add it to willBeDestroyed() instead.
187 }
188
189 void RenderBoxModelObject::willBeDestroyed()
190 {
191     if (hasContinuation()) {
192         continuation()->destroy();
193         setContinuation(nullptr);
194     }
195
196     // If this is a first-letter object with a remaining text fragment then the
197     // entry needs to be cleared from the map.
198     if (firstLetterRemainingText())
199         setFirstLetterRemainingText(nullptr);
200
201     if (!renderTreeBeingDestroyed())
202         view().imageQualityController().rendererWillBeDestroyed(*this);
203
204     RenderLayerModelObject::willBeDestroyed();
205 }
206
207 bool RenderBoxModelObject::hasVisibleBoxDecorationStyle() const
208 {
209     return hasBackground() || style().hasVisibleBorderDecoration() || style().hasAppearance() || style().boxShadow();
210 }
211
212 void RenderBoxModelObject::updateFromStyle()
213 {
214     RenderLayerModelObject::updateFromStyle();
215
216     // Set the appropriate bits for a box model object.  Since all bits are cleared in styleWillChange,
217     // we only check for bits that could possibly be set to true.
218     const RenderStyle& styleToUse = style();
219     setHasVisibleBoxDecorations(hasVisibleBoxDecorationStyle());
220     setInline(styleToUse.isDisplayInlineType());
221     setPositionState(styleToUse.position());
222     setHorizontalWritingMode(styleToUse.isHorizontalWritingMode());
223     if (styleToUse.isFlippedBlocksWritingMode())
224         view().frameView().setHasFlippedBlockRenderers(true);
225 }
226
227 static LayoutSize accumulateInFlowPositionOffsets(const RenderObject* child)
228 {
229     if (!child->isAnonymousBlock() || !child->isInFlowPositioned())
230         return LayoutSize();
231     LayoutSize offset;
232     for (RenderElement* parent = downcast<RenderBlock>(*child).inlineElementContinuation(); is<RenderInline>(parent); parent = parent->parent()) {
233         if (parent->isInFlowPositioned())
234             offset += downcast<RenderInline>(*parent).offsetForInFlowPosition();
235     }
236     return offset;
237 }
238     
239 static inline bool isOutOfFlowPositionedWithImplicitHeight(const RenderBoxModelObject& child)
240 {
241     return child.isOutOfFlowPositioned() && !child.style().logicalTop().isAuto() && !child.style().logicalBottom().isAuto();
242 }
243     
244 RenderBlock* RenderBoxModelObject::containingBlockForAutoHeightDetection(Length logicalHeight) const
245 {
246     // For percentage heights: The percentage is calculated with respect to the
247     // height of the generated box's containing block. If the height of the
248     // containing block is not specified explicitly (i.e., it depends on content
249     // height), and this element is not absolutely positioned, the used height is
250     // calculated as if 'auto' was specified.
251     if (!logicalHeight.isPercentOrCalculated() || isOutOfFlowPositioned())
252         return nullptr;
253     
254     // Anonymous block boxes are ignored when resolving percentage values that
255     // would refer to it: the closest non-anonymous ancestor box is used instead.
256     auto* cb = containingBlock();
257     while (cb && cb->isAnonymous() && !is<RenderView>(cb))
258         cb = cb->containingBlock();
259     if (!cb)
260         return nullptr;
261
262     // Matching RenderBox::percentageLogicalHeightIsResolvable() by
263     // ignoring table cell's attribute value, where it says that table cells
264     // violate what the CSS spec says to do with heights. Basically we don't care
265     // if the cell specified a height or not.
266     if (cb->isTableCell())
267         return nullptr;
268     
269     // Match RenderBox::availableLogicalHeightUsing by special casing the layout
270     // view. The available height is taken from the frame.
271     if (cb->isRenderView())
272         return nullptr;
273     
274     if (isOutOfFlowPositionedWithImplicitHeight(*cb))
275         return nullptr;
276     
277     return cb;
278 }
279     
280 bool RenderBoxModelObject::hasAutoHeightOrContainingBlockWithAutoHeight() const
281 {
282     const auto* thisBox = isBox() ? downcast<RenderBox>(this) : nullptr;
283     Length logicalHeightLength = style().logicalHeight();
284     auto* cb = containingBlockForAutoHeightDetection(logicalHeightLength);
285     
286     if (logicalHeightLength.isPercentOrCalculated() && cb && isBox())
287         cb->addPercentHeightDescendant(*const_cast<RenderBox*>(downcast<RenderBox>(this)));
288
289     if (thisBox && thisBox->isFlexItem()) {
290         auto& flexBox = downcast<RenderFlexibleBox>(*parent());
291         if (flexBox.childLogicalHeightForPercentageResolution(*thisBox))
292             return false;
293     }
294     
295     if (thisBox && thisBox->isGridItem() && thisBox->hasOverrideContainingBlockLogicalHeight())
296         return false;
297     
298     if (logicalHeightLength.isAuto() && !isOutOfFlowPositionedWithImplicitHeight(*this))
299         return true;
300
301     if (document().inQuirksMode())
302         return false;
303
304     if (cb)
305         return !cb->hasDefiniteLogicalHeight();
306
307     return false;
308 }
309
310 DecodingMode RenderBoxModelObject::decodingModeForImageDraw(const Image& image, const PaintInfo& paintInfo) const
311 {
312     if (!is<BitmapImage>(image))
313         return DecodingMode::Synchronous;
314     
315     const BitmapImage& bitmapImage = downcast<BitmapImage>(image);
316     if (bitmapImage.canAnimate()) {
317         // The DecodingMode for the current frame has to be Synchronous. The DecodingMode
318         // for the next frame will be calculated in BitmapImage::internalStartAnimation().
319         return DecodingMode::Synchronous;
320     }
321
322     // Large image case.
323 #if PLATFORM(IOS)
324     if (IOSApplication::isIBooksStorytime())
325         return DecodingMode::Synchronous;
326 #endif
327     if (!settings().largeImageAsyncDecodingEnabled())
328         return DecodingMode::Synchronous;
329     if (!bitmapImage.canUseAsyncDecodingForLargeImages())
330         return DecodingMode::Synchronous;
331     if (paintInfo.paintBehavior & PaintBehaviorAllowAsyncImageDecoding)
332         return DecodingMode::Asynchronous;
333     return DecodingMode::Synchronous;
334 }
335
336 LayoutSize RenderBoxModelObject::relativePositionOffset() const
337 {
338     // This function has been optimized to avoid calls to containingBlock() in the common case
339     // where all values are either auto or fixed.
340
341     LayoutSize offset = accumulateInFlowPositionOffsets(this);
342
343     // Objects that shrink to avoid floats normally use available line width when computing containing block width.  However
344     // in the case of relative positioning using percentages, we can't do this.  The offset should always be resolved using the
345     // available width of the containing block.  Therefore we don't use containingBlockLogicalWidthForContent() here, but instead explicitly
346     // call availableWidth on our containing block.
347     if (!style().left().isAuto()) {
348         if (!style().right().isAuto() && !containingBlock()->style().isLeftToRightDirection())
349             offset.setWidth(-valueForLength(style().right(), !style().right().isFixed() ? containingBlock()->availableWidth() : LayoutUnit()));
350         else
351             offset.expand(valueForLength(style().left(), !style().left().isFixed() ? containingBlock()->availableWidth() : LayoutUnit()), 0);
352     } else if (!style().right().isAuto()) {
353         offset.expand(-valueForLength(style().right(), !style().right().isFixed() ? containingBlock()->availableWidth() : LayoutUnit()), 0);
354     }
355
356     // If the containing block of a relatively positioned element does not
357     // specify a height, a percentage top or bottom offset should be resolved as
358     // auto. An exception to this is if the containing block has the WinIE quirk
359     // where <html> and <body> assume the size of the viewport. In this case,
360     // calculate the percent offset based on this height.
361     // See <https://bugs.webkit.org/show_bug.cgi?id=26396>.
362     if (!style().top().isAuto()
363         && (!style().top().isPercentOrCalculated()
364             || !containingBlock()->hasAutoHeightOrContainingBlockWithAutoHeight()
365             || containingBlock()->stretchesToViewport()))
366         offset.expand(0, valueForLength(style().top(), !style().top().isFixed() ? containingBlock()->availableHeight() : LayoutUnit()));
367
368     else if (!style().bottom().isAuto()
369         && (!style().bottom().isPercentOrCalculated()
370             || !containingBlock()->hasAutoHeightOrContainingBlockWithAutoHeight()
371             || containingBlock()->stretchesToViewport()))
372         offset.expand(0, -valueForLength(style().bottom(), !style().bottom().isFixed() ? containingBlock()->availableHeight() : LayoutUnit()));
373
374     return offset;
375 }
376
377 LayoutPoint RenderBoxModelObject::adjustedPositionRelativeToOffsetParent(const LayoutPoint& startPoint) const
378 {
379     // If the element is the HTML body element or doesn't have a parent
380     // return 0 and stop this algorithm.
381     if (isBody() || !parent())
382         return LayoutPoint();
383
384     LayoutPoint referencePoint = startPoint;
385     
386     // If the offsetParent of the element is null, or is the HTML body element,
387     // return the distance between the canvas origin and the left border edge 
388     // of the element and stop this algorithm.
389     if (const RenderBoxModelObject* offsetParent = this->offsetParent()) {
390         if (is<RenderBox>(*offsetParent) && !offsetParent->isBody() && !is<RenderTable>(*offsetParent))
391             referencePoint.move(-downcast<RenderBox>(*offsetParent).borderLeft(), -downcast<RenderBox>(*offsetParent).borderTop());
392         if (!isOutOfFlowPositioned() || flowThreadContainingBlock()) {
393             if (isRelPositioned())
394                 referencePoint.move(relativePositionOffset());
395             else if (isStickyPositioned())
396                 referencePoint.move(stickyPositionOffset());
397             
398             // CSS regions specification says that region flows should return the body element as their offsetParent.
399             // Since we will bypass the body’s renderer anyway, just end the loop if we encounter a region flow (named flow thread).
400             // See http://dev.w3.org/csswg/css-regions/#cssomview-offset-attributes
401             auto* ancestor = parent();
402             while (ancestor != offsetParent && !is<RenderNamedFlowThread>(*ancestor)) {
403                 // FIXME: What are we supposed to do inside SVG content?
404                 
405                 if (is<RenderMultiColumnFlowThread>(*ancestor)) {
406                     // We need to apply a translation based off what region we are inside.
407                     RenderRegion* region = downcast<RenderMultiColumnFlowThread>(*ancestor).physicalTranslationFromFlowToRegion(referencePoint);
408                     if (region)
409                         referencePoint.moveBy(region->topLeftLocation());
410                 } else if (!isOutOfFlowPositioned()) {
411                     if (is<RenderBox>(*ancestor) && !is<RenderTableRow>(*ancestor))
412                         referencePoint.moveBy(downcast<RenderBox>(*ancestor).topLeftLocation());
413                 }
414                 
415                 ancestor = ancestor->parent();
416             }
417             
418             // Compute the offset position for elements inside named flow threads for which the offsetParent was the body.
419             // See https://bugs.webkit.org/show_bug.cgi?id=115899
420             if (is<RenderNamedFlowThread>(*ancestor))
421                 referencePoint = downcast<RenderNamedFlowThread>(*ancestor).adjustedPositionRelativeToOffsetParent(*this, referencePoint);
422             else if (is<RenderBox>(*offsetParent) && offsetParent->isBody() && !offsetParent->isPositioned())
423                 referencePoint.moveBy(downcast<RenderBox>(*offsetParent).topLeftLocation());
424         }
425     }
426
427     return referencePoint;
428 }
429
430 void RenderBoxModelObject::computeStickyPositionConstraints(StickyPositionViewportConstraints& constraints, const FloatRect& constrainingRect) const
431 {
432     constraints.setConstrainingRectAtLastLayout(constrainingRect);
433
434     RenderBlock* containingBlock = this->containingBlock();
435     RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
436     RenderBox& enclosingClippingBox = enclosingClippingLayer ? downcast<RenderBox>(enclosingClippingLayer->renderer()) : view();
437
438     LayoutRect containerContentRect;
439     if (!enclosingClippingLayer || (containingBlock != &enclosingClippingBox))
440         containerContentRect = containingBlock->contentBoxRect();
441     else {
442         containerContentRect = containingBlock->layoutOverflowRect();
443         LayoutPoint containerLocation = containerContentRect.location() + LayoutPoint(containingBlock->borderLeft() + containingBlock->paddingLeft(),
444             containingBlock->borderTop() + containingBlock->paddingTop());
445         containerContentRect.setLocation(containerLocation);
446     }
447
448     LayoutUnit maxWidth = containingBlock->availableLogicalWidth();
449
450     // Sticky positioned element ignore any override logical width on the containing block (as they don't call
451     // containingBlockLogicalWidthForContent). It's unclear whether this is totally fine.
452     LayoutBoxExtent minMargin(minimumValueForLength(style().marginTop(), maxWidth),
453         minimumValueForLength(style().marginRight(), maxWidth),
454         minimumValueForLength(style().marginBottom(), maxWidth),
455         minimumValueForLength(style().marginLeft(), maxWidth));
456
457     // Compute the container-relative area within which the sticky element is allowed to move.
458     containerContentRect.contract(minMargin);
459
460     // Finally compute container rect relative to the scrolling ancestor.
461     FloatRect containerRectRelativeToScrollingAncestor = containingBlock->localToContainerQuad(FloatRect(containerContentRect), &enclosingClippingBox).boundingBox();
462     if (enclosingClippingLayer) {
463         FloatPoint containerLocationRelativeToScrollingAncestor = containerRectRelativeToScrollingAncestor.location() -
464             FloatSize(enclosingClippingBox.borderLeft() + enclosingClippingBox.paddingLeft(),
465             enclosingClippingBox.borderTop() + enclosingClippingBox.paddingTop());
466         if (&enclosingClippingBox != containingBlock)
467             containerLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
468         containerRectRelativeToScrollingAncestor.setLocation(containerLocationRelativeToScrollingAncestor);
469     }
470     constraints.setContainingBlockRect(containerRectRelativeToScrollingAncestor);
471
472     // Now compute the sticky box rect, also relative to the scrolling ancestor.
473     LayoutRect stickyBoxRect = frameRectForStickyPositioning();
474     LayoutRect flippedStickyBoxRect = stickyBoxRect;
475     containingBlock->flipForWritingMode(flippedStickyBoxRect);
476     FloatRect stickyBoxRelativeToScrollingAnecstor = flippedStickyBoxRect;
477
478     // FIXME: sucks to call localToContainerQuad again, but we can't just offset from the previously computed rect if there are transforms.
479     // Map to the view to avoid including page scale factor.
480     FloatPoint stickyLocationRelativeToScrollingAncestor = flippedStickyBoxRect.location() + containingBlock->localToContainerQuad(FloatRect(FloatPoint(), containingBlock->size()), &enclosingClippingBox).boundingBox().location();
481     if (enclosingClippingLayer) {
482         stickyLocationRelativeToScrollingAncestor -= FloatSize(enclosingClippingBox.borderLeft() + enclosingClippingBox.paddingLeft(),
483             enclosingClippingBox.borderTop() + enclosingClippingBox.paddingTop());
484         if (&enclosingClippingBox != containingBlock)
485             stickyLocationRelativeToScrollingAncestor += enclosingClippingLayer->scrollOffset();
486     }
487     // FIXME: For now, assume that |this| is not transformed.
488     stickyBoxRelativeToScrollingAnecstor.setLocation(stickyLocationRelativeToScrollingAncestor);
489     constraints.setStickyBoxRect(stickyBoxRelativeToScrollingAnecstor);
490
491     if (!style().left().isAuto()) {
492         constraints.setLeftOffset(valueForLength(style().left(), constrainingRect.width()));
493         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeLeft);
494     }
495
496     if (!style().right().isAuto()) {
497         constraints.setRightOffset(valueForLength(style().right(), constrainingRect.width()));
498         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeRight);
499     }
500
501     if (!style().top().isAuto()) {
502         constraints.setTopOffset(valueForLength(style().top(), constrainingRect.height()));
503         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeTop);
504     }
505
506     if (!style().bottom().isAuto()) {
507         constraints.setBottomOffset(valueForLength(style().bottom(), constrainingRect.height()));
508         constraints.addAnchorEdge(ViewportConstraints::AnchorEdgeBottom);
509     }
510 }
511
512 FloatRect RenderBoxModelObject::constrainingRectForStickyPosition() const
513 {
514     RenderLayer* enclosingClippingLayer = layer()->enclosingOverflowClipLayer(ExcludeSelf);
515     if (enclosingClippingLayer) {
516         RenderBox& enclosingClippingBox = downcast<RenderBox>(enclosingClippingLayer->renderer());
517         LayoutRect clipRect = enclosingClippingBox.overflowClipRect(LayoutPoint(), nullptr); // FIXME: make this work in regions.
518         clipRect.contract(LayoutSize(enclosingClippingBox.paddingLeft() + enclosingClippingBox.paddingRight(),
519             enclosingClippingBox.paddingTop() + enclosingClippingBox.paddingBottom()));
520
521         FloatRect constrainingRect = enclosingClippingBox.localToContainerQuad(FloatRect(clipRect), &view()).boundingBox();
522
523         FloatPoint scrollOffset = FloatPoint() + enclosingClippingLayer->scrollOffset();
524
525         float scrollbarOffset = 0;
526         if (enclosingClippingBox.hasLayer() && enclosingClippingBox.shouldPlaceBlockDirectionScrollbarOnLeft())
527             scrollbarOffset = enclosingClippingBox.layer()->verticalScrollbarWidth(IgnoreOverlayScrollbarSize);
528
529         constrainingRect.setLocation(FloatPoint(scrollOffset.x() + scrollbarOffset, scrollOffset.y()));
530         return constrainingRect;
531     }
532     
533     return view().frameView().rectForFixedPositionLayout();
534 }
535
536 LayoutSize RenderBoxModelObject::stickyPositionOffset() const
537 {
538     ASSERT(hasLayer());
539     
540     FloatRect constrainingRect = constrainingRectForStickyPosition();
541     StickyPositionViewportConstraints constraints;
542     computeStickyPositionConstraints(constraints, constrainingRect);
543     
544     // The sticky offset is physical, so we can just return the delta computed in absolute coords (though it may be wrong with transforms).
545     return LayoutSize(constraints.computeStickyOffset(constrainingRect));
546 }
547
548 LayoutSize RenderBoxModelObject::offsetForInFlowPosition() const
549 {
550     if (isRelPositioned())
551         return relativePositionOffset();
552
553     if (isStickyPositioned())
554         return stickyPositionOffset();
555
556     return LayoutSize();
557 }
558
559 LayoutUnit RenderBoxModelObject::offsetLeft() const
560 {
561     // Note that RenderInline and RenderBox override this to pass a different
562     // startPoint to adjustedPositionRelativeToOffsetParent.
563     return adjustedPositionRelativeToOffsetParent(LayoutPoint()).x();
564 }
565
566 LayoutUnit RenderBoxModelObject::offsetTop() const
567 {
568     // Note that RenderInline and RenderBox override this to pass a different
569     // startPoint to adjustedPositionRelativeToOffsetParent.
570     return adjustedPositionRelativeToOffsetParent(LayoutPoint()).y();
571 }
572
573 LayoutUnit RenderBoxModelObject::computedCSSPadding(const Length& padding) const
574 {
575     LayoutUnit w = 0;
576     if (padding.isPercentOrCalculated())
577         w = containingBlockLogicalWidthForContent();
578     return minimumValueForLength(padding, w);
579 }
580
581 RoundedRect RenderBoxModelObject::getBackgroundRoundedRect(const LayoutRect& borderRect, InlineFlowBox* box, LayoutUnit inlineBoxWidth, LayoutUnit inlineBoxHeight,
582     bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
583 {
584     RoundedRect border = style().getRoundedBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge);
585     if (box && (box->nextLineBox() || box->prevLineBox())) {
586         RoundedRect segmentBorder = style().getRoundedBorderFor(LayoutRect(0, 0, inlineBoxWidth, inlineBoxHeight), includeLogicalLeftEdge, includeLogicalRightEdge);
587         border.setRadii(segmentBorder.radii());
588     }
589     return border;
590 }
591
592 void RenderBoxModelObject::clipRoundedInnerRect(GraphicsContext& context, const FloatRect& rect, const FloatRoundedRect& clipRect)
593 {
594     if (clipRect.isRenderable())
595         context.clipRoundedRect(clipRect);
596     else {
597         // We create a rounded rect for each of the corners and clip it, while making sure we clip opposing corners together.
598         if (!clipRect.radii().topLeft().isEmpty() || !clipRect.radii().bottomRight().isEmpty()) {
599             FloatRect topCorner(clipRect.rect().x(), clipRect.rect().y(), rect.maxX() - clipRect.rect().x(), rect.maxY() - clipRect.rect().y());
600             FloatRoundedRect::Radii topCornerRadii;
601             topCornerRadii.setTopLeft(clipRect.radii().topLeft());
602             context.clipRoundedRect(FloatRoundedRect(topCorner, topCornerRadii));
603
604             FloatRect bottomCorner(rect.x(), rect.y(), clipRect.rect().maxX() - rect.x(), clipRect.rect().maxY() - rect.y());
605             FloatRoundedRect::Radii bottomCornerRadii;
606             bottomCornerRadii.setBottomRight(clipRect.radii().bottomRight());
607             context.clipRoundedRect(FloatRoundedRect(bottomCorner, bottomCornerRadii));
608         } 
609
610         if (!clipRect.radii().topRight().isEmpty() || !clipRect.radii().bottomLeft().isEmpty()) {
611             FloatRect topCorner(rect.x(), clipRect.rect().y(), clipRect.rect().maxX() - rect.x(), rect.maxY() - clipRect.rect().y());
612             FloatRoundedRect::Radii topCornerRadii;
613             topCornerRadii.setTopRight(clipRect.radii().topRight());
614             context.clipRoundedRect(FloatRoundedRect(topCorner, topCornerRadii));
615
616             FloatRect bottomCorner(clipRect.rect().x(), rect.y(), rect.maxX() - clipRect.rect().x(), clipRect.rect().maxY() - rect.y());
617             FloatRoundedRect::Radii bottomCornerRadii;
618             bottomCornerRadii.setBottomLeft(clipRect.radii().bottomLeft());
619             context.clipRoundedRect(FloatRoundedRect(bottomCorner, bottomCornerRadii));
620         }
621     }
622 }
623
624 static LayoutRect shrinkRectByOneDevicePixel(const GraphicsContext& context, const LayoutRect& rect, float devicePixelRatio)
625 {
626     LayoutRect shrunkRect = rect;
627     AffineTransform transform = context.getCTM();
628     shrunkRect.inflateX(-ceilToDevicePixel(LayoutUnit::fromPixel(1) / transform.xScale(), devicePixelRatio));
629     shrunkRect.inflateY(-ceilToDevicePixel(LayoutUnit::fromPixel(1) / transform.yScale(), devicePixelRatio));
630     return shrunkRect;
631 }
632
633 LayoutRect RenderBoxModelObject::borderInnerRectAdjustedForBleedAvoidance(const GraphicsContext& context, const LayoutRect& rect, BackgroundBleedAvoidance bleedAvoidance) const
634 {
635     if (bleedAvoidance != BackgroundBleedBackgroundOverBorder)
636         return rect;
637
638     // We shrink the rectangle by one device pixel on each side to make it fully overlap the anti-aliased background border
639     return shrinkRectByOneDevicePixel(context, rect, document().deviceScaleFactor());
640 }
641
642 RoundedRect RenderBoxModelObject::backgroundRoundedRectAdjustedForBleedAvoidance(const GraphicsContext& context, const LayoutRect& borderRect, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, bool includeLogicalLeftEdge, bool includeLogicalRightEdge) const
643 {
644     if (bleedAvoidance == BackgroundBleedShrinkBackground) {
645         // We shrink the rectangle by one device pixel on each side because the bleed is one pixel maximum.
646         return getBackgroundRoundedRect(shrinkRectByOneDevicePixel(context, borderRect, document().deviceScaleFactor()), box, boxSize.width(), boxSize.height(),
647             includeLogicalLeftEdge, includeLogicalRightEdge);
648     }
649     if (bleedAvoidance == BackgroundBleedBackgroundOverBorder)
650         return style().getRoundedInnerBorderFor(borderRect, includeLogicalLeftEdge, includeLogicalRightEdge);
651
652     return getBackgroundRoundedRect(borderRect, box, boxSize.width(), boxSize.height(), includeLogicalLeftEdge, includeLogicalRightEdge);
653 }
654
655 static void applyBoxShadowForBackground(GraphicsContext& context, const RenderStyle* style)
656 {
657     const ShadowData* boxShadow = style->boxShadow();
658     while (boxShadow->style() != Normal)
659         boxShadow = boxShadow->next();
660
661     FloatSize shadowOffset(boxShadow->x(), boxShadow->y());
662     if (!boxShadow->isWebkitBoxShadow())
663         context.setShadow(shadowOffset, boxShadow->radius(), boxShadow->color());
664     else
665         context.setLegacyShadow(shadowOffset, boxShadow->radius(), boxShadow->color());
666 }
667
668 InterpolationQuality RenderBoxModelObject::chooseInterpolationQuality(GraphicsContext& context, Image& image, const void* layer, const LayoutSize& size)
669 {
670     return view().imageQualityController().chooseInterpolationQuality(context, this, image, layer, size);
671 }
672
673 void RenderBoxModelObject::paintMaskForTextFillBox(ImageBuffer* maskImage, const IntRect& maskRect, InlineFlowBox* box, const LayoutRect& scrolledPaintRect)
674 {
675     GraphicsContext& maskImageContext = maskImage->context();
676     maskImageContext.translate(-maskRect.x(), -maskRect.y());
677
678     // Now add the text to the clip. We do this by painting using a special paint phase that signals to
679     // InlineTextBoxes that they should just add their contents to the clip.
680     PaintInfo info(maskImageContext, maskRect, PaintPhaseTextClip, PaintBehaviorForceBlackText);
681     if (box) {
682         const RootInlineBox& rootBox = box->root();
683         box->paint(info, LayoutPoint(scrolledPaintRect.x() - box->x(), scrolledPaintRect.y() - box->y()), rootBox.lineTop(), rootBox.lineBottom());
684     } else if (isRenderNamedFlowFragmentContainer()) {
685         RenderNamedFlowFragment& region = *downcast<RenderBlockFlow>(*this).renderNamedFlowFragment();
686         if (region.isValid())
687             region.flowThread()->layer()->paintNamedFlowThreadInsideRegion(maskImageContext, &region, maskRect, maskRect.location(), PaintBehaviorForceBlackText, RenderLayer::PaintLayerTemporaryClipRects);
688     } else {
689         LayoutSize localOffset = is<RenderBox>(*this) ? downcast<RenderBox>(*this).locationOffset() : LayoutSize();
690         paint(info, scrolledPaintRect.location() - localOffset);
691     }
692 }
693
694 void RenderBoxModelObject::paintFillLayerExtended(const PaintInfo& paintInfo, const Color& color, const FillLayer& bgLayer, const LayoutRect& rect,
695     BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* box, const LayoutSize& boxSize, CompositeOperator op, RenderElement* backgroundObject, BaseBackgroundColorUsage baseBgColorUsage)
696 {
697     GraphicsContext& context = paintInfo.context();
698     if (context.paintingDisabled() || rect.isEmpty())
699         return;
700
701     bool includeLeftEdge = box ? box->includeLogicalLeftEdge() : true;
702     bool includeRightEdge = box ? box->includeLogicalRightEdge() : true;
703
704     bool hasRoundedBorder = style().hasBorderRadius() && (includeLeftEdge || includeRightEdge);
705     bool clippedWithLocalScrolling = hasOverflowClip() && bgLayer.attachment() == LocalBackgroundAttachment;
706     bool isBorderFill = bgLayer.clip() == BorderFillBox;
707     bool isRoot = this->isDocumentElementRenderer();
708
709     Color bgColor = color;
710     StyleImage* bgImage = bgLayer.image();
711     bool shouldPaintBackgroundImage = bgImage && bgImage->canRender(this, style().effectiveZoom());
712     
713     bool forceBackgroundToWhite = false;
714     if (document().printing()) {
715         if (style().printColorAdjust() == PrintColorAdjustEconomy)
716             forceBackgroundToWhite = true;
717         if (settings().shouldPrintBackgrounds())
718             forceBackgroundToWhite = false;
719     }
720
721     // When printing backgrounds is disabled or using economy mode,
722     // change existing background colors and images to a solid white background.
723     // If there's no bg color or image, leave it untouched to avoid affecting transparency.
724     // We don't try to avoid loading the background images, because this style flag is only set
725     // when printing, and at that point we've already loaded the background images anyway. (To avoid
726     // loading the background images we'd have to do this check when applying styles rather than
727     // while rendering.)
728     if (forceBackgroundToWhite) {
729         // Note that we can't reuse this variable below because the bgColor might be changed
730         bool shouldPaintBackgroundColor = !bgLayer.next() && bgColor.isVisible();
731         if (shouldPaintBackgroundImage || shouldPaintBackgroundColor) {
732             bgColor = Color::white;
733             shouldPaintBackgroundImage = false;
734         }
735     }
736
737     bool baseBgColorOnly = (baseBgColorUsage == BaseBackgroundColorOnly);
738     if (baseBgColorOnly && (!isRoot || bgLayer.next() || bgColor.isOpaque()))
739         return;
740
741     bool colorVisible = bgColor.isVisible();
742     float deviceScaleFactor = document().deviceScaleFactor();
743     FloatRect pixelSnappedRect = snapRectToDevicePixels(rect, deviceScaleFactor);
744
745     // Fast path for drawing simple color backgrounds.
746     if (!isRoot && !clippedWithLocalScrolling && !shouldPaintBackgroundImage && isBorderFill && !bgLayer.next()) {
747         if (!colorVisible)
748             return;
749
750         bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(rect.location(), bleedAvoidance, box);
751         GraphicsContextStateSaver shadowStateSaver(context, boxShadowShouldBeAppliedToBackground);
752         if (boxShadowShouldBeAppliedToBackground)
753             applyBoxShadowForBackground(context, &style());
754
755         if (hasRoundedBorder && bleedAvoidance != BackgroundBleedUseTransparencyLayer) {
756             FloatRoundedRect pixelSnappedBorder = backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize,
757                 includeLeftEdge, includeRightEdge).pixelSnappedRoundedRectForPainting(deviceScaleFactor);
758             if (pixelSnappedBorder.isRenderable())
759                 context.fillRoundedRect(pixelSnappedBorder, bgColor);
760             else {
761                 context.save();
762                 clipRoundedInnerRect(context, pixelSnappedRect, pixelSnappedBorder);
763                 context.fillRect(pixelSnappedBorder.rect(), bgColor);
764                 context.restore();
765             }
766         } else
767             context.fillRect(pixelSnappedRect, bgColor);
768
769         return;
770     }
771
772     // BorderFillBox radius clipping is taken care of by BackgroundBleedUseTransparencyLayer
773     bool clipToBorderRadius = hasRoundedBorder && !(isBorderFill && bleedAvoidance == BackgroundBleedUseTransparencyLayer);
774     GraphicsContextStateSaver clipToBorderStateSaver(context, clipToBorderRadius);
775     if (clipToBorderRadius) {
776         RoundedRect border = isBorderFill ? backgroundRoundedRectAdjustedForBleedAvoidance(context, rect, bleedAvoidance, box, boxSize, includeLeftEdge, includeRightEdge) : getBackgroundRoundedRect(rect, box, boxSize.width(), boxSize.height(), includeLeftEdge, includeRightEdge);
777
778         // Clip to the padding or content boxes as necessary.
779         if (bgLayer.clip() == ContentFillBox) {
780             border = style().getRoundedInnerBorderFor(border.rect(),
781                 paddingTop() + borderTop(), paddingBottom() + borderBottom(), paddingLeft() + borderLeft(), paddingRight() + borderRight(), includeLeftEdge, includeRightEdge);
782         } else if (bgLayer.clip() == PaddingFillBox)
783             border = style().getRoundedInnerBorderFor(border.rect(), includeLeftEdge, includeRightEdge);
784
785         clipRoundedInnerRect(context, pixelSnappedRect, border.pixelSnappedRoundedRectForPainting(deviceScaleFactor));
786     }
787     
788     LayoutUnit bLeft = includeLeftEdge ? borderLeft() : LayoutUnit::fromPixel(0);
789     LayoutUnit bRight = includeRightEdge ? borderRight() : LayoutUnit::fromPixel(0);
790     LayoutUnit pLeft = includeLeftEdge ? paddingLeft() : LayoutUnit();
791     LayoutUnit pRight = includeRightEdge ? paddingRight() : LayoutUnit();
792
793     GraphicsContextStateSaver clipWithScrollingStateSaver(context, clippedWithLocalScrolling);
794     LayoutRect scrolledPaintRect = rect;
795     if (clippedWithLocalScrolling) {
796         // Clip to the overflow area.
797         auto& thisBox = downcast<RenderBox>(*this);
798         context.clip(thisBox.overflowClipRect(rect.location(), currentRenderNamedFlowFragment()));
799         
800         // Adjust the paint rect to reflect a scrolled content box with borders at the ends.
801         scrolledPaintRect.moveBy(-thisBox.scrollPosition());
802         scrolledPaintRect.setWidth(bLeft + layer()->scrollWidth() + bRight);
803         scrolledPaintRect.setHeight(borderTop() + layer()->scrollHeight() + borderBottom());
804     }
805     
806     GraphicsContextStateSaver backgroundClipStateSaver(context, false);
807     std::unique_ptr<ImageBuffer> maskImage;
808     IntRect maskRect;
809
810     if (bgLayer.clip() == PaddingFillBox || bgLayer.clip() == ContentFillBox) {
811         // Clip to the padding or content boxes as necessary.
812         if (!clipToBorderRadius) {
813             bool includePadding = bgLayer.clip() == ContentFillBox;
814             LayoutRect clipRect = LayoutRect(scrolledPaintRect.x() + bLeft + (includePadding ? pLeft : LayoutUnit()),
815                 scrolledPaintRect.y() + borderTop() + (includePadding ? paddingTop() : LayoutUnit()),
816                 scrolledPaintRect.width() - bLeft - bRight - (includePadding ? pLeft + pRight : LayoutUnit()),
817                 scrolledPaintRect.height() - borderTop() - borderBottom() - (includePadding ? paddingTop() + paddingBottom() : LayoutUnit()));
818             backgroundClipStateSaver.save();
819             context.clip(clipRect);
820         }
821     } else if (bgLayer.clip() == TextFillBox) {
822         // We have to draw our text into a mask that can then be used to clip background drawing.
823         // First figure out how big the mask has to be.  It should be no bigger than what we need
824         // to actually render, so we should intersect the dirty rect with the border box of the background.
825         maskRect = snappedIntRect(rect);
826         maskRect.intersect(snappedIntRect(paintInfo.rect));
827
828         // Now create the mask.
829         maskImage = ImageBuffer::createCompatibleBuffer(maskRect.size(), ColorSpaceSRGB, context);
830         if (!maskImage)
831             return;
832         paintMaskForTextFillBox(maskImage.get(), maskRect, box, scrolledPaintRect);
833
834         // The mask has been created.  Now we just need to clip to it.
835         backgroundClipStateSaver.save();
836         context.clip(maskRect);
837         context.beginTransparencyLayer(1);
838     }
839
840     // Only fill with a base color (e.g., white) if we're the root document, since iframes/frames with
841     // no background in the child document should show the parent's background.
842     bool isOpaqueRoot = false;
843     if (isRoot) {
844         isOpaqueRoot = true;
845         if (!bgLayer.next() && !bgColor.isOpaque()) {
846             HTMLFrameOwnerElement* ownerElement = document().ownerElement();
847             if (ownerElement) {
848                 if (!ownerElement->hasTagName(frameTag)) {
849                     // Locate the <body> element using the DOM.  This is easier than trying
850                     // to crawl around a render tree with potential :before/:after content and
851                     // anonymous blocks created by inline <body> tags etc.  We can locate the <body>
852                     // render object very easily via the DOM.
853                     if (HTMLElement* body = document().bodyOrFrameset()) {
854                         // Can't scroll a frameset document anyway.
855                         isOpaqueRoot = is<HTMLFrameSetElement>(*body);
856                     } else {
857                         // SVG documents and XML documents with SVG root nodes are transparent.
858                         isOpaqueRoot = !document().hasSVGRootNode();
859                     }
860                 }
861             } else
862                 isOpaqueRoot = !view().frameView().isTransparent();
863         }
864         view().frameView().setContentIsOpaque(isOpaqueRoot);
865     }
866
867     // Paint the color first underneath all images, culled if background image occludes it.
868     // FIXME: In the bgLayer.hasFiniteBounds() case, we could improve the culling test
869     // by verifying whether the background image covers the entire layout rect.
870     if (!bgLayer.next()) {
871         LayoutRect backgroundRect(scrolledPaintRect);
872         bool boxShadowShouldBeAppliedToBackground = this->boxShadowShouldBeAppliedToBackground(rect.location(), bleedAvoidance, box);
873         if (boxShadowShouldBeAppliedToBackground || !shouldPaintBackgroundImage || !bgLayer.hasOpaqueImage(*this) || !bgLayer.hasRepeatXY()) {
874             if (!boxShadowShouldBeAppliedToBackground)
875                 backgroundRect.intersect(paintInfo.rect);
876
877             // If we have an alpha and we are painting the root element, blend with the base background color.
878             Color baseColor;
879             bool shouldClearBackground = false;
880             if ((baseBgColorUsage != BaseBackgroundColorSkip) && isOpaqueRoot) {
881                 baseColor = view().frameView().baseBackgroundColor();
882                 if (!baseColor.isVisible())
883                     shouldClearBackground = true;
884             }
885
886             GraphicsContextStateSaver shadowStateSaver(context, boxShadowShouldBeAppliedToBackground);
887             if (boxShadowShouldBeAppliedToBackground)
888                 applyBoxShadowForBackground(context, &style());
889
890             FloatRect backgroundRectForPainting = snapRectToDevicePixels(backgroundRect, deviceScaleFactor);
891             if (baseColor.isVisible()) {
892                 if (!baseBgColorOnly && bgColor.isVisible())
893                     baseColor = baseColor.blend(bgColor);
894                 context.fillRect(backgroundRectForPainting, baseColor, CompositeCopy);
895             } else if (!baseBgColorOnly && bgColor.isVisible()) {
896                 auto operation = shouldClearBackground ? CompositeCopy : context.compositeOperation();
897                 context.fillRect(backgroundRectForPainting, bgColor, operation);
898             } else if (shouldClearBackground)
899                 context.clearRect(backgroundRectForPainting);
900         }
901     }
902
903     // no progressive loading of the background image
904     if (!baseBgColorOnly && shouldPaintBackgroundImage) {
905         auto geometry = calculateBackgroundImageGeometry(paintInfo.paintContainer, bgLayer, rect.location(), scrolledPaintRect, backgroundObject);
906         geometry.clip(LayoutRect(pixelSnappedRect));
907         RefPtr<Image> image;
908         if (!geometry.destRect().isEmpty() && (image = bgImage->image(backgroundObject ? backgroundObject : this, geometry.tileSize()))) {
909             auto compositeOp = op == CompositeSourceOver ? bgLayer.composite() : op;
910             context.setDrawLuminanceMask(bgLayer.maskSourceType() == MaskLuminance);
911
912             if (is<BitmapImage>(image.get()))
913                 downcast<BitmapImage>(*image).updateFromSettings(settings());
914
915             auto interpolation = chooseInterpolationQuality(context, *image, &bgLayer, geometry.tileSize());
916             auto decodingMode = decodingModeForImageDraw(*image, paintInfo);
917             auto drawResult = context.drawTiledImage(*image, geometry.destRect(), toLayoutPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), ImagePaintingOptions(compositeOp, bgLayer.blendMode(), decodingMode, ImageOrientationDescription(), interpolation));
918             if (drawResult == ImageDrawResult::DidRequestDecoding) {
919                 ASSERT(bgImage->isCachedImage());
920                 bgImage->cachedImage()->addPendingImageDrawingClient(*this);
921             }
922         }
923     }
924
925     if (maskImage && bgLayer.clip() == TextFillBox) {
926         context.drawConsumingImageBuffer(WTFMove(maskImage), maskRect, CompositeDestinationIn);
927         context.endTransparencyLayer();
928     }
929 }
930
931 static inline LayoutUnit resolveWidthForRatio(LayoutUnit height, const LayoutSize& intrinsicRatio)
932 {
933     return height * intrinsicRatio.width() / intrinsicRatio.height();
934 }
935
936 static inline LayoutUnit resolveHeightForRatio(LayoutUnit width, const LayoutSize& intrinsicRatio)
937 {
938     return width * intrinsicRatio.height() / intrinsicRatio.width();
939 }
940
941 static inline LayoutSize resolveAgainstIntrinsicWidthOrHeightAndRatio(const LayoutSize& size, const LayoutSize& intrinsicRatio, LayoutUnit useWidth, LayoutUnit useHeight)
942 {
943     if (intrinsicRatio.isEmpty()) {
944         if (useWidth)
945             return LayoutSize(useWidth, size.height());
946         return LayoutSize(size.width(), useHeight);
947     }
948
949     if (useWidth)
950         return LayoutSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio));
951     return LayoutSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight);
952 }
953
954 static inline LayoutSize resolveAgainstIntrinsicRatio(const LayoutSize& size, const LayoutSize& intrinsicRatio)
955 {
956     // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height())
957     // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area.
958
959     LayoutUnit solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio);
960     LayoutUnit solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio);
961     if (solutionWidth <= size.width()) {
962         if (solutionHeight <= size.height()) {
963             // If both solutions fit, choose the one covering the larger area.
964             LayoutUnit areaOne = solutionWidth * size.height();
965             LayoutUnit areaTwo = size.width() * solutionHeight;
966             if (areaOne < areaTwo)
967                 return LayoutSize(size.width(), solutionHeight);
968             return LayoutSize(solutionWidth, size.height());
969         }
970
971         // Only the first solution fits.
972         return LayoutSize(solutionWidth, size.height());
973     }
974
975     // Only the second solution fits, assert that.
976     ASSERT(solutionHeight <= size.height());
977     return LayoutSize(size.width(), solutionHeight);
978 }
979
980 LayoutSize RenderBoxModelObject::calculateImageIntrinsicDimensions(StyleImage* image, const LayoutSize& positioningAreaSize, ScaleByEffectiveZoomOrNot shouldScaleOrNot) const
981 {
982     // A generated image without a fixed size, will always return the container size as intrinsic size.
983     if (image->isGeneratedImage() && image->usesImageContainerSize())
984         return LayoutSize(positioningAreaSize.width(), positioningAreaSize.height());
985
986     Length intrinsicWidth;
987     Length intrinsicHeight;
988     FloatSize intrinsicRatio;
989     image->computeIntrinsicDimensions(this, intrinsicWidth, intrinsicHeight, intrinsicRatio);
990
991     ASSERT(!intrinsicWidth.isPercentOrCalculated());
992     ASSERT(!intrinsicHeight.isPercentOrCalculated());
993
994     LayoutSize resolvedSize(intrinsicWidth.value(), intrinsicHeight.value());
995     LayoutSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0);
996
997     if (shouldScaleOrNot == ScaleByEffectiveZoom)
998         resolvedSize.scale(style().effectiveZoom());
999     resolvedSize.clampToMinimumSize(minimumSize);
1000
1001     if (!resolvedSize.isEmpty())
1002         return resolvedSize;
1003
1004     // If the image has one of either an intrinsic width or an intrinsic height:
1005     // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio.
1006     // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that
1007     //   establishes the coordinate system for the 'background-position' property.
1008     if (resolvedSize.width() > 0 || resolvedSize.height() > 0)
1009         return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, LayoutSize(intrinsicRatio), resolvedSize.width(), resolvedSize.height());
1010
1011     // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the
1012     // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
1013     // establishes the coordinate system for the 'background-position' property.
1014     if (!intrinsicRatio.isEmpty())
1015         return resolveAgainstIntrinsicRatio(positioningAreaSize, LayoutSize(intrinsicRatio));
1016
1017     // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that
1018     // establishes the coordinate system for the 'background-position' property.
1019     return positioningAreaSize;
1020 }
1021
1022 LayoutSize RenderBoxModelObject::calculateFillTileSize(const FillLayer& fillLayer, const LayoutSize& positioningAreaSize) const
1023 {
1024     StyleImage* image = fillLayer.image();
1025     EFillSizeType type = fillLayer.size().type;
1026
1027     LayoutSize imageIntrinsicSize;
1028     if (image) {
1029         imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize, ScaleByEffectiveZoom);
1030         imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
1031     } else
1032         imageIntrinsicSize = positioningAreaSize;
1033
1034     switch (type) {
1035         case SizeLength: {
1036             LayoutSize tileSize = positioningAreaSize;
1037
1038             Length layerWidth = fillLayer.size().size.width;
1039             Length layerHeight = fillLayer.size().size.height;
1040
1041             if (layerWidth.isFixed())
1042                 tileSize.setWidth(layerWidth.value());
1043             else if (layerWidth.isPercentOrCalculated())
1044                 tileSize.setWidth(valueForLength(layerWidth, positioningAreaSize.width()));
1045             
1046             if (layerHeight.isFixed())
1047                 tileSize.setHeight(layerHeight.value());
1048             else if (layerHeight.isPercentOrCalculated())
1049                 tileSize.setHeight(valueForLength(layerHeight, positioningAreaSize.height()));
1050
1051             // If one of the values is auto we have to use the appropriate
1052             // scale to maintain our aspect ratio.
1053             if (layerWidth.isAuto() && !layerHeight.isAuto()) {
1054                 if (imageIntrinsicSize.height())
1055                     tileSize.setWidth(imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height());
1056             } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
1057                 if (imageIntrinsicSize.width())
1058                     tileSize.setHeight(imageIntrinsicSize.height() * tileSize.width() / imageIntrinsicSize.width());
1059             } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
1060                 // If both width and height are auto, use the image's intrinsic size.
1061                 tileSize = imageIntrinsicSize;
1062             }
1063
1064             tileSize.clampNegativeToZero();
1065             return tileSize;
1066         }
1067         case SizeNone: {
1068             // If both values are ‘auto’ then the intrinsic width and/or height of the image should be used, if any.
1069             if (!imageIntrinsicSize.isEmpty())
1070                 return imageIntrinsicSize;
1071
1072             // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for ‘contain’.
1073             type = Contain;
1074         }
1075         FALLTHROUGH;
1076         case Contain:
1077         case Cover: {
1078             // Scale computation needs higher precision than what LayoutUnit can offer.
1079             FloatSize localImageIntrinsicSize = imageIntrinsicSize;
1080             FloatSize localPositioningAreaSize = positioningAreaSize;
1081
1082             float horizontalScaleFactor = localImageIntrinsicSize.width() ? (localPositioningAreaSize.width() / localImageIntrinsicSize.width()) : 1;
1083             float verticalScaleFactor = localImageIntrinsicSize.height() ? (localPositioningAreaSize.height() / localImageIntrinsicSize.height()) : 1;
1084             float scaleFactor = type == Contain ? std::min(horizontalScaleFactor, verticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
1085             float deviceScaleFactor = document().deviceScaleFactor();
1086             return LayoutSize(std::max<LayoutUnit>(1 / deviceScaleFactor, localImageIntrinsicSize.width() * scaleFactor),
1087                 std::max<LayoutUnit>(1 / deviceScaleFactor, localImageIntrinsicSize.height() * scaleFactor));
1088        }
1089     }
1090
1091     ASSERT_NOT_REACHED();
1092     return LayoutSize();
1093 }
1094
1095 static void pixelSnapBackgroundImageGeometryForPainting(LayoutRect& destinationRect, LayoutSize& tileSize, LayoutSize& phase, LayoutSize& space, float scaleFactor)
1096 {
1097     tileSize = LayoutSize(snapRectToDevicePixels(LayoutRect(destinationRect.location(), tileSize), scaleFactor).size());
1098     phase = LayoutSize(snapRectToDevicePixels(LayoutRect(destinationRect.location(), phase), scaleFactor).size());
1099     space = LayoutSize(snapRectToDevicePixels(LayoutRect(LayoutPoint(), space), scaleFactor).size());
1100     destinationRect = LayoutRect(snapRectToDevicePixels(destinationRect, scaleFactor));
1101 }
1102
1103 bool RenderBoxModelObject::fixedBackgroundPaintsInLocalCoordinates() const
1104 {
1105     if (!isDocumentElementRenderer())
1106         return false;
1107
1108     if (view().frameView().paintBehavior() & PaintBehaviorFlattenCompositingLayers)
1109         return false;
1110
1111     RenderLayer* rootLayer = view().layer();
1112     if (!rootLayer || !rootLayer->isComposited())
1113         return false;
1114
1115     return rootLayer->backing()->backgroundLayerPaintsFixedRootBackground();
1116 }
1117
1118 static inline LayoutUnit getSpace(LayoutUnit areaSize, LayoutUnit tileSize)
1119 {
1120     int numberOfTiles = areaSize / tileSize;
1121     LayoutUnit space = -1;
1122
1123     if (numberOfTiles > 1)
1124         space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1);
1125
1126     return space;
1127 }
1128
1129 static LayoutUnit resolveEdgeRelativeLength(const Length& length, Edge edge, LayoutUnit availableSpace, const LayoutSize& areaSize, const LayoutSize& tileSize)
1130 {
1131     LayoutUnit result = minimumValueForLength(length, availableSpace);
1132
1133     if (edge == Edge::Right)
1134         return areaSize.width() - tileSize.width() - result;
1135     
1136     if (edge == Edge::Bottom)
1137         return areaSize.height() - tileSize.height() - result;
1138
1139     return result;
1140 }
1141
1142 BackgroundImageGeometry RenderBoxModelObject::calculateBackgroundImageGeometry(const RenderLayerModelObject* paintContainer, const FillLayer& fillLayer, const LayoutPoint& paintOffset,
1143     const LayoutRect& borderBoxRect, RenderElement* backgroundObject) const
1144 {
1145     LayoutUnit left = 0;
1146     LayoutUnit top = 0;
1147     LayoutSize positioningAreaSize;
1148     // Determine the background positioning area and set destination rect to the background painting area.
1149     // Destination rect will be adjusted later if the background is non-repeating.
1150     // FIXME: transforms spec says that fixed backgrounds behave like scroll inside transforms. https://bugs.webkit.org/show_bug.cgi?id=15679
1151     LayoutRect destinationRect(borderBoxRect);
1152     bool fixedAttachment = fillLayer.attachment() == FixedBackgroundAttachment;
1153     float deviceScaleFactor = document().deviceScaleFactor();
1154     if (!fixedAttachment) {
1155         LayoutUnit right = 0;
1156         LayoutUnit bottom = 0;
1157         // Scroll and Local.
1158         if (fillLayer.origin() != BorderFillBox) {
1159             left = borderLeft();
1160             right = borderRight();
1161             top = borderTop();
1162             bottom = borderBottom();
1163             if (fillLayer.origin() == ContentFillBox) {
1164                 left += paddingLeft();
1165                 right += paddingRight();
1166                 top += paddingTop();
1167                 bottom += paddingBottom();
1168             }
1169         }
1170
1171         // The background of the box generated by the root element covers the entire canvas including
1172         // its margins. Since those were added in already, we have to factor them out when computing
1173         // the background positioning area.
1174         if (isDocumentElementRenderer()) {
1175             positioningAreaSize = downcast<RenderBox>(*this).size() - LayoutSize(left + right, top + bottom);
1176             positioningAreaSize = LayoutSize(snapSizeToDevicePixel(positioningAreaSize, LayoutPoint(), deviceScaleFactor));
1177             if (view().frameView().hasExtendedBackgroundRectForPainting()) {
1178                 LayoutRect extendedBackgroundRect = view().frameView().extendedBackgroundRectForPainting();
1179                 left += (marginLeft() - extendedBackgroundRect.x());
1180                 top += (marginTop() - extendedBackgroundRect.y());
1181             }
1182         } else {
1183             positioningAreaSize = borderBoxRect.size() - LayoutSize(left + right, top + bottom);
1184             positioningAreaSize = LayoutSize(snapRectToDevicePixels(LayoutRect(paintOffset, positioningAreaSize), deviceScaleFactor).size());
1185         }
1186     } else {
1187         LayoutRect viewportRect;
1188         float topContentInset = 0;
1189         if (settings().fixedBackgroundsPaintRelativeToDocument())
1190             viewportRect = view().unscaledDocumentRect();
1191         else {
1192             FrameView& frameView = view().frameView();
1193             bool useFixedLayout = frameView.useFixedLayout() && !frameView.fixedLayoutSize().isEmpty();
1194
1195             if (useFixedLayout) {
1196                 // Use the fixedLayoutSize() when useFixedLayout() because the rendering will scale
1197                 // down the frameView to to fit in the current viewport.
1198                 viewportRect.setSize(frameView.fixedLayoutSize());
1199             } else
1200                 viewportRect.setSize(frameView.sizeForVisibleContent());
1201
1202             if (fixedBackgroundPaintsInLocalCoordinates()) {
1203                 if (!useFixedLayout) {
1204                     // Shifting location up by topContentInset is needed for layout tests which expect
1205                     // layout to be shifted down when calling window.internals.setTopContentInset().
1206                     topContentInset = frameView.topContentInset(ScrollView::TopContentInsetType::WebCoreOrPlatformContentInset);
1207                     viewportRect.setLocation(LayoutPoint(0, -topContentInset));
1208                 }
1209             } else if (useFixedLayout || frameView.frameScaleFactor() != 1) {
1210                 // scrollPositionForFixedPosition() is adjusted for page scale and it does not include
1211                 // topContentInset so do not add it to the calculation below.
1212                 viewportRect.setLocation(frameView.scrollPositionForFixedPosition());
1213             } else {
1214                 // documentScrollPositionRelativeToViewOrigin() includes -topContentInset in its height
1215                 // so we need to account for that in calculating the phase size
1216                 topContentInset = frameView.topContentInset(ScrollView::TopContentInsetType::WebCoreOrPlatformContentInset);
1217                 viewportRect.setLocation(frameView.documentScrollPositionRelativeToViewOrigin());
1218             }
1219
1220             top += topContentInset;
1221         }
1222         
1223         if (paintContainer)
1224             viewportRect.moveBy(LayoutPoint(-paintContainer->localToAbsolute(FloatPoint())));
1225
1226         destinationRect = viewportRect;
1227         positioningAreaSize = destinationRect.size();
1228         positioningAreaSize.setHeight(positioningAreaSize.height() - topContentInset);
1229         positioningAreaSize = LayoutSize(snapRectToDevicePixels(LayoutRect(destinationRect.location(), positioningAreaSize), deviceScaleFactor).size());
1230     }
1231
1232     auto clientForBackgroundImage = backgroundObject ? backgroundObject : this;
1233     LayoutSize tileSize = calculateFillTileSize(fillLayer, positioningAreaSize);
1234     if (StyleImage* layerImage = fillLayer.image())
1235         layerImage->setContainerSizeForRenderer(clientForBackgroundImage, tileSize, style().effectiveZoom());
1236     
1237     EFillRepeat backgroundRepeatX = fillLayer.repeatX();
1238     EFillRepeat backgroundRepeatY = fillLayer.repeatY();
1239     LayoutUnit availableWidth = positioningAreaSize.width() - tileSize.width();
1240     LayoutUnit availableHeight = positioningAreaSize.height() - tileSize.height();
1241
1242     LayoutSize spaceSize;
1243     LayoutSize phase;
1244     LayoutSize noRepeat;
1245     LayoutUnit computedXPosition = resolveEdgeRelativeLength(fillLayer.xPosition(), fillLayer.backgroundXOrigin(), availableWidth, positioningAreaSize, tileSize);
1246     if (backgroundRepeatX == RoundFill && positioningAreaSize.width() > 0 && tileSize.width() > 0) {
1247         int numTiles = std::max(1, roundToInt(positioningAreaSize.width() / tileSize.width()));
1248         if (fillLayer.size().size.height.isAuto() && backgroundRepeatY != RoundFill)
1249             tileSize.setHeight(tileSize.height() * positioningAreaSize.width() / (numTiles * tileSize.width()));
1250
1251         tileSize.setWidth(positioningAreaSize.width() / numTiles);
1252         phase.setWidth(tileSize.width() ? tileSize.width() - fmodf((computedXPosition + left), tileSize.width()) : 0);
1253     }
1254
1255     LayoutUnit computedYPosition = resolveEdgeRelativeLength(fillLayer.yPosition(), fillLayer.backgroundYOrigin(), availableHeight, positioningAreaSize, tileSize);
1256     if (backgroundRepeatY == RoundFill && positioningAreaSize.height() > 0 && tileSize.height() > 0) {
1257         int numTiles = std::max(1, roundToInt(positioningAreaSize.height() / tileSize.height()));
1258         if (fillLayer.size().size.width.isAuto() && backgroundRepeatX != RoundFill)
1259             tileSize.setWidth(tileSize.width() * positioningAreaSize.height() / (numTiles * tileSize.height()));
1260
1261         tileSize.setHeight(positioningAreaSize.height() / numTiles);
1262         phase.setHeight(tileSize.height() ? tileSize.height() - fmodf((computedYPosition + top), tileSize.height()) : 0);
1263     }
1264
1265     if (backgroundRepeatX == RepeatFill) {
1266         phase.setWidth(tileSize.width() ? tileSize.width() - fmodf(computedXPosition + left, tileSize.width()) : 0);
1267         spaceSize.setWidth(0);
1268     } else if (backgroundRepeatX == SpaceFill && tileSize.width() > 0) {
1269         LayoutUnit space = getSpace(positioningAreaSize.width(), tileSize.width());
1270         if (space >= 0) {
1271             LayoutUnit actualWidth = tileSize.width() + space;
1272             computedXPosition = minimumValueForLength(Length(), availableWidth);
1273             spaceSize.setWidth(space);
1274             spaceSize.setHeight(0);
1275             phase.setWidth(actualWidth ? actualWidth - fmodf((computedXPosition + left), actualWidth) : 0);
1276         } else
1277             backgroundRepeatX = NoRepeatFill;
1278     }
1279
1280     if (backgroundRepeatX == NoRepeatFill) {
1281         LayoutUnit xOffset = left + computedXPosition;
1282         if (xOffset > 0)
1283             destinationRect.move(xOffset, 0);
1284         xOffset = std::min<LayoutUnit>(xOffset, 0);
1285         phase.setWidth(-xOffset);
1286         destinationRect.setWidth(tileSize.width() + xOffset);
1287         spaceSize.setWidth(0);
1288     }
1289
1290     if (backgroundRepeatY == RepeatFill) {
1291         phase.setHeight(tileSize.height() ? tileSize.height() - fmodf(computedYPosition + top, tileSize.height()) : 0);
1292         spaceSize.setHeight(0);
1293     } else if (backgroundRepeatY == SpaceFill && tileSize.height() > 0) {
1294         LayoutUnit space = getSpace(positioningAreaSize.height(), tileSize.height());
1295
1296         if (space >= 0) {
1297             LayoutUnit actualHeight = tileSize.height() + space;
1298             computedYPosition = minimumValueForLength(Length(), availableHeight);
1299             spaceSize.setHeight(space);
1300             phase.setHeight(actualHeight ? actualHeight - fmodf((computedYPosition + top), actualHeight) : 0);
1301         } else
1302             backgroundRepeatY = NoRepeatFill;
1303     }
1304     if (backgroundRepeatY == NoRepeatFill) {
1305         LayoutUnit yOffset = top + computedYPosition;
1306         if (yOffset > 0)
1307             destinationRect.move(0, yOffset);
1308         yOffset = std::min<LayoutUnit>(yOffset, 0);
1309         phase.setHeight(-yOffset);
1310         destinationRect.setHeight(tileSize.height() + yOffset);
1311         spaceSize.setHeight(0);
1312     }
1313
1314     if (fixedAttachment) {
1315         LayoutPoint attachmentPoint = borderBoxRect.location();
1316         phase.expand(std::max<LayoutUnit>(attachmentPoint.x() - destinationRect.x(), 0), std::max<LayoutUnit>(attachmentPoint.y() - destinationRect.y(), 0));
1317     }
1318
1319     destinationRect.intersect(borderBoxRect);
1320     pixelSnapBackgroundImageGeometryForPainting(destinationRect, tileSize, phase, spaceSize, deviceScaleFactor);
1321     return BackgroundImageGeometry(destinationRect, tileSize, phase, spaceSize, fixedAttachment);
1322 }
1323
1324 void RenderBoxModelObject::getGeometryForBackgroundImage(const RenderLayerModelObject* paintContainer, const LayoutPoint& paintOffset, FloatRect& destRect, FloatSize& phase, FloatSize& tileSize) const
1325 {
1326     LayoutRect paintRect(destRect);
1327     auto geometry = calculateBackgroundImageGeometry(paintContainer, style().backgroundLayers(), paintOffset, paintRect);
1328     phase = geometry.phase();
1329     tileSize = geometry.tileSize();
1330     destRect = geometry.destRect();
1331 }
1332
1333 bool RenderBoxModelObject::paintNinePieceImage(GraphicsContext& graphicsContext, const LayoutRect& rect, const RenderStyle& style,
1334                                                const NinePieceImage& ninePieceImage, CompositeOperator op)
1335 {
1336     StyleImage* styleImage = ninePieceImage.image();
1337     if (!styleImage)
1338         return false;
1339
1340     if (!styleImage->isLoaded())
1341         return true; // Never paint a nine-piece image incrementally, but don't paint the fallback borders either.
1342
1343     if (!styleImage->canRender(this, style.effectiveZoom()))
1344         return false;
1345
1346     // FIXME: border-image is broken with full page zooming when tiling has to happen, since the tiling function
1347     // doesn't have any understanding of the zoom that is in effect on the tile.
1348     float deviceScaleFactor = document().deviceScaleFactor();
1349
1350     LayoutRect rectWithOutsets = rect;
1351     rectWithOutsets.expand(style.imageOutsets(ninePieceImage));
1352     LayoutRect destination = LayoutRect(snapRectToDevicePixels(rectWithOutsets, deviceScaleFactor));
1353
1354     LayoutSize source = calculateImageIntrinsicDimensions(styleImage, destination.size(), DoNotScaleByEffectiveZoom);
1355
1356     // If both values are ‘auto’ then the intrinsic width and/or height of the image should be used, if any.
1357     styleImage->setContainerSizeForRenderer(this, source, style.effectiveZoom());
1358
1359     ninePieceImage.paint(graphicsContext, this, style, destination, source, deviceScaleFactor, op);
1360     return true;
1361 }
1362
1363 static bool allCornersClippedOut(const RoundedRect& border, const LayoutRect& clipRect)
1364 {
1365     LayoutRect boundingRect = border.rect();
1366     if (clipRect.contains(boundingRect))
1367         return false;
1368
1369     RoundedRect::Radii radii = border.radii();
1370
1371     LayoutRect topLeftRect(boundingRect.location(), radii.topLeft());
1372     if (clipRect.intersects(topLeftRect))
1373         return false;
1374
1375     LayoutRect topRightRect(boundingRect.location(), radii.topRight());
1376     topRightRect.setX(boundingRect.maxX() - topRightRect.width());
1377     if (clipRect.intersects(topRightRect))
1378         return false;
1379
1380     LayoutRect bottomLeftRect(boundingRect.location(), radii.bottomLeft());
1381     bottomLeftRect.setY(boundingRect.maxY() - bottomLeftRect.height());
1382     if (clipRect.intersects(bottomLeftRect))
1383         return false;
1384
1385     LayoutRect bottomRightRect(boundingRect.location(), radii.bottomRight());
1386     bottomRightRect.setX(boundingRect.maxX() - bottomRightRect.width());
1387     bottomRightRect.setY(boundingRect.maxY() - bottomRightRect.height());
1388     if (clipRect.intersects(bottomRightRect))
1389         return false;
1390
1391     return true;
1392 }
1393
1394 static bool borderWillArcInnerEdge(const LayoutSize& firstRadius, const FloatSize& secondRadius)
1395 {
1396     return !firstRadius.isZero() || !secondRadius.isZero();
1397 }
1398
1399 inline bool styleRequiresClipPolygon(EBorderStyle style)
1400 {
1401     return style == DOTTED || style == DASHED; // These are drawn with a stroke, so we have to clip to get corner miters.
1402 }
1403
1404 static bool borderStyleFillsBorderArea(EBorderStyle style)
1405 {
1406     return !(style == DOTTED || style == DASHED || style == DOUBLE);
1407 }
1408
1409 static bool borderStyleHasInnerDetail(EBorderStyle style)
1410 {
1411     return style == GROOVE || style == RIDGE || style == DOUBLE;
1412 }
1413
1414 static bool borderStyleIsDottedOrDashed(EBorderStyle style)
1415 {
1416     return style == DOTTED || style == DASHED;
1417 }
1418
1419 // OUTSET darkens the bottom and right (and maybe lightens the top and left)
1420 // INSET darkens the top and left (and maybe lightens the bottom and right)
1421 static inline bool borderStyleHasUnmatchedColorsAtCorner(EBorderStyle style, BoxSide side, BoxSide adjacentSide)
1422 {
1423     // These styles match at the top/left and bottom/right.
1424     if (style == INSET || style == GROOVE || style == RIDGE || style == OUTSET) {
1425         const BorderEdgeFlags topRightFlags = edgeFlagForSide(BSTop) | edgeFlagForSide(BSRight);
1426         const BorderEdgeFlags bottomLeftFlags = edgeFlagForSide(BSBottom) | edgeFlagForSide(BSLeft);
1427
1428         BorderEdgeFlags flags = edgeFlagForSide(side) | edgeFlagForSide(adjacentSide);
1429         return flags == topRightFlags || flags == bottomLeftFlags;
1430     }
1431     return false;
1432 }
1433
1434 static inline bool colorsMatchAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1435 {
1436     if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1437         return false;
1438
1439     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1440         return false;
1441
1442     return !borderStyleHasUnmatchedColorsAtCorner(edges[side].style(), side, adjacentSide);
1443 }
1444
1445
1446 static inline bool colorNeedsAntiAliasAtCorner(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1447 {
1448     if (edges[side].color().isOpaque())
1449         return false;
1450
1451     if (edges[side].shouldRender() != edges[adjacentSide].shouldRender())
1452         return false;
1453
1454     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1455         return true;
1456
1457     return borderStyleHasUnmatchedColorsAtCorner(edges[side].style(), side, adjacentSide);
1458 }
1459
1460 // This assumes that we draw in order: top, bottom, left, right.
1461 static inline bool willBeOverdrawn(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[])
1462 {
1463     switch (side) {
1464     case BSTop:
1465     case BSBottom:
1466         if (edges[adjacentSide].presentButInvisible())
1467             return false;
1468
1469         if (!edgesShareColor(edges[side], edges[adjacentSide]) && !edges[adjacentSide].color().isOpaque())
1470             return false;
1471         
1472         if (!borderStyleFillsBorderArea(edges[adjacentSide].style()))
1473             return false;
1474
1475         return true;
1476
1477     case BSLeft:
1478     case BSRight:
1479         // These draw last, so are never overdrawn.
1480         return false;
1481     }
1482     return false;
1483 }
1484
1485 static inline bool borderStylesRequireMitre(BoxSide side, BoxSide adjacentSide, EBorderStyle style, EBorderStyle adjacentStyle)
1486 {
1487     if (style == DOUBLE || adjacentStyle == DOUBLE || adjacentStyle == GROOVE || adjacentStyle == RIDGE)
1488         return true;
1489
1490     if (borderStyleIsDottedOrDashed(style) != borderStyleIsDottedOrDashed(adjacentStyle))
1491         return true;
1492
1493     if (style != adjacentStyle)
1494         return true;
1495
1496     return borderStyleHasUnmatchedColorsAtCorner(style, side, adjacentSide);
1497 }
1498
1499 static bool joinRequiresMitre(BoxSide side, BoxSide adjacentSide, const BorderEdge edges[], bool allowOverdraw)
1500 {
1501     if ((edges[side].isTransparent() && edges[adjacentSide].isTransparent()) || !edges[adjacentSide].isPresent())
1502         return false;
1503
1504     if (allowOverdraw && willBeOverdrawn(side, adjacentSide, edges))
1505         return false;
1506
1507     if (!edgesShareColor(edges[side], edges[adjacentSide]))
1508         return true;
1509
1510     if (borderStylesRequireMitre(side, adjacentSide, edges[side].style(), edges[adjacentSide].style()))
1511         return true;
1512     
1513     return false;
1514 }
1515
1516 static RoundedRect calculateAdjustedInnerBorder(const RoundedRect&innerBorder, BoxSide side)
1517 {
1518     // Expand the inner border as necessary to make it a rounded rect (i.e. radii contained within each edge).
1519     // This function relies on the fact we only get radii not contained within each edge if one of the radii
1520     // for an edge is zero, so we can shift the arc towards the zero radius corner.
1521     RoundedRect::Radii newRadii = innerBorder.radii();
1522     LayoutRect newRect = innerBorder.rect();
1523
1524     float overshoot;
1525     float maxRadii;
1526
1527     switch (side) {
1528     case BSTop:
1529         overshoot = newRadii.topLeft().width() + newRadii.topRight().width() - newRect.width();
1530         if (overshoot > 0) {
1531             ASSERT(!(newRadii.topLeft().width() && newRadii.topRight().width()));
1532             newRect.setWidth(newRect.width() + overshoot);
1533             if (!newRadii.topLeft().width())
1534                 newRect.move(-overshoot, 0);
1535         }
1536         newRadii.setBottomLeft(IntSize(0, 0));
1537         newRadii.setBottomRight(IntSize(0, 0));
1538         maxRadii = std::max(newRadii.topLeft().height(), newRadii.topRight().height());
1539         if (maxRadii > newRect.height())
1540             newRect.setHeight(maxRadii);
1541         break;
1542
1543     case BSBottom:
1544         overshoot = newRadii.bottomLeft().width() + newRadii.bottomRight().width() - newRect.width();
1545         if (overshoot > 0) {
1546             ASSERT(!(newRadii.bottomLeft().width() && newRadii.bottomRight().width()));
1547             newRect.setWidth(newRect.width() + overshoot);
1548             if (!newRadii.bottomLeft().width())
1549                 newRect.move(-overshoot, 0);
1550         }
1551         newRadii.setTopLeft(IntSize(0, 0));
1552         newRadii.setTopRight(IntSize(0, 0));
1553         maxRadii = std::max(newRadii.bottomLeft().height(), newRadii.bottomRight().height());
1554         if (maxRadii > newRect.height()) {
1555             newRect.move(0, newRect.height() - maxRadii);
1556             newRect.setHeight(maxRadii);
1557         }
1558         break;
1559
1560     case BSLeft:
1561         overshoot = newRadii.topLeft().height() + newRadii.bottomLeft().height() - newRect.height();
1562         if (overshoot > 0) {
1563             ASSERT(!(newRadii.topLeft().height() && newRadii.bottomLeft().height()));
1564             newRect.setHeight(newRect.height() + overshoot);
1565             if (!newRadii.topLeft().height())
1566                 newRect.move(0, -overshoot);
1567         }
1568         newRadii.setTopRight(IntSize(0, 0));
1569         newRadii.setBottomRight(IntSize(0, 0));
1570         maxRadii = std::max(newRadii.topLeft().width(), newRadii.bottomLeft().width());
1571         if (maxRadii > newRect.width())
1572             newRect.setWidth(maxRadii);
1573         break;
1574
1575     case BSRight:
1576         overshoot = newRadii.topRight().height() + newRadii.bottomRight().height() - newRect.height();
1577         if (overshoot > 0) {
1578             ASSERT(!(newRadii.topRight().height() && newRadii.bottomRight().height()));
1579             newRect.setHeight(newRect.height() + overshoot);
1580             if (!newRadii.topRight().height())
1581                 newRect.move(0, -overshoot);
1582         }
1583         newRadii.setTopLeft(IntSize(0, 0));
1584         newRadii.setBottomLeft(IntSize(0, 0));
1585         maxRadii = std::max(newRadii.topRight().width(), newRadii.bottomRight().width());
1586         if (maxRadii > newRect.width()) {
1587             newRect.move(newRect.width() - maxRadii, 0);
1588             newRect.setWidth(maxRadii);
1589         }
1590         break;
1591     }
1592
1593     return RoundedRect(newRect, newRadii);
1594 }
1595
1596 void RenderBoxModelObject::paintOneBorderSide(GraphicsContext& graphicsContext, const RenderStyle& style, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1597     const LayoutRect& sideRect, BoxSide side, BoxSide adjacentSide1, BoxSide adjacentSide2, const BorderEdge edges[], const Path* path,
1598     BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor)
1599 {
1600     const BorderEdge& edgeToRender = edges[side];
1601     ASSERT(edgeToRender.widthForPainting());
1602     const BorderEdge& adjacentEdge1 = edges[adjacentSide1];
1603     const BorderEdge& adjacentEdge2 = edges[adjacentSide2];
1604
1605     bool mitreAdjacentSide1 = joinRequiresMitre(side, adjacentSide1, edges, !antialias);
1606     bool mitreAdjacentSide2 = joinRequiresMitre(side, adjacentSide2, edges, !antialias);
1607     
1608     bool adjacentSide1StylesMatch = colorsMatchAtCorner(side, adjacentSide1, edges);
1609     bool adjacentSide2StylesMatch = colorsMatchAtCorner(side, adjacentSide2, edges);
1610
1611     const Color& colorToPaint = overrideColor ? *overrideColor : edgeToRender.color();
1612
1613     if (path) {
1614         GraphicsContextStateSaver stateSaver(graphicsContext);
1615
1616         clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, adjacentSide1StylesMatch, adjacentSide2StylesMatch);
1617
1618         if (!innerBorder.isRenderable())
1619             graphicsContext.clipOutRoundedRect(FloatRoundedRect(calculateAdjustedInnerBorder(innerBorder, side)));
1620
1621         float thickness = std::max(std::max(edgeToRender.widthForPainting(), adjacentEdge1.widthForPainting()), adjacentEdge2.widthForPainting());
1622         drawBoxSideFromPath(graphicsContext, outerBorder.rect(), *path, edges, edgeToRender.widthForPainting(), thickness, side, style,
1623             colorToPaint, edgeToRender.style(), bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
1624     } else {
1625         bool clipForStyle = styleRequiresClipPolygon(edgeToRender.style()) && (mitreAdjacentSide1 || mitreAdjacentSide2);
1626         bool clipAdjacentSide1 = colorNeedsAntiAliasAtCorner(side, adjacentSide1, edges) && mitreAdjacentSide1;
1627         bool clipAdjacentSide2 = colorNeedsAntiAliasAtCorner(side, adjacentSide2, edges) && mitreAdjacentSide2;
1628         bool shouldClip = clipForStyle || clipAdjacentSide1 || clipAdjacentSide2;
1629         
1630         GraphicsContextStateSaver clipStateSaver(graphicsContext, shouldClip);
1631         if (shouldClip) {
1632             bool aliasAdjacentSide1 = clipAdjacentSide1 || (clipForStyle && mitreAdjacentSide1);
1633             bool aliasAdjacentSide2 = clipAdjacentSide2 || (clipForStyle && mitreAdjacentSide2);
1634             clipBorderSidePolygon(graphicsContext, outerBorder, innerBorder, side, !aliasAdjacentSide1, !aliasAdjacentSide2);
1635             // Since we clipped, no need to draw with a mitre.
1636             mitreAdjacentSide1 = false;
1637             mitreAdjacentSide2 = false;
1638         }
1639         drawLineForBoxSide(graphicsContext, sideRect, side, colorToPaint, edgeToRender.style(), mitreAdjacentSide1 ? adjacentEdge1.widthForPainting() : 0, mitreAdjacentSide2 ? adjacentEdge2.widthForPainting() : 0, antialias);
1640     }
1641 }
1642
1643 static LayoutRect calculateSideRect(const RoundedRect& outerBorder, const BorderEdge edges[], int side)
1644 {
1645     LayoutRect sideRect = outerBorder.rect();
1646     float width = edges[side].widthForPainting();
1647
1648     if (side == BSTop)
1649         sideRect.setHeight(width);
1650     else if (side == BSBottom)
1651         sideRect.shiftYEdgeTo(sideRect.maxY() - width);
1652     else if (side == BSLeft)
1653         sideRect.setWidth(width);
1654     else
1655         sideRect.shiftXEdgeTo(sideRect.maxX() - width);
1656
1657     return sideRect;
1658 }
1659
1660 void RenderBoxModelObject::paintBorderSides(GraphicsContext& graphicsContext, const RenderStyle& style, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
1661     const IntPoint& innerBorderAdjustment, const BorderEdge edges[], BorderEdgeFlags edgeSet, BackgroundBleedAvoidance bleedAvoidance,
1662     bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias, const Color* overrideColor)
1663 {
1664     bool renderRadii = outerBorder.isRounded();
1665
1666     Path roundedPath;
1667     if (renderRadii)
1668         roundedPath.addRoundedRect(outerBorder);
1669     
1670     // The inner border adjustment for bleed avoidance mode BackgroundBleedBackgroundOverBorder
1671     // is only applied to sideRect, which is okay since BackgroundBleedBackgroundOverBorder
1672     // is only to be used for solid borders and the shape of the border painted by drawBoxSideFromPath
1673     // only depends on sideRect when painting solid borders.
1674
1675     if (edges[BSTop].shouldRender() && includesEdge(edgeSet, BSTop)) {
1676         LayoutRect sideRect = outerBorder.rect();
1677         sideRect.setHeight(edges[BSTop].widthForPainting() + innerBorderAdjustment.y());
1678
1679         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSTop].style()) || borderWillArcInnerEdge(innerBorder.radii().topLeft(), innerBorder.radii().topRight()));
1680         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSTop, BSLeft, BSRight, edges, usePath ? &roundedPath : nullptr, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1681     }
1682
1683     if (edges[BSBottom].shouldRender() && includesEdge(edgeSet, BSBottom)) {
1684         LayoutRect sideRect = outerBorder.rect();
1685         sideRect.shiftYEdgeTo(sideRect.maxY() - edges[BSBottom].widthForPainting() - innerBorderAdjustment.y());
1686
1687         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSBottom].style()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().bottomRight()));
1688         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSBottom, BSLeft, BSRight, edges, usePath ? &roundedPath : nullptr, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1689     }
1690
1691     if (edges[BSLeft].shouldRender() && includesEdge(edgeSet, BSLeft)) {
1692         LayoutRect sideRect = outerBorder.rect();
1693         sideRect.setWidth(edges[BSLeft].widthForPainting() + innerBorderAdjustment.x());
1694
1695         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSLeft].style()) || borderWillArcInnerEdge(innerBorder.radii().bottomLeft(), innerBorder.radii().topLeft()));
1696         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSLeft, BSTop, BSBottom, edges, usePath ? &roundedPath : nullptr, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1697     }
1698
1699     if (edges[BSRight].shouldRender() && includesEdge(edgeSet, BSRight)) {
1700         LayoutRect sideRect = outerBorder.rect();
1701         sideRect.shiftXEdgeTo(sideRect.maxX() - edges[BSRight].widthForPainting() - innerBorderAdjustment.x());
1702
1703         bool usePath = renderRadii && (borderStyleHasInnerDetail(edges[BSRight].style()) || borderWillArcInnerEdge(innerBorder.radii().bottomRight(), innerBorder.radii().topRight()));
1704         paintOneBorderSide(graphicsContext, style, outerBorder, innerBorder, sideRect, BSRight, BSTop, BSBottom, edges, usePath ? &roundedPath : nullptr, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, overrideColor);
1705     }
1706 }
1707
1708 void RenderBoxModelObject::paintTranslucentBorderSides(GraphicsContext& graphicsContext, const RenderStyle& style, const RoundedRect& outerBorder, const RoundedRect& innerBorder, const IntPoint& innerBorderAdjustment,
1709     const BorderEdge edges[], BorderEdgeFlags edgesToDraw, BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge, bool antialias)
1710 {
1711     // willBeOverdrawn assumes that we draw in order: top, bottom, left, right.
1712     // This is different from BoxSide enum order.
1713     static const BoxSide paintOrder[] = { BSTop, BSBottom, BSLeft, BSRight };
1714
1715     while (edgesToDraw) {
1716         // Find undrawn edges sharing a color.
1717         Color commonColor;
1718         
1719         BorderEdgeFlags commonColorEdgeSet = 0;
1720         for (size_t i = 0; i < sizeof(paintOrder) / sizeof(paintOrder[0]); ++i) {
1721             BoxSide currSide = paintOrder[i];
1722             if (!includesEdge(edgesToDraw, currSide))
1723                 continue;
1724
1725             bool includeEdge;
1726             if (!commonColorEdgeSet) {
1727                 commonColor = edges[currSide].color();
1728                 includeEdge = true;
1729             } else
1730                 includeEdge = edges[currSide].color() == commonColor;
1731
1732             if (includeEdge)
1733                 commonColorEdgeSet |= edgeFlagForSide(currSide);
1734         }
1735
1736         bool useTransparencyLayer = includesAdjacentEdges(commonColorEdgeSet) && !commonColor.isOpaque();
1737         if (useTransparencyLayer) {
1738             graphicsContext.beginTransparencyLayer(commonColor.alphaAsFloat());
1739             commonColor = commonColor.opaqueColor();
1740         }
1741
1742         paintBorderSides(graphicsContext, style, outerBorder, innerBorder, innerBorderAdjustment, edges, commonColorEdgeSet, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias, &commonColor);
1743             
1744         if (useTransparencyLayer)
1745             graphicsContext.endTransparencyLayer();
1746         
1747         edgesToDraw &= ~commonColorEdgeSet;
1748     }
1749 }
1750
1751 void RenderBoxModelObject::paintBorder(const PaintInfo& info, const LayoutRect& rect, const RenderStyle& style,
1752                                        BackgroundBleedAvoidance bleedAvoidance, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1753 {
1754     GraphicsContext& graphicsContext = info.context();
1755
1756     if (graphicsContext.paintingDisabled())
1757         return;
1758
1759     if (rect.isEmpty())
1760         return;
1761
1762     auto rectToClipOut = paintRectToClipOutFromBorder(rect);
1763     bool appliedClipAlready = !rectToClipOut.isEmpty();
1764     GraphicsContextStateSaver stateSave(graphicsContext, appliedClipAlready);
1765     if (!rectToClipOut.isEmpty())
1766         graphicsContext.clipOut(snapRectToDevicePixels(rectToClipOut, document().deviceScaleFactor()));
1767
1768     // border-image is not affected by border-radius.
1769     if (paintNinePieceImage(graphicsContext, rect, style, style.borderImage()))
1770         return;
1771
1772     BorderEdge edges[4];
1773     BorderEdge::getBorderEdgeInfo(edges, style, document().deviceScaleFactor(), includeLogicalLeftEdge, includeLogicalRightEdge);
1774     RoundedRect outerBorder = style.getRoundedBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge);
1775     RoundedRect innerBorder = style.getRoundedInnerBorderFor(borderInnerRectAdjustedForBleedAvoidance(graphicsContext, rect, bleedAvoidance), includeLogicalLeftEdge, includeLogicalRightEdge);
1776
1777     // If no borders intersects with the dirty area, we can skip the border painting.
1778     if (innerBorder.contains(info.rect))
1779         return;
1780
1781     bool haveAlphaColor = false;
1782     bool haveAllSolidEdges = true;
1783     bool haveAllDoubleEdges = true;
1784     int numEdgesVisible = 4;
1785     bool allEdgesShareColor = true;
1786     int firstVisibleEdge = -1;
1787     BorderEdgeFlags edgesToDraw = 0;
1788
1789     for (int i = BSTop; i <= BSLeft; ++i) {
1790         const BorderEdge& currEdge = edges[i];
1791
1792         if (edges[i].shouldRender())
1793             edgesToDraw |= edgeFlagForSide(static_cast<BoxSide>(i));
1794
1795         if (currEdge.presentButInvisible()) {
1796             --numEdgesVisible;
1797             allEdgesShareColor = false;
1798             continue;
1799         }
1800         
1801         if (!currEdge.widthForPainting()) {
1802             --numEdgesVisible;
1803             continue;
1804         }
1805
1806         if (firstVisibleEdge == -1)
1807             firstVisibleEdge = i;
1808         else if (currEdge.color() != edges[firstVisibleEdge].color())
1809             allEdgesShareColor = false;
1810
1811         if (!currEdge.color().isOpaque())
1812             haveAlphaColor = true;
1813         
1814         if (currEdge.style() != SOLID)
1815             haveAllSolidEdges = false;
1816
1817         if (currEdge.style() != DOUBLE)
1818             haveAllDoubleEdges = false;
1819     }
1820
1821     // If no corner intersects the clip region, we can pretend outerBorder is
1822     // rectangular to improve performance.
1823     if (haveAllSolidEdges && outerBorder.isRounded() && allCornersClippedOut(outerBorder, info.rect))
1824         outerBorder.setRadii(RoundedRect::Radii());
1825
1826     float deviceScaleFactor = document().deviceScaleFactor();
1827     // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787
1828     if ((haveAllSolidEdges || haveAllDoubleEdges) && allEdgesShareColor && innerBorder.isRenderable()) {
1829         // Fast path for drawing all solid edges and all unrounded double edges
1830         if (numEdgesVisible == 4 && (outerBorder.isRounded() || haveAlphaColor)
1831             && (haveAllSolidEdges || (!outerBorder.isRounded() && !innerBorder.isRounded()))) {
1832             Path path;
1833             
1834             FloatRoundedRect pixelSnappedOuterBorder = outerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
1835             if (pixelSnappedOuterBorder.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer)
1836                 path.addRoundedRect(pixelSnappedOuterBorder);
1837             else
1838                 path.addRect(pixelSnappedOuterBorder.rect());
1839
1840             if (haveAllDoubleEdges) {
1841                 LayoutRect innerThirdRect = outerBorder.rect();
1842                 LayoutRect outerThirdRect = outerBorder.rect();
1843                 for (int side = BSTop; side <= BSLeft; ++side) {
1844                     LayoutUnit outerWidth;
1845                     LayoutUnit innerWidth;
1846                     edges[side].getDoubleBorderStripeWidths(outerWidth, innerWidth);
1847
1848                     if (side == BSTop) {
1849                         innerThirdRect.shiftYEdgeTo(innerThirdRect.y() + innerWidth);
1850                         outerThirdRect.shiftYEdgeTo(outerThirdRect.y() + outerWidth);
1851                     } else if (side == BSBottom) {
1852                         innerThirdRect.setHeight(innerThirdRect.height() - innerWidth);
1853                         outerThirdRect.setHeight(outerThirdRect.height() - outerWidth);
1854                     } else if (side == BSLeft) {
1855                         innerThirdRect.shiftXEdgeTo(innerThirdRect.x() + innerWidth);
1856                         outerThirdRect.shiftXEdgeTo(outerThirdRect.x() + outerWidth);
1857                     } else {
1858                         innerThirdRect.setWidth(innerThirdRect.width() - innerWidth);
1859                         outerThirdRect.setWidth(outerThirdRect.width() - outerWidth);
1860                     }
1861                 }
1862
1863                 FloatRoundedRect pixelSnappedOuterThird = outerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
1864                 pixelSnappedOuterThird.setRect(snapRectToDevicePixels(outerThirdRect, deviceScaleFactor));
1865
1866                 if (pixelSnappedOuterThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer)
1867                     path.addRoundedRect(pixelSnappedOuterThird);
1868                 else
1869                     path.addRect(pixelSnappedOuterThird.rect());
1870
1871                 FloatRoundedRect pixelSnappedInnerThird = innerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
1872                 pixelSnappedInnerThird.setRect(snapRectToDevicePixels(innerThirdRect, deviceScaleFactor));
1873                 if (pixelSnappedInnerThird.isRounded() && bleedAvoidance != BackgroundBleedUseTransparencyLayer)
1874                     path.addRoundedRect(pixelSnappedInnerThird);
1875                 else
1876                     path.addRect(pixelSnappedInnerThird.rect());
1877             }
1878
1879             FloatRoundedRect pixelSnappedInnerBorder = innerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
1880             if (pixelSnappedInnerBorder.isRounded())
1881                 path.addRoundedRect(pixelSnappedInnerBorder);
1882             else
1883                 path.addRect(pixelSnappedInnerBorder.rect());
1884             
1885             graphicsContext.setFillRule(RULE_EVENODD);
1886             graphicsContext.setFillColor(edges[firstVisibleEdge].color());
1887             graphicsContext.fillPath(path);
1888             return;
1889         } 
1890         // Avoid creating transparent layers
1891         if (haveAllSolidEdges && numEdgesVisible != 4 && !outerBorder.isRounded() && haveAlphaColor) {
1892             Path path;
1893
1894             for (int i = BSTop; i <= BSLeft; ++i) {
1895                 const BorderEdge& currEdge = edges[i];
1896                 if (currEdge.shouldRender()) {
1897                     LayoutRect sideRect = calculateSideRect(outerBorder, edges, i);
1898                     path.addRect(sideRect);
1899                 }
1900             }
1901
1902             graphicsContext.setFillRule(RULE_NONZERO);
1903             graphicsContext.setFillColor(edges[firstVisibleEdge].color());
1904             graphicsContext.fillPath(path);
1905             return;
1906         }
1907     }
1908
1909     bool clipToOuterBorder = outerBorder.isRounded();
1910     GraphicsContextStateSaver stateSaver(graphicsContext, clipToOuterBorder && !appliedClipAlready);
1911     if (clipToOuterBorder) {
1912         // Clip to the inner and outer radii rects.
1913         if (bleedAvoidance != BackgroundBleedUseTransparencyLayer)
1914             graphicsContext.clipRoundedRect(outerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor));
1915         // isRenderable() check avoids issue described in https://bugs.webkit.org/show_bug.cgi?id=38787
1916         // The inside will be clipped out later (in clipBorderSideForComplexInnerPath)
1917         if (innerBorder.isRenderable())
1918             graphicsContext.clipOutRoundedRect(innerBorder.pixelSnappedRoundedRectForPainting(deviceScaleFactor));
1919     }
1920
1921     // If only one edge visible antialiasing doesn't create seams
1922     bool antialias = shouldAntialiasLines(graphicsContext) || numEdgesVisible == 1;
1923     RoundedRect unadjustedInnerBorder = (bleedAvoidance == BackgroundBleedBackgroundOverBorder) ? style.getRoundedInnerBorderFor(rect, includeLogicalLeftEdge, includeLogicalRightEdge) : innerBorder;
1924     IntPoint innerBorderAdjustment(innerBorder.rect().x() - unadjustedInnerBorder.rect().x(), innerBorder.rect().y() - unadjustedInnerBorder.rect().y());
1925     if (haveAlphaColor)
1926         paintTranslucentBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias);
1927     else
1928         paintBorderSides(graphicsContext, style, outerBorder, unadjustedInnerBorder, innerBorderAdjustment, edges, edgesToDraw, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge, antialias);
1929 }
1930
1931 void RenderBoxModelObject::drawBoxSideFromPath(GraphicsContext& graphicsContext, const LayoutRect& borderRect, const Path& borderPath, const BorderEdge edges[],
1932     float thickness, float drawThickness, BoxSide side, const RenderStyle& style, Color color, EBorderStyle borderStyle, BackgroundBleedAvoidance bleedAvoidance,
1933     bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
1934 {
1935     if (thickness <= 0)
1936         return;
1937
1938     if (borderStyle == DOUBLE && thickness < 3)
1939         borderStyle = SOLID;
1940
1941     switch (borderStyle) {
1942     case BNONE:
1943     case BHIDDEN:
1944         return;
1945     case DOTTED:
1946     case DASHED: {
1947         graphicsContext.setStrokeColor(color);
1948
1949         // The stroke is doubled here because the provided path is the 
1950         // outside edge of the border so half the stroke is clipped off. 
1951         // The extra multiplier is so that the clipping mask can antialias
1952         // the edges to prevent jaggies.
1953         graphicsContext.setStrokeThickness(drawThickness * 2 * 1.1f);
1954         graphicsContext.setStrokeStyle(borderStyle == DASHED ? DashedStroke : DottedStroke);
1955
1956         // If the number of dashes that fit in the path is odd and non-integral then we
1957         // will have an awkwardly-sized dash at the end of the path. To try to avoid that
1958         // here, we simply make the whitespace dashes ever so slightly bigger.
1959         // FIXME: This could be even better if we tried to manipulate the dash offset
1960         // and possibly the gapLength to get the corners dash-symmetrical.
1961         float dashLength = thickness * ((borderStyle == DASHED) ? 3.0f : 1.0f);
1962         float gapLength = dashLength;
1963         float numberOfDashes = borderPath.length() / dashLength;
1964         // Don't try to show dashes if we have less than 2 dashes + 2 gaps.
1965         // FIXME: should do this test per side.
1966         if (numberOfDashes >= 4) {
1967             bool evenNumberOfFullDashes = !((int)numberOfDashes % 2);
1968             bool integralNumberOfDashes = !(numberOfDashes - (int)numberOfDashes);
1969             if (!evenNumberOfFullDashes && !integralNumberOfDashes) {
1970                 float numberOfGaps = numberOfDashes / 2;
1971                 gapLength += (dashLength  / numberOfGaps);
1972             }
1973
1974             DashArray lineDash;
1975             lineDash.append(dashLength);
1976             lineDash.append(gapLength);
1977             graphicsContext.setLineDash(lineDash, dashLength);
1978         }
1979         
1980         // FIXME: stroking the border path causes issues with tight corners:
1981         // https://bugs.webkit.org/show_bug.cgi?id=58711
1982         // Also, to get the best appearance we should stroke a path between the two borders.
1983         graphicsContext.strokePath(borderPath);
1984         return;
1985     }
1986     case DOUBLE: {
1987         // Get the inner border rects for both the outer border line and the inner border line
1988         LayoutUnit outerBorderTopWidth;
1989         LayoutUnit innerBorderTopWidth;
1990         edges[BSTop].getDoubleBorderStripeWidths(outerBorderTopWidth, innerBorderTopWidth);
1991
1992         LayoutUnit outerBorderRightWidth;
1993         LayoutUnit innerBorderRightWidth;
1994         edges[BSRight].getDoubleBorderStripeWidths(outerBorderRightWidth, innerBorderRightWidth);
1995
1996         LayoutUnit outerBorderBottomWidth;
1997         LayoutUnit innerBorderBottomWidth;
1998         edges[BSBottom].getDoubleBorderStripeWidths(outerBorderBottomWidth, innerBorderBottomWidth);
1999
2000         LayoutUnit outerBorderLeftWidth;
2001         LayoutUnit innerBorderLeftWidth;
2002         edges[BSLeft].getDoubleBorderStripeWidths(outerBorderLeftWidth, innerBorderLeftWidth);
2003
2004         // Draw inner border line
2005         {
2006             GraphicsContextStateSaver stateSaver(graphicsContext);
2007             RoundedRect innerClip = style.getRoundedInnerBorderFor(borderRect,
2008                 innerBorderTopWidth, innerBorderBottomWidth, innerBorderLeftWidth, innerBorderRightWidth,
2009                 includeLogicalLeftEdge, includeLogicalRightEdge);
2010             
2011             graphicsContext.clipRoundedRect(FloatRoundedRect(innerClip));
2012             drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
2013         }
2014
2015         // Draw outer border line
2016         {
2017             GraphicsContextStateSaver stateSaver(graphicsContext);
2018             LayoutRect outerRect = borderRect;
2019             if (bleedAvoidance == BackgroundBleedUseTransparencyLayer) {
2020                 outerRect.inflate(1);
2021                 ++outerBorderTopWidth;
2022                 ++outerBorderBottomWidth;
2023                 ++outerBorderLeftWidth;
2024                 ++outerBorderRightWidth;
2025             }
2026                 
2027             RoundedRect outerClip = style.getRoundedInnerBorderFor(outerRect,
2028                 outerBorderTopWidth, outerBorderBottomWidth, outerBorderLeftWidth, outerBorderRightWidth,
2029                 includeLogicalLeftEdge, includeLogicalRightEdge);
2030             graphicsContext.clipOutRoundedRect(FloatRoundedRect(outerClip));
2031             drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, SOLID, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
2032         }
2033         return;
2034     }
2035     case RIDGE:
2036     case GROOVE:
2037     {
2038         EBorderStyle s1;
2039         EBorderStyle s2;
2040         if (borderStyle == GROOVE) {
2041             s1 = INSET;
2042             s2 = OUTSET;
2043         } else {
2044             s1 = OUTSET;
2045             s2 = INSET;
2046         }
2047         
2048         // Paint full border
2049         drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s1, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
2050
2051         // Paint inner only
2052         GraphicsContextStateSaver stateSaver(graphicsContext);
2053         LayoutUnit topWidth = edges[BSTop].widthForPainting() / 2;
2054         LayoutUnit bottomWidth = edges[BSBottom].widthForPainting() / 2;
2055         LayoutUnit leftWidth = edges[BSLeft].widthForPainting() / 2;
2056         LayoutUnit rightWidth = edges[BSRight].widthForPainting() / 2;
2057
2058         RoundedRect clipRect = style.getRoundedInnerBorderFor(borderRect,
2059             topWidth, bottomWidth, leftWidth, rightWidth,
2060             includeLogicalLeftEdge, includeLogicalRightEdge);
2061
2062         graphicsContext.clipRoundedRect(FloatRoundedRect(clipRect));
2063         drawBoxSideFromPath(graphicsContext, borderRect, borderPath, edges, thickness, drawThickness, side, style, color, s2, bleedAvoidance, includeLogicalLeftEdge, includeLogicalRightEdge);
2064         return;
2065     }
2066     case INSET:
2067     case OUTSET:
2068         calculateBorderStyleColor(borderStyle, side, color);
2069         break;
2070     default:
2071         break;
2072     }
2073
2074     graphicsContext.setStrokeStyle(NoStroke);
2075     graphicsContext.setFillColor(color);
2076     graphicsContext.drawRect(snapRectToDevicePixels(borderRect, document().deviceScaleFactor()));
2077 }
2078
2079 void RenderBoxModelObject::clipBorderSidePolygon(GraphicsContext& graphicsContext, const RoundedRect& outerBorder, const RoundedRect& innerBorder,
2080                                                  BoxSide side, bool firstEdgeMatches, bool secondEdgeMatches)
2081 {
2082     float deviceScaleFactor = document().deviceScaleFactor();
2083     const FloatRect& outerRect = snapRectToDevicePixels(outerBorder.rect(), deviceScaleFactor);
2084     const FloatRect& innerRect = snapRectToDevicePixels(innerBorder.rect(), deviceScaleFactor);
2085
2086     // For each side, create a quad that encompasses all parts of that side that may draw,
2087     // including areas inside the innerBorder.
2088     //
2089     //         0----------------3
2090     //       0  \              /  0
2091     //       |\  1----------- 2  /|
2092     //       | 1                1 |   
2093     //       | |                | |
2094     //       | |                | |  
2095     //       | 2                2 |  
2096     //       |/  1------------2  \| 
2097     //       3  /              \  3   
2098     //         0----------------3
2099     //
2100     Vector<FloatPoint> quad;
2101     quad.reserveInitialCapacity(4);
2102     switch (side) {
2103     case BSTop:
2104         quad.uncheckedAppend(outerRect.minXMinYCorner());
2105         quad.uncheckedAppend(innerRect.minXMinYCorner());
2106         quad.uncheckedAppend(innerRect.maxXMinYCorner());
2107         quad.uncheckedAppend(outerRect.maxXMinYCorner());
2108
2109         if (!innerBorder.radii().topLeft().isZero())
2110             findIntersection(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), innerRect.minXMaxYCorner(), innerRect.maxXMinYCorner(), quad[1]);
2111
2112         if (!innerBorder.radii().topRight().isZero())
2113             findIntersection(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[2]);
2114         break;
2115
2116     case BSLeft:
2117         quad.uncheckedAppend(outerRect.minXMinYCorner());
2118         quad.uncheckedAppend(innerRect.minXMinYCorner());
2119         quad.uncheckedAppend(innerRect.minXMaxYCorner());
2120         quad.uncheckedAppend(outerRect.minXMaxYCorner());
2121
2122         if (!innerBorder.radii().topLeft().isZero())
2123             findIntersection(outerRect.minXMinYCorner(), innerRect.minXMinYCorner(), innerRect.minXMaxYCorner(), innerRect.maxXMinYCorner(), quad[1]);
2124
2125         if (!innerBorder.radii().bottomLeft().isZero())
2126             findIntersection(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[2]);
2127         break;
2128
2129     case BSBottom:
2130         quad.uncheckedAppend(outerRect.minXMaxYCorner());
2131         quad.uncheckedAppend(innerRect.minXMaxYCorner());
2132         quad.uncheckedAppend(innerRect.maxXMaxYCorner());
2133         quad.uncheckedAppend(outerRect.maxXMaxYCorner());
2134
2135         if (!innerBorder.radii().bottomLeft().isZero())
2136             findIntersection(outerRect.minXMaxYCorner(), innerRect.minXMaxYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[1]);
2137
2138         if (!innerBorder.radii().bottomRight().isZero())
2139             findIntersection(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMaxYCorner(), quad[2]);
2140         break;
2141
2142     case BSRight:
2143         quad.uncheckedAppend(outerRect.maxXMinYCorner());
2144         quad.uncheckedAppend(innerRect.maxXMinYCorner());
2145         quad.uncheckedAppend(innerRect.maxXMaxYCorner());
2146         quad.uncheckedAppend(outerRect.maxXMaxYCorner());
2147
2148         if (!innerBorder.radii().topRight().isZero())
2149             findIntersection(outerRect.maxXMinYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMinYCorner(), innerRect.maxXMaxYCorner(), quad[1]);
2150
2151         if (!innerBorder.radii().bottomRight().isZero())
2152             findIntersection(outerRect.maxXMaxYCorner(), innerRect.maxXMaxYCorner(), innerRect.maxXMinYCorner(), innerRect.minXMaxYCorner(), quad[2]);
2153         break;
2154     }
2155
2156     // If the border matches both of its adjacent sides, don't anti-alias the clip, and
2157     // if neither side matches, anti-alias the clip.
2158     if (firstEdgeMatches == secondEdgeMatches) {
2159         bool wasAntialiased = graphicsContext.shouldAntialias();
2160         graphicsContext.setShouldAntialias(!firstEdgeMatches);
2161         graphicsContext.clipPath(Path::polygonPathFromPoints(quad), RULE_NONZERO);
2162         graphicsContext.setShouldAntialias(wasAntialiased);
2163         return;
2164     }
2165
2166     // Square off the end which shouldn't be affected by antialiasing, and clip.
2167     Vector<FloatPoint> firstQuad = {
2168         quad[0],
2169         quad[1],
2170         quad[2],
2171         side == BSTop || side == BSBottom ? FloatPoint(quad[3].x(), quad[2].y()) : FloatPoint(quad[2].x(), quad[3].y()),
2172         quad[3]
2173     };
2174     bool wasAntialiased = graphicsContext.shouldAntialias();
2175     graphicsContext.setShouldAntialias(!firstEdgeMatches);
2176     graphicsContext.clipPath(Path::polygonPathFromPoints(firstQuad), RULE_NONZERO);
2177
2178     Vector<FloatPoint> secondQuad = {
2179         quad[0],
2180         side == BSTop || side == BSBottom ? FloatPoint(quad[0].x(), quad[1].y()) : FloatPoint(quad[1].x(), quad[0].y()),
2181         quad[1],
2182         quad[2],
2183         quad[3]
2184     };
2185     // Antialiasing affects the second side.
2186     graphicsContext.setShouldAntialias(!secondEdgeMatches);
2187     graphicsContext.clipPath(Path::polygonPathFromPoints(secondQuad), RULE_NONZERO);
2188
2189     graphicsContext.setShouldAntialias(wasAntialiased);
2190 }
2191
2192 bool RenderBoxModelObject::borderObscuresBackgroundEdge(const FloatSize& contextScale) const
2193 {
2194     BorderEdge edges[4];
2195     BorderEdge::getBorderEdgeInfo(edges, style(), document().deviceScaleFactor());
2196
2197     for (int i = BSTop; i <= BSLeft; ++i) {
2198         const BorderEdge& currEdge = edges[i];
2199         // FIXME: for vertical text
2200         float axisScale = (i == BSTop || i == BSBottom) ? contextScale.height() : contextScale.width();
2201         if (!currEdge.obscuresBackgroundEdge(axisScale))
2202             return false;
2203     }
2204
2205     return true;
2206 }
2207
2208 bool RenderBoxModelObject::borderObscuresBackground() const
2209 {
2210     if (!style().hasBorder())
2211         return false;
2212
2213     // Bail if we have any border-image for now. We could look at the image alpha to improve this.
2214     if (style().borderImage().image())
2215         return false;
2216
2217     BorderEdge edges[4];
2218     BorderEdge::getBorderEdgeInfo(edges, style(), document().deviceScaleFactor());
2219
2220     for (int i = BSTop; i <= BSLeft; ++i) {
2221         const BorderEdge& currEdge = edges[i];
2222         if (!currEdge.obscuresBackground())
2223             return false;
2224     }
2225
2226     return true;
2227 }
2228
2229 bool RenderBoxModelObject::boxShadowShouldBeAppliedToBackground(const LayoutPoint&, BackgroundBleedAvoidance bleedAvoidance, InlineFlowBox* inlineFlowBox) const
2230 {
2231     if (bleedAvoidance != BackgroundBleedNone)
2232         return false;
2233
2234     if (style().hasAppearance())
2235         return false;
2236
2237     bool hasOneNormalBoxShadow = false;
2238     for (const ShadowData* currentShadow = style().boxShadow(); currentShadow; currentShadow = currentShadow->next()) {
2239         if (currentShadow->style() != Normal)
2240             continue;
2241
2242         if (hasOneNormalBoxShadow)
2243             return false;
2244         hasOneNormalBoxShadow = true;
2245
2246         if (currentShadow->spread())
2247             return false;
2248     }
2249
2250     if (!hasOneNormalBoxShadow)
2251         return false;
2252
2253     Color backgroundColor = style().visitedDependentColor(CSSPropertyBackgroundColor);
2254     if (!backgroundColor.isOpaque())
2255         return false;
2256
2257     auto* lastBackgroundLayer = &style().backgroundLayers();
2258     while (auto* next = lastBackgroundLayer->next())
2259         lastBackgroundLayer = next;
2260
2261     if (lastBackgroundLayer->clip() != BorderFillBox)
2262         return false;
2263
2264     if (lastBackgroundLayer->image() && style().hasBorderRadius())
2265         return false;
2266
2267     if (inlineFlowBox && !inlineFlowBox->boxShadowCanBeAppliedToBackground(*lastBackgroundLayer))
2268         return false;
2269
2270     if (hasOverflowClip() && lastBackgroundLayer->attachment() == LocalBackgroundAttachment)
2271         return false;
2272
2273     return true;
2274 }
2275
2276 static inline LayoutRect areaCastingShadowInHole(const LayoutRect& holeRect, int shadowExtent, int shadowSpread, const IntSize& shadowOffset)
2277 {
2278     LayoutRect bounds(holeRect);
2279     
2280     bounds.inflate(shadowExtent);
2281
2282     if (shadowSpread < 0)
2283         bounds.inflate(-shadowSpread);
2284     
2285     LayoutRect offsetBounds = bounds;
2286     offsetBounds.move(-shadowOffset);
2287     return unionRect(bounds, offsetBounds);
2288 }
2289
2290 void RenderBoxModelObject::paintBoxShadow(const PaintInfo& info, const LayoutRect& paintRect, const RenderStyle& style, ShadowStyle shadowStyle, bool includeLogicalLeftEdge, bool includeLogicalRightEdge)
2291 {
2292     // FIXME: Deal with border-image.  Would be great to use border-image as a mask.
2293     GraphicsContext& context = info.context();
2294     if (context.paintingDisabled() || !style.boxShadow())
2295         return;
2296
2297     RoundedRect border = (shadowStyle == Inset) ? style.getRoundedInnerBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge)
2298         : style.getRoundedBorderFor(paintRect, includeLogicalLeftEdge, includeLogicalRightEdge);
2299
2300     bool hasBorderRadius = style.hasBorderRadius();
2301     bool isHorizontal = style.isHorizontalWritingMode();
2302     float deviceScaleFactor = document().deviceScaleFactor();
2303
2304     bool hasOpaqueBackground = style.visitedDependentColor(CSSPropertyBackgroundColor).isOpaque();
2305     for (const ShadowData* shadow = style.boxShadow(); shadow; shadow = shadow->next()) {
2306         if (shadow->style() != shadowStyle)
2307             continue;
2308
2309         // FIXME: Add subpixel support for the shadow values. Soon after the shadow offset becomes fractional,
2310         // all the early snappings here need to be pushed to the actual painting operations.
2311         IntSize shadowOffset(shadow->x(), shadow->y());
2312         int shadowRadius = shadow->radius();
2313         int shadowPaintingExtent = shadow->paintingExtent();
2314         int shadowSpread = shadow->spread();
2315         
2316         if (shadowOffset.isZero() && !shadowRadius && !shadowSpread)
2317             continue;
2318         
2319         const Color& shadowColor = shadow->color();
2320
2321         if (shadow->style() == Normal) {
2322             RoundedRect fillRect = border;
2323             fillRect.inflate(shadowSpread);
2324             if (fillRect.isEmpty())
2325                 continue;
2326
2327             FloatRect pixelSnappedShadowRect = snapRectToDevicePixels(border.rect(), deviceScaleFactor);
2328             pixelSnappedShadowRect.inflate(shadowPaintingExtent + shadowSpread);
2329             pixelSnappedShadowRect.move(shadowOffset);
2330
2331             GraphicsContextStateSaver stateSaver(context);
2332             context.clip(pixelSnappedShadowRect);
2333
2334             // Move the fill just outside the clip, adding 1 pixel separation so that the fill does not
2335             // bleed in (due to antialiasing) if the context is transformed.
2336             IntSize extraOffset(roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent + 2 * shadowSpread + 1, 0);
2337             shadowOffset -= extraOffset;
2338             fillRect.move(extraOffset);
2339
2340             if (shadow->isWebkitBoxShadow())
2341                 context.setLegacyShadow(shadowOffset, shadowRadius, shadowColor);
2342             else
2343                 context.setShadow(shadowOffset, shadowRadius, shadowColor);
2344
2345             FloatRoundedRect rectToClipOut = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
2346             FloatRoundedRect pixelSnappedFillRect = fillRect.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
2347             if (hasBorderRadius) {
2348                 // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time
2349                 // when painting the shadow. On the other hand, it introduces subpixel gaps along the
2350                 // corners. Those are avoided by insetting the clipping path by one pixel.
2351                 if (hasOpaqueBackground)
2352                     rectToClipOut.inflateWithRadii(LayoutUnit::fromPixel(-1));
2353
2354                 if (!rectToClipOut.isEmpty())
2355                     context.clipOutRoundedRect(rectToClipOut);
2356
2357                 RoundedRect influenceRect(LayoutRect(pixelSnappedShadowRect), border.radii());
2358                 influenceRect.expandRadii(2 * shadowPaintingExtent + shadowSpread);
2359
2360                 if (allCornersClippedOut(influenceRect, info.rect))
2361                     context.fillRect(pixelSnappedFillRect.rect(), Color::black);
2362                 else {
2363                     pixelSnappedFillRect.expandRadii(shadowSpread);
2364                     if (!pixelSnappedFillRect.isRenderable())
2365                         pixelSnappedFillRect.adjustRadii();
2366                     context.fillRoundedRect(pixelSnappedFillRect, Color::black);
2367                 }
2368             } else {
2369                 // If the box is opaque, it is unnecessary to clip it out. However, doing so saves time
2370                 // when painting the shadow. On the other hand, it introduces subpixel gaps along the
2371                 // edges if they are not pixel-aligned. Those are avoided by insetting the clipping path
2372                 // by one pixel.
2373                 if (hasOpaqueBackground) {
2374                     // FIXME: The function to decide on the policy based on the transform should be a named function.
2375                     // FIXME: It's not clear if this check is right. What about integral scale factors?
2376                     AffineTransform transform = context.getCTM();
2377                     if (transform.a() != 1 || (transform.d() != 1 && transform.d() != -1) || transform.b() || transform.c())
2378                         rectToClipOut.inflate(LayoutUnit::fromPixel(-1).toFloat());
2379                 }
2380
2381                 if (!rectToClipOut.isEmpty())
2382                     context.clipOut(rectToClipOut.rect());
2383                 context.fillRect(pixelSnappedFillRect.rect(), Color::black);
2384             }
2385         } else {
2386             // Inset shadow.
2387             FloatRoundedRect pixelSnappedBorderRect = border.pixelSnappedRoundedRectForPainting(deviceScaleFactor);
2388             FloatRect pixelSnappedHoleRect = pixelSnappedBorderRect.rect();
2389             pixelSnappedHoleRect.inflate(-shadowSpread);
2390
2391             if (pixelSnappedHoleRect.isEmpty()) {
2392                 if (hasBorderRadius)
2393                     context.fillRoundedRect(pixelSnappedBorderRect, shadowColor);
2394                 else
2395                     context.fillRect(pixelSnappedBorderRect.rect(), shadowColor);
2396                 continue;
2397             }
2398
2399             if (!includeLogicalLeftEdge) {
2400                 if (isHorizontal) {
2401                     pixelSnappedHoleRect.move(-std::max(shadowOffset.width(), 0) - shadowPaintingExtent, 0);
2402                     pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() + std::max(shadowOffset.width(), 0) + shadowPaintingExtent);
2403                 } else {
2404                     pixelSnappedHoleRect.move(0, -std::max(shadowOffset.height(), 0) - shadowPaintingExtent);
2405                     pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() + std::max(shadowOffset.height(), 0) + shadowPaintingExtent);
2406                 }
2407             }
2408             if (!includeLogicalRightEdge) {
2409                 if (isHorizontal)
2410                     pixelSnappedHoleRect.setWidth(pixelSnappedHoleRect.width() - std::min(shadowOffset.width(), 0) + shadowPaintingExtent);
2411                 else
2412                     pixelSnappedHoleRect.setHeight(pixelSnappedHoleRect.height() - std::min(shadowOffset.height(), 0) + shadowPaintingExtent);
2413             }
2414
2415             Color fillColor(shadowColor.red(), shadowColor.green(), shadowColor.blue(), 255);
2416
2417             FloatRect pixelSnappedOuterRect = snapRectToDevicePixels(areaCastingShadowInHole(LayoutRect(pixelSnappedBorderRect.rect()), shadowPaintingExtent, shadowSpread, shadowOffset), deviceScaleFactor);
2418             FloatRoundedRect pixelSnappedRoundedHole = FloatRoundedRect(pixelSnappedHoleRect, pixelSnappedBorderRect.radii());
2419
2420             GraphicsContextStateSaver stateSaver(context);
2421             if (hasBorderRadius) {
2422                 context.clipRoundedRect(pixelSnappedBorderRect);
2423                 pixelSnappedRoundedHole.shrinkRadii(shadowSpread);
2424             } else
2425                 context.clip(pixelSnappedBorderRect.rect());
2426
2427             IntSize extraOffset(2 * roundToInt(paintRect.width()) + std::max(0, shadowOffset.width()) + shadowPaintingExtent - 2 * shadowSpread + 1, 0);
2428             context.translate(extraOffset.width(), extraOffset.height());
2429             shadowOffset -= extraOffset;
2430
2431             if (shadow->isWebkitBoxShadow())
2432                 context.setLegacyShadow(shadowOffset, shadowRadius, shadowColor);
2433             else
2434                 context.setShadow(shadowOffset, shadowRadius, shadowColor);
2435
2436             context.fillRectWithRoundedHole(pixelSnappedOuterRect, pixelSnappedRoundedHole, fillColor);
2437         }
2438     }
2439 }
2440
2441 LayoutUnit RenderBoxModelObject::containingBlockLogicalWidthForContent() const
2442 {
2443     return containingBlock()->availableLogicalWidth();
2444 }
2445
2446 RenderBoxModelObject* RenderBoxModelObject::continuation() const
2447 {
2448     if (!hasContinuation())
2449         return nullptr;
2450     return continuationMap().get(this);
2451 }
2452
2453 void RenderBoxModelObject::setContinuation(RenderBoxModelObject* continuation)
2454 {
2455     if (continuation)
2456         continuationMap().set(this, continuation);
2457     else if (hasContinuation())
2458         continuationMap().remove(this);
2459     setHasContinuation(!!continuation);
2460 }
2461
2462 RenderTextFragment* RenderBoxModelObject::firstLetterRemainingText() const
2463 {
2464     if (!firstLetterRemainingTextMap)
2465         return nullptr;
2466     return firstLetterRemainingTextMap->get(this);
2467 }
2468
2469 void RenderBoxModelObject::setFirstLetterRemainingText(RenderTextFragment* remainingText)
2470 {
2471     if (remainingText) {
2472         if (!firstLetterRemainingTextMap)
2473             firstLetterRemainingTextMap = new FirstLetterRemainingTextMap;
2474         firstLetterRemainingTextMap->set(this, remainingText);
2475     } else if (firstLetterRemainingTextMap)
2476         firstLetterRemainingTextMap->remove(this);
2477 }
2478
2479 LayoutRect RenderBoxModelObject::localCaretRectForEmptyElement(LayoutUnit width, LayoutUnit textIndentOffset)
2480 {
2481     ASSERT(!firstChild());
2482
2483     // FIXME: This does not take into account either :first-line or :first-letter
2484     // However, as soon as some content is entered, the line boxes will be
2485     // constructed and this kludge is not called any more. So only the caret size
2486     // of an empty :first-line'd block is wrong. I think we can live with that.
2487     const RenderStyle& currentStyle = firstLineStyle();
2488     LayoutUnit height = lineHeight(true, currentStyle.isHorizontalWritingMode() ? HorizontalLine : VerticalLine);
2489
2490     enum CaretAlignment { alignLeft, alignRight, alignCenter };
2491
2492     CaretAlignment alignment = alignLeft;
2493
2494     switch (currentStyle.textAlign()) {
2495     case LEFT:
2496     case WEBKIT_LEFT:
2497         break;
2498     case CENTER:
2499     case WEBKIT_CENTER:
2500         alignment = alignCenter;
2501         break;
2502     case RIGHT:
2503     case WEBKIT_RIGHT:
2504         alignment = alignRight;
2505         break;
2506     case JUSTIFY:
2507     case TASTART:
2508         if (!currentStyle.isLeftToRightDirection())
2509             alignment = alignRight;
2510         break;
2511     case TAEND:
2512         if (currentStyle.isLeftToRightDirection())
2513             alignment = alignRight;
2514         break;
2515     }
2516
2517     LayoutUnit x = borderLeft() + paddingLeft();
2518     LayoutUnit maxX = width - borderRight() - paddingRight();
2519
2520     switch (alignment) {
2521     case alignLeft:
2522         if (currentStyle.isLeftToRightDirection())
2523             x += textIndentOffset;
2524         break;
2525     case alignCenter:
2526         x = (x + maxX) / 2;
2527         if (currentStyle.isLeftToRightDirection())
2528             x += textIndentOffset / 2;
2529         else
2530             x -= textIndentOffset / 2;
2531         break;
2532     case alignRight:
2533         x = maxX - caretWidth;
2534         if (!currentStyle.isLeftToRightDirection())
2535             x -= textIndentOffset;
2536         break;
2537     }
2538     x = std::min(x, std::max<LayoutUnit>(maxX - caretWidth, 0));
2539
2540     LayoutUnit y = paddingTop() + borderTop();
2541
2542     return currentStyle.isHorizontalWritingMode() ? LayoutRect(x, y, caretWidth, height) : LayoutRect(y, x, height, caretWidth);
2543 }
2544
2545 bool RenderBoxModelObject::shouldAntialiasLines(GraphicsContext& context)
2546 {
2547     // FIXME: We may want to not antialias when scaled by an integral value,
2548     // and we may want to antialias when translated by a non-integral value.
2549     return !context.getCTM().isIdentityOrTranslationOrFlipped();
2550 }
2551
2552 void RenderBoxModelObject::mapAbsoluteToLocalPoint(MapCoordinatesFlags mode, TransformState& transformState) const
2553 {
2554     RenderElement* container = this->container();
2555     if (!container)
2556         return;
2557     
2558     // FIXME: This code is wrong for named flow threads since it only works for content in the first region.
2559     // We also don't want to run it for multicolumn flow threads, since we can use our knowledge of column
2560     // geometry to actually get a better result.
2561     // The point inside a box that's inside a region has its coordinates relative to the region,
2562     // not the FlowThread that is its container in the RenderObject tree.
2563     if (is<RenderBox>(*this) && container->isOutOfFlowRenderFlowThread()) {
2564         RenderRegion* startRegion = nullptr;
2565         RenderRegion* endRegion = nullptr;
2566         if (downcast<RenderFlowThread>(*container).getRegionRangeForBox(downcast<RenderBox>(this), startRegion, endRegion))
2567             container = startRegion;
2568     }
2569
2570     container->mapAbsoluteToLocalPoint(mode, transformState);
2571
2572     LayoutSize containerOffset = offsetFromContainer(*container, LayoutPoint());
2573
2574     bool preserve3D = mode & UseTransforms && (container->style().preserves3D() || style().preserves3D());
2575     if (mode & UseTransforms && shouldUseTransformFromContainer(container)) {
2576         TransformationMatrix t;
2577         getTransformFromContainer(container, containerOffset, t);
2578         transformState.applyTransform(t, preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2579     } else
2580         transformState.move(containerOffset.width(), containerOffset.height(), preserve3D ? TransformState::AccumulateTransform : TransformState::FlattenTransform);
2581 }
2582
2583 void RenderBoxModelObject::moveChildTo(RenderBoxModelObject* toBoxModelObject, RenderObject* child, RenderObject* beforeChild, bool fullRemoveInsert)
2584 {
2585 #if !ASSERT_DISABLED
2586     SetForScope<bool> reparentingChild(m_reparentingChild, true);
2587 #endif
2588     // We assume that callers have cleared their positioned objects list for child moves (!fullRemoveInsert) so the
2589     // positioned renderer maps don't become stale. It would be too slow to do the map lookup on each call.
2590     ASSERT(!fullRemoveInsert || !is<RenderBlock>(*this) || !downcast<RenderBlock>(*this).hasPositionedObjects());
2591
2592     ASSERT(this == child->parent());
2593     ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
2594     if (fullRemoveInsert && (toBoxModelObject->isRenderBlock() || toBoxModelObject->isRenderInline())) {
2595         // Takes care of adding the new child correctly if toBlock and fromBlock
2596         // have different kind of children (block vs inline).
2597         removeChildInternal(*child, NotifyChildren);
2598         toBoxModelObject->addChild(child, beforeChild);
2599     } else {
2600         NotifyChildrenType notifyType = fullRemoveInsert ? NotifyChildren : DontNotifyChildren;
2601         removeChildInternal(*child, notifyType);
2602         toBoxModelObject->insertChildInternal(child, beforeChild, notifyType);
2603     }
2604 }
2605
2606 void RenderBoxModelObject::moveChildrenTo(RenderBoxModelObject* toBoxModelObject, RenderObject* startChild, RenderObject* endChild, RenderObject* beforeChild, bool fullRemoveInsert)
2607 {
2608     // This condition is rarely hit since this function is usually called on
2609     // anonymous blocks which can no longer carry positioned objects (see r120761)
2610     // or when fullRemoveInsert is false.
2611     if (fullRemoveInsert && is<RenderBlock>(*this)) {
2612         downcast<RenderBlock>(*this).removePositionedObjects(nullptr);
2613         if (is<RenderBlockFlow>(*this))
2614             downcast<RenderBlockFlow>(*this).removeFloatingObjects();
2615     }
2616
2617     ASSERT(!beforeChild || toBoxModelObject == beforeChild->parent());
2618     for (RenderObject* child = startChild; child && child != endChild; ) {
2619         // Save our next sibling as moveChildTo will clear it.
2620         RenderObject* nextSibling = child->nextSibling();
2621         
2622         // FIXME: This logic here fails to detect the first letter in certain cases
2623         // and skips a valid sibling renderer (see webkit.org/b/163737).
2624         // Check to make sure we're not saving the firstLetter as the nextSibling.
2625         // When the |child| object will be moved, its firstLetter will be recreated,
2626         // so saving it now in nextSibling would leave us with a stale object.
2627         if (is<RenderTextFragment>(*child) && is<RenderText>(nextSibling)) {
2628             RenderObject* firstLetterObj = nullptr;
2629             if (RenderBlock* block = downcast<RenderTextFragment>(*child).blockForAccompanyingFirstLetter()) {
2630                 RenderElement* firstLetterContainer = nullptr;
2631                 block->getFirstLetter(firstLetterObj, firstLetterContainer, child);
2632             }
2633             
2634             // This is the first letter, skip it.
2635             if (firstLetterObj == nextSibling)
2636                 nextSibling = nextSibling->nextSibling();
2637         }
2638
2639         moveChildTo(toBoxModelObject, child, beforeChild, fullRemoveInsert);
2640         child = nextSibling;
2641     }
2642 }
2643
2644 } // namespace WebCore