Title: [276275] trunk
Revision
276275
Author
[email protected]
Date
2021-04-19 15:20:53 -0700 (Mon, 19 Apr 2021)

Log Message

Rename FloatQuad::isEmpty() to boundingBoxIsEmpty() and reimplement isEmpty()
https://bugs.webkit.org/show_bug.cgi?id=224769

Reviewed by Tim Horton.

Source/WebCore:

The existing `isEmpty()` method on `FloatQuad` only checks that the bounding box of the quad is empty (as
indicated by the comment above the method declaration). This means `isEmpty()` returns `false` in cases where
the quad consists of one or more non-rectilinear line segments, even though the quad contains no area.

To address this, we rename the existing `isEmpty()` helper to `boundingBoxIsEmpty()` and reintroduce an
`isEmpty()` method that accounts for quads which are equivalent to non-rectilinear line segments.

No change in behavior.

* inspector/InspectorOverlay.cpp:
(WebCore::drawFragmentHighlight):
* platform/graphics/FloatQuad.cpp:
* platform/graphics/FloatQuad.h:
(WebCore::FloatQuad::isEmpty const): Deleted.
(WebCore::FloatQuad::boundingBoxIsEmpty const):

Tools:

Add an API test to exercise the new `FloatQuad::isEmpty()` method.

* TestWebKitAPI/Tests/WebCore/FloatQuadTests.cpp:
(TestWebKitAPI::checkIsEmpty):
(TestWebKitAPI::TEST):

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (276274 => 276275)


--- trunk/Source/WebCore/ChangeLog	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Source/WebCore/ChangeLog	2021-04-19 22:20:53 UTC (rev 276275)
@@ -1,3 +1,26 @@
+2021-04-19  Wenson Hsieh  <[email protected]>
+
+        Rename FloatQuad::isEmpty() to boundingBoxIsEmpty() and reimplement isEmpty()
+        https://bugs.webkit.org/show_bug.cgi?id=224769
+
+        Reviewed by Tim Horton.
+
+        The existing `isEmpty()` method on `FloatQuad` only checks that the bounding box of the quad is empty (as
+        indicated by the comment above the method declaration). This means `isEmpty()` returns `false` in cases where
+        the quad consists of one or more non-rectilinear line segments, even though the quad contains no area.
+
+        To address this, we rename the existing `isEmpty()` helper to `boundingBoxIsEmpty()` and reintroduce an
+        `isEmpty()` method that accounts for quads which are equivalent to non-rectilinear line segments.
+
+        No change in behavior.
+
+        * inspector/InspectorOverlay.cpp:
+        (WebCore::drawFragmentHighlight):
+        * platform/graphics/FloatQuad.cpp:
+        * platform/graphics/FloatQuad.h:
+        (WebCore::FloatQuad::isEmpty const): Deleted.
+        (WebCore::FloatQuad::boundingBoxIsEmpty const):
+
 2021-04-19  Patrick Angle  <[email protected]>
 
         Web Inspector: Grid overlay column line label placement copy/paste error

Modified: trunk/Source/WebCore/inspector/InspectorOverlay.cpp (276274 => 276275)


--- trunk/Source/WebCore/inspector/InspectorOverlay.cpp	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Source/WebCore/inspector/InspectorOverlay.cpp	2021-04-19 22:20:53 UTC (rev 276275)
@@ -286,16 +286,16 @@
     if (size >= 4)
         contentQuad = highlight.quads[3];
 
-    if (!marginQuad.isEmpty() && marginQuad != borderQuad && highlight.marginColor.isVisible())
+    if (!marginQuad.boundingBoxIsEmpty() && marginQuad != borderQuad && highlight.marginColor.isVisible())
         drawOutlinedQuadWithClip(context, marginQuad, borderQuad, highlight.marginColor, bounds);
 
-    if (!borderQuad.isEmpty() && borderQuad != paddingQuad && highlight.borderColor.isVisible())
+    if (!borderQuad.boundingBoxIsEmpty() && borderQuad != paddingQuad && highlight.borderColor.isVisible())
         drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, highlight.borderColor, bounds);
 
-    if (!paddingQuad.isEmpty() && paddingQuad != contentQuad && highlight.paddingColor.isVisible())
+    if (!paddingQuad.boundingBoxIsEmpty() && paddingQuad != contentQuad && highlight.paddingColor.isVisible())
         drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, highlight.paddingColor, bounds);
 
-    if (!contentQuad.isEmpty() && (highlight.contentColor.isVisible() || highlight.contentOutlineColor.isVisible()))
+    if (!contentQuad.boundingBoxIsEmpty() && (highlight.contentColor.isVisible() || highlight.contentOutlineColor.isVisible()))
         drawOutlinedQuad(context, contentQuad, highlight.contentColor, highlight.contentOutlineColor, bounds);
 }
 

Modified: trunk/Source/WebCore/platform/graphics/FloatQuad.cpp (276274 => 276275)


--- trunk/Source/WebCore/platform/graphics/FloatQuad.cpp	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Source/WebCore/platform/graphics/FloatQuad.cpp	2021-04-19 22:20:53 UTC (rev 276275)
@@ -228,6 +228,49 @@
     return determinant(m_p2 - m_p1, m_p3 - m_p2) < 0;
 }
 
+bool FloatQuad::isEmpty() const
+{
+    if (areEssentiallyEqual(m_p1, m_p3) || areEssentiallyEqual(m_p2, m_p4)) {
+        // If either diagonal is zero length, then the "quad" either consists of 1 or 2 line segments, or it's just a point.
+        return true;
+    }
+
+    if (areEssentiallyEqual(m_p1, m_p2) && areEssentiallyEqual(m_p3, m_p4)) {
+        // If both top points and both bottom points are equal, then the "quad" is just a single line segment.
+        return true;
+    }
+
+    if (areEssentiallyEqual(m_p1, m_p4) && areEssentiallyEqual(m_p2, m_p3)) {
+        // If both left points and both right points are equal, then the "quad" is just a single line segment.
+        return true;
+    }
+
+    // Fall back to checking whether the 4 points of the quad are colinear (in other words, check whether the three
+    // vectors from one point to each of the other points are capable of forming a 2D basis).
+    auto b1 = m_p1 - m_p2;
+    auto b2 = m_p1 - m_p3;
+    auto b3 = m_p1 - m_p4;
+
+    if (!b1.isZero())
+        b1 = b1 / b1.diagonalLength();
+
+    if (!b2.isZero())
+        b2 = b2 / b2.diagonalLength();
+
+    if (!b3.isZero())
+        b3 = b3 / b3.diagonalLength();
+
+    auto areNormalizedVectorsLinearlyIndependent = [](const FloatSize& u, const FloatSize& v) {
+        if (u.isZero() || v.isZero())
+            return false;
+
+        auto dotProduct = u.width() * v.width() + u.height() * v.height();
+        return !WTF::areEssentiallyEqual<float>(dotProduct, 1) && !WTF::areEssentiallyEqual<float>(dotProduct, -1);
+    };
+
+    return !areNormalizedVectorsLinearlyIndependent(b1, b2) && !areNormalizedVectorsLinearlyIndependent(b2, b3) && !areNormalizedVectorsLinearlyIndependent(b1, b3);
+}
+
 Vector<FloatRect> boundingBoxes(const Vector<FloatQuad>& quads)
 {
     Vector<FloatRect> boxes;

Modified: trunk/Source/WebCore/platform/graphics/FloatQuad.h (276274 => 276275)


--- trunk/Source/WebCore/platform/graphics/FloatQuad.h	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Source/WebCore/platform/graphics/FloatQuad.h	2021-04-19 22:20:53 UTC (rev 276275)
@@ -76,10 +76,11 @@
     void setP3(const FloatPoint& p) { m_p3 = p; }
     void setP4(const FloatPoint& p) { m_p4 = p; }
 
-    // isEmpty tests that the bounding box is empty. This will not identify
-    // "slanted" empty quads.
-    bool isEmpty() const { return boundingBox().isEmpty(); }
+    WEBCORE_EXPORT bool isEmpty() const;
 
+    // This method will not identify "slanted" empty quads.
+    bool boundingBoxIsEmpty() const { return boundingBox().isEmpty(); }
+
     // Tests whether this quad can be losslessly represented by a FloatRect,
     // that is, if two edges are parallel to the x-axis and the other two
     // are parallel to the y-axis. If this method returns true, the
@@ -214,7 +215,7 @@
     return !(a == b);
 }
 
-WTF::TextStream& operator<<(WTF::TextStream&, const FloatQuad&);
+WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, const FloatQuad&);
 
 Vector<FloatRect> boundingBoxes(const Vector<FloatQuad>&);
 WEBCORE_EXPORT FloatRect unitedBoundingBoxes(const Vector<FloatQuad>&);

Modified: trunk/Tools/ChangeLog (276274 => 276275)


--- trunk/Tools/ChangeLog	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Tools/ChangeLog	2021-04-19 22:20:53 UTC (rev 276275)
@@ -1,3 +1,16 @@
+2021-04-19  Wenson Hsieh  <[email protected]>
+
+        Rename FloatQuad::isEmpty() to boundingBoxIsEmpty() and reimplement isEmpty()
+        https://bugs.webkit.org/show_bug.cgi?id=224769
+
+        Reviewed by Tim Horton.
+
+        Add an API test to exercise the new `FloatQuad::isEmpty()` method.
+
+        * TestWebKitAPI/Tests/WebCore/FloatQuadTests.cpp:
+        (TestWebKitAPI::checkIsEmpty):
+        (TestWebKitAPI::TEST):
+
 2021-04-19  Tim Horton  <[email protected]>
 
         Fix the macCatalyst TestWebKitAPI build

Modified: trunk/Tools/TestWebKitAPI/Tests/WebCore/FloatQuadTests.cpp (276274 => 276275)


--- trunk/Tools/TestWebKitAPI/Tests/WebCore/FloatQuadTests.cpp	2021-04-19 21:18:00 UTC (rev 276274)
+++ trunk/Tools/TestWebKitAPI/Tests/WebCore/FloatQuadTests.cpp	2021-04-19 22:20:53 UTC (rev 276275)
@@ -27,6 +27,7 @@
 
 #include <WebCore/FloatQuad.h>
 #include <WebCore/GeometryUtilities.h>
+#include <wtf/text/TextStream.h>
 
 namespace TestWebKitAPI {
 using namespace WebCore;
@@ -109,4 +110,60 @@
     }, 0.01));
 }
 
+static void checkIsEmpty(bool expectation, FloatQuad&& quad)
+{
+    EXPECT_TRUE(expectation == quad.isEmpty());
+    if (expectation == quad.isEmpty())
+        return;
+
+    TextStream stream;
+    stream << quad;
+    WTFLogAlways("Expected quad: %s to be %s", stream.release().utf8().data(), expectation ? "empty" : "non-empty");
+}
+
+TEST(FloatQuad, IsEmpty)
+{
+    checkIsEmpty(true, { // Line segment.
+        FloatPoint(0, 0),
+        FloatPoint(0, 0),
+        FloatPoint(0, 3),
+        FloatPoint(0, 3),
+    });
+
+    checkIsEmpty(false, { // Triangle.
+        FloatPoint(0, 1),
+        FloatPoint(0, 0),
+        FloatPoint(3, 3),
+        FloatPoint(3, 3),
+    });
+
+    checkIsEmpty(false, { // Another triangle.
+        FloatPoint(0, 0),
+        FloatPoint(0, 0),
+        FloatPoint(3, 3),
+        FloatPoint(0, 3),
+    });
+
+    checkIsEmpty(true, { // Single point.
+        FloatPoint(100, 100),
+        FloatPoint(100, 100),
+        FloatPoint(100, 100),
+        FloatPoint(100, 100),
+    });
+
+    checkIsEmpty(true, { // Two line segments.
+        FloatPoint(0, 0),
+        FloatPoint(100, 100),
+        FloatPoint(0, 0),
+        FloatPoint(50, -100),
+    });
+
+    checkIsEmpty(true, { // 4 distinct but colinear points.
+        FloatPoint(-1, -1),
+        FloatPoint(0, 0),
+        FloatPoint(1, 1),
+        FloatPoint(3, 3),
+    });
+}
+
 } // namespace TestWebKitAPI
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to