Title: [275112] trunk
Revision
275112
Author
[email protected]
Date
2021-03-26 14:23:17 -0700 (Fri, 26 Mar 2021)

Log Message

Allow some image overlay content to render in fully transparent image elements
https://bugs.webkit.org/show_bug.cgi?id=223781
<rdar://problem/75886351>

Reviewed by Tim Horton.

Source/WebCore:

Introduce `ImageOverlayController`, and use it to render selections in image overlay content when the image
overlay's host element is fully transparent.

Test: fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html

* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* dom/Document.cpp:
(WebCore::Document::willBeRemovedFromFrame):

Add plumbing to allow `ImageOverlayController` to uninstall its `PageOverlay` when the document is about to be
detached. See `ImageOverlayController::` below.

* editing/SelectionRectGatherer.cpp:
(WebCore::SelectionRectGatherer::Notifier::~Notifier):

Have `SelectionRectGatherer` notify the image overlay controller as well, when selection rects change.

* page/ChromeClient.h:
(WebCore::ChromeClient::needsImageOverlayControllerForSelectionPainting const):

Add a new client hook that returns whether or not we should use `ImageOverlayController` to paint selections.
If not (i.e. we're on iOS, where we use UIKit to draw selections in the UI process), then we'll never install
page overlays, since `selectionRectsDidChange` is effectively a no-op.

* page/ImageOverlayController.cpp: Added.
(WebCore::ImageOverlayController::ImageOverlayController):
(WebCore::ImageOverlayController::selectionRectsDidChange):

When selection rects change, if the selection is inside an image overlay whose host is completely transparent
(or very close to being completely transparent), then remember the selection rects along with the renderer's
background color, and use this to render selection highlights separately, in a `PageOverlay`.

(WebCore::ImageOverlayController::documentDetached):

If the `Document` containing the current rendered overlay selection is detached, immediately uninstall the
current `PageOverlay`. This ensures that the overlays don't persist through navigation.

(WebCore::ImageOverlayController::installPageOverlayIfNeeded):
(WebCore::ImageOverlayController::uninstallPageOverlayIfNeeded):

Helper methods to add or remove the `PageOverlay` from the current `Page`.

(WebCore::ImageOverlayController::willMoveToPage):

Uninstall the current page overlay if needed.

(WebCore::ImageOverlayController::drawRect):

Use the information stored in `ImageOverlayController::selectionRectsDidChange` to render custom selection
rects.

* page/ImageOverlayController.h: Added.
* page/Page.cpp:
* page/Page.h:

Add an `ImageOverlayController` to the `Page`.

(WebCore::Page::imageOverlayController):

Source/WebKit:

Implement a new chrome client hook. See WebCore ChangeLog for more information.

* WebProcess/WebCoreSupport/WebChromeClient.h:

LayoutTests:

Adjust an existing layout test so that it actually checks what it was intended to check; add a new layout test
to cover the changes in this bug.

* fast/images/image-extraction/mac/select-word-in-draggable-image-overlay.html:

Drive-by fix: remove some extraneous imported scripts from this layout test, and additionally simplify the test
so that it doesn't rely on event sender to select text.

* fast/images/image-extraction/mac/select-word-in-transparent-image-overlay-expected-mismatch.html: Added.
* fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html: Added.

Add a new layout test with a fully transparent image element that covers a div of the same size, with a
background image that is identical to the image element's image. This emulates the behavior of certain websites
that prompted this fallback image overlay rendering codepath in the first place.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (275111 => 275112)


--- trunk/LayoutTests/ChangeLog	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/LayoutTests/ChangeLog	2021-03-26 21:23:17 UTC (rev 275112)
@@ -1,3 +1,26 @@
+2021-03-26  Wenson Hsieh  <[email protected]>
+
+        Allow some image overlay content to render in fully transparent image elements
+        https://bugs.webkit.org/show_bug.cgi?id=223781
+        <rdar://problem/75886351>
+
+        Reviewed by Tim Horton.
+
+        Adjust an existing layout test so that it actually checks what it was intended to check; add a new layout test
+        to cover the changes in this bug.
+
+        * fast/images/image-extraction/mac/select-word-in-draggable-image-overlay.html:
+
+        Drive-by fix: remove some extraneous imported scripts from this layout test, and additionally simplify the test
+        so that it doesn't rely on event sender to select text.
+
+        * fast/images/image-extraction/mac/select-word-in-transparent-image-overlay-expected-mismatch.html: Added.
+        * fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html: Added.
+
+        Add a new layout test with a fully transparent image element that covers a div of the same size, with a
+        background image that is identical to the image element's image. This emulates the behavior of certain websites
+        that prompted this fallback image overlay rendering codepath in the first place.
+
 2021-03-26  Imanol Fernandez  <[email protected]>
 
         Implement cachedPropertyValue for WebXR [SameObject] attributes

Modified: trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-draggable-image-overlay.html (275111 => 275112)


--- trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-draggable-image-overlay.html	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-draggable-image-overlay.html	2021-03-26 21:23:17 UTC (rev 275112)
@@ -1,8 +1,6 @@
 <!DOCTYPE html>
 <html>
 <head>
-<script src=""
-<script src=""
 <style>
 img {
     position: absolute;
@@ -15,7 +13,8 @@
 <img draggable="true" src=""
 <script>
 addEventListener("load", () => {
-    internals.installImageOverlay(document.querySelector("img"), [
+    const image = document.querySelector("img");
+    internals.installImageOverlay(image, [
         {
             text : "hello",
             topLeft : new DOMPointReadOnly(0, 0),
@@ -24,10 +23,8 @@
             bottomLeft : new DOMPointReadOnly(0, 0.5),
         }
     ]);
-    eventSender.mouseMoveTo(50, 300);
-    eventSender.mouseDown();
-    eventSender.mouseMoveTo(350, 300);
-    eventSender.mouseUp();
+
+    getSelection().selectAllChildren(internals.shadowRoot(image).querySelector(".image-overlay-text"));
 });
 </script>
 </body>

Added: trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay-expected-mismatch.html (0 => 275112)


--- trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay-expected-mismatch.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay-expected-mismatch.html	2021-03-26 21:23:17 UTC (rev 275112)
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+body, html {
+    margin: 0;
+}
+
+div {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 400px;
+    height: 400px;
+    background-size: contain;
+    background-image: url(../../resources/green-400x400.png);
+}
+</style>
+</head>
+<body>
+<div></div>
+</body>
+</html>
\ No newline at end of file

Added: trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html (0 => 275112)


--- trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html	                        (rev 0)
+++ trunk/LayoutTests/fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html	2021-03-26 21:23:17 UTC (rev 275112)
@@ -0,0 +1,47 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+.back {
+    background-size: contain;
+    background-image: url(../../resources/green-400x400.png);
+}
+
+.front {
+    opacity: 0;
+}
+
+body, html {
+    margin: 0;
+}
+
+.front, .back {
+    position: absolute;
+    top: 0;
+    left: 0;
+    width: 400px;
+    height: 400px;
+}
+</style>
+</head>
+<body>
+<div class="back"></div>
+<img class="front" src=""
+<script>
+addEventListener("load", () => {
+    let image = document.querySelector("img");
+    internals.installImageOverlay(image, [
+        {
+            text : "hello",
+            topLeft : new DOMPointReadOnly(0, 0),
+            topRight : new DOMPointReadOnly(1, 0),
+            bottomRight : new DOMPointReadOnly(1, 0.5),
+            bottomLeft : new DOMPointReadOnly(0, 0.5),
+        }
+    ]);
+
+    getSelection().selectAllChildren(internals.shadowRoot(image).querySelector(".image-overlay-text"));
+});
+</script>
+</body>
+</html>
\ No newline at end of file

Modified: trunk/Source/WebCore/ChangeLog (275111 => 275112)


--- trunk/Source/WebCore/ChangeLog	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/ChangeLog	2021-03-26 21:23:17 UTC (rev 275112)
@@ -1,3 +1,71 @@
+2021-03-26  Wenson Hsieh  <[email protected]>
+
+        Allow some image overlay content to render in fully transparent image elements
+        https://bugs.webkit.org/show_bug.cgi?id=223781
+        <rdar://problem/75886351>
+
+        Reviewed by Tim Horton.
+
+        Introduce `ImageOverlayController`, and use it to render selections in image overlay content when the image
+        overlay's host element is fully transparent.
+
+        Test: fast/images/image-extraction/mac/select-word-in-transparent-image-overlay.html
+
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/Document.cpp:
+        (WebCore::Document::willBeRemovedFromFrame):
+
+        Add plumbing to allow `ImageOverlayController` to uninstall its `PageOverlay` when the document is about to be
+        detached. See `ImageOverlayController::` below.
+
+        * editing/SelectionRectGatherer.cpp:
+        (WebCore::SelectionRectGatherer::Notifier::~Notifier):
+
+        Have `SelectionRectGatherer` notify the image overlay controller as well, when selection rects change.
+
+        * page/ChromeClient.h:
+        (WebCore::ChromeClient::needsImageOverlayControllerForSelectionPainting const):
+
+        Add a new client hook that returns whether or not we should use `ImageOverlayController` to paint selections.
+        If not (i.e. we're on iOS, where we use UIKit to draw selections in the UI process), then we'll never install
+        page overlays, since `selectionRectsDidChange` is effectively a no-op.
+
+        * page/ImageOverlayController.cpp: Added.
+        (WebCore::ImageOverlayController::ImageOverlayController):
+        (WebCore::ImageOverlayController::selectionRectsDidChange):
+
+        When selection rects change, if the selection is inside an image overlay whose host is completely transparent
+        (or very close to being completely transparent), then remember the selection rects along with the renderer's
+        background color, and use this to render selection highlights separately, in a `PageOverlay`.
+
+        (WebCore::ImageOverlayController::documentDetached):
+
+        If the `Document` containing the current rendered overlay selection is detached, immediately uninstall the
+        current `PageOverlay`. This ensures that the overlays don't persist through navigation.
+
+        (WebCore::ImageOverlayController::installPageOverlayIfNeeded):
+        (WebCore::ImageOverlayController::uninstallPageOverlayIfNeeded):
+
+        Helper methods to add or remove the `PageOverlay` from the current `Page`.
+
+        (WebCore::ImageOverlayController::willMoveToPage):
+
+        Uninstall the current page overlay if needed.
+
+        (WebCore::ImageOverlayController::drawRect):
+
+        Use the information stored in `ImageOverlayController::selectionRectsDidChange` to render custom selection
+        rects.
+
+        * page/ImageOverlayController.h: Added.
+        * page/Page.cpp:
+        * page/Page.h:
+
+        Add an `ImageOverlayController` to the `Page`.
+
+        (WebCore::Page::imageOverlayController):
+
 2021-03-26  Don Olmstead  <[email protected]>
 
         [CMake] Deprecate using DERIVED_SOURCES_DIR/FOWARDING_HEADERS_DIR directly

Modified: trunk/Source/WebCore/Sources.txt (275111 => 275112)


--- trunk/Source/WebCore/Sources.txt	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/Sources.txt	2021-03-26 21:23:17 UTC (rev 275112)
@@ -1699,6 +1699,7 @@
 page/FrameView.cpp
 page/FrameViewLayoutContext.cpp
 page/History.cpp
+page/ImageOverlayController.cpp
 page/IntersectionObserver.cpp
 page/IntersectionObserverEntry.cpp
 page/Location.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (275111 => 275112)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-03-26 21:23:17 UTC (rev 275112)
@@ -5308,6 +5308,7 @@
 		F48223101E3869B80066FC79 /* WebItemProviderPasteboard.mm in Sources */ = {isa = PBXBuildFile; fileRef = F482230E1E3869B80066FC79 /* WebItemProviderPasteboard.mm */; };
 		F48223111E3869B80066FC79 /* WebItemProviderPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F482230F1E3869B80066FC79 /* WebItemProviderPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48223131E386E240066FC79 /* AbstractPasteboard.h in Headers */ = {isa = PBXBuildFile; fileRef = F48223121E386E240066FC79 /* AbstractPasteboard.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		F482434B260C33060022497C /* ImageOverlayController.h in Headers */ = {isa = PBXBuildFile; fileRef = F4824348260C32F10022497C /* ImageOverlayController.h */; };
 		F48B7D5325C341E6009E75DD /* ImageExtractionResult.h in Headers */ = {isa = PBXBuildFile; fileRef = F48B7D5225C341E6009E75DD /* ImageExtractionResult.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48D2A6C215623B400C6752B /* FontShadow.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2A6A215623B400C6752B /* FontShadow.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F48D2A7E2157182600C6752B /* FontAttributes.h in Headers */ = {isa = PBXBuildFile; fileRef = F48D2A712156DC0A00C6752B /* FontAttributes.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -16733,6 +16734,8 @@
 		F482230E1E3869B80066FC79 /* WebItemProviderPasteboard.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = WebItemProviderPasteboard.mm; sourceTree = "<group>"; };
 		F482230F1E3869B80066FC79 /* WebItemProviderPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebItemProviderPasteboard.h; sourceTree = "<group>"; };
 		F48223121E386E240066FC79 /* AbstractPasteboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AbstractPasteboard.h; sourceTree = "<group>"; };
+		F4824348260C32F10022497C /* ImageOverlayController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageOverlayController.h; sourceTree = "<group>"; };
+		F482434A260C32F10022497C /* ImageOverlayController.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ImageOverlayController.cpp; sourceTree = "<group>"; };
 		F48389831E1DDF2B0076B7EA /* DumpEditingHistory.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; name = DumpEditingHistory.js; path = Scripts/DumpEditingHistory.js; sourceTree = "<group>"; };
 		F48389841E1DDF2B0076B7EA /* EditingHistoryUtil.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode._javascript_; name = EditingHistoryUtil.js; path = Scripts/EditingHistoryUtil.js; sourceTree = "<group>"; };
 		F48B7D5225C341E6009E75DD /* ImageExtractionResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageExtractionResult.h; sourceTree = "<group>"; };
@@ -22256,6 +22259,8 @@
 				BC94D1500C275C8B006BC617 /* History.cpp */,
 				BC94D1510C275C8B006BC617 /* History.h */,
 				BC94D1520C275C8B006BC617 /* History.idl */,
+				F482434A260C32F10022497C /* ImageOverlayController.cpp */,
+				F4824348260C32F10022497C /* ImageOverlayController.h */,
 				0F4710D51DB6FE22002DCEC3 /* IntersectionObserver.cpp */,
 				0F4710D61DB6FE22002DCEC3 /* IntersectionObserver.h */,
 				0F4710D71DB6FE22002DCEC3 /* IntersectionObserver.idl */,
@@ -32775,6 +32780,7 @@
 				089582560E857A7E00F82C83 /* ImageLoader.h in Headers */,
 				BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
 				2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
+				F482434B260C33060022497C /* ImageOverlayController.h in Headers */,
 				72283F0E230B268C00F5D828 /* ImagePaintingOptions.h in Headers */,
 				B51A2F3F17D7D3AE0072517A /* ImageQualityController.h in Headers */,
 				49291E4B134172C800E753DE /* ImageRenderingMode.h in Headers */,

Modified: trunk/Source/WebCore/dom/Document.cpp (275111 => 275112)


--- trunk/Source/WebCore/dom/Document.cpp	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/dom/Document.cpp	2021-03-26 21:23:17 UTC (rev 275112)
@@ -118,6 +118,7 @@
 #include "IdleCallbackController.h"
 #include "ImageBitmapRenderingContext.h"
 #include "ImageLoader.h"
+#include "ImageOverlayController.h"
 #include "InspectorInstrumentation.h"
 #include "IntersectionObserver.h"
 #include "JSCustomElementInterface.h"
@@ -2613,12 +2614,11 @@
     if (is<PluginDocument>(*this))
         downcast<PluginDocument>(*this).detachFromPluginElement();
 
+    if (auto* page = this->page()) {
 #if ENABLE(POINTER_LOCK)
-    if (page())
-        page()->pointerLockController().documentDetached(*this);
+        page->pointerLockController().documentDetached(*this);
 #endif
-
-    if (auto* page = this->page()) {
+        page->imageOverlayController().documentDetached(*this);
         if (auto* validationMessageClient = page->validationMessageClient())
             validationMessageClient->documentDetached(*this);
     }

Modified: trunk/Source/WebCore/editing/SelectionRectGatherer.cpp (275111 => 275112)


--- trunk/Source/WebCore/editing/SelectionRectGatherer.cpp	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/editing/SelectionRectGatherer.cpp	2021-03-26 21:23:17 UTC (rev 275112)
@@ -31,6 +31,7 @@
 #include "Editor.h"
 #include "EditorClient.h"
 #include "Frame.h"
+#include "ImageOverlayController.h"
 #include "RenderView.h"
 #include "ServicesOverlayController.h"
 
@@ -71,8 +72,12 @@
 
 SelectionRectGatherer::Notifier::~Notifier()
 {
-    if (auto* page = m_gatherer.m_renderView.view().frame().page())
-        page->servicesOverlayController().selectionRectsDidChange(m_gatherer.m_rects, m_gatherer.m_gapRects, m_gatherer.isTextOnly());
+    auto page = m_gatherer.m_renderView.view().frame().page();
+    if (!page)
+        return;
+
+    page->servicesOverlayController().selectionRectsDidChange(m_gatherer.m_rects, m_gatherer.m_gapRects, m_gatherer.isTextOnly());
+    page->imageOverlayController().selectionRectsDidChange(m_gatherer.m_renderView.frame(), m_gatherer.m_rects);
 }
 
 std::unique_ptr<SelectionRectGatherer::Notifier> SelectionRectGatherer::clearAndCreateNotifier()

Modified: trunk/Source/WebCore/page/ChromeClient.h (275111 => 275112)


--- trunk/Source/WebCore/page/ChromeClient.h	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/page/ChromeClient.h	2021-03-26 21:23:17 UTC (rev 275112)
@@ -562,6 +562,7 @@
 #if ENABLE(IMAGE_EXTRACTION)
     virtual void requestImageExtraction(Element&) { }
 #endif
+    virtual bool needsImageOverlayControllerForSelectionPainting() const { return false; }
 
 #if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
     virtual void showMediaControlsContextMenu(FloatRect&&, Vector<MediaControlsContextMenuItem>&&, CompletionHandler<void(MediaControlsContextMenuItem::ID)>&& completionHandler) { completionHandler(MediaControlsContextMenuItem::invalidID); }

Added: trunk/Source/WebCore/page/ImageOverlayController.cpp (0 => 275112)


--- trunk/Source/WebCore/page/ImageOverlayController.cpp	                        (rev 0)
+++ trunk/Source/WebCore/page/ImageOverlayController.cpp	2021-03-26 21:23:17 UTC (rev 275112)
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ImageOverlayController.h"
+
+#include "Chrome.h"
+#include "ChromeClient.h"
+#include "Document.h"
+#include "Editor.h"
+#include "Frame.h"
+#include "FrameSelection.h"
+#include "GapRects.h"
+#include "GraphicsContext.h"
+#include "HTMLElement.h"
+#include "IntRect.h"
+#include "LayoutRect.h"
+#include "Page.h"
+#include "PageOverlayController.h"
+#include "RenderElement.h"
+#include "RenderStyle.h"
+#include "SimpleRange.h"
+#include "VisiblePosition.h"
+
+namespace WebCore {
+
+ImageOverlayController::ImageOverlayController(Page& page)
+    : m_page(makeWeakPtr(page))
+{
+}
+
+void ImageOverlayController::selectionRectsDidChange(Frame& frame, const Vector<LayoutRect>& rects)
+{
+    if (!m_page || !m_page->chrome().client().needsImageOverlayControllerForSelectionPainting())
+        return;
+
+    if (frame.editor().ignoreSelectionChanges())
+        return;
+
+    auto overlayHostRenderer = ([&] () -> RenderElement* {
+        if (rects.isEmpty())
+            return nullptr;
+
+        auto selectedRange = frame.selection().selection().range();
+        if (!selectedRange)
+            return nullptr;
+
+        if (!HTMLElement::isInsideImageOverlay(*selectedRange) || selectedRange->collapsed())
+            return nullptr;
+
+        auto overlayHost = makeRefPtr(selectedRange->startContainer().shadowHost());
+        if (!overlayHost) {
+            ASSERT_NOT_REACHED();
+            return nullptr;
+        }
+
+        return overlayHost->renderer();
+    })();
+
+    if (!overlayHostRenderer || !shouldUsePageOverlayToPaintSelection(*overlayHostRenderer)) {
+        uninstallPageOverlayIfNeeded();
+        return;
+    }
+
+    m_overlaySelectionRects = rects;
+    m_selectionBackgroundColor = overlayHostRenderer->selectionBackgroundColor();
+    m_currentOverlayDocument = makeWeakPtr(overlayHostRenderer->document());
+
+    installPageOverlayIfNeeded().setNeedsDisplay();
+}
+
+bool ImageOverlayController::shouldUsePageOverlayToPaintSelection(const RenderElement& renderer)
+{
+    // If the selection is already painted (with nonzero opacity) in the overlay host's renderer,
+    // then we don't need to fall back to a page overlay to paint the selection.
+    return renderer.style().opacity() <= 0.01;
+}
+
+void ImageOverlayController::documentDetached(const Document& document)
+{
+    if (&document == m_currentOverlayDocument)
+        uninstallPageOverlayIfNeeded();
+}
+
+PageOverlay& ImageOverlayController::installPageOverlayIfNeeded()
+{
+    if (m_overlay)
+        return *m_overlay;
+
+    m_overlay = PageOverlay::create(*this, PageOverlay::OverlayType::Document);
+    m_page->pageOverlayController().installPageOverlay(*m_overlay, PageOverlay::FadeMode::DoNotFade);
+    return *m_overlay;
+}
+
+void ImageOverlayController::uninstallPageOverlayIfNeeded()
+{
+    m_overlaySelectionRects.clear();
+    m_selectionBackgroundColor = Color::transparentBlack;
+    m_currentOverlayDocument = nullptr;
+
+    auto overlayToUninstall = std::exchange(m_overlay, nullptr);
+    if (!m_page || !overlayToUninstall)
+        return;
+
+    m_page->pageOverlayController().uninstallPageOverlay(*overlayToUninstall, PageOverlay::FadeMode::DoNotFade);
+}
+
+void ImageOverlayController::willMoveToPage(PageOverlay&, Page* page)
+{
+    if (!page)
+        uninstallPageOverlayIfNeeded();
+}
+
+void ImageOverlayController::drawRect(PageOverlay& pageOverlay, GraphicsContext& context, const IntRect& dirtyRect)
+{
+    if (&pageOverlay != m_overlay) {
+        ASSERT_NOT_REACHED();
+        return;
+    }
+
+    GraphicsContextStateSaver stateSaver(context);
+    context.clearRect(dirtyRect);
+    context.setFillColor(m_selectionBackgroundColor);
+    for (auto& rect : m_overlaySelectionRects)
+        context.fillRect(rect);
+}
+
+} // namespace WebCore

Added: trunk/Source/WebCore/page/ImageOverlayController.h (0 => 275112)


--- trunk/Source/WebCore/page/ImageOverlayController.h	                        (rev 0)
+++ trunk/Source/WebCore/page/ImageOverlayController.h	2021-03-26 21:23:17 UTC (rev 275112)
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "Color.h"
+#include "PageOverlay.h"
+#include <wtf/Vector.h>
+#include <wtf/WeakPtr.h>
+
+namespace WebCore {
+
+class Document;
+class Frame;
+class GraphicsContext;
+class IntRect;
+class LayoutRect;
+class Page;
+class RenderElement;
+struct GapRects;
+
+class ImageOverlayController final : private PageOverlay::Client {
+    WTF_MAKE_FAST_ALLOCATED;
+public:
+    explicit ImageOverlayController(Page&);
+
+    void selectionRectsDidChange(Frame&, const Vector<LayoutRect>&);
+    void documentDetached(const Document&);
+
+private:
+    void willMoveToPage(PageOverlay&, Page*) final;
+    void didMoveToPage(PageOverlay&, Page*) final { }
+    void drawRect(PageOverlay&, GraphicsContext&, const IntRect& dirtyRect) final;
+    bool mouseEvent(PageOverlay&, const PlatformMouseEvent&) final { return false; }
+
+    bool shouldUsePageOverlayToPaintSelection(const RenderElement&);
+
+    PageOverlay& installPageOverlayIfNeeded();
+    void uninstallPageOverlayIfNeeded();
+
+    WeakPtr<Page> m_page;
+    RefPtr<PageOverlay> m_overlay;
+    WeakPtr<Document> m_currentOverlayDocument;
+    Vector<LayoutRect> m_overlaySelectionRects;
+    Color m_selectionBackgroundColor { Color::transparentBlack };
+};
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/page/Page.cpp (275111 => 275112)


--- trunk/Source/WebCore/page/Page.cpp	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/page/Page.cpp	2021-03-26 21:23:17 UTC (rev 275112)
@@ -72,6 +72,7 @@
 #include "HTMLTextFormControlElement.h"
 #include "HistoryController.h"
 #include "HistoryItem.h"
+#include "ImageOverlayController.h"
 #include "InspectorClient.h"
 #include "InspectorController.h"
 #include "InspectorInstrumentation.h"
@@ -290,6 +291,7 @@
 #if PLATFORM(MAC) && (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION))
     , m_servicesOverlayController(makeUnique<ServicesOverlayController>(*this))
 #endif
+    , m_imageOverlayController(makeUnique<ImageOverlayController>(*this))
     , m_recentWheelEventDeltaFilter(WheelEventDeltaFilter::create())
     , m_pageOverlayController(makeUnique<PageOverlayController>(*this))
 #if ENABLE(APPLE_PAY)

Modified: trunk/Source/WebCore/page/Page.h (275111 => 275112)


--- trunk/Source/WebCore/page/Page.h	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebCore/page/Page.h	2021-03-26 21:23:17 UTC (rev 275112)
@@ -108,6 +108,7 @@
 class Frame;
 class HTMLMediaElement;
 class HistoryItem;
+class ImageOverlayController;
 class InspectorClient;
 class InspectorController;
 class LibWebRTCProvider;
@@ -496,6 +497,7 @@
 #if PLATFORM(MAC) && (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION))
     ServicesOverlayController& servicesOverlayController() { return *m_servicesOverlayController; }
 #endif
+    ImageOverlayController& imageOverlayController() { return *m_imageOverlayController; }
 
 #if ENABLE(WHEEL_EVENT_LATCHING)
     ScrollLatchingController& scrollLatchingController();
@@ -1111,6 +1113,7 @@
 #if PLATFORM(MAC) && (ENABLE(SERVICE_CONTROLS) || ENABLE(TELEPHONE_NUMBER_DETECTION))
     std::unique_ptr<ServicesOverlayController> m_servicesOverlayController;
 #endif
+    std::unique_ptr<ImageOverlayController> m_imageOverlayController;
 
     std::unique_ptr<WheelEventDeltaFilter> m_recentWheelEventDeltaFilter;
     std::unique_ptr<PageOverlayController> m_pageOverlayController;

Modified: trunk/Source/WebKit/ChangeLog (275111 => 275112)


--- trunk/Source/WebKit/ChangeLog	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebKit/ChangeLog	2021-03-26 21:23:17 UTC (rev 275112)
@@ -1,3 +1,15 @@
+2021-03-26  Wenson Hsieh  <[email protected]>
+
+        Allow some image overlay content to render in fully transparent image elements
+        https://bugs.webkit.org/show_bug.cgi?id=223781
+        <rdar://problem/75886351>
+
+        Reviewed by Tim Horton.
+
+        Implement a new chrome client hook. See WebCore ChangeLog for more information.
+
+        * WebProcess/WebCoreSupport/WebChromeClient.h:
+
 2021-03-26  Don Olmstead  <[email protected]>
 
         [CMake] Deprecate using DERIVED_SOURCES_DIR/FOWARDING_HEADERS_DIR directly

Modified: trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h (275111 => 275112)


--- trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2021-03-26 20:37:09 UTC (rev 275111)
+++ trunk/Source/WebKit/WebProcess/WebCoreSupport/WebChromeClient.h	2021-03-26 21:23:17 UTC (rev 275112)
@@ -418,6 +418,15 @@
     void requestImageExtraction(WebCore::Element&) final;
 #endif
 
+    bool needsImageOverlayControllerForSelectionPainting() const final
+    {
+#if USE(UIKIT_EDITING)
+        return false;
+#else
+        return true;
+#endif
+    }
+
 #if ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
     void showMediaControlsContextMenu(WebCore::FloatRect&&, Vector<WebCore::MediaControlsContextMenuItem>&&, CompletionHandler<void(WebCore::MediaControlsContextMenuItem::ID)>&&) final;
 #endif // ENABLE(MEDIA_CONTROLS_CONTEXT_MENUS) && USE(UICONTEXTMENU)
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to