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;