Title: [268955] trunk/Source/WebCore
Revision
268955
Author
[email protected]
Date
2020-10-24 21:27:10 -0700 (Sat, 24 Oct 2020)

Log Message

[LFC Display] Implement background image painting
https://bugs.webkit.org/show_bug.cgi?id=218155

Reviewed by Zalan Bujtas.

Introduce BoxDecorationData, which stores per-Box box pixel-snapped geometry for
backgrounds and borders. A BoxModelBox that has box decorations will own one.

BoxDecorationData has a vector of FillLayerImageGeometry, which stores pixel-snapped
geometry for background image painting. Code in DisplayFillLayerImageGeometry computes
this geometry (code based on rendering code).

BoxModelBox needs to store pixel snapped padding and content boxes for decoration painting.

Currently TreeBuilder::computeBoxDecorationData() sets up these rects and makes BoxDecorationData,
but this isn't really tree building, so I'd like to move that code somewhere else in
future patches.

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* display/DisplayTreeBuilder.cpp:
(WebCore::Display::TreeBuilder::computeBoxDecorationData const):
(WebCore::Display::TreeBuilder::displayBoxForLayoutBox const):
* display/DisplayTreeBuilder.h:
* display/css/DisplayBox.cpp:
* display/css/DisplayBox.h:
* display/css/DisplayBoxDecorationData.cpp: Copied from Source/WebCore/display/css/DisplayBox.cpp.
(WebCore::Display::BoxDecorationData::create):
* display/css/DisplayBoxDecorationData.h: Copied from Source/WebCore/display/css/DisplayCSSPainter.h.
(WebCore::Display::BoxDecorationData::backgroundImageGeometry const):
(WebCore::Display::BoxDecorationData::setBackgroundImageGeometry):
(WebCore::Display::BoxDecorationData::roundedBorderRect const):
(WebCore::Display::BoxDecorationData::setRoundedBorderRect):
* display/css/DisplayBoxModelBox.cpp:
(WebCore::Display::BoxModelBox::setBoxDecorationData):
* display/css/DisplayBoxModelBox.h:
(WebCore::Display::BoxModelBox::absolutePaddingBoxRect const):
(WebCore::Display::BoxModelBox::setAbsolutePaddingBoxRect):
(WebCore::Display::BoxModelBox::absoluteContentBoxRect const):
(WebCore::Display::BoxModelBox::setAbsoluteContentBoxRect):
(WebCore::Display::BoxModelBox::boxDecorationData const):
* display/css/DisplayCSSPainter.cpp:
(WebCore::Display::CSSPainter::paintFillLayer):
(WebCore::Display::CSSPainter::paintBackgroundImages):
(WebCore::Display::CSSPainter::paintBoxDecorations):
* display/css/DisplayCSSPainter.h:
* display/css/DisplayFillLayerImageGeometry.cpp: Added.
(WebCore::Display::resolveWidthForRatio):
(WebCore::Display::resolveHeightForRatio):
(WebCore::Display::resolveAgainstIntrinsicWidthOrHeightAndRatio):
(WebCore::Display::resolveAgainstIntrinsicRatio):
(WebCore::Display::calculateImageIntrinsicDimensions):
(WebCore::Display::calculateFillTileSize):
(WebCore::Display::getSpace):
(WebCore::Display::resolveEdgeRelativeLength):
(WebCore::Display::pixelSnappedFillLayerImageGeometry):
(WebCore::Display::geometryForLayer):
(WebCore::Display::calculateFillLayerImageGeometry):
* display/css/DisplayFillLayerImageGeometry.h: Copied from Source/WebCore/display/DisplayTreeBuilder.h.
(WebCore::Display::FillLayerImageGeometry::FillLayerImageGeometry):
(WebCore::Display::FillLayerImageGeometry::destRect const):
(WebCore::Display::FillLayerImageGeometry::phase const):
(WebCore::Display::FillLayerImageGeometry::tileSize const):
(WebCore::Display::FillLayerImageGeometry::spaceSize const):
(WebCore::Display::FillLayerImageGeometry::hasNonLocalGeometry const):
(WebCore::Display::FillLayerImageGeometry::relativePhase const):
(WebCore::Display::FillLayerImageGeometry::clip):
* display/css/DisplayStyle.cpp:
(WebCore::Display::deepCopy):
(WebCore::Display::Style::Style):
(WebCore::Display::Style::hasBackgroundImage const):
* display/css/DisplayStyle.h:
(WebCore::Display::Style::backgroundLayers const):
(WebCore::Display::Style::hasBackgroundImage const): Deleted.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (268954 => 268955)


--- trunk/Source/WebCore/ChangeLog	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/ChangeLog	2020-10-25 04:27:10 UTC (rev 268955)
@@ -1,5 +1,82 @@
 2020-10-24  Simon Fraser  <[email protected]>
 
+        [LFC Display] Implement background image painting
+        https://bugs.webkit.org/show_bug.cgi?id=218155
+
+        Reviewed by Zalan Bujtas.
+
+        Introduce BoxDecorationData, which stores per-Box box pixel-snapped geometry for
+        backgrounds and borders. A BoxModelBox that has box decorations will own one.
+
+        BoxDecorationData has a vector of FillLayerImageGeometry, which stores pixel-snapped
+        geometry for background image painting. Code in DisplayFillLayerImageGeometry computes
+        this geometry (code based on rendering code).
+
+        BoxModelBox needs to store pixel snapped padding and content boxes for decoration painting.
+
+        Currently TreeBuilder::computeBoxDecorationData() sets up these rects and makes BoxDecorationData,
+        but this isn't really tree building, so I'd like to move that code somewhere else in
+        future patches.
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * display/DisplayTreeBuilder.cpp:
+        (WebCore::Display::TreeBuilder::computeBoxDecorationData const):
+        (WebCore::Display::TreeBuilder::displayBoxForLayoutBox const):
+        * display/DisplayTreeBuilder.h:
+        * display/css/DisplayBox.cpp:
+        * display/css/DisplayBox.h:
+        * display/css/DisplayBoxDecorationData.cpp: Copied from Source/WebCore/display/css/DisplayBox.cpp.
+        (WebCore::Display::BoxDecorationData::create):
+        * display/css/DisplayBoxDecorationData.h: Copied from Source/WebCore/display/css/DisplayCSSPainter.h.
+        (WebCore::Display::BoxDecorationData::backgroundImageGeometry const):
+        (WebCore::Display::BoxDecorationData::setBackgroundImageGeometry):
+        (WebCore::Display::BoxDecorationData::roundedBorderRect const):
+        (WebCore::Display::BoxDecorationData::setRoundedBorderRect):
+        * display/css/DisplayBoxModelBox.cpp:
+        (WebCore::Display::BoxModelBox::setBoxDecorationData):
+        * display/css/DisplayBoxModelBox.h:
+        (WebCore::Display::BoxModelBox::absolutePaddingBoxRect const):
+        (WebCore::Display::BoxModelBox::setAbsolutePaddingBoxRect):
+        (WebCore::Display::BoxModelBox::absoluteContentBoxRect const):
+        (WebCore::Display::BoxModelBox::setAbsoluteContentBoxRect):
+        (WebCore::Display::BoxModelBox::boxDecorationData const):
+        * display/css/DisplayCSSPainter.cpp:
+        (WebCore::Display::CSSPainter::paintFillLayer):
+        (WebCore::Display::CSSPainter::paintBackgroundImages):
+        (WebCore::Display::CSSPainter::paintBoxDecorations):
+        * display/css/DisplayCSSPainter.h:
+        * display/css/DisplayFillLayerImageGeometry.cpp: Added.
+        (WebCore::Display::resolveWidthForRatio):
+        (WebCore::Display::resolveHeightForRatio):
+        (WebCore::Display::resolveAgainstIntrinsicWidthOrHeightAndRatio):
+        (WebCore::Display::resolveAgainstIntrinsicRatio):
+        (WebCore::Display::calculateImageIntrinsicDimensions):
+        (WebCore::Display::calculateFillTileSize):
+        (WebCore::Display::getSpace):
+        (WebCore::Display::resolveEdgeRelativeLength):
+        (WebCore::Display::pixelSnappedFillLayerImageGeometry):
+        (WebCore::Display::geometryForLayer):
+        (WebCore::Display::calculateFillLayerImageGeometry):
+        * display/css/DisplayFillLayerImageGeometry.h: Copied from Source/WebCore/display/DisplayTreeBuilder.h.
+        (WebCore::Display::FillLayerImageGeometry::FillLayerImageGeometry):
+        (WebCore::Display::FillLayerImageGeometry::destRect const):
+        (WebCore::Display::FillLayerImageGeometry::phase const):
+        (WebCore::Display::FillLayerImageGeometry::tileSize const):
+        (WebCore::Display::FillLayerImageGeometry::spaceSize const):
+        (WebCore::Display::FillLayerImageGeometry::hasNonLocalGeometry const):
+        (WebCore::Display::FillLayerImageGeometry::relativePhase const):
+        (WebCore::Display::FillLayerImageGeometry::clip):
+        * display/css/DisplayStyle.cpp:
+        (WebCore::Display::deepCopy):
+        (WebCore::Display::Style::Style):
+        (WebCore::Display::Style::hasBackgroundImage const):
+        * display/css/DisplayStyle.h:
+        (WebCore::Display::Style::backgroundLayers const):
+        (WebCore::Display::Style::hasBackgroundImage const): Deleted.
+
+2020-10-24  Simon Fraser  <[email protected]>
+
         [LFC Display] Create display boxes for atomic inlines and inline blocks
         https://bugs.webkit.org/show_bug.cgi?id=218153
 

Modified: trunk/Source/WebCore/Sources.txt (268954 => 268955)


--- trunk/Source/WebCore/Sources.txt	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/Sources.txt	2020-10-25 04:27:10 UTC (rev 268955)
@@ -813,9 +813,11 @@
 css/typedom/TypedOMCSSUnparsedValue.cpp
 cssjit/SelectorCompiler.cpp
 display/css/DisplayBox.cpp
+display/css/DisplayBoxDecorationData.cpp
 display/css/DisplayBoxModelBox.cpp
 display/css/DisplayContainerBox.cpp
 display/css/DisplayCSSPainter.cpp
+display/css/DisplayFillLayerImageGeometry.cpp
 display/css/DisplayImageBox.cpp
 display/css/DisplayReplacedBox.cpp
 display/css/DisplayStyle.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (268954 => 268955)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-10-25 04:27:10 UTC (rev 268955)
@@ -6010,6 +6010,10 @@
 		0F8B45741DC41DBA00443C3F /* JSIntersectionObserverCallback.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSIntersectionObserverCallback.h; sourceTree = "<group>"; };
 		0F94721E2534010900F153C8 /* DisplayBoxModelBox.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayBoxModelBox.h; sourceTree = "<group>"; };
 		0F9472202534010900F153C8 /* DisplayBoxModelBox.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayBoxModelBox.cpp; sourceTree = "<group>"; };
+		0F9472292534B04500F153C8 /* DisplayBoxDecorationData.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayBoxDecorationData.h; sourceTree = "<group>"; };
+		0F94722B2534B04500F153C8 /* DisplayBoxDecorationData.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayBoxDecorationData.cpp; sourceTree = "<group>"; };
+		0F94722C2534BA7300F153C8 /* DisplayFillLayerImageGeometry.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisplayFillLayerImageGeometry.cpp; sourceTree = "<group>"; };
+		0F94722D2534BA7300F153C8 /* DisplayFillLayerImageGeometry.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisplayFillLayerImageGeometry.h; sourceTree = "<group>"; };
 		0F94A3951EF1B10500FBAFFB /* JSDOMQuadCustom.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSDOMQuadCustom.cpp; sourceTree = "<group>"; };
 		0F94B6422208F70100157014 /* ScrollingTreeFixedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ScrollingTreeFixedNode.h; path = page/scrolling/cocoa/ScrollingTreeFixedNode.h; sourceTree = SOURCE_ROOT; };
 		0F94B6432208F70200157014 /* ScrollingTreeStickyNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ScrollingTreeStickyNode.h; path = page/scrolling/cocoa/ScrollingTreeStickyNode.h; sourceTree = SOURCE_ROOT; };
@@ -17617,6 +17621,8 @@
 			children = (
 				0FFF1B72251BC6570098795A /* DisplayBox.cpp */,
 				0FFF1B78251BC6570098795A /* DisplayBox.h */,
+				0F94722B2534B04500F153C8 /* DisplayBoxDecorationData.cpp */,
+				0F9472292534B04500F153C8 /* DisplayBoxDecorationData.h */,
 				0F9472202534010900F153C8 /* DisplayBoxModelBox.cpp */,
 				0F94721E2534010900F153C8 /* DisplayBoxModelBox.h */,
 				0FFF1B74251BC6570098795A /* DisplayContainerBox.cpp */,
@@ -17623,6 +17629,8 @@
 				0FFF1B7A251BC6570098795A /* DisplayContainerBox.h */,
 				0FFF1B7D251BC6570098795A /* DisplayCSSPainter.cpp */,
 				0FFF1B77251BC6570098795A /* DisplayCSSPainter.h */,
+				0F94722C2534BA7300F153C8 /* DisplayFillLayerImageGeometry.cpp */,
+				0F94722D2534BA7300F153C8 /* DisplayFillLayerImageGeometry.h */,
 				0FFF1B75251BC6570098795A /* DisplayImageBox.cpp */,
 				0FFF1B7B251BC6570098795A /* DisplayImageBox.h */,
 				0FFF1B7C251BC6570098795A /* DisplayReplacedBox.cpp */,
@@ -35473,7 +35481,6 @@
 				A8D06B3A0A265DCD005E7203 /* HTMLNames.cpp in Sources */,
 				1AC900C31943C0FC008625B5 /* HTTPHeaderNames.cpp in Sources */,
 				CD19FEAF1F574B6D000C42FB /* ImageDecoderAVFObjC.mm in Sources */,
-				CA3A4AAE25416E40006CDAE2 /* ImageResolution.cpp in Sources */,
 				CD27AE5122A9868700947FF9 /* ImageRotationSessionVT.mm in Sources */,
 				07E9E13018F62B370011A3A4 /* InbandMetadataTextTrackPrivateAVF.cpp in Sources */,
 				07B442D6166C70B000556CAD /* InbandTextTrackPrivateAVF.cpp in Sources */,

Modified: trunk/Source/WebCore/display/DisplayTreeBuilder.cpp (268954 => 268955)


--- trunk/Source/WebCore/display/DisplayTreeBuilder.cpp	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/DisplayTreeBuilder.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -28,6 +28,7 @@
 
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
+#include "DisplayBoxDecorationData.h"
 #include "DisplayContainerBox.h"
 #include "DisplayImageBox.h"
 #include "DisplayStyle.h"
@@ -123,6 +124,28 @@
     }
 }
 
+// FIXME: This should happen as part of Display::Box creation.
+void TreeBuilder::computeBoxDecorationData(BoxModelBox& box, const Layout::Box& layoutBox, const Layout::BoxGeometry& geometry, LayoutSize offsetFromRoot) const
+{
+    auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(geometry) };
+    borderBoxRect.move(offsetFromRoot);
+
+    auto paddingBoxRect = LayoutRect { geometry.paddingBox() };
+    paddingBoxRect.moveBy(borderBoxRect.location());
+    box.setAbsolutePaddingBoxRect(snapRectToDevicePixels(paddingBoxRect, m_pixelSnappingFactor));
+
+    auto contentBoxRect = LayoutRect { geometry.contentBox() };
+    contentBoxRect.moveBy(borderBoxRect.location());
+    box.setAbsoluteContentBoxRect(snapRectToDevicePixels(contentBoxRect, m_pixelSnappingFactor));
+
+    // FIXME: Check for rounded borders when supported.
+    if (!box.style().hasBackground())
+        return;
+
+    auto boxDecorationData = BoxDecorationData::create(box, layoutBox, geometry, offsetFromRoot, m_pixelSnappingFactor);
+    box.setBoxDecorationData(WTFMove(boxDecorationData));
+}
+
 void TreeBuilder::recursiveBuildDisplayTree(const Layout::LayoutState& layoutState, LayoutSize offsetFromRoot, const Layout::Box& box, InsertionPosition& insertionPosition) const
 {
     auto geometry = layoutState.geometryForBox(box);
@@ -187,12 +210,15 @@
         if (auto* cachedImage = downcast<Layout::ReplacedBox>(layoutBox).cachedImage())
             imageBox->setImage(cachedImage->image());
 
+        computeBoxDecorationData(*imageBox, layoutBox, geometry, offsetFromRoot);
         return imageBox;
     }
     
     if (is<Layout::ContainerBox>(layoutBox)) {
         // FIXME: The decision to make a ContainerBox should be made based on whether this Display::Box will have children.
-        return makeUnique<ContainerBox>(pixelSnappedBorderBoxRect, WTFMove(style));
+        auto containerBox = makeUnique<ContainerBox>(pixelSnappedBorderBoxRect, WTFMove(style));
+        computeBoxDecorationData(*containerBox, layoutBox, geometry, offsetFromRoot);
+        return containerBox;
     }
 
     return makeUnique<Box>(snapRectToDevicePixels(borderBoxRect, m_pixelSnappingFactor), WTFMove(style));

Modified: trunk/Source/WebCore/display/DisplayTreeBuilder.h (268954 => 268955)


--- trunk/Source/WebCore/display/DisplayTreeBuilder.h	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/DisplayTreeBuilder.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -65,6 +65,8 @@
     std::unique_ptr<Box> displayBoxForRootBox(const Layout::BoxGeometry&, const Layout::ContainerBox&) const;
     std::unique_ptr<Box> displayBoxForLayoutBox(const Layout::BoxGeometry&, const Layout::Box&, LayoutSize offsetFromRoot) const;
 
+    void computeBoxDecorationData(BoxModelBox&, const Layout::Box&, const Layout::BoxGeometry&, LayoutSize offsetFromRoot) const;
+
     void recursiveBuildDisplayTree(const Layout::LayoutState&, LayoutSize offsetFromRoot, const Layout::Box&, InsertionPosition&) const;
 
     void buildInlineDisplayTree(const Layout::LayoutState&, LayoutSize offsetFromRoot, const Layout::ContainerBox&, InsertionPosition&) const;

Modified: trunk/Source/WebCore/display/css/DisplayBox.cpp (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBox.cpp	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayBox.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -41,6 +41,8 @@
 {
 }
 
+Box::~Box() = default;
+
 void Box::setNextSibling(std::unique_ptr<Box>&& box)
 {
     m_nextSibling = WTFMove(box);

Modified: trunk/Source/WebCore/display/css/DisplayBox.h (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBox.h	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayBox.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -49,7 +49,7 @@
     };
 
     Box(AbsoluteFloatRect, Style&&, OptionSet<Flags> = { });
-    virtual ~Box() = default;
+    virtual ~Box();
 
     const Style& style() const { return m_style; }
 

Copied: trunk/Source/WebCore/display/css/DisplayBoxDecorationData.cpp (from rev 268954, trunk/Source/WebCore/display/css/DisplayBox.cpp) (0 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBoxDecorationData.cpp	                        (rev 0)
+++ trunk/Source/WebCore/display/css/DisplayBoxDecorationData.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DisplayBox.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "LayoutBox.h"
+#include "LayoutBoxGeometry.h"
+
+namespace WebCore {
+namespace Display {
+
+std::unique_ptr<BoxDecorationData> BoxDecorationData::create(const Box& displayBox, const Layout::Box& layoutBox, const Layout::BoxGeometry& layoutGeometry, LayoutSize offsetFromRoot, float pixelSnappingFactor)
+{
+    auto backgroundImageGeometry = calculateFillLayerImageGeometry(displayBox, layoutBox, layoutGeometry, offsetFromRoot, pixelSnappingFactor);
+
+    auto boxDecorationData = makeUnique<BoxDecorationData>();
+    boxDecorationData->setBackgroundImageGeometry(backgroundImageGeometry);
+
+    // FIXME: Compute rounded border rect.
+
+    return boxDecorationData;
+}
+
+BoxDecorationData::BoxDecorationData() = default;
+
+} // namespace Display
+} // namespace WebCore
+
+#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)

Copied: trunk/Source/WebCore/display/css/DisplayBoxDecorationData.h (from rev 268954, trunk/Source/WebCore/display/css/DisplayCSSPainter.h) (0 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBoxDecorationData.h	                        (rev 0)
+++ trunk/Source/WebCore/display/css/DisplayBoxDecorationData.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "DisplayFillLayerImageGeometry.h"
+#include "FloatRoundedRect.h"
+#include <wtf/IsoMalloc.h>
+
+namespace WebCore {
+
+namespace Layout {
+class Box;
+class BoxGeometry;
+}
+
+namespace Display {
+
+// Per-box data with pixel-snapped geometry for background images and border-radius.
+class BoxDecorationData {
+    WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(BoxDecorationData);
+public:
+    static std::unique_ptr<BoxDecorationData> create(const Box&, const Layout::Box&, const Layout::BoxGeometry&, LayoutSize offsetFromRoot, float pixelSnappingFactor);
+
+    BoxDecorationData();
+
+    const Vector<FillLayerImageGeometry, 1> backgroundImageGeometry() const { return m_backgroundImageGeometry; }
+    void setBackgroundImageGeometry(const Vector<FillLayerImageGeometry, 1>& geometry) { m_backgroundImageGeometry = geometry; }
+
+    const FloatRoundedRect& roundedBorderRect() const { return m_roundedBorderRect; }
+    void setRoundedBorderRect(const FloatRoundedRect& roundedRect) { m_roundedBorderRect = roundedRect; }
+
+private:
+    Vector<FillLayerImageGeometry, 1> m_backgroundImageGeometry;
+    FloatRoundedRect m_roundedBorderRect;
+};
+
+} // namespace Display
+} // namespace WebCore
+
+
+#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)

Modified: trunk/Source/WebCore/display/css/DisplayBoxModelBox.cpp (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBoxModelBox.cpp	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayBoxModelBox.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -28,6 +28,7 @@
 
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
+#include "DisplayBoxDecorationData.h"
 #include <wtf/IsoMallocInlines.h>
 #include <wtf/text/TextStream.h>
 
@@ -39,6 +40,14 @@
 {
 }
 
+BoxModelBox::~BoxModelBox() = default;
+
+void BoxModelBox::setBoxDecorationData(std::unique_ptr<BoxDecorationData>&& decorationData)
+{
+    m_boxDecorationData = WTFMove(decorationData);
+}
+
+
 String BoxModelBox::debugDescription() const
 {
     TextStream stream;

Modified: trunk/Source/WebCore/display/css/DisplayBoxModelBox.h (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayBoxModelBox.h	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayBoxModelBox.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -32,6 +32,8 @@
 namespace WebCore {
 namespace Display {
 
+class BoxDecorationData;
+
 // A box in the sense of the CSS Box Model.
 // This box can draw backgrounds and borders.
 class BoxModelBox : public Box {
@@ -38,11 +40,26 @@
     WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(BoxModelBox);
 public:
     BoxModelBox(AbsoluteFloatRect borderBox, Style&&, OptionSet<Flags> = { });
-    virtual ~BoxModelBox() = default;
+    virtual ~BoxModelBox();
 
     AbsoluteFloatRect absoluteBorderBoxRect() const { return absoluteBoxRect(); }
 
+    AbsoluteFloatRect absolutePaddingBoxRect() const { return m_paddingBoxRect; }
+    void setAbsolutePaddingBoxRect(const AbsoluteFloatRect& box) { m_paddingBoxRect = box; }
+
+    AbsoluteFloatRect absoluteContentBoxRect() const { return m_contentBoxRect; }
+    void setAbsoluteContentBoxRect(const AbsoluteFloatRect& box) { m_contentBoxRect = box; }
+
+    const BoxDecorationData* boxDecorationData() const { return m_boxDecorationData.get(); }
+    void setBoxDecorationData(std::unique_ptr<BoxDecorationData>&&);
+
     virtual String debugDescription() const;
+
+private:
+    AbsoluteFloatRect m_paddingBoxRect;
+    AbsoluteFloatRect m_contentBoxRect;
+
+    std::unique_ptr<BoxDecorationData> m_boxDecorationData;
 };
 
 } // namespace Display

Modified: trunk/Source/WebCore/display/css/DisplayCSSPainter.cpp (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayCSSPainter.cpp	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayCSSPainter.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -30,13 +30,17 @@
 
 #include "CachedImage.h"
 #include "Color.h"
+#include "DisplayBoxDecorationData.h"
 #include "DisplayContainerBox.h"
+#include "DisplayFillLayerImageGeometry.h"
 #include "DisplayImageBox.h"
 #include "DisplayStyle.h"
 #include "DisplayTextBox.h"
 #include "DisplayTree.h"
+#include "FillLayer.h"
 #include "GraphicsContext.h"
 #include "IntRect.h"
+#include "LayoutPoint.h"
 #include "LayoutState.h"
 #include "TextRun.h"
 
@@ -43,18 +47,95 @@
 namespace WebCore {
 namespace Display {
 
-void CSSPainter::paintBoxDecorations(const BoxModelBox& displayBox, GraphicsContext& context)
+void CSSPainter::paintFillLayer(const BoxModelBox& box, const FillLayer& layer, const FillLayerImageGeometry& geometry, GraphicsContext& context)
 {
+    GraphicsContextStateSaver stateSaver(context, false);
+
+    auto clipRectForLayer = [](const BoxModelBox& box, const FillLayer& layer) {
+        switch (layer.clip()) {
+        case FillBox::Border:
+            return box.absoluteBorderBoxRect();
+        case FillBox::Padding:
+            return box.absolutePaddingBoxRect();
+        case FillBox::Content:
+            return box.absoluteContentBoxRect();
+        case FillBox::Text:
+            break;
+        }
+        return AbsoluteFloatRect();
+    };
+
+    switch (layer.clip()) {
+    case FillBox::Border:
+    case FillBox::Padding:
+    case FillBox::Content: {
+        stateSaver.save();
+        context.clip(clipRectForLayer(box, layer));
+        break;
+    }
+    case FillBox::Text:
+        break;
+    }
+
+    // FIXME: Handle background compositing modes.
+
+    auto* backgroundImage = layer.image();
+    CompositeOperator op = CompositeOperator::SourceOver;
+
+    if (geometry.destRect().isEmpty())
+        return;
+
+    auto image = backgroundImage->image(nullptr, geometry.tileSize());
+    if (!image)
+        return;
+
+    // FIXME: call image->updateFromSettings().
+
+    ImagePaintingOptions options = {
+        op == CompositeOperator::SourceOver ? layer.composite() : op,
+        layer.blendMode(),
+        DecodingMode::Synchronous,
+        ImageOrientation::FromImage,
+        InterpolationQuality::Default
+    };
+
+    context.drawTiledImage(*image, geometry.destRect(), toFloatPoint(geometry.relativePhase()), geometry.tileSize(), geometry.spaceSize(), options);
+}
+
+void CSSPainter::paintBackgroundImages(const BoxModelBox& box, GraphicsContext& context)
+{
+    const auto& style = box.style();
+
+    Vector<const FillLayer*, 8> layers;
+
+    for (auto* layer = style.backgroundLayers(); layer; layer = layer->next())
+        layers.append(layer);
+
+    auto* boxDecorationData = box.boxDecorationData();
+    ASSERT(boxDecorationData);
+
+    auto& layerGeometryList = boxDecorationData->backgroundImageGeometry();
+
+    for (int i = layers.size() - 1; i >=0; --i) {
+        const auto* layer = layers[i];
+        const auto& geometry = layerGeometryList[i];
+        paintFillLayer(box, *layer, geometry, context);
+    }
+}
+
+void CSSPainter::paintBoxDecorations(const BoxModelBox& box, GraphicsContext& context)
+{
     // FIXME: Table decoration painting is special.
 
-    auto borderBoxRect = displayBox.absoluteBorderBoxRect();
-    
-    const auto& style = displayBox.style();
+    auto borderBoxRect = box.absoluteBorderBoxRect();
 
+    const auto& style = box.style();
+
     // Background color
     if (style.hasBackground()) {
         context.fillRect(borderBoxRect, style.backgroundColor());
-        // FIXME: Paint background image.
+        if (style.hasBackgroundImage())
+            paintBackgroundImages(box, context);
     }
 
     // Border

Modified: trunk/Source/WebCore/display/css/DisplayCSSPainter.h (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayCSSPainter.h	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayCSSPainter.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -32,11 +32,13 @@
 
 namespace WebCore {
 
+class FillLayer;
 class GraphicsContext;
 class IntRect;
 
 namespace Display {
 
+class FillLayerImageGeometry;
 class Box;
 class BoxModelBox;
 class ContainerBox;
@@ -52,6 +54,8 @@
 private:
     static void paintBox(const Box&, GraphicsContext&, const IntRect& dirtyRect);
     static void paintBoxDecorations(const BoxModelBox&, GraphicsContext&);
+    static void paintBackgroundImages(const BoxModelBox&, GraphicsContext&);
+    static void paintFillLayer(const BoxModelBox&, const FillLayer&, const FillLayerImageGeometry&, GraphicsContext&);
     static void paintBoxContent(const Box&, GraphicsContext&);
 
     enum class PaintPhase {

Added: trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.cpp (0 => 268955)


--- trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.cpp	                        (rev 0)
+++ trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -0,0 +1,396 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "DisplayFillLayerImageGeometry.h"
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "DisplayBox.h"
+#include "FillLayer.h"
+#include "LayoutBox.h"
+#include "LayoutBoxGeometry.h"
+#include "LengthFunctions.h"
+#include "RenderStyle.h"
+
+namespace WebCore {
+namespace Display {
+
+static inline LayoutUnit resolveWidthForRatio(LayoutUnit height, const LayoutSize& intrinsicRatio)
+{
+    return height * intrinsicRatio.width() / intrinsicRatio.height();
+}
+
+static inline LayoutUnit resolveHeightForRatio(LayoutUnit width, const LayoutSize& intrinsicRatio)
+{
+    return width * intrinsicRatio.height() / intrinsicRatio.width();
+}
+
+static inline LayoutSize resolveAgainstIntrinsicWidthOrHeightAndRatio(LayoutSize size, LayoutSize intrinsicRatio, LayoutUnit useWidth, LayoutUnit useHeight)
+{
+    if (intrinsicRatio.isEmpty()) {
+        if (useWidth)
+            return LayoutSize(useWidth, size.height());
+
+        return LayoutSize(size.width(), useHeight);
+    }
+
+    if (useWidth)
+        return LayoutSize(useWidth, resolveHeightForRatio(useWidth, intrinsicRatio));
+
+    return LayoutSize(resolveWidthForRatio(useHeight, intrinsicRatio), useHeight);
+}
+
+static inline LayoutSize resolveAgainstIntrinsicRatio(LayoutSize size, const LayoutSize& intrinsicRatio)
+{
+    // Two possible solutions: (size.width(), solutionHeight) or (solutionWidth, size.height())
+    // "... must be assumed to be the largest dimensions..." = easiest answer: the rect with the largest surface area.
+
+    LayoutUnit solutionWidth = resolveWidthForRatio(size.height(), intrinsicRatio);
+    LayoutUnit solutionHeight = resolveHeightForRatio(size.width(), intrinsicRatio);
+    if (solutionWidth <= size.width()) {
+        if (solutionHeight <= size.height()) {
+            // If both solutions fit, choose the one covering the larger area.
+            LayoutUnit areaOne = solutionWidth * size.height();
+            LayoutUnit areaTwo = size.width() * solutionHeight;
+            if (areaOne < areaTwo)
+                return LayoutSize(size.width(), solutionHeight);
+
+            return LayoutSize(solutionWidth, size.height());
+        }
+
+        // Only the first solution fits.
+        return LayoutSize(solutionWidth, size.height());
+    }
+
+    // Only the second solution fits, assert that.
+    ASSERT(solutionHeight <= size.height());
+    return LayoutSize(size.width(), solutionHeight);
+}
+
+static LayoutSize calculateImageIntrinsicDimensions(StyleImage* image, LayoutSize positioningAreaSize)
+{
+    // A generated image without a fixed size, will always return the container size as intrinsic size.
+    if (image->isGeneratedImage() && image->usesImageContainerSize())
+        return LayoutSize(positioningAreaSize.width(), positioningAreaSize.height());
+
+    // FIXME: Call computeIntrinsicDimensions().
+    auto imageSize = image->imageSize(nullptr, 1);
+    auto intrinsicRatio = imageSize;
+    Length intrinsicWidth = Length(intrinsicRatio.width(), Fixed);
+    Length intrinsicHeight = Length(intrinsicRatio.height(), Fixed);
+
+    ASSERT(!intrinsicWidth.isPercentOrCalculated());
+    ASSERT(!intrinsicHeight.isPercentOrCalculated());
+
+    LayoutSize resolvedSize(intrinsicWidth.value(), intrinsicHeight.value());
+    LayoutSize minimumSize(resolvedSize.width() > 0 ? 1 : 0, resolvedSize.height() > 0 ? 1 : 0);
+
+    // FIXME: Respect ScaleByEffectiveZoom.
+    resolvedSize.clampToMinimumSize(minimumSize);
+
+    if (!resolvedSize.isEmpty())
+        return resolvedSize;
+
+    // If the image has one of either an intrinsic width or an intrinsic height:
+    // * and an intrinsic aspect ratio, then the missing dimension is calculated from the given dimension and the ratio.
+    // * and no intrinsic aspect ratio, then the missing dimension is assumed to be the size of the rectangle that
+    //   establishes the coordinate system for the 'background-position' property.
+    if (resolvedSize.width() > 0 || resolvedSize.height() > 0)
+        return resolveAgainstIntrinsicWidthOrHeightAndRatio(positioningAreaSize, LayoutSize(intrinsicRatio), resolvedSize.width(), resolvedSize.height());
+
+    // If the image has no intrinsic dimensions and has an intrinsic ratio the dimensions must be assumed to be the
+    // largest dimensions at that ratio such that neither dimension exceeds the dimensions of the rectangle that
+    // establishes the coordinate system for the 'background-position' property.
+    if (!intrinsicRatio.isEmpty())
+        return resolveAgainstIntrinsicRatio(positioningAreaSize, LayoutSize(intrinsicRatio));
+
+    // If the image has no intrinsic ratio either, then the dimensions must be assumed to be the rectangle that
+    // establishes the coordinate system for the 'background-position' property.
+    return positioningAreaSize;
+}
+
+static LayoutSize calculateFillTileSize(const FillLayer& fillLayer, LayoutSize positioningAreaSize, float pixelSnappingFactor)
+{
+    StyleImage* image = fillLayer.image();
+    FillSizeType type = fillLayer.size().type;
+    auto devicePixelSize = LayoutUnit { 1.0 / pixelSnappingFactor };
+
+    LayoutSize imageIntrinsicSize;
+    if (image) {
+        imageIntrinsicSize = calculateImageIntrinsicDimensions(image, positioningAreaSize);
+        imageIntrinsicSize.scale(1 / image->imageScaleFactor(), 1 / image->imageScaleFactor());
+    } else
+        imageIntrinsicSize = positioningAreaSize;
+
+    switch (type) {
+    case FillSizeType::Size: {
+        LayoutSize tileSize = positioningAreaSize;
+
+        Length layerWidth = fillLayer.size().size.width;
+        Length layerHeight = fillLayer.size().size.height;
+
+        if (layerWidth.isFixed())
+            tileSize.setWidth(layerWidth.value());
+        else if (layerWidth.isPercentOrCalculated()) {
+            auto resolvedWidth = valueForLength(layerWidth, positioningAreaSize.width());
+            // Non-zero resolved value should always produce some content.
+            tileSize.setWidth(!resolvedWidth ? resolvedWidth : std::max(devicePixelSize, resolvedWidth));
+        }
+        
+        if (layerHeight.isFixed())
+            tileSize.setHeight(layerHeight.value());
+        else if (layerHeight.isPercentOrCalculated()) {
+            auto resolvedHeight = valueForLength(layerHeight, positioningAreaSize.height());
+            // Non-zero resolved value should always produce some content.
+            tileSize.setHeight(!resolvedHeight ? resolvedHeight : std::max(devicePixelSize, resolvedHeight));
+        }
+
+        // If one of the values is auto we have to use the appropriate
+        // scale to maintain our aspect ratio.
+        if (layerWidth.isAuto() && !layerHeight.isAuto()) {
+            if (imageIntrinsicSize.height())
+                tileSize.setWidth(imageIntrinsicSize.width() * tileSize.height() / imageIntrinsicSize.height());
+        } else if (!layerWidth.isAuto() && layerHeight.isAuto()) {
+            if (imageIntrinsicSize.width())
+                tileSize.setHeight(imageIntrinsicSize.height() * tileSize.width() / imageIntrinsicSize.width());
+        } else if (layerWidth.isAuto() && layerHeight.isAuto()) {
+            // If both width and height are auto, use the image's intrinsic size.
+            tileSize = imageIntrinsicSize;
+        }
+
+        tileSize.clampNegativeToZero();
+        return tileSize;
+    }
+    case FillSizeType::None: {
+        // If both values are ‘auto’ then the intrinsic width and/or height of the image should be used, if any.
+        if (!imageIntrinsicSize.isEmpty())
+            return imageIntrinsicSize;
+
+        // If the image has neither an intrinsic width nor an intrinsic height, its size is determined as for ‘contain’.
+        type = FillSizeType::Contain;
+    }
+    FALLTHROUGH;
+    case FillSizeType::Contain:
+    case FillSizeType::Cover: {
+        // Scale computation needs higher precision than what LayoutUnit can offer.
+        FloatSize localImageIntrinsicSize = imageIntrinsicSize;
+        FloatSize localPositioningAreaSize = positioningAreaSize;
+
+        float horizontalScaleFactor = localImageIntrinsicSize.width() ? (localPositioningAreaSize.width() / localImageIntrinsicSize.width()) : 1;
+        float verticalScaleFactor = localImageIntrinsicSize.height() ? (localPositioningAreaSize.height() / localImageIntrinsicSize.height()) : 1;
+        float scaleFactor = type == FillSizeType::Contain ? std::min(horizontalScaleFactor, verticalScaleFactor) : std::max(horizontalScaleFactor, verticalScaleFactor);
+        
+        if (localImageIntrinsicSize.isEmpty())
+            return { };
+        
+        return LayoutSize(localImageIntrinsicSize.scaled(scaleFactor).expandedTo({ devicePixelSize, devicePixelSize }));
+    }
+    }
+
+    ASSERT_NOT_REACHED();
+    return { };
+}
+
+static inline LayoutUnit getSpace(LayoutUnit areaSize, LayoutUnit tileSize)
+{
+    int numberOfTiles = areaSize / tileSize;
+    LayoutUnit space = -1;
+
+    if (numberOfTiles > 1)
+        space = (areaSize - numberOfTiles * tileSize) / (numberOfTiles - 1);
+
+    return space;
+}
+
+static LayoutUnit resolveEdgeRelativeLength(const Length& length, Edge edge, LayoutUnit availableSpace, const LayoutSize& areaSize, const LayoutSize& tileSize)
+{
+    LayoutUnit result = minimumValueForLength(length, availableSpace);
+
+    if (edge == Edge::Right)
+        return areaSize.width() - tileSize.width() - result;
+    
+    if (edge == Edge::Bottom)
+        return areaSize.height() - tileSize.height() - result;
+
+    return result;
+}
+
+static FillLayerImageGeometry pixelSnappedFillLayerImageGeometry(LayoutRect& destinationRect, LayoutSize& tileSize, LayoutSize& phase, LayoutSize& space, FillAttachment attachment, float pixelSnappingFactor)
+{
+    return FillLayerImageGeometry {
+        snapRectToDevicePixels(destinationRect, pixelSnappingFactor),
+        snapRectToDevicePixels({ destinationRect.location(), tileSize }, pixelSnappingFactor).size(),
+        snapRectToDevicePixels({ destinationRect.location(), phase }, pixelSnappingFactor).size(),
+        snapRectToDevicePixels({ { }, space }, pixelSnappingFactor).size(),
+        attachment
+    };
+}
+
+static FillLayerImageGeometry geometryForLayer(const FillLayer& fillLayer, LayoutRect borderBoxRect, const Layout::BoxGeometry& geometry, float pixelSnappingFactor)
+{
+    LayoutUnit left;
+    LayoutUnit top;
+    LayoutSize positioningAreaSize;
+
+    auto destinationRect = borderBoxRect;
+
+    switch (fillLayer.attachment()) {
+    case FillAttachment::ScrollBackground:
+    case FillAttachment::LocalBackground: {
+        LayoutUnit right;
+        LayoutUnit bottom;
+        if (fillLayer.origin() != FillBox::Border) {
+            left = geometry.borderLeft();
+            right = geometry.borderRight();
+            top = geometry.borderTop();
+            bottom = geometry.borderBottom();
+            if (fillLayer.origin() == FillBox::Content) {
+                left += geometry.paddingLeft().valueOr(0);
+                right += geometry.paddingRight().valueOr(0);
+                top += geometry.paddingTop().valueOr(0);
+                bottom += geometry.paddingBottom().valueOr(0);
+            }
+        }
+
+        // FIXME: Handle the root element sizing.
+        positioningAreaSize = borderBoxRect.size() - LayoutSize(left + right, top + bottom);
+        break;
+    }
+    case FillAttachment::FixedBackground: {
+        // FIXME: Handle fixed backgrounds.
+        positioningAreaSize = borderBoxRect.size();
+        break;
+    }
+    }
+
+    LayoutSize tileSize = calculateFillTileSize(fillLayer, positioningAreaSize, pixelSnappingFactor);
+    
+    FillRepeat backgroundRepeatX = fillLayer.repeatX();
+    FillRepeat backgroundRepeatY = fillLayer.repeatY();
+    LayoutUnit availableWidth = positioningAreaSize.width() - tileSize.width();
+    LayoutUnit availableHeight = positioningAreaSize.height() - tileSize.height();
+
+    LayoutSize spaceSize;
+    LayoutSize phase;
+    LayoutSize noRepeat;
+    LayoutUnit computedXPosition = resolveEdgeRelativeLength(fillLayer.xPosition(), fillLayer.backgroundXOrigin(), availableWidth, positioningAreaSize, tileSize);
+    if (backgroundRepeatX == FillRepeat::Round && positioningAreaSize.width() > 0 && tileSize.width() > 0) {
+        int numTiles = std::max(1, roundToInt(positioningAreaSize.width() / tileSize.width()));
+        if (fillLayer.size().size.height.isAuto() && backgroundRepeatY != FillRepeat::Round)
+            tileSize.setHeight(tileSize.height() * positioningAreaSize.width() / (numTiles * tileSize.width()));
+
+        tileSize.setWidth(positioningAreaSize.width() / numTiles);
+        phase.setWidth(tileSize.width() ? tileSize.width() - fmodf((computedXPosition + left), tileSize.width()) : 0);
+    }
+
+    LayoutUnit computedYPosition = resolveEdgeRelativeLength(fillLayer.yPosition(), fillLayer.backgroundYOrigin(), availableHeight, positioningAreaSize, tileSize);
+    if (backgroundRepeatY == FillRepeat::Round && positioningAreaSize.height() > 0 && tileSize.height() > 0) {
+        int numTiles = std::max(1, roundToInt(positioningAreaSize.height() / tileSize.height()));
+        if (fillLayer.size().size.width.isAuto() && backgroundRepeatX != FillRepeat::Round)
+            tileSize.setWidth(tileSize.width() * positioningAreaSize.height() / (numTiles * tileSize.height()));
+
+        tileSize.setHeight(positioningAreaSize.height() / numTiles);
+        phase.setHeight(tileSize.height() ? tileSize.height() - fmodf((computedYPosition + top), tileSize.height()) : 0);
+    }
+
+    if (backgroundRepeatX == FillRepeat::Repeat) {
+        phase.setWidth(tileSize.width() ? tileSize.width() - fmodf(computedXPosition + left, tileSize.width()) : 0);
+        spaceSize.setWidth(0);
+    } else if (backgroundRepeatX == FillRepeat::Space && tileSize.width() > 0) {
+        LayoutUnit space = getSpace(positioningAreaSize.width(), tileSize.width());
+        if (space >= 0) {
+            LayoutUnit actualWidth = tileSize.width() + space;
+            computedXPosition = minimumValueForLength(Length(), availableWidth);
+            spaceSize.setWidth(space);
+            spaceSize.setHeight(0);
+            phase.setWidth(actualWidth ? actualWidth - fmodf((computedXPosition + left), actualWidth) : 0);
+        } else
+            backgroundRepeatX = FillRepeat::NoRepeat;
+    }
+
+    if (backgroundRepeatX == FillRepeat::NoRepeat) {
+        LayoutUnit xOffset = left + computedXPosition;
+        if (xOffset > 0)
+            destinationRect.move(xOffset, 0_lu);
+        xOffset = std::min<LayoutUnit>(xOffset, 0);
+        phase.setWidth(-xOffset);
+        destinationRect.setWidth(tileSize.width() + xOffset);
+        spaceSize.setWidth(0);
+    }
+
+    if (backgroundRepeatY == FillRepeat::Repeat) {
+        phase.setHeight(tileSize.height() ? tileSize.height() - fmodf(computedYPosition + top, tileSize.height()) : 0);
+        spaceSize.setHeight(0);
+    } else if (backgroundRepeatY == FillRepeat::Space && tileSize.height() > 0) {
+        LayoutUnit space = getSpace(positioningAreaSize.height(), tileSize.height());
+
+        if (space >= 0) {
+            LayoutUnit actualHeight = tileSize.height() + space;
+            computedYPosition = minimumValueForLength(Length(), availableHeight);
+            spaceSize.setHeight(space);
+            phase.setHeight(actualHeight ? actualHeight - fmodf((computedYPosition + top), actualHeight) : 0);
+        } else
+            backgroundRepeatY = FillRepeat::NoRepeat;
+    }
+    if (backgroundRepeatY == FillRepeat::NoRepeat) {
+        LayoutUnit yOffset = top + computedYPosition;
+        if (yOffset > 0)
+            destinationRect.move(0_lu, yOffset);
+        yOffset = std::min<LayoutUnit>(yOffset, 0);
+        phase.setHeight(-yOffset);
+        destinationRect.setHeight(tileSize.height() + yOffset);
+        spaceSize.setHeight(0);
+    }
+
+    if (fillLayer.attachment() == FillAttachment::FixedBackground) {
+        LayoutPoint attachmentPoint = borderBoxRect.location();
+        phase.expand(std::max<LayoutUnit>(attachmentPoint.x() - destinationRect.x(), 0), std::max<LayoutUnit>(attachmentPoint.y() - destinationRect.y(), 0));
+    }
+
+    destinationRect.intersect(borderBoxRect);
+    return pixelSnappedFillLayerImageGeometry(destinationRect, tileSize, phase, spaceSize, fillLayer.attachment(), pixelSnappingFactor);
+}
+
+Vector<FillLayerImageGeometry, 1> calculateFillLayerImageGeometry(const Box&, const Layout::Box& layoutBox, const Layout::BoxGeometry& boxGeometry, LayoutSize offsetFromRoot, float pixelSnappingFactor)
+{
+    auto& renderStyle = layoutBox.style();
+
+    // FIXME: Need to map logical to physical rects.
+    auto borderBoxRect = LayoutRect { Layout::BoxGeometry::borderBoxRect(boxGeometry) };
+    borderBoxRect.move(offsetFromRoot);
+
+    Vector<FillLayerImageGeometry, 1> backgroundGeometry;
+
+    for (auto fillLayer = &renderStyle.backgroundLayers(); fillLayer; fillLayer = fillLayer->next())
+        backgroundGeometry.append(geometryForLayer(*fillLayer, borderBoxRect, boxGeometry, pixelSnappingFactor));
+
+    return backgroundGeometry;
+}
+
+} // namespace Display
+} // namespace WebCore
+
+#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)

Copied: trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.h (from rev 268954, trunk/Source/WebCore/display/DisplayTreeBuilder.h) (0 => 268955)


--- trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.h	                        (rev 0)
+++ trunk/Source/WebCore/display/css/DisplayFillLayerImageGeometry.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2020 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(LAYOUT_FORMATTING_CONTEXT)
+
+#include "FloatRect.h"
+#include "LayoutRect.h"
+
+namespace WebCore {
+class FillLayer;
+class StyleImage;
+
+namespace Layout {
+class Box;
+class BoxGeometry;
+}
+
+namespace Display {
+class Box;
+
+// Pixel-snapped image geometry for a single fill layer (used for backgrounds and masks).
+class FillLayerImageGeometry {
+public:
+    FillLayerImageGeometry(const FloatRect& destinationRect, const FloatSize& tileSize, const FloatSize& phase, const FloatSize& space, FillAttachment attachment)
+        : m_destRect(destinationRect)
+        , m_destOrigin(m_destRect.location())
+        , m_tileSize(tileSize)
+        , m_phase(phase)
+        , m_space(space)
+        , m_hasNonLocalGeometry(attachment == FillAttachment::FixedBackground)
+    {
+    }
+
+    FloatRect destRect() const { return m_destRect; }
+    FloatSize phase() const { return m_phase; }
+    FloatSize tileSize() const { return m_tileSize; }
+    FloatSize spaceSize() const { return m_space; }
+    bool hasNonLocalGeometry() const { return m_hasNonLocalGeometry; }
+
+    FloatSize relativePhase() const
+    {
+        FloatSize phase = m_phase;
+        phase += m_destRect.location() - m_destOrigin;
+        return phase;
+    }
+
+    void clip(const FloatRect& clipRect) { m_destRect.intersect(clipRect); }
+
+private:
+    FloatRect m_destRect;
+    FloatPoint m_destOrigin;
+    FloatSize m_tileSize;
+    FloatSize m_phase;
+    FloatSize m_space;
+    bool m_hasNonLocalGeometry { false }; // Has background-attachment: fixed. Implies that we can't always cheaply compute destRect.
+};
+
+Vector<FillLayerImageGeometry, 1> calculateFillLayerImageGeometry(const Box&, const Layout::Box&, const Layout::BoxGeometry&, LayoutSize offsetFromRoot, float pixelSnappingFactor);
+
+} // namespace Display
+} // namespace WebCore
+
+#endif // ENABLE(LAYOUT_FORMATTING_CONTEXT)

Modified: trunk/Source/WebCore/display/css/DisplayStyle.cpp (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayStyle.cpp	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayStyle.cpp	2020-10-25 04:27:10 UTC (rev 268955)
@@ -29,6 +29,7 @@
 #if ENABLE(LAYOUT_FORMATTING_CONTEXT)
 
 #include "BorderData.h"
+#include "FillLayer.h"
 #include "RenderStyle.h"
 #include <wtf/IsoMallocInlines.h>
 
@@ -35,15 +36,36 @@
 namespace WebCore {
 namespace Display {
 
+static RefPtr<FillLayer> deepCopy(const FillLayer& layer)
+{
+    RefPtr<FillLayer> firstLayer;
+    FillLayer* currCopiedLayer = nullptr;
+
+    for (auto* currLayer = &layer; currLayer; currLayer = currLayer->next()) {
+        RefPtr<FillLayer> layerCopy = currLayer->copy();
+
+        if (!firstLayer) {
+            firstLayer = layerCopy;
+            currCopiedLayer = layerCopy.get();
+        } else {
+            auto nextCopiedLayer = layerCopy.get();
+            currCopiedLayer->setNext(WTFMove(layerCopy));
+            currCopiedLayer = nextCopiedLayer;
+        }
+    }
+    return firstLayer;
+}
+
 Style::Style(const RenderStyle& style)
     : m_fontCascade(style.fontCascade())
     , m_whiteSpace(style.whiteSpace())
     , m_tabSize(style.tabSize())
 {
-    // FIXME: Is currentColor resovled here?
+    // FIXME: Is currentColor resolved here?
     m_color = style.visitedDependentColorWithColorFilter(CSSPropertyColor);
 
     m_backgroundColor = style.visitedDependentColorWithColorFilter(CSSPropertyBackgroundColor);
+    m_backgroundLayers = deepCopy(style.backgroundLayers());
 
     const auto& borderData = style.border();
     
@@ -72,6 +94,11 @@
     return m_backgroundColor.isVisible() || hasBackgroundImage();
 }
 
+bool Style::hasBackgroundImage() const
+{
+    return m_backgroundLayers && m_backgroundLayers->hasImage();
+}
+
 bool Style::hasVisibleBorder() const
 {
     bool haveImage = m_border.image.hasImage();

Modified: trunk/Source/WebCore/display/css/DisplayStyle.h (268954 => 268955)


--- trunk/Source/WebCore/display/css/DisplayStyle.h	2020-10-24 22:55:57 UTC (rev 268954)
+++ trunk/Source/WebCore/display/css/DisplayStyle.h	2020-10-25 04:27:10 UTC (rev 268955)
@@ -39,6 +39,7 @@
 
 namespace WebCore {
 
+class FillLayer;
 class RenderStyle;
 
 namespace Display {
@@ -46,7 +47,7 @@
 // Style information needed to paint a Display::Box.
 // All colors should be resolved to their painted values [visitedDependentColorWithColorFilter()].
 // Should contain only absolute float values; no Lengths (which can contain calc values).
-
+// Should be sharable between boxes with different geometry but the same style.
 class Style {
     WTF_MAKE_FAST_ALLOCATED_WITH_HEAP_IDENTIFIER(Style);
 public:
@@ -62,8 +63,10 @@
 
     const Color& backgroundColor() const { return m_backgroundColor; }
     bool hasBackground() const;
-    bool hasBackgroundImage() const { return false; } // FIXME
+    bool hasBackgroundImage() const;
 
+    const FillLayer* backgroundLayers() const { return m_backgroundLayers.get(); }
+
     bool hasVisibleBorder() const;
     const BorderValue& borderLeft() const { return m_border.left; }
     const BorderValue& borderRight() const { return m_border.right; }
@@ -95,6 +98,8 @@
     Color m_color;
     Color m_backgroundColor;
 
+    RefPtr<FillLayer> m_backgroundLayers;
+
     struct {
         BorderValue left;
         BorderValue right;
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to