Diff
Modified: trunk/Source/WebCore/ChangeLog (287872 => 287873)
--- trunk/Source/WebCore/ChangeLog 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/ChangeLog 2022-01-11 12:57:41 UTC (rev 287873)
@@ -1,3 +1,48 @@
+2022-01-11 Nikolas Zimmermann <[email protected]>
+
+ [LBSE] Introduce SVGBoundingBoxComputation
+ https://bugs.webkit.org/show_bug.cgi?id=234632
+ <rdar://problem/87001334>
+
+ Reviewed by Rob Buis.
+
+ Upstream SVGBoundingBoxComputation, a utility class
+ implementing the SVG2 "bounding box computation" algorithm,
+ as spec'ed in https://svgwg.org/svg2-draft/coords.html#BoundingBoxes.
+
+ SVG2 also specifies a new optional argument for getBBox() & friends:
+ DOMRect getBBox(optional SVGBoundingBoxOptions options = {});
+
+ SVGBoundingBoxOptions can be implemented using SVGBoundingBoxComputation:
+ exposing this to the Web is left for the future, once more of LBSE is ready.
+
+ LBSE utilizes SVGBoundingBoxComputation whenever any kind of bounding box
+ needs to be computed (object / stroke / decorated (e.g. including markers).
+
+ Covered by existing tests, no change in behaviour.
+
+ * Sources.txt:
+ * WebCore.xcodeproj/project.pbxproj:
+ * rendering/svg/LegacyRenderSVGModelObject.h:
+ (WebCore::LegacyRenderSVGModelObject::visualOverflowRectEquivalent const): Deleted.
+ * rendering/svg/RenderSVGModelObject.h:
+ (WebCore::RenderSVGModelObject::visualOverflowRectEquivalent const):
+ * rendering/svg/RenderSVGRoot.cpp:
+ (WebCore::RenderSVGRoot::layout):
+ * rendering/svg/RenderSVGRoot.h:
+ * rendering/svg/SVGBoundingBoxComputation.cpp: Added.
+ (WebCore::SVGBoundingBoxComputation::SVGBoundingBoxComputation):
+ (WebCore::SVGBoundingBoxComputation::~SVGBoundingBoxComputation):
+ (WebCore::SVGBoundingBoxComputation::computeDecoratedBoundingBox const):
+ (WebCore::SVGBoundingBoxComputation::handleShapeOrTextOrInline const):
+ (WebCore::SVGBoundingBoxComputation::handleRootOrContainer const):
+ (WebCore::SVGBoundingBoxComputation::handleForeignObjectOrImage const):
+ (WebCore::SVGBoundingBoxComputation::adjustBoxForClippingAndEffects const):
+ * rendering/svg/SVGBoundingBoxComputation.h: Added.
+ (WebCore::SVGBoundingBoxComputation::computeDecoratedBoundingBox):
+ (WebCore::SVGBoundingBoxComputation::computeRepaintBoundingBox):
+ (WebCore::SVGBoundingBoxComputation::computeVisualOverflowRect):
+
2022-01-11 Carlos Garcia Campos <[email protected]>
[GTK][a11y] WTR: do not immediately process main thread events while waiting for ax thread task
Modified: trunk/Source/WebCore/Sources.txt (287872 => 287873)
--- trunk/Source/WebCore/Sources.txt 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/Sources.txt 2022-01-11 12:57:41 UTC (rev 287873)
@@ -2501,6 +2501,7 @@
rendering/svg/RenderSVGTextPath.cpp
rendering/svg/RenderSVGTransformableContainer.cpp
rendering/svg/RenderSVGViewportContainer.cpp
+rendering/svg/SVGBoundingBoxComputation.cpp
rendering/svg/SVGInlineFlowBox.cpp
rendering/svg/SVGInlineTextBox.cpp
rendering/svg/SVGPathData.cpp
Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (287872 => 287873)
--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj 2022-01-11 12:57:41 UTC (rev 287873)
@@ -244,6 +244,7 @@
0854B0191255E4E600B9CDD0 /* RenderSVGText.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B0071255E4E600B9CDD0 /* RenderSVGText.h */; };
0854B01B1255E4E600B9CDD0 /* RenderSVGTextPath.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B0091255E4E600B9CDD0 /* RenderSVGTextPath.h */; };
0854B01D1255E4E600B9CDD0 /* RenderSVGTSpan.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B00B1255E4E600B9CDD0 /* RenderSVGTSpan.h */; };
+ 0844B01D1255B4E600B9CDD0 /* SVGBoundingBoxComputation.h in Headers */ = {isa = PBXBuildFile; fileRef = 0844B01D1255E4E600B9CDD0 /* SVGBoundingBoxComputation.h */; };
0854B01F1255E4E600B9CDD0 /* SVGInlineFlowBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B00D1255E4E600B9CDD0 /* SVGInlineFlowBox.h */; };
0854B0211255E4E600B9CDD0 /* SVGInlineTextBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B00F1255E4E600B9CDD0 /* SVGInlineTextBox.h */; };
0854B0231255E4E600B9CDD0 /* SVGRootInlineBox.h in Headers */ = {isa = PBXBuildFile; fileRef = 0854B0111255E4E600B9CDD0 /* SVGRootInlineBox.h */; };
@@ -6185,6 +6186,8 @@
0854B0081255E4E600B9CDD0 /* RenderSVGTextPath.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = RenderSVGTextPath.cpp; sourceTree = "<group>"; };
0854B0091255E4E600B9CDD0 /* RenderSVGTextPath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGTextPath.h; sourceTree = "<group>"; };
0854B00B1255E4E600B9CDD0 /* RenderSVGTSpan.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RenderSVGTSpan.h; sourceTree = "<group>"; };
+ 0834B00C1244E4E600B9CDD0 /* SVGBoundingBoxComputation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGBoundingBoxComputation.cpp; sourceTree = "<group>"; };
+ 0844B01D1255E4E600B9CDD0 /* SVGBoundingBoxComputation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGBoundingBoxComputation.h; sourceTree = "<group>"; };
0854B00C1255E4E600B9CDD0 /* SVGInlineFlowBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGInlineFlowBox.cpp; sourceTree = "<group>"; };
0854B00D1255E4E600B9CDD0 /* SVGInlineFlowBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SVGInlineFlowBox.h; sourceTree = "<group>"; };
0854B00E1255E4E600B9CDD0 /* SVGInlineTextBox.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SVGInlineTextBox.cpp; sourceTree = "<group>"; };
@@ -18994,6 +18997,8 @@
0854B00B1255E4E600B9CDD0 /* RenderSVGTSpan.h */,
436708AB12D9CA4B00044234 /* RenderSVGViewportContainer.cpp */,
436708AC12D9CA4B00044234 /* RenderSVGViewportContainer.h */,
+ 0834B00C1244E4E600B9CDD0 /* SVGBoundingBoxComputation.cpp */,
+ 0844B01D1255E4E600B9CDD0 /* SVGBoundingBoxComputation.h */,
0854B00C1255E4E600B9CDD0 /* SVGInlineFlowBox.cpp */,
0854B00D1255E4E600B9CDD0 /* SVGInlineFlowBox.h */,
0854B00E1255E4E600B9CDD0 /* SVGInlineTextBox.cpp */,
@@ -37315,6 +37320,7 @@
B22279930D00BF220071B782 /* SVGAnimateMotionElement.h in Headers */,
B22279950D00BF220071B782 /* SVGAnimateTransformElement.h in Headers */,
B22279980D00BF220071B782 /* SVGAnimationElement.h in Headers */,
+ 0844B01D1255B4E600B9CDD0 /* SVGBoundingBoxComputation.h in Headers */,
B222799C0D00BF220071B782 /* SVGCircleElement.h in Headers */,
B222799F0D00BF220071B782 /* SVGClipPathElement.h in Headers */,
B22279A50D00BF220071B782 /* SVGComponentTransferFunctionElement.h in Headers */,
Modified: trunk/Source/WebCore/rendering/svg/LegacyRenderSVGModelObject.h (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/LegacyRenderSVGModelObject.h 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/LegacyRenderSVGModelObject.h 2022-01-11 12:57:41 UTC (rev 287873)
@@ -62,10 +62,6 @@
SVGElement& element() const { return downcast<SVGElement>(nodeForNonAnonymous()); }
- // FIXME: [LBSE] Upstream SVGBoundingBoxComputation
- // LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
- LayoutRect visualOverflowRectEquivalent() const { return LayoutRect(); }
-
protected:
LegacyRenderSVGModelObject(SVGElement&, RenderStyle&&);
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGModelObject.h 2022-01-11 12:57:41 UTC (rev 287873)
@@ -34,8 +34,7 @@
#if ENABLE(LAYER_BASED_SVG_ENGINE)
#include "RenderLayer.h"
#include "RenderLayerModelObject.h"
-// FIXME: [LBSE] Upstream SVGBoundingBoxComputation
-// #include "SVGBoundingBoxComputation.h"
+#include "SVGBoundingBoxComputation.h"
#include "SVGElement.h"
#include "SVGRenderSupport.h"
@@ -69,12 +68,7 @@
LayoutRect contentBoxRectEquivalent() const { return borderBoxRectEquivalent(); }
LayoutRect frameRectEquivalent() const { return m_layoutRect; }
- LayoutRect visualOverflowRectEquivalent() const
- {
- // FIXME: [LBSE] Upstream SVGBoundingBoxComputation
- // return SVGBoundingBoxComputation::computeVisualOverflowRect(*this);
- return LayoutRect();
- }
+ LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
void applyTopLeftLocationOffsetEquivalent(LayoutPoint& point) const { point.moveBy(layoutLocation()); }
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRoot.cpp 2022-01-11 12:57:41 UTC (rev 287873)
@@ -193,16 +193,16 @@
// SVGLayerTransformUpdater transformUpdater(*this);
updateLayerInformation();
- /* FIXME: [LBSE] Upstream SVGContainerLayout / SVGBoundingBoxComputation
{
+ /* FIXME: [LBSE] Upstream SVGContainerLayout
SVGContainerLayout containerLayout(*this);
containerLayout.layoutChildren(needsLayout || SVGRenderSupport::filtersForceContainerLayout(*this));
+ */
SVGBoundingBoxComputation boundingBoxComputation(*this);
m_objectBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::objectBoundingBoxDecoration);
m_strokeBoundingBox = boundingBoxComputation.computeDecoratedBoundingBox(SVGBoundingBoxComputation::strokeBoundingBoxDecoration);
}
- */
// FIXME: [LBSE] Upstream SVGContainerLayout -- remove SVGRenderSupport::layoutChildren.
SVGRenderSupport::layoutChildren(*this, needsLayout);
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGRoot.h 2022-01-11 12:57:41 UTC (rev 287873)
@@ -26,8 +26,7 @@
#if ENABLE(LAYER_BASED_SVG_ENGINE)
#include "FloatRect.h"
#include "RenderReplaced.h"
-// FIXME: [LBSE] Upstream SVGBoundingBoxComputation
-// #include "SVGBoundingBoxComputation.h"
+#include "SVGBoundingBoxComputation.h"
namespace WebCore {
@@ -72,22 +71,10 @@
FloatRect objectBoundingBox() const final { return m_objectBoundingBox; }
FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
+ FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
- // FIXME: [LBSE] Mark final, add repaintBoundingBox() to RenderObject
- FloatRect repaintBoundingBox() const
- {
- // FIXME: [LBSE] Upstream SVGBoundingBoxComputation
- // return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this);
- return m_strokeBoundingBox;
- }
+ LayoutRect visualOverflowRectEquivalent() const { return SVGBoundingBoxComputation::computeVisualOverflowRect(*this); }
- LayoutRect visualOverflowRectEquivalent() const
- {
- // FIXME: [LBSE] Upstream SVGBoundingBoxComputation
- // return SVGBoundingBoxComputation::computeVisualOverflowRect(*this);
- return LayoutRect();
- }
-
private:
void element() const = delete;
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGShape.cpp 2022-01-11 12:57:41 UTC (rev 287873)
@@ -400,7 +400,7 @@
return 0;
}
-FloatRect RenderSVGShape::computeMarkerBoundingBox() const
+FloatRect RenderSVGShape::computeMarkerBoundingBox(const SVGBoundingBoxComputation::DecorationOptions&) const
{
if (m_markerPositions.isEmpty())
return FloatRect();
@@ -417,8 +417,11 @@
FloatRect boundaries;
unsigned size = m_markerPositions.size();
for (unsigned i = 0; i < size; ++i) {
- if (RenderSVGResourceMarker* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd))
+ if (auto* marker = markerForType(m_markerPositions[i].type, markerStart, markerMid, markerEnd)) {
+ // FIXME: [LBSE] Upstream RenderSVGResourceMarker changes
+ // boundaries.unite(marker->computeMarkerBoundingBox(options, marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth())));
boundaries.unite(marker->markerBoundaries(marker->markerTransformation(m_markerPositions[i].origin, m_markerPositions[i].angle, strokeWidth())));
+ }
}
return boundaries;
}
Modified: trunk/Source/WebCore/rendering/svg/RenderSVGShape.h (287872 => 287873)
--- trunk/Source/WebCore/rendering/svg/RenderSVGShape.h 2022-01-11 08:53:55 UTC (rev 287872)
+++ trunk/Source/WebCore/rendering/svg/RenderSVGShape.h 2022-01-11 12:57:41 UTC (rev 287873)
@@ -30,8 +30,7 @@
#include "AffineTransform.h"
#include "FloatRect.h"
#include "RenderSVGModelObject.h"
-// FIXME: [LBSE] Upstream SVGBoundingBoxComputation
-// #include "SVGBoundingBoxComputation.h"
+#include "SVGBoundingBoxComputation.h"
#include "SVGGraphicsElement.h"
#include "SVGMarkerData.h"
#include <memory>
@@ -80,16 +79,10 @@
FloatRect objectBoundingBox() const final { return m_fillBoundingBox; }
FloatRect strokeBoundingBox() const final { return m_strokeBoundingBox; }
+ FloatRect repaintRectInLocalCoordinates() const final { return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
- FloatRect repaintRectInLocalCoordinates() const final
- {
- // FIXME: [LBSE] Upstream SVGBoundingBoxComputation
- // return SVGBoundingBoxComputation::computeRepaintBoundingBox(*this); }
- return FloatRect();
- }
+ FloatRect computeMarkerBoundingBox(const SVGBoundingBoxComputation::DecorationOptions&) const;
- FloatRect computeMarkerBoundingBox() const;
-
protected:
void element() const = delete;
Added: trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp (0 => 287873)
--- trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp (rev 0)
+++ trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.cpp 2022-01-11 12:57:41 UTC (rev 287873)
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2021, 2022 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "SVGBoundingBoxComputation.h"
+
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+#include "RenderChildIterator.h"
+#include "RenderSVGForeignObject.h"
+#include "RenderSVGImage.h"
+#include "RenderSVGInline.h"
+#include "RenderSVGResourceClipper.h"
+#include "RenderSVGResourceFilter.h"
+#include "RenderSVGResourceMarker.h"
+#include "RenderSVGResourceMasker.h"
+#include "RenderSVGRoot.h"
+#include "RenderSVGShape.h"
+#include "RenderSVGText.h"
+#include "SVGResources.h"
+#include "SVGResourcesCache.h"
+
+namespace WebCore {
+
+SVGBoundingBoxComputation::SVGBoundingBoxComputation(const RenderLayerModelObject& renderer)
+ : m_renderer(renderer)
+{
+}
+
+FloatRect SVGBoundingBoxComputation::computeDecoratedBoundingBox(const SVGBoundingBoxComputation::DecorationOptions& options, bool* boundingBoxValid) const
+{
+ // SVG2: Bounding boxes algorithm (https://svgwg.org/svg2-draft/coords.html#BoundingBoxes)
+
+ // The following algorithm defines how to compute a bounding box for a given element. The inputs to the algorithm are:
+ // - element, the element we are computing a bounding box for;
+ // - space, a coordinate space in which the bounding box will be computed;
+ // - fill, a boolean indicating whether the bounding box includes the geometry of the element and its descendants;
+ // - stroke, a boolean indicating whether the bounding box includes the stroke of the element and its descendants;
+ // - markers, a boolean indicating whether the bounding box includes the markers of the element and its descendants; and
+ // - clipped, a boolean indicating whether the bounding box is affected by any clipping paths applied to the element and its descendants.
+
+ // The algorithm to compute the bounding box is as follows, depending on the type of element:
+ // - a shape (RenderSVGShape)
+ // - a text content element (RenderSVGText or RenderSVGInline)
+ // - an "a" element within a text content element (-> creates RenderSVGInline)
+ if (is<RenderSVGShape>(m_renderer) || is<RenderSVGText>(m_renderer) || is<RenderSVGInline>(m_renderer))
+ return handleShapeOrTextOrInline(options, boundingBoxValid);
+
+ // - a container element (RenderSVGRoot / RenderSVGContainer)
+ // - "use" (RenderSVGTransformableContainer)
+ // FIXME: [LBSE] Upstream new RenderSVGContainer implementation
+ // if (is<RenderSVGRoot>(m_renderer) || is<RenderSVGContainer>(m_renderer))
+ if (is<RenderSVGRoot>(m_renderer))
+ return handleRootOrContainer(options, boundingBoxValid);
+
+ // - "foreignObject"
+ // - "image"
+ // FIXME: [LBSE] Upstream new RenderSVGImage implementation
+ // if (is<RenderSVGForeignObject>(m_renderer) || is<RenderSVGImage>(m_renderer))
+ if (is<RenderSVGForeignObject>(m_renderer))
+ return handleForeignObjectOrImage(options, boundingBoxValid);
+
+ ASSERT_NOT_REACHED();
+ return FloatRect();
+}
+
+FloatRect SVGBoundingBoxComputation::handleShapeOrTextOrInline(const SVGBoundingBoxComputation::DecorationOptions& options, bool* boundingBoxValid) const
+{
+ // 1. Let box be a rectangle initialized to (0, 0, 0, 0).
+ FloatRect box;
+
+ // 2. Let fill-shape be the equivalent path of element if it is a shape, or a shape that includes each of the
+ // glyph cells corresponding to the text within the elements otherwise.
+ // 3. If fill is true, then set box to the tightest rectangle in the coordinate system space that contains fill-shape.
+ //
+ // Note: The values of the fill, fill-opacity and fill-rule properties do not affect fill-shape.
+ if (options.contains(DecorationOption::IncludeFillShape))
+ box = m_renderer.objectBoundingBox();
+
+ // 4. If stroke is true and the element's stroke is anything other than none, then set box to be the union of box
+ // and the tightest rectangle in coordinate system space that contains the stroke shape of the element, with the
+ // assumption that the element has no dash pattern.
+ //
+ // Note: The values of the stroke-opacity, stroke-dasharray and stroke-dashoffset do not affect the calculation of the stroke shape.
+ if (options.contains(DecorationOption::IncludeStrokeShape))
+ box.unite(m_renderer.strokeBoundingBox());
+
+ // 5. If markers is true, then for each marker marker rendered on the element:
+ // - For each descendant graphics element child of the "marker" element that defines marker's content:
+ // - If child has an ancestor element within the "marker" that is 'display: none', has a failing conditional processing attribute,
+ // or is not an "a", "g", "svg" or "switch" element, then continue to the next descendant graphics element.
+ // - Otherwise, set box to be the union of box and the result of invoking the algorithm to compute a bounding box with child as
+ // the element, space as the target coordinate space, true for fill, stroke and markers, and clipped for clipped.
+ if (options.contains(DecorationOption::IncludeMarkers) && is<RenderSVGShape>(m_renderer)) {
+ DecorationOptions optionsForMarker = { DecorationOption::IncludeFillShape, DecorationOption::IncludeStrokeShape, DecorationOption::IncludeMarkers };
+ if (options.contains(DecorationOption::IncludeClippers))
+ optionsForMarker.add(DecorationOption::IncludeClippers);
+ box.unite(downcast<RenderSVGShape>(m_renderer).computeMarkerBoundingBox(options));
+ }
+
+ // 6. If clipped is true and the value of clip-path on element is not none, then set box to be the tightest rectangle
+ // in coordinate system space that contains the intersection of box and the clipping path.
+ adjustBoxForClippingAndEffects(options, box);
+
+ // 7. Return box.
+ if (boundingBoxValid)
+ *boundingBoxValid = true;
+ return box;
+}
+
+FloatRect SVGBoundingBoxComputation::handleRootOrContainer(const SVGBoundingBoxComputation::DecorationOptions& options, bool* boundingBoxValid) const
+{
+ auto transformationMatrixFromChild = [] (const RenderLayerModelObject& child) -> std::optional<TransformationMatrix> {
+ if (!child.hasTransform())
+ return std::nullopt;
+
+ auto* container = child.parent();
+ ASSERT(container);
+
+ bool containerSkipped = false;
+ ASSERT(container == child.container(nullptr, containerSkipped));
+ ASSERT_UNUSED(containerSkipped, !containerSkipped);
+
+ TransformationMatrix layerTransform;
+ child.getTransformFromContainer(container, LayoutSize(), layerTransform);
+ return layerTransform.isIdentity() ? std::nullopt : std::make_optional(WTFMove(layerTransform));
+ };
+
+ auto uniteBoundingBoxRespectingValidity = [] (bool& boxValid, FloatRect& box, const RenderLayerModelObject& /* child */, const FloatRect& childBoundingBox) {
+ // FIXME: [LBSE] Upstream new RenderSVGContainer implementation
+ // bool isBoundingBoxValid = is<RenderSVGContainer>(child) ? downcast<RenderSVGContainer>(child).isObjectBoundingBoxValid() : true;
+ bool isBoundingBoxValid = true;
+ if (!isBoundingBoxValid)
+ return;
+
+ if (boxValid) {
+ box.uniteEvenIfEmpty(childBoundingBox);
+ return;
+ }
+
+ box = childBoundingBox;
+ boxValid = true;
+ };
+
+ // 1. Let box be a rectangle initialized to (0, 0, 0, 0).
+ FloatRect box;
+ bool boxValid = false;
+
+ // 2. Let parent be the container element if it is one, or the root of the "use" element's shadow tree otherwise.
+
+ // 3. For each descendant graphics element child of parent:
+ // - If child is not rendered then continue to the next descendant graphics element.
+ // - Otherwise, set box to be the union of box and the result of invoking the algorithm to compute a bounding box with child
+ // as the element and the same values for space, fill, stroke, markers and clipped as the corresponding algorithm input values.
+ for (auto& child : childrenOfType<RenderLayerModelObject>(m_renderer)) {
+ // FIXME: [LBSE] Upstream new RenderSVGContainer implementation
+ // if (is<RenderSVGHiddenContainer>(child) || (is<RenderSVGShape>(child) && downcast<RenderSVGShape>(child).isRenderingDisabled()))
+ if (is<RenderSVGShape>(child) && downcast<RenderSVGShape>(child).isRenderingDisabled())
+ continue;
+
+ SVGBoundingBoxComputation childBoundingBoxComputation(child);
+ auto childBox = childBoundingBoxComputation.computeDecoratedBoundingBox(options);
+ // FIXME: Upstream new RenderSVGContainer implementation
+ // if (options.contains(DecorationOption::OverrideBoxWithFilterBoxForChildren) && is<RenderSVGContainer>(child))
+ // childBoundingBoxComputation.adjustBoxForClippingAndEffects({ DecorationOption::OverrideBoxWithFilterBox }, childBox);
+
+ if (auto layerTransform = transformationMatrixFromChild(child))
+ childBox = layerTransform->mapRect(childBox);
+
+ if (options == objectBoundingBoxDecoration)
+ uniteBoundingBoxRespectingValidity(boxValid, box, child, childBox);
+ else
+ box.unite(childBox);
+ }
+
+ // 4. If clipped is true:
+ // - If the value of clip-path on element is not none, then set box to be the tightest rectangle in coordinate system space that
+ // contains the intersection of box and the clipping path.
+ // - If the overflow property applies to the element and does not have a value of visible, then set box to be the tightest rectangle
+ // in coordinate system space that contains the intersection of box and the element's overflow bounds.
+ // - If the clip property applies to the element and does not have a value of auto, then set box to be the tightest rectangle in coordinate
+ // system space that contains the intersection of box and the rectangle specified by clip. (TODO!)
+ adjustBoxForClippingAndEffects(options, box, { DecorationOption::OverrideBoxWithFilterBox });
+
+ if (options.contains(DecorationOption::IncludeClippers) && m_renderer.hasNonVisibleOverflow()) {
+ ASSERT(m_renderer.hasLayer());
+
+ // FIXME: [LBSE] Upstream new RenderSVGContainer / RenderSVGResourceMarker implementation
+ // ASSERT(is<RenderSVGViewportContainer>(m_renderer) || is<RenderSVGResourceMarker>(m_renderer) || is<RenderSVGRoot>(m_renderer));
+ ASSERT(is<RenderSVGRoot>(m_renderer));
+
+ LayoutRect overflowClipRect;
+ if (is<RenderSVGModelObject>(m_renderer))
+ overflowClipRect = downcast<RenderSVGModelObject>(m_renderer).overflowClipRect(LayoutPoint());
+ else if (is<RenderBox>(m_renderer))
+ overflowClipRect = downcast<RenderBox>(m_renderer).overflowClipRect(LayoutPoint());
+ else {
+ ASSERT_NOT_REACHED();
+ return FloatRect();
+ }
+
+ box.intersect(overflowClipRect);
+ }
+
+ // 5. Return box.
+ if (boundingBoxValid)
+ *boundingBoxValid = boxValid;
+ return box;
+}
+
+FloatRect SVGBoundingBoxComputation::handleForeignObjectOrImage(const SVGBoundingBoxComputation::DecorationOptions& options, bool* boundingBoxValid) const
+{
+ // 1. Let box be the tightest rectangle in coordinate space space that contains the positioning rectangle
+ // defined by the "x", "y", "width" and "height" geometric properties of the element.
+ //
+ // Note: The fill, stroke and markers input arguments to this algorithm do not affect the bounding box returned for these elements.
+ auto box = m_renderer.objectBoundingBox();
+
+ // 2. If clipped is true and the value of clip-path on element is not none, then set box to be the tightest rectangle
+ // in coordinate system space that contains the intersection of box and the clipping path.
+ adjustBoxForClippingAndEffects(options, box);
+
+ // 3. Return box.
+ if (boundingBoxValid)
+ *boundingBoxValid = true;
+ return box;
+}
+
+void SVGBoundingBoxComputation::adjustBoxForClippingAndEffects(const SVGBoundingBoxComputation::DecorationOptions& options, FloatRect& box, const SVGBoundingBoxComputation::DecorationOptions& optionsToCheckForFilters) const
+{
+ bool includeFilter = false;
+ for (auto filterOption : optionsToCheckForFilters) {
+ if (options.contains(filterOption)) {
+ includeFilter = true;
+ break;
+ }
+ }
+
+ bool includeClipper = options.contains(DecorationOption::IncludeClippers);
+ bool includeMasker = options.contains(DecorationOption::IncludeMaskers);
+
+ if (includeFilter || includeClipper || includeMasker) {
+ if (auto* resources = SVGResourcesCache::cachedResourcesForRenderer(m_renderer)) {
+ if (includeFilter) {
+ if (auto* filter = resources->filter())
+ box = filter->resourceBoundingBox(m_renderer);
+ }
+
+ if (includeClipper) {
+ if (auto* clipper = resources->clipper())
+ box.intersect(clipper->resourceBoundingBox(m_renderer));
+ }
+
+ if (includeMasker) {
+ if (auto* masker = resources->masker())
+ box.intersect(masker->resourceBoundingBox(m_renderer));
+ }
+ }
+ }
+
+ if (options.contains(DecorationOption::IncludeOutline))
+ box.inflate(m_renderer.outlineStyleForRepaint().outlineSize());
+}
+
+}
+
+#endif
Added: trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h (0 => 287873)
--- trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h (rev 0)
+++ trunk/Source/WebCore/rendering/svg/SVGBoundingBoxComputation.h 2022-01-11 12:57:41 UTC (rev 287873)
@@ -0,0 +1,92 @@
+/**
+ * Copyright (C) 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#if ENABLE(LAYER_BASED_SVG_ENGINE)
+
+#include "RenderLayerModelObject.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OptionSet.h>
+
+namespace WebCore {
+
+class FloatRect;
+
+class SVGBoundingBoxComputation {
+ WTF_MAKE_NONCOPYABLE(SVGBoundingBoxComputation);
+public:
+ explicit SVGBoundingBoxComputation(const RenderLayerModelObject&);
+ ~SVGBoundingBoxComputation() = default;
+
+ enum class DecorationOption : uint8_t {
+ IncludeFillShape = 1 << 0, /* corresponds to 'bool fill' */
+ IncludeStrokeShape = 1 << 1, /* corresponds to 'bool stroke' */
+ IncludeMarkers = 1 << 2, /* corresponds to 'bool markers' */
+ IncludeClippers = 1 << 3, /* corresponds to 'bool clippers' */
+ IncludeMaskers = 1 << 4, /* WebKit extension - internal */
+ IncludeOutline = 1 << 5, /* WebKit extension - internal */
+ OverrideBoxWithFilterBox = 1 << 6, /* WebKit extension - internal */
+ OverrideBoxWithFilterBoxForChildren = 1 << 7 /* WebKit extension - internal */
+ };
+
+ using DecorationOptions = OptionSet<DecorationOption>;
+
+ static constexpr DecorationOptions objectBoundingBoxDecoration = { DecorationOption::IncludeFillShape };
+ static constexpr DecorationOptions strokeBoundingBoxDecoration = { DecorationOption::IncludeFillShape, DecorationOption::IncludeStrokeShape };
+ static constexpr DecorationOptions filterBoundingBoxDecoration = { DecorationOption::OverrideBoxWithFilterBox, DecorationOption::OverrideBoxWithFilterBoxForChildren };
+ static constexpr DecorationOptions repaintBoundingBoxDecoration = { DecorationOption::IncludeFillShape, DecorationOption::IncludeStrokeShape, DecorationOption::IncludeMarkers, DecorationOption::IncludeClippers, DecorationOption::IncludeMaskers, DecorationOption::OverrideBoxWithFilterBox };
+
+ FloatRect computeDecoratedBoundingBox(const DecorationOptions&, bool* boundingBoxValid = nullptr) const;
+
+ static FloatRect computeDecoratedBoundingBox(const RenderLayerModelObject& renderer, const DecorationOptions& options)
+ {
+ SVGBoundingBoxComputation boundingBoxComputation(renderer);
+ return boundingBoxComputation.computeDecoratedBoundingBox(options);
+ }
+
+ static FloatRect computeRepaintBoundingBox(const RenderLayerModelObject& renderer)
+ {
+ return computeDecoratedBoundingBox(renderer, repaintBoundingBoxDecoration);
+ }
+
+ static LayoutRect computeVisualOverflowRect(const RenderLayerModelObject& renderer)
+ {
+ auto repaintBoundingBox = computeDecoratedBoundingBox(renderer, repaintBoundingBoxDecoration | DecorationOption::IncludeOutline);
+ if (repaintBoundingBox.isEmpty())
+ return LayoutRect();
+
+ auto visualOverflowRect = enclosingLayoutRect(repaintBoundingBox);
+ visualOverflowRect.moveBy(-flooredLayoutPoint(renderer.objectBoundingBox().minXMinYCorner()));
+ return visualOverflowRect;
+ }
+
+private:
+ FloatRect handleShapeOrTextOrInline(const DecorationOptions&, bool* boundingBoxValid = nullptr) const;
+ FloatRect handleRootOrContainer(const DecorationOptions&, bool* boundingBoxValid = nullptr) const;
+ FloatRect handleForeignObjectOrImage(const DecorationOptions&, bool* boundingBoxValid = nullptr) const;
+
+ void adjustBoxForClippingAndEffects(const DecorationOptions&, FloatRect& box, const DecorationOptions& optionsToCheckForFilters = filterBoundingBoxDecoration) const;
+
+ const RenderLayerModelObject& m_renderer;
+};
+
+} // namespace WebCore
+
+#endif