Title: [268552] trunk/Source/WebCore
Revision
268552
Author
wenson_hs...@apple.com
Date
2020-10-15 13:56:03 -0700 (Thu, 15 Oct 2020)

Log Message

Add a fast codepath to compute the bounding rect of an inline arc path
https://bugs.webkit.org/show_bug.cgi?id=217764

Reviewed by Tim Horton.

This is a followup to r268320, which added an implementation of `Path::fastBoundingRect` for the inline
`ArcData` case, but left `Path::boundingRect` as-is. This means that currently, a call to `Path::boundingRect`
in the case of a simple arc path (represented in `ArcData`) will cause a `CGPath` to be allocated and set up,
when we could instead just compute the exact bounds of the path using the center, radius, and start and end
angles.

* platform/graphics/Path.cpp:
(WebCore::computeArcBounds):

Add a helper function to compute the exact bounds of a circular arc. This helper works by first fitting the rect
to the start and end positions, and then extending to the top, left, bottom, or right edges as needed (i.e. if
the start and end angles intersect the top-, left-, bottom- or right-most points in the circle).

(WebCore::Path::boundingRectFromInlineData const):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (268551 => 268552)


--- trunk/Source/WebCore/ChangeLog	2020-10-15 20:40:34 UTC (rev 268551)
+++ trunk/Source/WebCore/ChangeLog	2020-10-15 20:56:03 UTC (rev 268552)
@@ -1,3 +1,25 @@
+2020-10-15  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        Add a fast codepath to compute the bounding rect of an inline arc path
+        https://bugs.webkit.org/show_bug.cgi?id=217764
+
+        Reviewed by Tim Horton.
+
+        This is a followup to r268320, which added an implementation of `Path::fastBoundingRect` for the inline
+        `ArcData` case, but left `Path::boundingRect` as-is. This means that currently, a call to `Path::boundingRect`
+        in the case of a simple arc path (represented in `ArcData`) will cause a `CGPath` to be allocated and set up,
+        when we could instead just compute the exact bounds of the path using the center, radius, and start and end
+        angles.
+
+        * platform/graphics/Path.cpp:
+        (WebCore::computeArcBounds):
+
+        Add a helper function to compute the exact bounds of a circular arc. This helper works by first fitting the rect
+        to the start and end positions, and then extending to the top, left, bottom, or right edges as needed (i.e. if
+        the start and end angles intersect the top-, left-, bottom- or right-most points in the circle).
+
+        (WebCore::Path::boundingRectFromInlineData const):
+
 2020-10-15  Sam Weinig  <wei...@apple.com>
 
         [WebIDL] Bindings do not support two attributes or functions with the same name only differing by case of first character

Modified: trunk/Source/WebCore/platform/graphics/Path.cpp (268551 => 268552)


--- trunk/Source/WebCore/platform/graphics/Path.cpp	2020-10-15 20:40:34 UTC (rev 268551)
+++ trunk/Source/WebCore/platform/graphics/Path.cpp	2020-10-15 20:56:03 UTC (rev 268552)
@@ -431,9 +431,63 @@
     return boundingRectFromInlineData();
 }
 
+static FloatRect computeArcBounds(const FloatPoint& center, float radius, float start, float end, bool clockwise)
+{
+    if (clockwise)
+        std::swap(start, end);
+
+    constexpr float fullCircle = 2 * piFloat;
+    if (end - start >= fullCircle) {
+        auto diameter = radius * 2;
+        return { center.x() - radius, center.y() - radius, diameter, diameter };
+    }
+
+    auto normalize = [&] (float radians) {
+        double circles = radians / fullCircle;
+        return fullCircle * (circles - floor(circles));
+    };
+
+    start = normalize(start);
+    end = normalize(end);
+
+    auto lengthInRadians = end - start;
+    if (start > end)
+        lengthInRadians += fullCircle;
+
+    FloatPoint startPoint { center.x() + radius * cos(start), center.y() + radius * sin(start) };
+    FloatPoint endPoint { center.x() + radius * cos(end), center.y() + radius * sin(end) };
+    FloatRect result;
+    result.fitToPoints(startPoint, endPoint);
+
+    auto contains = [&] (float angleToCheck) {
+        return (start < angleToCheck && start + lengthInRadians > angleToCheck)
+            || (start > angleToCheck && start + lengthInRadians > angleToCheck + fullCircle);
+    };
+
+    if (contains(0))
+        result.shiftMaxXEdgeTo(center.x() + radius);
+
+    if (contains(piOverTwoFloat))
+        result.shiftMaxYEdgeTo(center.y() + radius);
+
+    if (contains(piFloat))
+        result.shiftXEdgeTo(center.x() - radius);
+
+    if (contains(3 * piOverTwoFloat))
+        result.shiftYEdgeTo(center.y() - radius);
+
+    return result;
+}
+
 Optional<FloatRect> Path::boundingRectFromInlineData() const
 {
-    // FIXME: Add logic to compute the exact bounding rect for an arc in inline data.
+    if (hasInlineData<ArcData>()) {
+        auto& arc = inlineData<ArcData>();
+        auto bounds = computeArcBounds(arc.center, arc.radius, arc.startAngle, arc.endAngle, arc.clockwise);
+        if (arc.type == ArcData::Type::LineAndArc || arc.type == ArcData::Type::ClosedLineAndArc)
+            bounds.extend(arc.start);
+        return bounds;
+    }
 
     if (hasInlineData<MoveData>())
         return FloatRect { };
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to