Title: [276388] trunk
Revision
276388
Author
[email protected]
Date
2021-04-21 13:11:31 -0700 (Wed, 21 Apr 2021)

Log Message

[iOS] Text selection in image overlays should not be limited to rectilinear quads
https://bugs.webkit.org/show_bug.cgi?id=224837
<rdar://76829981>

Reviewed by Tim Horton.

Source/WebCore:

Refactor the iOS-specific `WebCore::SelectionGeometry` such that it is backed by a `FloatQuad` instead of an
`IntRect`, and additionally support a flag to indicate that the selection geometry should render as individual
quads, instead of allowing adjacent rects to be coalesced based on each rects' enclosing bounds.

See comments below for more information.

Test: fast/images/image-extraction/ios/selection-rects-in-image-overlay.html

* html/HTMLElement.cpp:
(WebCore::HTMLElement::selectionRenderingBehavior):
* html/HTMLElement.h:
* platform/ios/SelectionGeometry.cpp:
(WebCore::SelectionGeometry::SelectionGeometry):

Change these constructors to take `FloatQuad` instead of an enclosing bounding box of a quad. Refer to call
sites below.

(WebCore::SelectionGeometry::setLogicalLeft):
(WebCore::SelectionGeometry::setLogicalWidth):
(WebCore::SelectionGeometry::setLogicalTop):
(WebCore::SelectionGeometry::setLogicalHeight):

Adjust these four setters so that they automatically inflate the selection quad to the quad's enclosing bounds
before changing any of the dimensions of the rect. Note that in practice, these methods are only used by code
that attempts to coalesce adjacent selection geometries, in which case we shouldn't be rendering non-rectilinear
quads anyways.

(WebCore::SelectionGeometry::rect const):

This method now computes the enclosing bounding rect of the selection quad. Since this can be called many times
for a single selection geometry, we cache the enclosing bounds in `m_cachedEnclosingRect` to avoid repeated
bounding box computation.

(WebCore::SelectionGeometry::setQuad):

Set the selection quad, and invalidate the enclosing bounding rect.

(WebCore::SelectionGeometry::setRect):

Since we're already setting the quad from an `IntRect`, we can go ahead and set the cached enclosing rect at the
same time to avoid computing it again in the future.

(WebCore::operator<<):
* platform/ios/SelectionGeometry.h:

Add a few new members to `SelectionGeometry`. Instead of maintaining an `IntRect`, store a `FloatRect` in
`m_quad`. Additionally, add a new enum describing how the `SelectionGeometry` should behave. This enum only has
two values: `CoalesceBoundingRects`, indicating that adjacent selection geometries should be coalesced based on
the enclosing bounding rects of their quads, and `UseIndividualQuads`, indicating that each quad should be
rendered individually.

(WebCore::SelectionGeometry::quad const):
(WebCore::SelectionGeometry::logicalLeft const):
(WebCore::SelectionGeometry::logicalWidth const):
(WebCore::SelectionGeometry::logicalTop const):
(WebCore::SelectionGeometry::logicalHeight const):
(WebCore::SelectionGeometry::behavior const):
(WebCore::SelectionGeometry::setBehavior):
(WebCore::SelectionGeometry::rect const): Deleted.
(WebCore::SelectionGeometry::setRect): Deleted.
* rendering/RenderImage.cpp:
(WebCore::RenderImage::collectSelectionGeometries):
* rendering/RenderLineBreak.cpp:
(WebCore::RenderLineBreak::collectSelectionGeometries):
* rendering/RenderObject.cpp:
(WebCore::RenderObject::collectSelectionGeometries):
(WebCore::adjustLineHeightOfSelectionGeometries):

When collecting selection geometry from renderers, avoid coalescing selection geometry when the
`SelectionGeometry` has `SelectionRenderingBehavior::UseIndividualQuads`.

(WebCore::coalesceSelectionGeometries):
(WebCore::RenderObject::collectSelectionGeometriesInternal):
* rendering/RenderText.cpp:
(WebCore::RenderText::collectSelectionGeometries):

Source/WebKit:

See WebCore ChangeLog for more details.

* Shared/WebCoreArgumentCoders.cpp:
(IPC::ArgumentCoder<SelectionGeometry>::encode):
(IPC::ArgumentCoder<SelectionGeometry>::decode):

Encode the `SelectionGeometry` by serializing a `FloatQuad` instead of an enclosing rect.

* UIProcess/ios/WKContentViewInteraction.mm:
(WebKit::operator==):
(-[WKContentView selectedTextRange]):
(-[WKContentView markedTextRange]):
* UIProcess/ios/WKTextSelectionRect.h:
* UIProcess/ios/WKTextSelectionRect.mm:
(-[WKTextSelectionRectCustomHandleInfo initWithFloatQuad:]):
(-[WKTextSelectionRectCustomHandleInfo bottomLeft]):
(-[WKTextSelectionRectCustomHandleInfo topLeft]):
(-[WKTextSelectionRectCustomHandleInfo bottomRight]):
(-[WKTextSelectionRectCustomHandleInfo topRight]):
(-[WKTextSelectionRect initWithCGRect:]):
(-[WKTextSelectionRect initWithSelectionGeometry:scaleFactor:]):
(-[WKTextSelectionRect _path]):
(-[WKTextSelectionRect _customHandleInfo]):

Implement SPI methods on `UITextSelectionRect` to render text selection UI using quads instead of rects.

(-[WKTextSelectionRect initWithSelectionGeometry:]): Deleted.
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::convertContentToRootView):

LayoutTests:

Add a new layout test to exercise the new selection rendering behavior.

* fast/images/image-extraction/ios/selection-rects-in-image-overlay-expected.txt: Added.
* fast/images/image-extraction/ios/selection-rects-in-image-overlay.html: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (276387 => 276388)


--- trunk/LayoutTests/ChangeLog	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/LayoutTests/ChangeLog	2021-04-21 20:11:31 UTC (rev 276388)
@@ -1,3 +1,16 @@
+2021-04-21  Wenson Hsieh  <[email protected]>
+
+        [iOS] Text selection in image overlays should not be limited to rectilinear quads
+        https://bugs.webkit.org/show_bug.cgi?id=224837
+        <rdar://76829981>
+
+        Reviewed by Tim Horton.
+
+        Add a new layout test to exercise the new selection rendering behavior.
+
+        * fast/images/image-extraction/ios/selection-rects-in-image-overlay-expected.txt: Added.
+        * fast/images/image-extraction/ios/selection-rects-in-image-overlay.html: Added.
+
 2021-04-21  Tyler Wilcock  <[email protected]>
 
         [css-counter-styles] Parse @counter-style descriptors

Added: trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay-expected.txt (0 => 276388)


--- trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay-expected.txt	2021-04-21 20:11:31 UTC (rev 276388)
@@ -0,0 +1,6 @@
+PASS initialSelectionRects.length is 1
+PASS selectionRectsAfterSelectingAll.length is 4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+

Added: trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay.html (0 => 276388)


--- trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/image-extraction/ios/selection-rects-in-image-overlay.html	2021-04-21 20:11:31 UTC (rev 276388)
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<style>
+img {
+    position: absolute;
+    top: 0;
+    left: 0;
+}
+</style>
+</head>
+<body>
+<img src=""
+<script>
+jsTestIsAsync = true;
+
+addEventListener("load", async () => {
+    let image = document.querySelector("img");
+    internals.installImageOverlay(image, [
+        {
+            text: "one",
+            topLeft: new DOMPointReadOnly(0.1, 0.25),
+            topRight: new DOMPointReadOnly(0.25, 0.1),
+            bottomRight: new DOMPointReadOnly(0.35, 0.2),
+            bottomLeft: new DOMPointReadOnly(0.2, 0.35)
+        },
+        {
+            text: "two",
+            topLeft: new DOMPointReadOnly(0.3, 0.45),
+            topRight: new DOMPointReadOnly(0.45, 0.3),
+            bottomRight: new DOMPointReadOnly(0.55, 0.4),
+            bottomLeft: new DOMPointReadOnly(0.4, 0.55)
+        },
+        {
+            text: "three",
+            topLeft: new DOMPointReadOnly(0.5, 0.65),
+            topRight: new DOMPointReadOnly(0.65, 0.5),
+            bottomRight: new DOMPointReadOnly(0.75, 0.6),
+            bottomLeft: new DOMPointReadOnly(0.6, 0.75)
+        },
+        {
+            text: "four",
+            topLeft: new DOMPointReadOnly(0.7, 0.85),
+            topRight: new DOMPointReadOnly(0.85, 0.7),
+            bottomRight: new DOMPointReadOnly(0.95, 0.8),
+            bottomLeft: new DOMPointReadOnly(0.8, 0.95)
+        }
+    ]);
+
+    await UIHelper.longPressAtPoint(90, 90);
+    initialSelectionRects = await UIHelper.waitForSelectionToAppear();
+    shouldBe("initialSelectionRects.length", "1");
+
+    testRunner.execCommand("SelectAll");
+    await UIHelper.ensurePresentationUpdate();
+    selectionRectsAfterSelectingAll = await UIHelper.getUISelectionViewRects();
+    shouldBe("selectionRectsAfterSelectingAll.length", "4");
+
+    finishJSTest();
+});
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (276387 => 276388)


--- trunk/Source/WebCore/ChangeLog	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/ChangeLog	2021-04-21 20:11:31 UTC (rev 276388)
@@ -1,3 +1,87 @@
+2021-04-21  Wenson Hsieh  <[email protected]>
+
+        [iOS] Text selection in image overlays should not be limited to rectilinear quads
+        https://bugs.webkit.org/show_bug.cgi?id=224837
+        <rdar://76829981>
+
+        Reviewed by Tim Horton.
+
+        Refactor the iOS-specific `WebCore::SelectionGeometry` such that it is backed by a `FloatQuad` instead of an
+        `IntRect`, and additionally support a flag to indicate that the selection geometry should render as individual
+        quads, instead of allowing adjacent rects to be coalesced based on each rects' enclosing bounds.
+
+        See comments below for more information.
+
+        Test: fast/images/image-extraction/ios/selection-rects-in-image-overlay.html
+
+        * html/HTMLElement.cpp:
+        (WebCore::HTMLElement::selectionRenderingBehavior):
+        * html/HTMLElement.h:
+        * platform/ios/SelectionGeometry.cpp:
+        (WebCore::SelectionGeometry::SelectionGeometry):
+
+        Change these constructors to take `FloatQuad` instead of an enclosing bounding box of a quad. Refer to call
+        sites below.
+
+        (WebCore::SelectionGeometry::setLogicalLeft):
+        (WebCore::SelectionGeometry::setLogicalWidth):
+        (WebCore::SelectionGeometry::setLogicalTop):
+        (WebCore::SelectionGeometry::setLogicalHeight):
+
+        Adjust these four setters so that they automatically inflate the selection quad to the quad's enclosing bounds
+        before changing any of the dimensions of the rect. Note that in practice, these methods are only used by code
+        that attempts to coalesce adjacent selection geometries, in which case we shouldn't be rendering non-rectilinear
+        quads anyways.
+
+        (WebCore::SelectionGeometry::rect const):
+
+        This method now computes the enclosing bounding rect of the selection quad. Since this can be called many times
+        for a single selection geometry, we cache the enclosing bounds in `m_cachedEnclosingRect` to avoid repeated
+        bounding box computation.
+
+        (WebCore::SelectionGeometry::setQuad):
+
+        Set the selection quad, and invalidate the enclosing bounding rect.
+
+        (WebCore::SelectionGeometry::setRect):
+
+        Since we're already setting the quad from an `IntRect`, we can go ahead and set the cached enclosing rect at the
+        same time to avoid computing it again in the future.
+
+        (WebCore::operator<<):
+        * platform/ios/SelectionGeometry.h:
+
+        Add a few new members to `SelectionGeometry`. Instead of maintaining an `IntRect`, store a `FloatRect` in
+        `m_quad`. Additionally, add a new enum describing how the `SelectionGeometry` should behave. This enum only has
+        two values: `CoalesceBoundingRects`, indicating that adjacent selection geometries should be coalesced based on
+        the enclosing bounding rects of their quads, and `UseIndividualQuads`, indicating that each quad should be
+        rendered individually.
+
+        (WebCore::SelectionGeometry::quad const):
+        (WebCore::SelectionGeometry::logicalLeft const):
+        (WebCore::SelectionGeometry::logicalWidth const):
+        (WebCore::SelectionGeometry::logicalTop const):
+        (WebCore::SelectionGeometry::logicalHeight const):
+        (WebCore::SelectionGeometry::behavior const):
+        (WebCore::SelectionGeometry::setBehavior):
+        (WebCore::SelectionGeometry::rect const): Deleted.
+        (WebCore::SelectionGeometry::setRect): Deleted.
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::collectSelectionGeometries):
+        * rendering/RenderLineBreak.cpp:
+        (WebCore::RenderLineBreak::collectSelectionGeometries):
+        * rendering/RenderObject.cpp:
+        (WebCore::RenderObject::collectSelectionGeometries):
+        (WebCore::adjustLineHeightOfSelectionGeometries):
+
+        When collecting selection geometry from renderers, avoid coalescing selection geometry when the
+        `SelectionGeometry` has `SelectionRenderingBehavior::UseIndividualQuads`.
+
+        (WebCore::coalesceSelectionGeometries):
+        (WebCore::RenderObject::collectSelectionGeometriesInternal):
+        * rendering/RenderText.cpp:
+        (WebCore::RenderText::collectSelectionGeometries):
+
 2021-04-21  Tyler Wilcock  <[email protected]>
 
         CSSComputedStyleDeclaration.cpp should use C++ style comments

Modified: trunk/Source/WebCore/html/HTMLElement.cpp (276387 => 276388)


--- trunk/Source/WebCore/html/HTMLElement.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/html/HTMLElement.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -82,6 +82,10 @@
 #include "ImageExtractionResult.h"
 #endif
 
+#if PLATFORM(IOS_FAMILY)
+#include "SelectionGeometry.h"
+#endif
+
 namespace WebCore {
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLElement);
@@ -1372,6 +1376,15 @@
 
 #endif // ENABLE(IMAGE_EXTRACTION)
 
+#if PLATFORM(IOS_FAMILY)
+
+SelectionRenderingBehavior HTMLElement::selectionRenderingBehavior(const Node* node)
+{
+    return isImageOverlayText(node) ? SelectionRenderingBehavior::UseIndividualQuads : SelectionRenderingBehavior::CoalesceBoundingRects;
+}
+
+#endif // PLATFORM(IOS_FAMILY)
+
 } // namespace WebCore
 
 #ifndef NDEBUG

Modified: trunk/Source/WebCore/html/HTMLElement.h (276387 => 276388)


--- trunk/Source/WebCore/html/HTMLElement.h	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/html/HTMLElement.h	2021-04-21 20:11:31 UTC (rev 276388)
@@ -43,6 +43,10 @@
 
 enum class EnterKeyHint : uint8_t;
 
+#if PLATFORM(IOS_FAMILY)
+enum class SelectionRenderingBehavior : uint8_t;
+#endif
+
 class HTMLElement : public StyledElement {
     WTF_MAKE_ISO_ALLOCATED(HTMLElement);
 public:
@@ -140,6 +144,10 @@
     WEBCORE_EXPORT void updateWithImageExtractionResult(ImageExtractionResult&&);
 #endif
 
+#if PLATFORM(IOS_FAMILY)
+    static SelectionRenderingBehavior selectionRenderingBehavior(const Node*);
+#endif
+
 protected:
     HTMLElement(const QualifiedName& tagName, Document&, ConstructionType);
 

Modified: trunk/Source/WebCore/platform/ios/SelectionGeometry.cpp (276387 => 276388)


--- trunk/Source/WebCore/platform/ios/SelectionGeometry.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/platform/ios/SelectionGeometry.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -26,13 +26,14 @@
 #include "config.h"
 #include "SelectionGeometry.h"
 
+#include "FloatQuad.h"
 #include <wtf/text/TextStream.h>
 
 namespace WebCore {
 
-SelectionGeometry::SelectionGeometry(const IntRect& rect, bool isHorizontal, int pageNumber)
-    : m_rect(rect)
-    , m_direction(TextDirection::LTR)
+SelectionGeometry::SelectionGeometry(const FloatQuad& quad, SelectionRenderingBehavior behavior, bool isHorizontal, int pageNumber)
+    : m_quad(quad)
+    , m_behavior(behavior)
     , m_isHorizontal(isHorizontal)
     , m_pageNumber(pageNumber)
 {
@@ -39,8 +40,9 @@
 }
 
 // FIXME: We should move some of these arguments to an auxillary struct.
-SelectionGeometry::SelectionGeometry(const IntRect& rect, TextDirection direction, int minX, int maxX, int maxY, int lineNumber, bool isLineBreak, bool isFirstOnLine, bool isLastOnLine, bool containsStart, bool containsEnd, bool isHorizontal, bool isInFixedPosition, bool isRubyText, int pageNumber)
-    : m_rect(rect)
+SelectionGeometry::SelectionGeometry(const FloatQuad& quad, SelectionRenderingBehavior behavior, TextDirection direction, int minX, int maxX, int maxY, int lineNumber, bool isLineBreak, bool isFirstOnLine, bool isLastOnLine, bool containsStart, bool containsEnd, bool isHorizontal, bool isInFixedPosition, bool isRubyText, int pageNumber)
+    : m_quad(quad)
+    , m_behavior(behavior)
     , m_direction(direction)
     , m_minX(minX)
     , m_maxX(maxX)
@@ -60,42 +62,69 @@
 
 void SelectionGeometry::setLogicalLeft(int left)
 {
+    auto rect = this->rect();
     if (m_isHorizontal)
-        m_rect.setX(left);
+        rect.setX(left);
     else
-        m_rect.setY(left);
+        rect.setY(left);
+    setRect(rect);
 }
 
 void SelectionGeometry::setLogicalWidth(int width)
 {
+    auto rect = this->rect();
     if (m_isHorizontal)
-        m_rect.setWidth(width);
+        rect.setWidth(width);
     else
-        m_rect.setHeight(width);
+        rect.setHeight(width);
+    setRect(rect);
 }
 
 void SelectionGeometry::setLogicalTop(int top)
 {
+    auto rect = this->rect();
     if (m_isHorizontal)
-        m_rect.setY(top);
+        rect.setY(top);
     else
-        m_rect.setX(top);
+        rect.setX(top);
+    setRect(rect);
 }
 
 void SelectionGeometry::setLogicalHeight(int height)
 {
+    auto rect = this->rect();
     if (m_isHorizontal)
-        m_rect.setHeight(height);
+        rect.setHeight(height);
     else
-        m_rect.setWidth(height);
+        rect.setWidth(height);
+    setRect(rect);
 }
 
+IntRect SelectionGeometry::rect() const
+{
+    if (!m_cachedEnclosingRect)
+        m_cachedEnclosingRect = m_quad.enclosingBoundingBox();
+    return *m_cachedEnclosingRect;
+}
+
+void SelectionGeometry::setQuad(const FloatQuad& quad)
+{
+    m_quad = quad;
+    m_cachedEnclosingRect.reset();
+}
+
+void SelectionGeometry::setRect(const IntRect& rect)
+{
+    m_quad = FloatQuad { rect };
+    m_cachedEnclosingRect = rect;
+}
+
 TextStream& operator<<(TextStream& stream, SelectionGeometry rect)
 {
     TextStream::GroupScope group(stream);
     stream << "selection geometry";
 
-    stream.dumpProperty("rect", rect.rect());
+    stream.dumpProperty("quad", rect.quad());
     stream.dumpProperty("direction", isLeftToRightDirection(rect.direction()) ? "ltr" : "rtl");
 
     stream.dumpProperty("min-x", rect.minX());
@@ -125,6 +154,9 @@
     if (rect.isRubyText())
         stream.dumpProperty("is ruby text", true);
 
+    if (rect.behavior() == SelectionRenderingBehavior::UseIndividualQuads)
+        stream.dumpProperty("using individual quads", true);
+
     stream.dumpProperty("page number", rect.pageNumber());
     return stream;
 }

Modified: trunk/Source/WebCore/platform/ios/SelectionGeometry.h (276387 => 276388)


--- trunk/Source/WebCore/platform/ios/SelectionGeometry.h	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/platform/ios/SelectionGeometry.h	2021-04-21 20:11:31 UTC (rev 276388)
@@ -25,29 +25,40 @@
 
 #pragma once
 
+#include "FloatQuad.h"
 #include "IntRect.h"
 #include "WritingMode.h"
 #include <wtf/FastMalloc.h>
+#include <wtf/Optional.h>
 
 namespace WebCore {
 
+enum class SelectionRenderingBehavior : uint8_t {
+    CoalesceBoundingRects,
+    UseIndividualQuads,
+};
+
 class SelectionGeometry {
     WTF_MAKE_FAST_ALLOCATED;
 public:
-    WEBCORE_EXPORT explicit SelectionGeometry(const IntRect&, bool isHorizontal, int columnNumber);
+    WEBCORE_EXPORT explicit SelectionGeometry(const FloatQuad&, SelectionRenderingBehavior, bool isHorizontal, int columnNumber);
 
     // FIXME: We should move some of these arguments to an auxillary struct.
-    SelectionGeometry(const IntRect&, TextDirection, int, int, int, int, bool, bool, bool, bool, bool, bool, bool, bool, int);
+    SelectionGeometry(const FloatQuad&, SelectionRenderingBehavior, TextDirection, int, int, int, int, bool, bool, bool, bool, bool, bool, bool, bool, int);
     SelectionGeometry() = default;
     ~SelectionGeometry() = default;
 
-    IntRect rect() const { return m_rect; }
+    FloatQuad quad() const { return m_quad; }
+    WEBCORE_EXPORT void setQuad(const FloatQuad&);
 
-    int logicalLeft() const { return m_isHorizontal ? m_rect.x() : m_rect.y(); }
-    int logicalWidth() const { return m_isHorizontal ? m_rect.width() : m_rect.height(); }
-    int logicalTop() const { return m_isHorizontal ? m_rect.y() : m_rect.x(); }
-    int logicalHeight() const { return m_isHorizontal ? m_rect.height() : m_rect.width(); }
+    WEBCORE_EXPORT IntRect rect() const;
+    WEBCORE_EXPORT void setRect(const IntRect&);
 
+    int logicalLeft() const { return m_isHorizontal ? rect().x() : rect().y(); }
+    int logicalWidth() const { return m_isHorizontal ? rect().width() : rect().height(); }
+    int logicalTop() const { return m_isHorizontal ? rect().y() : rect().x(); }
+    int logicalHeight() const { return m_isHorizontal ? rect().height() : rect().width(); }
+
     TextDirection direction() const { return m_direction; }
     int minX() const { return m_minX; }
     int maxX() const { return m_maxX; }
@@ -62,9 +73,8 @@
     bool isInFixedPosition() const { return m_isInFixedPosition; }
     bool isRubyText() const { return m_isRubyText; }
     int pageNumber() const { return m_pageNumber; }
+    SelectionRenderingBehavior behavior() const { return m_behavior; }
 
-    void setRect(const IntRect& rect) { m_rect = rect; }
-
     void setLogicalLeft(int);
     void setLogicalWidth(int);
     void setLogicalTop(int);
@@ -81,9 +91,11 @@
     void setContainsStart(bool containsStart) { m_containsStart = containsStart; }
     void setContainsEnd(bool containsEnd) { m_containsEnd = containsEnd; }
     void setIsHorizontal(bool isHorizontal) { m_isHorizontal = isHorizontal; }
+    void setBehavior(SelectionRenderingBehavior behavior) { m_behavior = behavior; }
 
 private:
-    IntRect m_rect;
+    FloatQuad m_quad;
+    SelectionRenderingBehavior m_behavior { SelectionRenderingBehavior::CoalesceBoundingRects };
     TextDirection m_direction { TextDirection::LTR };
     int m_minX { 0 };
     int m_maxX { 0 };
@@ -98,8 +110,22 @@
     bool m_isInFixedPosition { false };
     bool m_isRubyText { false };
     int m_pageNumber { 0 };
+
+    mutable Optional<IntRect> m_cachedEnclosingRect;
 };
 
 WEBCORE_EXPORT WTF::TextStream& operator<<(WTF::TextStream&, SelectionGeometry);
 
 } // namespace WebCore
+
+namespace WTF {
+
+template<> struct EnumTraits<WebCore::SelectionRenderingBehavior> {
+    using values = EnumValues<
+        WebCore::SelectionRenderingBehavior,
+        WebCore::SelectionRenderingBehavior::CoalesceBoundingRects,
+        WebCore::SelectionRenderingBehavior::UseIndividualQuads
+    >;
+};
+
+} // namespace WTF

Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (276387 => 276388)


--- trunk/Source/WebCore/rendering/RenderImage.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -123,14 +123,14 @@
     }
 
     bool isFixed = false;
-    IntRect absoluteBounds = localToAbsoluteQuad(FloatRect(imageRect), UseTransforms, &isFixed).enclosingBoundingBox();
-    IntRect lineExtentBounds = localToAbsoluteQuad(FloatRect(lineExtentRect)).enclosingBoundingBox();
+    auto absoluteQuad = localToAbsoluteQuad(FloatRect(imageRect), UseTransforms, &isFixed);
+    auto lineExtentBounds = localToAbsoluteQuad(FloatRect(lineExtentRect)).enclosingBoundingBox();
     if (!containingBlock->isHorizontalWritingMode())
         lineExtentBounds = lineExtentBounds.transposedRect();
 
     // FIXME: We should consider either making SelectionGeometry a struct or better organize its optional fields into
     // an auxiliary struct to simplify its initialization.
-    geometries.append(SelectionGeometry(absoluteBounds, containingBlock->style().direction(), lineExtentBounds.x(), lineExtentBounds.maxX(), lineExtentBounds.maxY(), 0, false /* line break */, isFirstOnLine, isLastOnLine, false /* contains start */, false /* contains end */, containingBlock->style().isHorizontalWritingMode(), isFixed, false /* ruby text */, view().pageNumberForBlockProgressionOffset(absoluteBounds.x())));
+    geometries.append(SelectionGeometry(absoluteQuad, SelectionRenderingBehavior::CoalesceBoundingRects, containingBlock->style().direction(), lineExtentBounds.x(), lineExtentBounds.maxX(), lineExtentBounds.maxY(), 0, false /* line break */, isFirstOnLine, isLastOnLine, false /* contains start */, false /* contains end */, containingBlock->style().isHorizontalWritingMode(), isFixed, false /* ruby text */, view().pageNumberForBlockProgressionOffset(absoluteQuad.enclosingBoundingBox().x())));
 }
 #endif
 

Modified: trunk/Source/WebCore/rendering/RenderLineBreak.cpp (276387 => 276388)


--- trunk/Source/WebCore/rendering/RenderLineBreak.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/rendering/RenderLineBreak.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -220,7 +220,7 @@
         isLastOnLine = !containingBlock->containingBlock()->inlineBoxWrapper()->nextOnLineExists();
 
     bool isFixed = false;
-    IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox();
+    auto absoluteQuad = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed);
     bool boxIsHorizontal = !is<SVGInlineTextBox>(run->legacyInlineBox()) ? run->isHorizontal() : !style().isVerticalWritingMode();
     // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
     // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
@@ -232,7 +232,7 @@
         }
     }
 
-    rects.append(SelectionGeometry(absRect, run->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, run->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x())));
+    rects.append(SelectionGeometry(absoluteQuad, HTMLElement::selectionRenderingBehavior(element()), run->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, run->isLineBreak(), isFirstOnLine, isLastOnLine, false, false, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absoluteQuad.enclosingBoundingBox().x())));
 }
 #endif
 

Modified: trunk/Source/WebCore/rendering/RenderObject.cpp (276387 => 276388)


--- trunk/Source/WebCore/rendering/RenderObject.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/rendering/RenderObject.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -737,9 +737,8 @@
             child->absoluteQuads(quads);
     }
 
-    unsigned numberOfQuads = quads.size();
-    for (unsigned i = 0; i < numberOfQuads; ++i)
-        geometries.append(SelectionGeometry(quads[i].enclosingBoundingBox(), isHorizontalWritingMode(), view().pageNumberForBlockProgressionOffset(quads[i].enclosingBoundingBox().x())));
+    for (auto& quad : quads)
+        geometries.append(SelectionGeometry(quad, HTMLElement::selectionRenderingBehavior(node()), isHorizontalWritingMode(), view().pageNumberForBlockProgressionOffset(quad.enclosingBoundingBox().x())));
 }
 #endif
 
@@ -2124,6 +2123,8 @@
         --i;
         if (geometries[i].lineNumber())
             break;
+        if (geometries[i].behavior() == SelectionRenderingBehavior::UseIndividualQuads)
+            continue;
         geometries[i].setLineNumber(lineNumber);
         geometries[i].setLogicalTop(lineTop);
         geometries[i].setLogicalHeight(lineHeight);
@@ -2132,7 +2133,7 @@
 
 static SelectionGeometry coalesceSelectionGeometries(const SelectionGeometry& original, const SelectionGeometry& previous)
 {
-    SelectionGeometry result(unionRect(previous.rect(), original.rect()), original.isHorizontal(), original.pageNumber());
+    SelectionGeometry result({ unionRect(previous.rect(), original.rect()) }, SelectionRenderingBehavior::CoalesceBoundingRects, original.isHorizontal(), original.pageNumber());
     result.setDirection(original.containsStart() || original.containsEnd() ? original.direction() : previous.direction());
     result.setContainsStart(previous.containsStart() || original.containsStart());
     result.setContainsEnd(previous.containsEnd() || original.containsEnd());
@@ -2272,6 +2273,8 @@
     for (size_t j = 1; j < numberOfGeometries; ++j) {
         if (geometries[j].lineNumber() != geometries[j - 1].lineNumber())
             continue;
+        if (geometries[j].behavior() == SelectionRenderingBehavior::UseIndividualQuads)
+            continue;
         auto& previousRect = geometries[j - 1];
         bool previousRectMayNotReachRightEdge = (previousRect.direction() == TextDirection::LTR && previousRect.containsEnd()) || (previousRect.direction() == TextDirection::RTL && previousRect.containsStart());
         if (previousRectMayNotReachRightEdge)
@@ -2288,6 +2291,8 @@
         auto& selectionGeometry = geometries[i];
         if (!selectionGeometry.isLineBreak() && selectionGeometry.lineNumber() >= maxLineNumber)
             continue;
+        if (selectionGeometry.behavior() == SelectionRenderingBehavior::UseIndividualQuads)
+            continue;
         if (selectionGeometry.direction() == TextDirection::RTL && selectionGeometry.isFirstOnLine()) {
             selectionGeometry.setLogicalWidth(selectionGeometry.logicalWidth() + selectionGeometry.logicalLeft() - selectionGeometry.minX());
             selectionGeometry.setLogicalLeft(selectionGeometry.minX());
@@ -2309,6 +2314,15 @@
     IntRect interiorUnionRect;
     for (size_t i = 0; i < numberOfGeometries; ++i) {
         auto& currentGeometry = result.geometries[i];
+        if (currentGeometry.behavior() == SelectionRenderingBehavior::UseIndividualQuads) {
+            // FIXME: We still probably want some way to coalesce quads, probably by projecting them onto rotated bounding rects
+            // and then checking whether the rotated bounding rects are overlapping and share the same rotation angle. Until then,
+            // we simply append all non-empty quads.
+            if (!currentGeometry.quad().isEmpty())
+                coalescedGeometries.append(currentGeometry);
+            continue;
+        }
+
         if (currentGeometry.lineNumber() == 1) {
             ASSERT(interiorUnionRect.isEmpty());
             if (!coalescedGeometries.isEmpty()) {
@@ -2333,13 +2347,13 @@
                 // For iBooks, the interior lines may cross multiple horizontal pages.
                 interiorUnionRect.unite(currentGeometry.rect());
             } else {
-                coalescedGeometries.append(SelectionGeometry(interiorUnionRect, currentGeometry.isHorizontal(), currentGeometry.pageNumber()));
+                coalescedGeometries.append(SelectionGeometry({ interiorUnionRect }, SelectionRenderingBehavior::CoalesceBoundingRects, currentGeometry.isHorizontal(), currentGeometry.pageNumber()));
                 interiorUnionRect = currentGeometry.rect();
             }
         } else {
             // Processing last line.
             if (!interiorUnionRect.isEmpty()) {
-                coalescedGeometries.append(SelectionGeometry(interiorUnionRect, currentGeometry.isHorizontal(), currentGeometry.pageNumber()));
+                coalescedGeometries.append(SelectionGeometry({ interiorUnionRect }, SelectionRenderingBehavior::CoalesceBoundingRects, currentGeometry.isHorizontal(), currentGeometry.pageNumber()));
                 interiorUnionRect = IntRect();
             }
 

Modified: trunk/Source/WebCore/rendering/RenderText.cpp (276387 => 276388)


--- trunk/Source/WebCore/rendering/RenderText.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebCore/rendering/RenderText.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -369,7 +369,7 @@
         bool containsEnd = run->start() <= end && run->end() >= end;
 
         bool isFixed = false;
-        IntRect absRect = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed).enclosingBoundingBox();
+        auto absoluteQuad = localToAbsoluteQuad(FloatRect(rect), UseTransforms, &isFixed);
         bool boxIsHorizontal = !is<SVGInlineTextBox>(run->legacyInlineBox()) ? run->isHorizontal() : !style().isVerticalWritingMode();
         // If the containing block is an inline element, we want to check the inlineBoxWrapper orientation
         // to determine the orientation of the block. In this case we also use the inlineBoxWrapper to
@@ -381,7 +381,7 @@
             }
         }
 
-        rects.append(SelectionGeometry(absRect, run->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, run->isLineBreak(), isFirstOnLine, isLastOnLine, containsStart, containsEnd, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absRect.x())));
+        rects.append(SelectionGeometry(absoluteQuad, HTMLElement::selectionRenderingBehavior(textNode()), run->direction(), extentsRect.x(), extentsRect.maxX(), extentsRect.maxY(), 0, run->isLineBreak(), isFirstOnLine, isLastOnLine, containsStart, containsEnd, boxIsHorizontal, isFixed, containingBlock->isRubyText(), view().pageNumberForBlockProgressionOffset(absoluteQuad.enclosingBoundingBox().x())));
     }
 }
 #endif

Modified: trunk/Source/WebKit/ChangeLog (276387 => 276388)


--- trunk/Source/WebKit/ChangeLog	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/ChangeLog	2021-04-21 20:11:31 UTC (rev 276388)
@@ -1,3 +1,41 @@
+2021-04-21  Wenson Hsieh  <[email protected]>
+
+        [iOS] Text selection in image overlays should not be limited to rectilinear quads
+        https://bugs.webkit.org/show_bug.cgi?id=224837
+        <rdar://76829981>
+
+        Reviewed by Tim Horton.
+
+        See WebCore ChangeLog for more details.
+
+        * Shared/WebCoreArgumentCoders.cpp:
+        (IPC::ArgumentCoder<SelectionGeometry>::encode):
+        (IPC::ArgumentCoder<SelectionGeometry>::decode):
+
+        Encode the `SelectionGeometry` by serializing a `FloatQuad` instead of an enclosing rect.
+
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (WebKit::operator==):
+        (-[WKContentView selectedTextRange]):
+        (-[WKContentView markedTextRange]):
+        * UIProcess/ios/WKTextSelectionRect.h:
+        * UIProcess/ios/WKTextSelectionRect.mm:
+        (-[WKTextSelectionRectCustomHandleInfo initWithFloatQuad:]):
+        (-[WKTextSelectionRectCustomHandleInfo bottomLeft]):
+        (-[WKTextSelectionRectCustomHandleInfo topLeft]):
+        (-[WKTextSelectionRectCustomHandleInfo bottomRight]):
+        (-[WKTextSelectionRectCustomHandleInfo topRight]):
+        (-[WKTextSelectionRect initWithCGRect:]):
+        (-[WKTextSelectionRect initWithSelectionGeometry:scaleFactor:]):
+        (-[WKTextSelectionRect _path]):
+        (-[WKTextSelectionRect _customHandleInfo]):
+
+        Implement SPI methods on `UITextSelectionRect` to render text selection UI using quads instead of rects.
+
+        (-[WKTextSelectionRect initWithSelectionGeometry:]): Deleted.
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::convertContentToRootView):
+
 2021-04-21  Adrian Perez de Castro  <[email protected]>
 
         Non-unified build fixes, mid April 2021 edition

Modified: trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp (276387 => 276388)


--- trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/Shared/WebCoreArgumentCoders.cpp	2021-04-21 20:11:31 UTC (rev 276388)
@@ -1304,7 +1304,8 @@
 
 void ArgumentCoder<SelectionGeometry>::encode(Encoder& encoder, const SelectionGeometry& selectionGeometry)
 {
-    encoder << selectionGeometry.rect();
+    encoder << selectionGeometry.quad();
+    encoder << selectionGeometry.behavior();
     encoder << static_cast<uint32_t>(selectionGeometry.direction());
     encoder << selectionGeometry.minX();
     encoder << selectionGeometry.maxX();
@@ -1321,11 +1322,17 @@
 Optional<SelectionGeometry> ArgumentCoder<SelectionGeometry>::decode(Decoder& decoder)
 {
     SelectionGeometry selectionGeometry;
-    IntRect rect;
-    if (!decoder.decode(rect))
+    FloatQuad quad;
+    if (!decoder.decode(quad))
         return WTF::nullopt;
-    selectionGeometry.setRect(rect);
+    selectionGeometry.setQuad(quad);
 
+    Optional<SelectionRenderingBehavior> behavior;
+    decoder >> behavior;
+    if (!behavior)
+        return WTF::nullopt;
+    selectionGeometry.setBehavior(*behavior);
+
     uint32_t direction;
     if (!decoder.decode(direction))
         return WTF::nullopt;

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (276387 => 276388)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-04-21 20:11:31 UTC (rev 276388)
@@ -243,8 +243,17 @@
             return false;
 
         for (unsigned i = 0; i < a.selectionGeometries.size(); ++i) {
-            if (a.selectionGeometries[i].rect() != b.selectionGeometries[i].rect())
+            auto& aGeometry = a.selectionGeometries[i];
+            auto& bGeometry = b.selectionGeometries[i];
+            auto behavior = aGeometry.behavior();
+            if (behavior != bGeometry.behavior())
                 return false;
+
+            if (behavior == WebCore::SelectionRenderingBehavior::CoalesceBoundingRects && aGeometry.rect() != bGeometry.rect())
+                return false;
+
+            if (behavior == WebCore::SelectionRenderingBehavior::UseIndividualQuads && aGeometry.quad() != bGeometry.quad())
+                return false;
         }
     }
 
@@ -4796,10 +4805,10 @@
 {
 }
 
-static NSArray<WKTextSelectionRect *> *wkTextSelectionRects(const Vector<WebCore::SelectionGeometry>& rects)
+static NSArray<WKTextSelectionRect *> *textSelectionRects(const Vector<WebCore::SelectionGeometry>& rects, CGFloat scaleFactor)
 {
-    return createNSArray(rects, [] (auto& rect) {
-        return adoptNS([[WKTextSelectionRect alloc] initWithSelectionGeometry:rect]);
+    return createNSArray(rects, [scaleFactor] (auto& rect) {
+        return adoptNS([[WKTextSelectionRect alloc] initWithSelectionGeometry:rect scaleFactor:scaleFactor]);
     }).autorelease();
 }
 
@@ -4852,7 +4861,7 @@
 
     auto caretStartRect = [self _scaledCaretRectForSelectionStart:_page->editorState().postLayoutData().caretRectAtStart];
     auto caretEndRect = [self _scaledCaretRectForSelectionEnd:_page->editorState().postLayoutData().caretRectAtEnd];
-    auto selectionRects = wkTextSelectionRects(_page->editorState().postLayoutData().selectionGeometries);
+    auto selectionRects = textSelectionRects(_page->editorState().postLayoutData().selectionGeometries, self._contentZoomScale);
     auto selectedTextLength = editorState.postLayoutData().selectedTextLength;
     _cachedSelectedTextRange = [WKTextRange textRangeWithState:!hasSelection isRange:isRange isEditable:isContentEditable startRect:caretStartRect endRect:caretEndRect selectionRects:selectionRects selectedTextLength:selectedTextLength];
     return _cachedSelectedTextRange.get();
@@ -4902,7 +4911,7 @@
     auto isContentEditable = editorState.isContentEditable;
     auto caretStartRect = [self _scaledCaretRectForSelectionStart:unscaledCaretRectAtStart];
     auto caretEndRect = [self _scaledCaretRectForSelectionEnd:unscaledCaretRectAtEnd];
-    auto selectionRects = wkTextSelectionRects(postLayoutData.markedTextRects);
+    auto selectionRects = textSelectionRects(postLayoutData.markedTextRects, self._contentZoomScale);
     auto selectedTextLength = postLayoutData.markedText.length();
     return [WKTextRange textRangeWithState:!hasComposition isRange:isRange isEditable:isContentEditable startRect:caretStartRect endRect:caretEndRect selectionRects:selectionRects selectedTextLength:selectedTextLength];
 }

Modified: trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.h (276387 => 276388)


--- trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.h	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.h	2021-04-21 20:11:31 UTC (rev 276388)
@@ -34,7 +34,7 @@
 @interface WKTextSelectionRect : UITextSelectionRect
 
 - (instancetype)initWithCGRect:(CGRect)rect;
-- (instancetype)initWithSelectionGeometry:(const WebCore::SelectionGeometry&)selectionRect;
+- (instancetype)initWithSelectionGeometry:(const WebCore::SelectionGeometry&)selectionGeometry scaleFactor:(CGFloat)scaleFactor;
 
 @end
 

Modified: trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.mm (276387 => 276388)


--- trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.mm	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/UIProcess/ios/WKTextSelectionRect.mm	2021-04-21 20:11:31 UTC (rev 276388)
@@ -30,8 +30,52 @@
 
 #import <WebCore/SelectionGeometry.h>
 
+#if HAVE(UI_TEXT_SELECTION_RECT_CUSTOM_HANDLE_INFO)
+
+@interface WKTextSelectionRectCustomHandleInfo : UITextSelectionRectCustomHandleInfo
+- (instancetype)initWithFloatQuad:(const WebCore::FloatQuad&)quad;
+@end
+
+@implementation WKTextSelectionRectCustomHandleInfo {
+    WebCore::FloatQuad _quad;
+}
+
+- (instancetype)initWithFloatQuad:(const WebCore::FloatQuad&)quad
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _quad = quad;
+    return self;
+}
+
+- (CGPoint)bottomLeft
+{
+    return _quad.p4();
+}
+
+- (CGPoint)topLeft
+{
+    return _quad.p1();
+}
+
+- (CGPoint)bottomRight
+{
+    return _quad.p3();
+}
+
+- (CGPoint)topRight
+{
+    return _quad.p2();
+}
+
+@end
+
+#endif // HAVE(UI_TEXT_SELECTION_RECT_CUSTOM_HANDLE_INFO)
+
 @implementation WKTextSelectionRect {
     WebCore::SelectionGeometry _selectionGeometry;
+    CGFloat _scaleFactor;
 }
 
 - (instancetype)initWithCGRect:(CGRect)rect
@@ -38,17 +82,53 @@
 {
     WebCore::SelectionGeometry selectionGeometry;
     selectionGeometry.setRect(WebCore::enclosingIntRect(rect));
-    return [self initWithSelectionGeometry:WTFMove(selectionGeometry)];
+    return [self initWithSelectionGeometry:WTFMove(selectionGeometry) scaleFactor:1];
 }
 
-- (instancetype)initWithSelectionGeometry:(const WebCore::SelectionGeometry&)selectionRect
+- (instancetype)initWithSelectionGeometry:(const WebCore::SelectionGeometry&)selectionGeometry scaleFactor:(CGFloat)scaleFactor
 {
     if (!(self = [super init]))
         return nil;
-    _selectionGeometry = selectionRect;
+
+    _selectionGeometry = selectionGeometry;
+    _scaleFactor = scaleFactor;
     return self;
 }
 
+- (UIBezierPath *)_path
+{
+    if (_selectionGeometry.behavior() == WebCore::SelectionRenderingBehavior::CoalesceBoundingRects)
+        return nil;
+
+    auto selectionBounds = _selectionGeometry.rect();
+    auto quad = _selectionGeometry.quad();
+    quad.scale(_scaleFactor);
+    quad.move(-selectionBounds.x() * _scaleFactor, -selectionBounds.y() * _scaleFactor);
+
+    auto result = [UIBezierPath bezierPath];
+    [result moveToPoint:quad.p1()];
+    [result addLineToPoint:quad.p2()];
+    [result addLineToPoint:quad.p3()];
+    [result addLineToPoint:quad.p4()];
+    [result addLineToPoint:quad.p1()];
+    [result closePath];
+    return result;
+}
+
+#if HAVE(UI_TEXT_SELECTION_RECT_CUSTOM_HANDLE_INFO)
+
+- (WKTextSelectionRectCustomHandleInfo *)_customHandleInfo
+{
+    if (_selectionGeometry.behavior() == WebCore::SelectionRenderingBehavior::CoalesceBoundingRects)
+        return nil;
+
+    auto scaledQuad = _selectionGeometry.quad();
+    scaledQuad.scale(_scaleFactor);
+    return adoptNS([[WKTextSelectionRectCustomHandleInfo alloc] initWithFloatQuad:scaledQuad]).autorelease();
+}
+
+#endif // HAVE(UI_TEXT_SELECTION_RECT_CUSTOM_HANDLE_INFO)
+
 - (CGRect)rect
 {
     return _selectionGeometry.rect();

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (276387 => 276388)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-04-21 20:06:42 UTC (rev 276387)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-04-21 20:11:31 UTC (rev 276388)
@@ -258,10 +258,16 @@
     return needsLayout;
 }
 
-static void convertContentToRootView(const FrameView& view, Vector<SelectionGeometry>& rects)
+static void convertContentToRootView(const FrameView& view, Vector<SelectionGeometry>& geometries)
 {
-    for (auto& rect : rects)
-        rect.setRect(view.contentsToRootView(rect.rect()));
+    for (auto& geometry : geometries) {
+        auto convertedQuad = geometry.quad();
+        convertedQuad.setP1(view.contentsToRootView(convertedQuad.p1()));
+        convertedQuad.setP2(view.contentsToRootView(convertedQuad.p2()));
+        convertedQuad.setP3(view.contentsToRootView(convertedQuad.p3()));
+        convertedQuad.setP4(view.contentsToRootView(convertedQuad.p4()));
+        geometry.setQuad(convertedQuad);
+    }
 }
 
 void WebPage::getPlatformEditorState(Frame& frame, EditorState& result) const
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to