Title: [285655] trunk/Source
Revision
285655
Author
[email protected]
Date
2021-11-11 13:52:01 -0800 (Thu, 11 Nov 2021)

Log Message

Move image overlay code out of HTMLElement and into a separate helper file
https://bugs.webkit.org/show_bug.cgi?id=232974

Reviewed by Antti Koivisto.

Source/WebCore:

Move code for updating, querying, and removing image overlays out of HTMLElement.cpp and HTMLElement.h and into
separate helper files instead (ImageOverlay.h and ImageOverlay.cpp). Future patches in this area will extend the
functionality of these overlays, so this will help avoid code bloat inside HTMLElement when doing so.

No change in behavior.

* Headers.cmake:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* dom/ImageOverlay.cpp: Added.
(WebCore::ImageOverlay::imageOverlayElementIdentifier):
(WebCore::ImageOverlay::imageOverlayDataDetectorClassName):
(WebCore::ImageOverlay::hasOverlay):
(WebCore::ImageOverlay::imageOverlayHost):
(WebCore::ImageOverlay::isDataDetectorResult):
(WebCore::ImageOverlay::isInsideOverlay):
(WebCore::ImageOverlay::isOverlayText):
(WebCore::ImageOverlay::removeOverlaySoonIfNeeded):
(WebCore::ImageOverlay::containerRect):
(WebCore::ImageOverlay::updateWithTextRecognitionResult):
* dom/ImageOverlay.h: Added.

Additionally wrap the new image overlay helper functions in the `ImageOverlay` namespace. This also allows us to
shorten some of the function names, since they're already under the namespace, so duplicating "ImageOverlay" in
the function name itself is unnecessary.

* editing/Editor.cpp:
(WebCore::Editor::performCutOrCopy):
(WebCore::scanForTelephoneNumbers):
* editing/FrameSelection.cpp:
(WebCore::FrameSelection::contains const):
* editing/TextIterator.cpp:
(WebCore::TextIterator::handleReplacedElement):
* html/HTMLElement.cpp:
(WebCore::HTMLElement::shouldExtendSelectionToTargetNode):
(WebCore::HTMLElement::selectionRenderingBehavior):
(WebCore::imageOverlayElementIdentifier): Deleted.
(WebCore::imageOverlayDataDetectorClassName): Deleted.
(WebCore::HTMLElement::hasImageOverlay const): Deleted.
(WebCore::imageOverlayHost): Deleted.
(WebCore::HTMLElement::isImageOverlayDataDetectorResult const): Deleted.
(WebCore::HTMLElement::isInsideImageOverlay): Deleted.
(WebCore::HTMLElement::isImageOverlayText): Deleted.
(WebCore::HTMLElement::removeImageOverlaySoonIfNeeded): Deleted.
(WebCore::HTMLElement::containerRectForTextRecognition): Deleted.
(WebCore::HTMLElement::updateWithTextRecognitionResult): Deleted.
* html/HTMLElement.h:
* html/HTMLMediaElement.cpp:
(WebCore::HTMLMediaElement::seekWithTolerance):
(WebCore::HTMLMediaElement::playInternal):
* page/ContextMenuController.cpp:
(WebCore::ContextMenuController::populate):
* page/DragController.cpp:
(WebCore::DragController::draggableElement const):
(WebCore::DragController::startDrag):
* page/EventHandler.cpp:
(WebCore::nodeToSelectOnMouseDownForNode):
(WebCore::EventHandler::canMouseDownStartSelect):
(WebCore::EventHandler::handleMousePressEvent):
(WebCore::EventHandler::updateSelectionForMouseDrag):
(WebCore::EventHandler::hitTestResultAtPoint const):
(WebCore::EventHandler::selectCursor):
* page/ImageOverlayController.cpp:
(WebCore::ImageOverlayController::selectionQuadsDidChange):
* page/Page.cpp:
(WebCore::Page::updateElementsWithTextRecognitionResults):
* page/mac/ImageOverlayControllerMac.mm:
(WebCore::ImageOverlayController::updateDataDetectorHighlights):
(WebCore::ImageOverlayController::elementUnderMouseDidChange):
* rendering/HitTestResult.cpp:
(WebCore::HitTestResult::nodeForImageData const):
(WebCore::HitTestResult::addNodeToListBasedTestResultCommon):
* rendering/RenderImage.cpp:
(WebCore::RenderImage::RenderImage):
* testing/Internals.cpp:
(WebCore::Internals::installImageOverlay):

Source/WebKit:

See WebCore/ChangeLog for more details.

* WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
(WebKit::WebPage::dictionaryPopupInfoForRange):
* WebProcess/WebPage/FindController.cpp:
(WebKit::FindController::updateFindIndicator):
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::editorState const):
(WebKit::WebPage::findDataDetectionResultElementInImageOverlay):
(WebKit::WebPage::requestTextRecognition):
(WebKit::WebPage::updateWithTextRecognitionResult):
* WebProcess/WebPage/ios/FindControllerIOS.mm:
(WebKit::findTextIndicatorOptions):
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::insideImageOverlay):
(WebKit::rangeForPointInRootViewCoordinates):
(WebKit::hostVideoElementIgnoringImageOverlay):
(WebKit::elementPositionInformation):
* WebProcess/WebPage/mac/WebPageMac.mm:
(WebKit::WebPage::performImmediateActionHitTestAtLocation):

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (285654 => 285655)


--- trunk/Source/WebCore/ChangeLog	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/ChangeLog	2021-11-11 21:52:01 UTC (rev 285655)
@@ -1,3 +1,87 @@
+2021-11-11  Wenson Hsieh  <[email protected]>
+
+        Move image overlay code out of HTMLElement and into a separate helper file
+        https://bugs.webkit.org/show_bug.cgi?id=232974
+
+        Reviewed by Antti Koivisto.
+
+        Move code for updating, querying, and removing image overlays out of HTMLElement.cpp and HTMLElement.h and into
+        separate helper files instead (ImageOverlay.h and ImageOverlay.cpp). Future patches in this area will extend the
+        functionality of these overlays, so this will help avoid code bloat inside HTMLElement when doing so.
+
+        No change in behavior.
+
+        * Headers.cmake:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * dom/ImageOverlay.cpp: Added.
+        (WebCore::ImageOverlay::imageOverlayElementIdentifier):
+        (WebCore::ImageOverlay::imageOverlayDataDetectorClassName):
+        (WebCore::ImageOverlay::hasOverlay):
+        (WebCore::ImageOverlay::imageOverlayHost):
+        (WebCore::ImageOverlay::isDataDetectorResult):
+        (WebCore::ImageOverlay::isInsideOverlay):
+        (WebCore::ImageOverlay::isOverlayText):
+        (WebCore::ImageOverlay::removeOverlaySoonIfNeeded):
+        (WebCore::ImageOverlay::containerRect):
+        (WebCore::ImageOverlay::updateWithTextRecognitionResult):
+        * dom/ImageOverlay.h: Added.
+
+        Additionally wrap the new image overlay helper functions in the `ImageOverlay` namespace. This also allows us to
+        shorten some of the function names, since they're already under the namespace, so duplicating "ImageOverlay" in
+        the function name itself is unnecessary.
+
+        * editing/Editor.cpp:
+        (WebCore::Editor::performCutOrCopy):
+        (WebCore::scanForTelephoneNumbers):
+        * editing/FrameSelection.cpp:
+        (WebCore::FrameSelection::contains const):
+        * editing/TextIterator.cpp:
+        (WebCore::TextIterator::handleReplacedElement):
+        * html/HTMLElement.cpp:
+        (WebCore::HTMLElement::shouldExtendSelectionToTargetNode):
+        (WebCore::HTMLElement::selectionRenderingBehavior):
+        (WebCore::imageOverlayElementIdentifier): Deleted.
+        (WebCore::imageOverlayDataDetectorClassName): Deleted.
+        (WebCore::HTMLElement::hasImageOverlay const): Deleted.
+        (WebCore::imageOverlayHost): Deleted.
+        (WebCore::HTMLElement::isImageOverlayDataDetectorResult const): Deleted.
+        (WebCore::HTMLElement::isInsideImageOverlay): Deleted.
+        (WebCore::HTMLElement::isImageOverlayText): Deleted.
+        (WebCore::HTMLElement::removeImageOverlaySoonIfNeeded): Deleted.
+        (WebCore::HTMLElement::containerRectForTextRecognition): Deleted.
+        (WebCore::HTMLElement::updateWithTextRecognitionResult): Deleted.
+        * html/HTMLElement.h:
+        * html/HTMLMediaElement.cpp:
+        (WebCore::HTMLMediaElement::seekWithTolerance):
+        (WebCore::HTMLMediaElement::playInternal):
+        * page/ContextMenuController.cpp:
+        (WebCore::ContextMenuController::populate):
+        * page/DragController.cpp:
+        (WebCore::DragController::draggableElement const):
+        (WebCore::DragController::startDrag):
+        * page/EventHandler.cpp:
+        (WebCore::nodeToSelectOnMouseDownForNode):
+        (WebCore::EventHandler::canMouseDownStartSelect):
+        (WebCore::EventHandler::handleMousePressEvent):
+        (WebCore::EventHandler::updateSelectionForMouseDrag):
+        (WebCore::EventHandler::hitTestResultAtPoint const):
+        (WebCore::EventHandler::selectCursor):
+        * page/ImageOverlayController.cpp:
+        (WebCore::ImageOverlayController::selectionQuadsDidChange):
+        * page/Page.cpp:
+        (WebCore::Page::updateElementsWithTextRecognitionResults):
+        * page/mac/ImageOverlayControllerMac.mm:
+        (WebCore::ImageOverlayController::updateDataDetectorHighlights):
+        (WebCore::ImageOverlayController::elementUnderMouseDidChange):
+        * rendering/HitTestResult.cpp:
+        (WebCore::HitTestResult::nodeForImageData const):
+        (WebCore::HitTestResult::addNodeToListBasedTestResultCommon):
+        * rendering/RenderImage.cpp:
+        (WebCore::RenderImage::RenderImage):
+        * testing/Internals.cpp:
+        (WebCore::Internals::installImageOverlay):
+
 2021-11-11  Adrian Perez de Castro  <[email protected]>
 
         Non-unified build fixes, early November 2021 edition, bis

Modified: trunk/Source/WebCore/Headers.cmake (285654 => 285655)


--- trunk/Source/WebCore/Headers.cmake	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/Headers.cmake	2021-11-11 21:52:01 UTC (rev 285655)
@@ -513,6 +513,7 @@
     dom/FragmentScriptingPermission.h
     dom/FullscreenManager.h
     dom/GCReachableRef.h
+    dom/ImageOverlay.h
     dom/InlineStyleSheetOwner.h
     dom/KeyboardEvent.h
     dom/LiveNodeList.h

Modified: trunk/Source/WebCore/Sources.txt (285654 => 285655)


--- trunk/Source/WebCore/Sources.txt	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/Sources.txt	2021-11-11 21:52:01 UTC (rev 285655)
@@ -964,6 +964,7 @@
 dom/IdTargetObserverRegistry.cpp
 dom/IdleCallbackController.cpp
 dom/IdleDeadline.cpp
+dom/ImageOverlay.cpp
 dom/InlineClassicScript.cpp
 dom/InlineStyleSheetOwner.cpp
 dom/InputEvent.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (285654 => 285655)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2021-11-11 21:52:01 UTC (rev 285655)
@@ -5444,6 +5444,7 @@
 		F45775CE241437D5002DF1A0 /* InlinePathData.h in Headers */ = {isa = PBXBuildFile; fileRef = F45775CD241437D5002DF1A0 /* InlinePathData.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F46729281E0DE68500ACC3D8 /* ScrollSnapOffsetsInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F46C447E234654540039A79D /* ClipboardItemBindingsDataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = F46C447C234654540039A79D /* ClipboardItemBindingsDataSource.h */; };
+		F46D5386273D7E460009FA80 /* ImageOverlay.h in Headers */ = {isa = PBXBuildFile; fileRef = F46D5385273D7E3F0009FA80 /* ImageOverlay.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F473845825DDE9FB006DE8DD /* DataOwnerType.h in Headers */ = {isa = PBXBuildFile; fileRef = F473845725DDE9FB006DE8DD /* DataOwnerType.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F47A09D120A93A9700240FAE /* DisabledAdaptations.h in Headers */ = {isa = PBXBuildFile; fileRef = F47A09CF20A939F600240FAE /* DisabledAdaptations.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		F47A5E3E195B8C8A00483100 /* StyleScrollSnapPoints.h in Headers */ = {isa = PBXBuildFile; fileRef = F47A5E3B195B8C8A00483100 /* StyleScrollSnapPoints.h */; settings = {ATTRIBUTES = (Private, ); }; };
@@ -17244,6 +17245,8 @@
 		F46C447D234654540039A79D /* ClipboardItemBindingsDataSource.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ClipboardItemBindingsDataSource.cpp; sourceTree = "<group>"; };
 		F46C44802346547A0039A79D /* ClipboardItemPasteboardDataSource.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ClipboardItemPasteboardDataSource.h; sourceTree = "<group>"; };
 		F46C44812346547A0039A79D /* ClipboardItemPasteboardDataSource.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ClipboardItemPasteboardDataSource.cpp; sourceTree = "<group>"; };
+		F46D5384273D7E3E0009FA80 /* ImageOverlay.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ImageOverlay.cpp; sourceTree = "<group>"; };
+		F46D5385273D7E3F0009FA80 /* ImageOverlay.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageOverlay.h; sourceTree = "<group>"; };
 		F473845725DDE9FB006DE8DD /* DataOwnerType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataOwnerType.h; sourceTree = "<group>"; };
 		F47A09CF20A939F600240FAE /* DisabledAdaptations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisabledAdaptations.h; sourceTree = "<group>"; };
 		F47A09D420A9DD0400240FAE /* DisabledAdaptations.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DisabledAdaptations.cpp; sourceTree = "<group>"; };
@@ -31407,6 +31410,8 @@
 				C3CF17A315B0063F00276D39 /* IdTargetObserverRegistry.h */,
 				8AB4BC76126FDB7100DEB727 /* IgnoreDestructiveWriteCountIncrementer.h */,
 				467302011C4EFE6600BCB357 /* IgnoreOpensDuringUnloadCountIncrementer.h */,
+				F46D5384273D7E3E0009FA80 /* ImageOverlay.cpp */,
+				F46D5385273D7E3F0009FA80 /* ImageOverlay.h */,
 				E30592611E27A38C00D57C98 /* InlineClassicScript.cpp */,
 				E30592621E27A38C00D57C98 /* InlineClassicScript.h */,
 				AA4C3A740B2B1679002334A2 /* InlineStyleSheetOwner.cpp */,
@@ -33832,6 +33837,7 @@
 				089582560E857A7E00F82C83 /* ImageLoader.h in Headers */,
 				BC7F44A80B9E324E00A9D081 /* ImageObserver.h in Headers */,
 				2D5A5931152525D00036EE51 /* ImageOrientation.h in Headers */,
+				F46D5386273D7E460009FA80 /* ImageOverlay.h in Headers */,
 				F482434B260C33060022497C /* ImageOverlayController.h in Headers */,
 				F446EDE1265DB1E50031DA8F /* ImageOverlayDataDetectionResultIdentifier.h in Headers */,
 				72283F0E230B268C00F5D828 /* ImagePaintingOptions.h in Headers */,

Added: trunk/Source/WebCore/dom/ImageOverlay.cpp (0 => 285655)


--- trunk/Source/WebCore/dom/ImageOverlay.cpp	                        (rev 0)
+++ trunk/Source/WebCore/dom/ImageOverlay.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -0,0 +1,457 @@
+/*
+ * 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 "ImageOverlay.h"
+
+#include "DOMTokenList.h"
+#include "Document.h"
+#include "ElementChildIterator.h"
+#include "EventHandler.h"
+#include "EventLoop.h"
+#include "FloatSize.h"
+#include "GeometryUtilities.h"
+#include "HTMLBRElement.h"
+#include "HTMLDivElement.h"
+#include "HTMLMediaElement.h"
+#include "HTMLStyleElement.h"
+#include "MediaControlsHost.h"
+#include "Page.h"
+#include "Quirks.h"
+#include "RenderImage.h"
+#include "ShadowRoot.h"
+#include "SimpleRange.h"
+#include "Text.h"
+#include "TextRecognitionResult.h"
+#include "UserAgentStyleSheets.h"
+#include <wtf/Range.h>
+#include <wtf/WeakPtr.h>
+#include <wtf/text/AtomString.h>
+
+#if ENABLE(DATA_DETECTION)
+#include "DataDetection.h"
+#endif
+
+namespace WebCore {
+namespace ImageOverlay {
+
+static const AtomString& imageOverlayElementIdentifier()
+{
+    static MainThreadNeverDestroyed<const AtomString> identifier("image-overlay", AtomString::ConstructFromLiteral);
+    return identifier;
+}
+
+static const AtomString& imageOverlayDataDetectorClassName()
+{
+    static MainThreadNeverDestroyed<const AtomString> className("image-overlay-data-detector-result", AtomString::ConstructFromLiteral);
+    return className;
+}
+
+bool hasOverlay(const HTMLElement& element)
+{
+    auto shadowRoot = element.shadowRoot();
+    if (LIKELY(!shadowRoot || shadowRoot->mode() != ShadowRootMode::UserAgent))
+        return false;
+
+    return shadowRoot->hasElementWithId(*imageOverlayElementIdentifier().impl());
+}
+
+static RefPtr<HTMLElement> imageOverlayHost(const Node& node)
+{
+    auto host = node.shadowHost();
+    if (!is<HTMLElement>(host))
+        return nullptr;
+
+    RefPtr element { &downcast<HTMLElement>(*host) };
+    return hasOverlay(*element) ? element : nullptr;
+}
+
+bool isDataDetectorResult(const HTMLElement& element)
+{
+    return imageOverlayHost(element) && element.hasClass() && element.classNames().contains(imageOverlayDataDetectorClassName());
+}
+
+bool isInsideOverlay(const SimpleRange& range)
+{
+    RefPtr commonAncestor = commonInclusiveAncestor<ComposedTree>(range);
+    if (!commonAncestor)
+        return false;
+
+    return isInsideOverlay(*commonAncestor);
+}
+
+bool isInsideOverlay(const Node& node)
+{
+    auto host = imageOverlayHost(node);
+    if (!host)
+        return false;
+
+    return host->userAgentShadowRoot()->contains(node);
+}
+
+bool isOverlayText(const Node* node)
+{
+    return node && isOverlayText(*node);
+}
+
+bool isOverlayText(const Node& node)
+{
+    auto host = imageOverlayHost(node);
+    if (!host)
+        return false;
+
+    if (RefPtr overlay = static_cast<TreeScope&>(*host->userAgentShadowRoot()).getElementById(imageOverlayElementIdentifier()))
+        return node.isDescendantOf(*overlay);
+
+    return false;
+}
+
+void removeOverlaySoonIfNeeded(HTMLElement& element)
+{
+    if (!hasOverlay(element))
+        return;
+
+    element.document().eventLoop().queueTask(TaskSource::InternalAsyncTask, [weakElement = WeakPtr { element }] {
+        RefPtr protectedElement = weakElement.get();
+        if (!protectedElement)
+            return;
+
+        RefPtr shadowRoot = protectedElement->userAgentShadowRoot();
+        if (!shadowRoot)
+            return;
+
+        if (RefPtr overlay = static_cast<TreeScope&>(*shadowRoot).getElementById(imageOverlayElementIdentifier()))
+            overlay->remove();
+
+#if ENABLE(IMAGE_ANALYSIS)
+        if (auto page = protectedElement->document().page())
+            page->resetTextRecognitionResult(*protectedElement);
+#endif
+    });
+}
+
+#if ENABLE(IMAGE_ANALYSIS)
+
+IntRect containerRect(HTMLElement& element)
+{
+    auto* renderer = element.renderer();
+    if (!is<RenderImage>(renderer))
+        return { };
+
+    if (!renderer->opacity())
+        return { 0, 0, element.offsetWidth(), element.offsetHeight() };
+
+    return enclosingIntRect(downcast<RenderImage>(*renderer).replacedContentRect());
+}
+
+void updateWithTextRecognitionResult(HTMLElement& element, const TextRecognitionResult& result, CacheTextRecognitionResults cacheTextRecognitionResults)
+{
+    static MainThreadNeverDestroyed<const AtomString> imageOverlayLineClass("image-overlay-line", AtomString::ConstructFromLiteral);
+    static MainThreadNeverDestroyed<const AtomString> imageOverlayTextClass("image-overlay-text", AtomString::ConstructFromLiteral);
+
+    struct TextRecognitionLineElements {
+        Ref<HTMLDivElement> line;
+        Vector<Ref<HTMLElement>> children;
+    };
+
+    struct TextRecognitionElements {
+        RefPtr<HTMLDivElement> root;
+        Vector<TextRecognitionLineElements> lines;
+        Vector<Ref<HTMLDivElement>> dataDetectors;
+    };
+
+    bool hadExistingTextRecognitionElements = false;
+    TextRecognitionElements textRecognitionElements;
+    RefPtr<HTMLElement> mediaControlsContainer;
+    if (RefPtr shadowRoot = element.shadowRoot()) {
+#if ENABLE(MODERN_MEDIA_CONTROLS)
+        if (is<HTMLMediaElement>(element)) {
+            if (RefPtr controlsHost = downcast<HTMLMediaElement>(element).mediaControlsHost()) {
+                auto& containerClass = controlsHost->mediaControlsContainerClassName();
+                for (auto& child : childrenOfType<HTMLDivElement>(*shadowRoot)) {
+                    if (child.hasClass() && child.classNames().contains(containerClass)) {
+                        mediaControlsContainer = &child;
+                        break;
+                    }
+                }
+            }
+        }
+#endif
+        if (hasOverlay(element)) {
+            RefPtr<ContainerNode> containerForImageOverlay;
+            if (mediaControlsContainer)
+                containerForImageOverlay = mediaControlsContainer;
+            else
+                containerForImageOverlay = shadowRoot;
+            for (auto& child : childrenOfType<HTMLDivElement>(*containerForImageOverlay)) {
+                if (child.getIdAttribute() == imageOverlayElementIdentifier()) {
+                    textRecognitionElements.root = &child;
+                    hadExistingTextRecognitionElements = true;
+                    continue;
+                }
+            }
+        }
+    }
+
+    if (textRecognitionElements.root) {
+        for (auto& lineOrDataDetector : childrenOfType<HTMLDivElement>(*textRecognitionElements.root)) {
+            if (!lineOrDataDetector.hasClass())
+                continue;
+
+            if (lineOrDataDetector.classList().contains(imageOverlayLineClass)) {
+                TextRecognitionLineElements lineElements { lineOrDataDetector, { } };
+                for (auto& text : childrenOfType<HTMLDivElement>(lineOrDataDetector))
+                    lineElements.children.append(text);
+                textRecognitionElements.lines.append(WTFMove(lineElements));
+            } else if (lineOrDataDetector.classList().contains(imageOverlayDataDetectorClassName()))
+                textRecognitionElements.dataDetectors.append(lineOrDataDetector);
+        }
+
+        bool canUseExistingTextRecognitionElements = ([&] {
+            if (result.dataDetectors.size() != textRecognitionElements.dataDetectors.size())
+                return false;
+
+            if (result.lines.size() != textRecognitionElements.lines.size())
+                return false;
+
+            for (size_t lineIndex = 0; lineIndex < result.lines.size(); ++lineIndex) {
+                auto& childResults = result.lines[lineIndex].children;
+                auto& childTextElements = textRecognitionElements.lines[lineIndex].children;
+                if (childResults.size() != childTextElements.size())
+                    return false;
+
+                for (size_t childIndex = 0; childIndex < childResults.size(); ++childIndex) {
+                    if (childResults[childIndex].text != childTextElements[childIndex]->textContent().stripWhiteSpace())
+                        return false;
+                }
+            }
+
+            return true;
+        })();
+
+        if (!canUseExistingTextRecognitionElements) {
+            textRecognitionElements.root->remove();
+            textRecognitionElements = { };
+        }
+    }
+
+    if (result.isEmpty())
+        return;
+
+    Ref document = element.document();
+    Ref shadowRoot = element.ensureUserAgentShadowRoot();
+    if (!textRecognitionElements.root) {
+        auto rootContainer = HTMLDivElement::create(document.get());
+        rootContainer->setIdAttribute(imageOverlayElementIdentifier());
+        if (document->isImageDocument())
+            rootContainer->setInlineStyleProperty(CSSPropertyWebkitUserSelect, CSSValueText);
+
+        if (mediaControlsContainer)
+            mediaControlsContainer->appendChild(rootContainer);
+        else
+            shadowRoot->appendChild(rootContainer);
+        textRecognitionElements.root = rootContainer.copyRef();
+        textRecognitionElements.lines.reserveInitialCapacity(result.lines.size());
+        for (auto& line : result.lines) {
+            auto lineContainer = HTMLDivElement::create(document.get());
+            lineContainer->classList().add(imageOverlayLineClass);
+            rootContainer->appendChild(lineContainer);
+            TextRecognitionLineElements lineElements { lineContainer, { } };
+            lineElements.children.reserveInitialCapacity(line.children.size());
+            for (size_t childIndex = 0; childIndex < line.children.size(); ++childIndex) {
+                auto& child = line.children[childIndex];
+                auto textContainer = HTMLDivElement::create(document.get());
+                textContainer->classList().add(imageOverlayTextClass);
+                lineContainer->appendChild(textContainer);
+                textContainer->appendChild(Text::create(document.get(), child.hasLeadingWhitespace ? makeString('\n', child.text) : child.text));
+                lineElements.children.uncheckedAppend(WTFMove(textContainer));
+            }
+
+            lineContainer->appendChild(HTMLBRElement::create(document.get()));
+            textRecognitionElements.lines.uncheckedAppend(WTFMove(lineElements));
+        }
+
+#if ENABLE(DATA_DETECTION)
+        textRecognitionElements.dataDetectors.reserveInitialCapacity(result.dataDetectors.size());
+        for (auto& dataDetector : result.dataDetectors) {
+            auto dataDetectorContainer = DataDetection::createElementForImageOverlay(document.get(), dataDetector);
+            dataDetectorContainer->classList().add(imageOverlayDataDetectorClassName());
+            rootContainer->appendChild(dataDetectorContainer);
+            textRecognitionElements.dataDetectors.uncheckedAppend(WTFMove(dataDetectorContainer));
+        }
+#endif // ENABLE(DATA_DETECTION)
+
+        if (document->quirks().needsToForceUserSelectWhenInstallingImageOverlay())
+            element.setInlineStyleProperty(CSSPropertyWebkitUserSelect, CSSValueText);
+    }
+
+    if (!hadExistingTextRecognitionElements) {
+        static MainThreadNeverDestroyed<const String> shadowStyle(StringImpl::createWithoutCopying(imageOverlayUserAgentStyleSheet, sizeof(imageOverlayUserAgentStyleSheet)));
+        auto style = HTMLStyleElement::create(HTMLNames::styleTag, document.get(), false);
+        style->setTextContent(shadowStyle);
+        shadowRoot->appendChild(WTFMove(style));
+    }
+
+    document->updateLayoutIgnorePendingStylesheets();
+
+    auto* renderer = element.renderer();
+    if (!is<RenderImage>(renderer))
+        return;
+
+    downcast<RenderImage>(*renderer).setHasImageOverlay();
+
+    auto containerRect = ImageOverlay::containerRect(element);
+    auto convertToContainerCoordinates = [&](const FloatQuad& normalizedQuad) {
+        auto quad = normalizedQuad;
+        quad.scale(containerRect.width(), containerRect.height());
+        quad.move(containerRect.x(), containerRect.y());
+        return quad;
+    };
+
+    bool applyUserSelectAll = document->isImageDocument() || renderer->style().userSelect() != UserSelect::None;
+    for (size_t lineIndex = 0; lineIndex < result.lines.size(); ++lineIndex) {
+        auto& lineElements = textRecognitionElements.lines[lineIndex];
+        auto& lineContainer = lineElements.line;
+        auto& line = result.lines[lineIndex];
+        auto lineQuad = convertToContainerCoordinates(line.normalizedQuad);
+        if (lineQuad.isEmpty())
+            continue;
+
+        auto lineBounds = rotatedBoundingRectWithMinimumAngleOfRotation(lineQuad, 0.01);
+        lineContainer->setInlineStyleProperty(CSSPropertyWidth, lineBounds.size.width(), CSSUnitType::CSS_PX);
+        lineContainer->setInlineStyleProperty(CSSPropertyHeight, lineBounds.size.height(), CSSUnitType::CSS_PX);
+        lineContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
+            "translate("_s,
+            std::round(lineBounds.center.x() - (lineBounds.size.width() / 2)), "px, "_s,
+            std::round(lineBounds.center.y() - (lineBounds.size.height() / 2)), "px) "_s,
+            lineBounds.angleInRadians ? makeString("rotate("_s, lineBounds.angleInRadians, "rad) "_s) : emptyString()
+        ));
+
+        auto offsetAlongHorizontalAxis = [&](const FloatPoint& quadPoint1, const FloatPoint& quadPoint2) {
+            auto intervalLength = lineBounds.size.width();
+            auto mid = midPoint(quadPoint1, quadPoint2);
+            mid.moveBy(-lineBounds.center);
+            mid.rotate(-lineBounds.angleInRadians);
+            return intervalLength * clampTo<float>(0.5 + mid.x() / intervalLength, 0, 1);
+        };
+
+        auto offsetsAlongHorizontalAxis = line.children.map([&](auto& child) -> WTF::Range<float> {
+            auto textQuad = convertToContainerCoordinates(child.normalizedQuad);
+            return {
+                offsetAlongHorizontalAxis(textQuad.p1(), textQuad.p4()),
+                offsetAlongHorizontalAxis(textQuad.p2(), textQuad.p3())
+            };
+        });
+
+        for (size_t childIndex = 0; childIndex < line.children.size(); ++childIndex) {
+            auto& textContainer = lineElements.children[childIndex];
+            bool lineHasOneChild = line.children.size() == 1;
+            float horizontalMarginToMinimizeSelectionGaps = lineHasOneChild ? 0 : 0.125;
+            float horizontalOffset = lineHasOneChild ? 0 : -horizontalMarginToMinimizeSelectionGaps;
+            float horizontalExtent = lineHasOneChild ? 0 : horizontalMarginToMinimizeSelectionGaps;
+
+            if (lineHasOneChild) {
+                horizontalOffset += offsetsAlongHorizontalAxis[childIndex].begin();
+                horizontalExtent += offsetsAlongHorizontalAxis[childIndex].end();
+            } else if (!childIndex) {
+                horizontalOffset += offsetsAlongHorizontalAxis[childIndex].begin();
+                horizontalExtent += (offsetsAlongHorizontalAxis[childIndex].end() + offsetsAlongHorizontalAxis[childIndex + 1].begin()) / 2;
+            } else if (childIndex == line.children.size() - 1) {
+                horizontalOffset += (offsetsAlongHorizontalAxis[childIndex - 1].end() + offsetsAlongHorizontalAxis[childIndex].begin()) / 2;
+                horizontalExtent += offsetsAlongHorizontalAxis[childIndex].end();
+            } else {
+                horizontalOffset += (offsetsAlongHorizontalAxis[childIndex - 1].end() + offsetsAlongHorizontalAxis[childIndex].begin()) / 2;
+                horizontalExtent += (offsetsAlongHorizontalAxis[childIndex].end() + offsetsAlongHorizontalAxis[childIndex + 1].begin()) / 2;
+            }
+
+            FloatSize targetSize { horizontalExtent - horizontalOffset, lineBounds.size.height() };
+            if (targetSize.isEmpty()) {
+                textContainer->setInlineStyleProperty(CSSPropertyTransform, "scale(0, 0)");
+                continue;
+            }
+
+            document->updateLayoutIfDimensionsOutOfDate(textContainer);
+
+            FloatSize sizeBeforeTransform;
+            if (auto* renderer = textContainer->renderBoxModelObject()) {
+                sizeBeforeTransform = {
+                    adjustLayoutUnitForAbsoluteZoom(renderer->offsetWidth(), *renderer).toFloat(),
+                    adjustLayoutUnitForAbsoluteZoom(renderer->offsetHeight(), *renderer).toFloat(),
+                };
+            }
+
+            if (sizeBeforeTransform.isEmpty()) {
+                textContainer->setInlineStyleProperty(CSSPropertyTransform, "scale(0, 0)");
+                continue;
+            }
+
+            textContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
+                "translate("_s,
+                horizontalOffset + (targetSize.width() - sizeBeforeTransform.width()) / 2, "px, "_s,
+                (targetSize.height() - sizeBeforeTransform.height()) / 2, "px) "_s,
+                "scale("_s, targetSize.width() / sizeBeforeTransform.width(), ", "_s, targetSize.height() / sizeBeforeTransform.height(), ") "_s
+            ));
+
+            textContainer->setInlineStyleProperty(CSSPropertyWebkitUserSelect, applyUserSelectAll ? CSSValueAll : CSSValueNone);
+        }
+
+        if (document->isImageDocument())
+            lineContainer->setInlineStyleProperty(CSSPropertyCursor, CSSValueText);
+    }
+
+#if ENABLE(DATA_DETECTION)
+    for (size_t index = 0; index < result.dataDetectors.size(); ++index) {
+        auto dataDetectorContainer = textRecognitionElements.dataDetectors[index];
+        auto& dataDetector = result.dataDetectors[index];
+        if (dataDetector.normalizedQuads.isEmpty())
+            continue;
+
+        // FIXME: We should come up with a way to coalesce the bounding quads into one or more rotated rects with the same angle of rotation.
+        auto targetQuad = convertToContainerCoordinates(dataDetector.normalizedQuads.first());
+        auto targetBounds = rotatedBoundingRectWithMinimumAngleOfRotation(targetQuad, 0.01);
+        dataDetectorContainer->setInlineStyleProperty(CSSPropertyWidth, targetBounds.size.width(), CSSUnitType::CSS_PX);
+        dataDetectorContainer->setInlineStyleProperty(CSSPropertyHeight, targetBounds.size.height(), CSSUnitType::CSS_PX);
+        dataDetectorContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
+            "translate("_s,
+            std::round(targetBounds.center.x() - (targetBounds.size.width() / 2)), "px, "_s,
+            std::round(targetBounds.center.y() - (targetBounds.size.height() / 2)), "px) "_s,
+            targetBounds.angleInRadians ? makeString("rotate("_s, targetBounds.angleInRadians, "rad) "_s) : emptyString()
+        ));
+    }
+#endif // ENABLE(DATA_DETECTION)
+
+    if (RefPtr frame = document->frame())
+        frame->eventHandler().scheduleCursorUpdate();
+
+    if (cacheTextRecognitionResults == CacheTextRecognitionResults::Yes) {
+        if (auto* page = document->page())
+            page->cacheTextRecognitionResult(element, containerRect, result);
+    }
+}
+
+#endif // ENABLE(IMAGE_ANALYSIS)
+
+} // namespace ImageOverlay
+} // namespace WebCore

Added: trunk/Source/WebCore/dom/ImageOverlay.h (0 => 285655)


--- trunk/Source/WebCore/dom/ImageOverlay.h	                        (rev 0)
+++ trunk/Source/WebCore/dom/ImageOverlay.h	2021-11-11 21:52:01 UTC (rev 285655)
@@ -0,0 +1,56 @@
+/*
+ * 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 "IntRect.h"
+
+namespace WebCore {
+
+class HTMLElement;
+class Node;
+
+struct SimpleRange;
+struct TextRecognitionResult;
+
+namespace ImageOverlay {
+
+WEBCORE_EXPORT bool hasOverlay(const HTMLElement&);
+WEBCORE_EXPORT bool isDataDetectorResult(const HTMLElement&);
+WEBCORE_EXPORT bool isInsideOverlay(const SimpleRange&);
+WEBCORE_EXPORT bool isInsideOverlay(const Node&);
+WEBCORE_EXPORT bool isOverlayText(const Node&);
+WEBCORE_EXPORT bool isOverlayText(const Node*);
+void removeOverlaySoonIfNeeded(HTMLElement&);
+IntRect containerRect(HTMLElement&);
+
+#if ENABLE(IMAGE_ANALYSIS)
+enum class CacheTextRecognitionResults : bool { No, Yes };
+WEBCORE_EXPORT void updateWithTextRecognitionResult(HTMLElement&, const TextRecognitionResult&, CacheTextRecognitionResults = CacheTextRecognitionResults::Yes);
+#endif
+
+} // namespace ImageOverlay
+
+} // namespace WebCore

Modified: trunk/Source/WebCore/editing/Editor.cpp (285654 => 285655)


--- trunk/Source/WebCore/editing/Editor.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/editing/Editor.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -74,6 +74,7 @@
 #include "HTMLSpanElement.h"
 #include "HTMLUListElement.h"
 #include "HitTestResult.h"
+#include "ImageOverlay.h"
 #include "IndentOutdentCommand.h"
 #include "InputEvent.h"
 #include "InsertListCommand.h"
@@ -1426,7 +1427,7 @@
         updateMarkersForWordsAffectedByEditing(true);
     }
 
-    if (enclosingTextFormControl(m_document.selection().selection().start()) || (selection && HTMLElement::isInsideImageOverlay(*selection)))
+    if (enclosingTextFormControl(m_document.selection().selection().start()) || (selection && ImageOverlay::isInsideOverlay(*selection)))
         Pasteboard::createForCopyAndPaste(PagePasteboardContext::create(m_document.pageID()))->writePlainText(selectedTextForDataTransfer(), canSmartCopyOrDelete() ? Pasteboard::CanSmartReplace : Pasteboard::CannotSmartReplace);
     else {
         RefPtr<HTMLImageElement> imageElement;
@@ -3679,7 +3680,7 @@
     if (Ref startNode = range.startContainer(); startNode->hasEditableStyle())
         return { };
 
-    if (HTMLElement::isInsideImageOverlay(range))
+    if (ImageOverlay::isInsideOverlay(range))
         return { };
 
     auto text = plainText(range);

Modified: trunk/Source/WebCore/editing/FrameSelection.cpp (285654 => 285655)


--- trunk/Source/WebCore/editing/FrameSelection.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/editing/FrameSelection.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -52,6 +52,7 @@
 #include "HTMLSelectElement.h"
 #include "HitTestRequest.h"
 #include "HitTestResult.h"
+#include "ImageOverlay.h"
 #include "InlineRunAndOffset.h"
 #include "LegacyInlineTextBox.h"
 #include "Logging.h"
@@ -1917,7 +1918,7 @@
     if (!innerNode || !innerNode->renderer())
         return false;
 
-    if (HTMLElement::isInsideImageOverlay(*range) && HTMLElement::isInsideImageOverlay(*innerNode)) {
+    if (ImageOverlay::isInsideOverlay(*range) && ImageOverlay::isInsideOverlay(*innerNode)) {
         for (auto quad : RenderObject::absoluteTextQuads(*range, { RenderObject::BoundingRectBehavior::UseSelectionHeight })) {
             if (!quad.isEmpty() && quad.containsPoint(point))
                 return true;

Modified: trunk/Source/WebCore/editing/TextIterator.cpp (285654 => 285655)


--- trunk/Source/WebCore/editing/TextIterator.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/editing/TextIterator.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -45,6 +45,7 @@
 #include "HTMLSlotElement.h"
 #include "HTMLTextAreaElement.h"
 #include "HTMLTextFormControlElement.h"
+#include "ImageOverlay.h"
 #include "LegacyInlineTextBox.h"
 #include "NodeTraversal.h"
 #include "Range.h"
@@ -737,7 +738,7 @@
         }
     }
 
-    if (m_behaviors.contains(TextIteratorBehavior::EntersImageOverlays) && is<HTMLElement>(m_node) && downcast<HTMLElement>(*m_node).hasImageOverlay()) {
+    if (m_behaviors.contains(TextIteratorBehavior::EntersImageOverlays) && is<HTMLElement>(m_node) && ImageOverlay::hasOverlay(downcast<HTMLElement>(*m_node))) {
         if (RefPtr shadowRoot = m_node->shadowRoot()) {
             m_node = shadowRoot.get();
             pushFullyClippedState(m_fullyClippedStack, *m_node);

Modified: trunk/Source/WebCore/html/HTMLElement.cpp (285654 => 285655)


--- trunk/Source/WebCore/html/HTMLElement.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/html/HTMLElement.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -44,11 +44,9 @@
 #include "Frame.h"
 #include "FrameLoader.h"
 #include "FrameView.h"
-#include "GeometryUtilities.h"
 #include "HTMLBDIElement.h"
 #include "HTMLBRElement.h"
 #include "HTMLButtonElement.h"
-#include "HTMLDivElement.h"
 #include "HTMLDocument.h"
 #include "HTMLElementFactory.h"
 #include "HTMLFieldSetElement.h"
@@ -60,13 +58,12 @@
 #include "HTMLOptionElement.h"
 #include "HTMLParserIdioms.h"
 #include "HTMLSelectElement.h"
-#include "HTMLStyleElement.h"
 #include "HTMLTextAreaElement.h"
 #include "HTMLTextFormControlElement.h"
+#include "ImageOverlay.h"
 #include "MediaControlsHost.h"
 #include "NodeTraversal.h"
 #include "RenderElement.h"
-#include "RenderImage.h"
 #include "ScriptController.h"
 #include "ScriptDisallowedScope.h"
 #include "ShadowRoot.h"
@@ -83,18 +80,10 @@
 #include <wtf/text/CString.h>
 #include <wtf/text/StringBuilder.h>
 
-#if ENABLE(IMAGE_ANALYSIS)
-#include "TextRecognitionResult.h"
-#endif
-
 #if PLATFORM(IOS_FAMILY)
 #include "SelectionGeometry.h"
 #endif
 
-#if ENABLE(DATA_DETECTION)
-#include "DataDetection.h"
-#endif
-
 namespace WebCore {
 
 WTF_MAKE_ISO_ALLOCATED_IMPL(HTMLElement);
@@ -1253,417 +1242,19 @@
     setAttributeWithoutSynchronization(enterkeyhintAttr, value);
 }
 
-// FIXME: We should move all of this image overlay-specific logic out into a separate helper file (possibly as standalone functions)
-// to better compartmentalize this code.
-
-static const AtomString& imageOverlayElementIdentifier()
-{
-    static MainThreadNeverDestroyed<const AtomString> identifier("image-overlay", AtomString::ConstructFromLiteral);
-    return identifier;
-}
-
-static const AtomString& imageOverlayDataDetectorClassName()
-{
-    static MainThreadNeverDestroyed<const AtomString> className("image-overlay-data-detector-result", AtomString::ConstructFromLiteral);
-    return className;
-}
-
 bool HTMLElement::shouldExtendSelectionToTargetNode(const Node& targetNode, const VisibleSelection& selectionBeforeUpdate)
 {
-    if (auto range = selectionBeforeUpdate.range(); range && isInsideImageOverlay(*range))
-        return isImageOverlayText(targetNode);
+    if (auto range = selectionBeforeUpdate.range(); range && ImageOverlay::isInsideOverlay(*range))
+        return ImageOverlay::isOverlayText(targetNode);
 
     return true;
 }
 
-bool HTMLElement::hasImageOverlay() const
-{
-    auto shadowRoot = this->shadowRoot();
-    if (LIKELY(!shadowRoot || shadowRoot->mode() != ShadowRootMode::UserAgent))
-        return false;
-
-    return shadowRoot->hasElementWithId(*imageOverlayElementIdentifier().impl());
-}
-
-static RefPtr<HTMLElement> imageOverlayHost(const Node& node)
-{
-    auto host = node.shadowHost();
-    if (!is<HTMLElement>(host))
-        return nullptr;
-
-    RefPtr element { &downcast<HTMLElement>(*host) };
-    return element->hasImageOverlay() ? element : nullptr;
-}
-
-bool HTMLElement::isImageOverlayDataDetectorResult() const
-{
-    return imageOverlayHost(*this) && hasClass() && classNames().contains(imageOverlayDataDetectorClassName());
-}
-
-bool HTMLElement::isInsideImageOverlay(const SimpleRange& range)
-{
-    RefPtr commonAncestor = commonInclusiveAncestor<ComposedTree>(range);
-    if (!commonAncestor)
-        return false;
-
-    return isInsideImageOverlay(*commonAncestor);
-}
-
-bool HTMLElement::isInsideImageOverlay(const Node& node)
-{
-    auto host = imageOverlayHost(node);
-    if (!host)
-        return false;
-
-    return host->userAgentShadowRoot()->contains(node);
-}
-
-bool HTMLElement::isImageOverlayText(const Node* node)
-{
-    return node && isImageOverlayText(*node);
-}
-
-bool HTMLElement::isImageOverlayText(const Node& node)
-{
-    auto host = imageOverlayHost(node);
-    if (!host)
-        return false;
-
-    if (RefPtr overlay = static_cast<TreeScope&>(*host->userAgentShadowRoot()).getElementById(imageOverlayElementIdentifier()))
-        return node.isDescendantOf(*overlay);
-
-    return false;
-}
-
-void HTMLElement::removeImageOverlaySoonIfNeeded()
-{
-    if (!hasImageOverlay())
-        return;
-
-    document().eventLoop().queueTask(TaskSource::InternalAsyncTask, [weakThis = WeakPtr { *this }] {
-        RefPtr protectedThis = weakThis.get();
-        if (!protectedThis)
-            return;
-
-        RefPtr shadowRoot = protectedThis->userAgentShadowRoot();
-        if (!shadowRoot)
-            return;
-
-        if (RefPtr overlay = static_cast<TreeScope&>(*shadowRoot).getElementById(imageOverlayElementIdentifier()))
-            overlay->remove();
-
-#if ENABLE(IMAGE_ANALYSIS)
-        if (auto page = protectedThis->document().page())
-            page->resetTextRecognitionResult(*protectedThis);
-#endif
-    });
-}
-
-#if ENABLE(IMAGE_ANALYSIS)
-
-IntRect HTMLElement::containerRectForTextRecognition()
-{
-    auto* renderer = this->renderer();
-    if (!is<RenderImage>(renderer))
-        return { };
-
-    if (!renderer->opacity())
-        return { 0, 0, offsetWidth(), offsetHeight() };
-
-    return enclosingIntRect(downcast<RenderImage>(*renderer).replacedContentRect());
-}
-
-void HTMLElement::updateWithTextRecognitionResult(const TextRecognitionResult& result, CacheTextRecognitionResults cacheTextRecognitionResults)
-{
-    static MainThreadNeverDestroyed<const AtomString> imageOverlayLineClass("image-overlay-line", AtomString::ConstructFromLiteral);
-    static MainThreadNeverDestroyed<const AtomString> imageOverlayTextClass("image-overlay-text", AtomString::ConstructFromLiteral);
-
-    struct TextRecognitionLineElements {
-        Ref<HTMLDivElement> line;
-        Vector<Ref<HTMLElement>> children;
-    };
-
-    struct TextRecognitionElements {
-        RefPtr<HTMLDivElement> root;
-        Vector<TextRecognitionLineElements> lines;
-        Vector<Ref<HTMLDivElement>> dataDetectors;
-    };
-
-    bool hadExistingTextRecognitionElements = false;
-    TextRecognitionElements textRecognitionElements;
-    RefPtr<HTMLElement> mediaControlsContainer;
-    if (RefPtr shadowRoot = this->shadowRoot()) {
-#if ENABLE(MODERN_MEDIA_CONTROLS)
-        if (is<HTMLMediaElement>(*this)) {
-            if (RefPtr controlsHost = downcast<HTMLMediaElement>(*this).mediaControlsHost()) {
-                auto& containerClass = controlsHost->mediaControlsContainerClassName();
-                for (auto& child : childrenOfType<HTMLDivElement>(*shadowRoot)) {
-                    if (child.hasClass() && child.classNames().contains(containerClass)) {
-                        mediaControlsContainer = &child;
-                        break;
-                    }
-                }
-            }
-        }
-#endif
-        if (hasImageOverlay()) {
-            RefPtr<ContainerNode> containerForImageOverlay;
-            if (mediaControlsContainer)
-                containerForImageOverlay = mediaControlsContainer;
-            else
-                containerForImageOverlay = shadowRoot;
-            for (auto& child : childrenOfType<HTMLDivElement>(*containerForImageOverlay)) {
-                if (child.getIdAttribute() == imageOverlayElementIdentifier()) {
-                    textRecognitionElements.root = &child;
-                    hadExistingTextRecognitionElements = true;
-                    continue;
-                }
-            }
-        }
-    }
-
-    if (textRecognitionElements.root) {
-        for (auto& lineOrDataDetector : childrenOfType<HTMLDivElement>(*textRecognitionElements.root)) {
-            if (!lineOrDataDetector.hasClass())
-                continue;
-
-            if (lineOrDataDetector.classList().contains(imageOverlayLineClass)) {
-                TextRecognitionLineElements lineElements { lineOrDataDetector, { } };
-                for (auto& text : childrenOfType<HTMLDivElement>(lineOrDataDetector))
-                    lineElements.children.append(text);
-                textRecognitionElements.lines.append(WTFMove(lineElements));
-            } else if (lineOrDataDetector.classList().contains(imageOverlayDataDetectorClassName()))
-                textRecognitionElements.dataDetectors.append(lineOrDataDetector);
-        }
-
-        bool canUseExistingTextRecognitionElements = ([&] {
-            if (result.dataDetectors.size() != textRecognitionElements.dataDetectors.size())
-                return false;
-
-            if (result.lines.size() != textRecognitionElements.lines.size())
-                return false;
-
-            for (size_t lineIndex = 0; lineIndex < result.lines.size(); ++lineIndex) {
-                auto& childResults = result.lines[lineIndex].children;
-                auto& childTextElements = textRecognitionElements.lines[lineIndex].children;
-                if (childResults.size() != childTextElements.size())
-                    return false;
-
-                for (size_t childIndex = 0; childIndex < childResults.size(); ++childIndex) {
-                    if (childResults[childIndex].text != childTextElements[childIndex]->textContent().stripWhiteSpace())
-                        return false;
-                }
-            }
-
-            return true;
-        })();
-
-        if (!canUseExistingTextRecognitionElements) {
-            textRecognitionElements.root->remove();
-            textRecognitionElements = { };
-        }
-    }
-
-    if (result.isEmpty())
-        return;
-
-    Ref shadowRoot = ensureUserAgentShadowRoot();
-    if (!textRecognitionElements.root) {
-        auto rootContainer = HTMLDivElement::create(document());
-        rootContainer->setIdAttribute(imageOverlayElementIdentifier());
-        if (document().isImageDocument())
-            rootContainer->setInlineStyleProperty(CSSPropertyWebkitUserSelect, CSSValueText);
-
-        if (mediaControlsContainer)
-            mediaControlsContainer->appendChild(rootContainer);
-        else
-            shadowRoot->appendChild(rootContainer);
-        textRecognitionElements.root = rootContainer.copyRef();
-        textRecognitionElements.lines.reserveInitialCapacity(result.lines.size());
-        for (auto& line : result.lines) {
-            auto lineContainer = HTMLDivElement::create(document());
-            lineContainer->classList().add(imageOverlayLineClass);
-            rootContainer->appendChild(lineContainer);
-            TextRecognitionLineElements lineElements { lineContainer, { } };
-            lineElements.children.reserveInitialCapacity(line.children.size());
-            for (size_t childIndex = 0; childIndex < line.children.size(); ++childIndex) {
-                auto& child = line.children[childIndex];
-                auto textContainer = HTMLDivElement::create(document());
-                textContainer->classList().add(imageOverlayTextClass);
-                lineContainer->appendChild(textContainer);
-                textContainer->appendChild(Text::create(document(), child.hasLeadingWhitespace ? makeString('\n', child.text) : child.text));
-                lineElements.children.uncheckedAppend(WTFMove(textContainer));
-            }
-
-            lineContainer->appendChild(HTMLBRElement::create(document()));
-            textRecognitionElements.lines.uncheckedAppend(WTFMove(lineElements));
-        }
-
-#if ENABLE(DATA_DETECTION)
-        textRecognitionElements.dataDetectors.reserveInitialCapacity(result.dataDetectors.size());
-        for (auto& dataDetector : result.dataDetectors) {
-            auto dataDetectorContainer = DataDetection::createElementForImageOverlay(document(), dataDetector);
-            dataDetectorContainer->classList().add(imageOverlayDataDetectorClassName());
-            rootContainer->appendChild(dataDetectorContainer);
-            textRecognitionElements.dataDetectors.uncheckedAppend(WTFMove(dataDetectorContainer));
-        }
-#endif // ENABLE(DATA_DETECTION)
-
-        if (document().quirks().needsToForceUserSelectWhenInstallingImageOverlay())
-            setInlineStyleProperty(CSSPropertyWebkitUserSelect, CSSValueText);
-    }
-
-    if (!hadExistingTextRecognitionElements) {
-        static MainThreadNeverDestroyed<const String> shadowStyle(StringImpl::createWithoutCopying(imageOverlayUserAgentStyleSheet, sizeof(imageOverlayUserAgentStyleSheet)));
-        auto style = HTMLStyleElement::create(HTMLNames::styleTag, document(), false);
-        style->setTextContent(shadowStyle);
-        shadowRoot->appendChild(WTFMove(style));
-    }
-
-    document().updateLayoutIgnorePendingStylesheets();
-
-    auto* renderer = this->renderer();
-    if (!is<RenderImage>(renderer))
-        return;
-
-    downcast<RenderImage>(*renderer).setHasImageOverlay();
-
-    auto containerRect = containerRectForTextRecognition();
-    auto convertToContainerCoordinates = [&](const FloatQuad& normalizedQuad) {
-        auto quad = normalizedQuad;
-        quad.scale(containerRect.width(), containerRect.height());
-        quad.move(containerRect.x(), containerRect.y());
-        return quad;
-    };
-
-    bool applyUserSelectAll = document().isImageDocument() || renderer->style().userSelect() != UserSelect::None;
-    for (size_t lineIndex = 0; lineIndex < result.lines.size(); ++lineIndex) {
-        auto& lineElements = textRecognitionElements.lines[lineIndex];
-        auto& lineContainer = lineElements.line;
-        auto& line = result.lines[lineIndex];
-        auto lineQuad = convertToContainerCoordinates(line.normalizedQuad);
-        if (lineQuad.isEmpty())
-            continue;
-
-        auto lineBounds = rotatedBoundingRectWithMinimumAngleOfRotation(lineQuad, 0.01);
-        lineContainer->setInlineStyleProperty(CSSPropertyWidth, lineBounds.size.width(), CSSUnitType::CSS_PX);
-        lineContainer->setInlineStyleProperty(CSSPropertyHeight, lineBounds.size.height(), CSSUnitType::CSS_PX);
-        lineContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
-            "translate("_s,
-            std::round(lineBounds.center.x() - (lineBounds.size.width() / 2)), "px, "_s,
-            std::round(lineBounds.center.y() - (lineBounds.size.height() / 2)), "px) "_s,
-            lineBounds.angleInRadians ? makeString("rotate("_s, lineBounds.angleInRadians, "rad) "_s) : emptyString()
-        ));
-
-        auto offsetAlongHorizontalAxis = [&](const FloatPoint& quadPoint1, const FloatPoint& quadPoint2) {
-            auto intervalLength = lineBounds.size.width();
-            auto mid = midPoint(quadPoint1, quadPoint2);
-            mid.moveBy(-lineBounds.center);
-            mid.rotate(-lineBounds.angleInRadians);
-            return intervalLength * clampTo<float>(0.5 + mid.x() / intervalLength, 0, 1);
-        };
-
-        auto offsetsAlongHorizontalAxis = line.children.map([&](auto& child) -> WTF::Range<float> {
-            auto textQuad = convertToContainerCoordinates(child.normalizedQuad);
-            return {
-                offsetAlongHorizontalAxis(textQuad.p1(), textQuad.p4()),
-                offsetAlongHorizontalAxis(textQuad.p2(), textQuad.p3())
-            };
-        });
-
-        for (size_t childIndex = 0; childIndex < line.children.size(); ++childIndex) {
-            auto& textContainer = lineElements.children[childIndex];
-            bool lineHasOneChild = line.children.size() == 1;
-            float horizontalMarginToMinimizeSelectionGaps = lineHasOneChild ? 0 : 0.125;
-            float horizontalOffset = lineHasOneChild ? 0 : -horizontalMarginToMinimizeSelectionGaps;
-            float horizontalExtent = lineHasOneChild ? 0 : horizontalMarginToMinimizeSelectionGaps;
-
-            if (lineHasOneChild) {
-                horizontalOffset += offsetsAlongHorizontalAxis[childIndex].begin();
-                horizontalExtent += offsetsAlongHorizontalAxis[childIndex].end();
-            } else if (!childIndex) {
-                horizontalOffset += offsetsAlongHorizontalAxis[childIndex].begin();
-                horizontalExtent += (offsetsAlongHorizontalAxis[childIndex].end() + offsetsAlongHorizontalAxis[childIndex + 1].begin()) / 2;
-            } else if (childIndex == line.children.size() - 1) {
-                horizontalOffset += (offsetsAlongHorizontalAxis[childIndex - 1].end() + offsetsAlongHorizontalAxis[childIndex].begin()) / 2;
-                horizontalExtent += offsetsAlongHorizontalAxis[childIndex].end();
-            } else {
-                horizontalOffset += (offsetsAlongHorizontalAxis[childIndex - 1].end() + offsetsAlongHorizontalAxis[childIndex].begin()) / 2;
-                horizontalExtent += (offsetsAlongHorizontalAxis[childIndex].end() + offsetsAlongHorizontalAxis[childIndex + 1].begin()) / 2;
-            }
-
-            FloatSize targetSize { horizontalExtent - horizontalOffset, lineBounds.size.height() };
-            if (targetSize.isEmpty()) {
-                textContainer->setInlineStyleProperty(CSSPropertyTransform, "scale(0, 0)");
-                continue;
-            }
-
-            document().updateLayoutIfDimensionsOutOfDate(textContainer);
-
-            FloatSize sizeBeforeTransform;
-            if (auto* renderer = textContainer->renderBoxModelObject()) {
-                sizeBeforeTransform = {
-                    adjustLayoutUnitForAbsoluteZoom(renderer->offsetWidth(), *renderer).toFloat(),
-                    adjustLayoutUnitForAbsoluteZoom(renderer->offsetHeight(), *renderer).toFloat(),
-                };
-            }
-
-            if (sizeBeforeTransform.isEmpty()) {
-                textContainer->setInlineStyleProperty(CSSPropertyTransform, "scale(0, 0)");
-                continue;
-            }
-
-            textContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
-                "translate("_s,
-                horizontalOffset + (targetSize.width() - sizeBeforeTransform.width()) / 2, "px, "_s,
-                (targetSize.height() - sizeBeforeTransform.height()) / 2, "px) "_s,
-                "scale("_s, targetSize.width() / sizeBeforeTransform.width(), ", "_s, targetSize.height() / sizeBeforeTransform.height(), ") "_s
-            ));
-
-            textContainer->setInlineStyleProperty(CSSPropertyWebkitUserSelect, applyUserSelectAll ? CSSValueAll : CSSValueNone);
-        }
-
-        if (document().isImageDocument())
-            lineContainer->setInlineStyleProperty(CSSPropertyCursor, CSSValueText);
-    }
-
-#if ENABLE(DATA_DETECTION)
-    for (size_t index = 0; index < result.dataDetectors.size(); ++index) {
-        auto dataDetectorContainer = textRecognitionElements.dataDetectors[index];
-        auto& dataDetector = result.dataDetectors[index];
-        if (dataDetector.normalizedQuads.isEmpty())
-            continue;
-
-        // FIXME: We should come up with a way to coalesce the bounding quads into one or more rotated rects with the same angle of rotation.
-        auto targetQuad = convertToContainerCoordinates(dataDetector.normalizedQuads.first());
-        auto targetBounds = rotatedBoundingRectWithMinimumAngleOfRotation(targetQuad, 0.01);
-        dataDetectorContainer->setInlineStyleProperty(CSSPropertyWidth, targetBounds.size.width(), CSSUnitType::CSS_PX);
-        dataDetectorContainer->setInlineStyleProperty(CSSPropertyHeight, targetBounds.size.height(), CSSUnitType::CSS_PX);
-        dataDetectorContainer->setInlineStyleProperty(CSSPropertyTransform, makeString(
-            "translate("_s,
-            std::round(targetBounds.center.x() - (targetBounds.size.width() / 2)), "px, "_s,
-            std::round(targetBounds.center.y() - (targetBounds.size.height() / 2)), "px) "_s,
-            targetBounds.angleInRadians ? makeString("rotate("_s, targetBounds.angleInRadians, "rad) "_s) : emptyString()
-        ));
-    }
-#endif // ENABLE(DATA_DETECTION)
-
-    if (RefPtr frame = document().frame())
-        frame->eventHandler().scheduleCursorUpdate();
-
-    if (cacheTextRecognitionResults == CacheTextRecognitionResults::Yes) {
-        if (auto* page = document().page())
-            page->cacheTextRecognitionResult(*this, containerRect, result);
-    }
-}
-
-#endif // ENABLE(IMAGE_ANALYSIS)
-
 #if PLATFORM(IOS_FAMILY)
 
 SelectionRenderingBehavior HTMLElement::selectionRenderingBehavior(const Node* node)
 {
-    return isImageOverlayText(node) ? SelectionRenderingBehavior::UseIndividualQuads : SelectionRenderingBehavior::CoalesceBoundingRects;
+    return ImageOverlay::isOverlayText(node) ? SelectionRenderingBehavior::UseIndividualQuads : SelectionRenderingBehavior::CoalesceBoundingRects;
 }
 
 #endif // PLATFORM(IOS_FAMILY)

Modified: trunk/Source/WebCore/html/HTMLElement.h (285654 => 285655)


--- trunk/Source/WebCore/html/HTMLElement.h	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/html/HTMLElement.h	2021-11-11 21:52:01 UTC (rev 285655)
@@ -132,20 +132,7 @@
     void setEnterKeyHint(const String& value);
 
     WEBCORE_EXPORT static bool shouldExtendSelectionToTargetNode(const Node& targetNode, const VisibleSelection& selectionBeforeUpdate);
-    WEBCORE_EXPORT bool hasImageOverlay() const;
-    WEBCORE_EXPORT bool isImageOverlayDataDetectorResult() const;
-    WEBCORE_EXPORT static bool isInsideImageOverlay(const SimpleRange&);
-    WEBCORE_EXPORT static bool isInsideImageOverlay(const Node&);
-    WEBCORE_EXPORT static bool isImageOverlayText(const Node&);
-    WEBCORE_EXPORT static bool isImageOverlayText(const Node*);
-    void removeImageOverlaySoonIfNeeded();
 
-#if ENABLE(IMAGE_ANALYSIS)
-    IntRect containerRectForTextRecognition();
-    enum class CacheTextRecognitionResults : bool { No, Yes };
-    WEBCORE_EXPORT void updateWithTextRecognitionResult(const TextRecognitionResult&, CacheTextRecognitionResults = CacheTextRecognitionResults::Yes);
-#endif
-
 #if PLATFORM(IOS_FAMILY)
     static SelectionRenderingBehavior selectionRenderingBehavior(const Node*);
 #endif

Modified: trunk/Source/WebCore/html/HTMLMediaElement.cpp (285654 => 285655)


--- trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/html/HTMLMediaElement.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -61,6 +61,7 @@
 #include "HTMLSourceElement.h"
 #include "HTMLTrackElement.h"
 #include "HTMLVideoElement.h"
+#include "ImageOverlay.h"
 #include "InbandGenericTextTrack.h"
 #include "InbandTextTrackPrivate.h"
 #include "InbandWebVTTTextTrack.h"
@@ -3140,7 +3141,7 @@
     if (processingUserGestureForMedia())
         mediaSession().removeBehaviorRestriction(MediaElementSession::RequireUserGestureToControlControlsManager);
 
-    removeImageOverlaySoonIfNeeded();
+    ImageOverlay::removeOverlaySoonIfNeeded(*this);
 }
 
 void HTMLMediaElement::seekTask()
@@ -3734,7 +3735,7 @@
     m_autoplaying = false;
     updatePlayState();
 
-    removeImageOverlaySoonIfNeeded();
+    ImageOverlay::removeOverlaySoonIfNeeded(*this);
 }
 
 void HTMLMediaElement::pause()

Modified: trunk/Source/WebCore/page/ContextMenuController.cpp (285654 => 285655)


--- trunk/Source/WebCore/page/ContextMenuController.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/ContextMenuController.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -51,6 +51,7 @@
 #include "HTMLFormControlElement.h"
 #include "HTMLFormElement.h"
 #include "HitTestResult.h"
+#include "ImageOverlay.h"
 #include "InspectorController.h"
 #include "LocalizedStrings.h"
 #include "MouseEvent.h"
@@ -943,7 +944,7 @@
         }
 
         auto selectedRange = frame->selection().selection().range();
-        bool selectionIsInsideImageOverlay = selectedRange && HTMLElement::isInsideImageOverlay(*selectedRange);
+        bool selectionIsInsideImageOverlay = selectedRange && ImageOverlay::isInsideOverlay(*selectedRange);
         bool shouldShowItemsForNonEditableText = ([&] {
             if (!linkURL.isEmpty())
                 return false;

Modified: trunk/Source/WebCore/page/DragController.cpp (285654 => 285655)


--- trunk/Source/WebCore/page/DragController.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/DragController.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -67,6 +67,7 @@
 #include "HitTestResult.h"
 #include "Image.h"
 #include "ImageOrientation.h"
+#include "ImageOverlay.h"
 #include "Model.h"
 #include "MoveSelectionCommand.h"
 #include "Page.h"
@@ -799,7 +800,7 @@
 #endif
 
     auto selectionDragElement = state.type.contains(DragSourceAction::Selection) && m_dragSourceAction.contains(DragSourceAction::Selection) ? startElement : nullptr;
-    if (HTMLElement::isImageOverlayText(startElement))
+    if (ImageOverlay::isOverlayText(startElement))
         return selectionDragElement;
 
     for (auto* element = startElement; element; element = element->parentOrShadowHostElement()) {
@@ -1041,7 +1042,7 @@
             src.editor().willWriteSelectionToPasteboard(*selectionRange);
             auto selection = src.selection().selection();
             bool shouldDragAsPlainText = enclosingTextFormControl(selection.start());
-            if (auto range = selection.range(); range && HTMLElement::isInsideImageOverlay(*range))
+            if (auto range = selection.range(); range && ImageOverlay::isInsideOverlay(*range))
                 shouldDragAsPlainText = true;
 
             if (shouldDragAsPlainText) {

Modified: trunk/Source/WebCore/page/EventHandler.cpp (285654 => 285655)


--- trunk/Source/WebCore/page/EventHandler.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/EventHandler.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -69,6 +69,7 @@
 #include "HitTestRequest.h"
 #include "HitTestResult.h"
 #include "Image.h"
+#include "ImageOverlay.h"
 #include "ImageOverlayController.h"
 #include "InspectorInstrumentation.h"
 #include "KeyboardEvent.h"
@@ -449,7 +450,7 @@
 
 static Node* nodeToSelectOnMouseDownForNode(Node& targetNode)
 {
-    if (HTMLElement::isInsideImageOverlay(targetNode))
+    if (ImageOverlay::isInsideOverlay(targetNode))
         return nullptr;
 
     if (RefPtr rootUserSelectAll = Position::rootUserSelectAllForNode(&targetNode))
@@ -720,7 +721,7 @@
     if (!node || !node->renderer())
         return true;
 
-    if (HTMLElement::isImageOverlayText(*node))
+    if (ImageOverlay::isOverlayText(*node))
         return node->renderer()->style().userSelectIncludingInert() != UserSelect::None;
 
     return node->canStartSelection() || Position::nodeIsUserSelectAll(node.get());
@@ -766,7 +767,7 @@
     // Bug: https://bugs.webkit.org/show_bug.cgi?id=155390
 
     // Single mouse down on links or images can always trigger drag-n-drop.
-    bool isImageOverlayText = HTMLElement::isImageOverlayText(event.targetNode());
+    bool isImageOverlayText = ImageOverlay::isOverlayText(event.targetNode());
     bool isMouseDownOnLinkOrImage = event.isOverLink() || (event.hitTestResult().image() && !isImageOverlayText);
     m_mouseDownMayStartDrag = singleClick && (!event.event().shiftKey() || isMouseDownOnLinkOrImage) && shouldAllowMouseDownToStartDrag();
 #endif
@@ -1023,7 +1024,7 @@
     m_frame.selection().setSelectionByMouseIfDifferent(newSelection, m_frame.selection().granularity(),
         FrameSelection::EndPointsAdjustmentMode::AdjustAtBidiBoundary);
 
-    if (oldSelection != newSelection && HTMLElement::isImageOverlayText(newSelection.start().containerNode()) && HTMLElement::isImageOverlayText(newSelection.end().containerNode()))
+    if (oldSelection != newSelection && ImageOverlay::isOverlayText(newSelection.start().containerNode()) && ImageOverlay::isOverlayText(newSelection.end().containerNode()))
         invalidateClick();
 }
 #endif // ENABLE(DRAG_SUPPORT)
@@ -1200,7 +1201,7 @@
 
     RefPtr innerNode = result.innerNode();
     if (request.disallowsUserAgentShadowContent()
-        || (request.disallowsUserAgentShadowContentExceptForImageOverlays() && innerNode && !HTMLElement::isInsideImageOverlay(*innerNode)))
+        || (request.disallowsUserAgentShadowContentExceptForImageOverlays() && innerNode && !ImageOverlay::isInsideOverlay(*innerNode)))
         result.setToNonUserAgentShadowAncestor();
 
     return result;
@@ -1521,7 +1522,7 @@
 
     switch (style ? style->cursor() : CursorType::Auto) {
     case CursorType::Auto: {
-        if (HTMLElement::isImageOverlayText(node.get())) {
+        if (ImageOverlay::isOverlayText(node.get())) {
             auto* renderer = node->renderer();
             if (renderer && renderer->style().userSelectIncludingInert() != UserSelect::None)
                 return iBeam;

Modified: trunk/Source/WebCore/page/ImageOverlayController.cpp (285654 => 285655)


--- trunk/Source/WebCore/page/ImageOverlayController.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/ImageOverlayController.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -34,6 +34,7 @@
 #include "FrameSelection.h"
 #include "GraphicsContext.h"
 #include "HTMLElement.h"
+#include "ImageOverlay.h"
 #include "IntRect.h"
 #include "LayoutRect.h"
 #include "Page.h"
@@ -71,7 +72,7 @@
         if (!selectedRange)
             return nullptr;
 
-        if (!HTMLElement::isInsideImageOverlay(*selectedRange))
+        if (!ImageOverlay::isInsideOverlay(*selectedRange))
             return nullptr;
 
         if (RefPtr host = selectedRange->startContainer().shadowHost(); is<HTMLElement>(host))

Modified: trunk/Source/WebCore/page/Page.cpp (285654 => 285655)


--- trunk/Source/WebCore/page/Page.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/Page.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -76,6 +76,7 @@
 #include "HistoryController.h"
 #include "HistoryItem.h"
 #include "IDBConnectionToServer.h"
+#include "ImageOverlay.h"
 #include "ImageOverlayController.h"
 #include "InspectorClient.h"
 #include "InspectorController.h"
@@ -3723,7 +3724,7 @@
             continue;
 
         auto& [result, containerRect] = entry.value;
-        auto newContainerRect = protectedElement->containerRectForTextRecognition();
+        auto newContainerRect = ImageOverlay::containerRect(protectedElement.get());
         if (containerRect == newContainerRect)
             continue;
 
@@ -3733,11 +3734,8 @@
 
     for (auto& [element, result] : elementsToUpdate) {
         element->document().eventLoop().queueTask(TaskSource::InternalAsyncTask, [result = TextRecognitionResult { result }, weakElement = WeakPtr { element }] {
-            RefPtr element { weakElement.get() };
-            if (!element)
-                return;
-
-            element->updateWithTextRecognitionResult(result, HTMLElement::CacheTextRecognitionResults::No);
+            if (RefPtr element = weakElement.get())
+                ImageOverlay::updateWithTextRecognitionResult(*element, result, ImageOverlay::CacheTextRecognitionResults::No);
         });
     }
 }

Modified: trunk/Source/WebCore/page/mac/ImageOverlayControllerMac.mm (285654 => 285655)


--- trunk/Source/WebCore/page/mac/ImageOverlayControllerMac.mm	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/page/mac/ImageOverlayControllerMac.mm	2021-11-11 21:52:01 UTC (rev 285655)
@@ -35,6 +35,7 @@
 #import "FrameView.h"
 #import "HTMLElement.h"
 #import "HTMLNames.h"
+#import "ImageOverlay.h"
 #import "ImageOverlayDataDetectionResultIdentifier.h"
 #import "IntRect.h"
 #import "Page.h"
@@ -50,7 +51,7 @@
 
 void ImageOverlayController::updateDataDetectorHighlights(const HTMLElement& overlayHost)
 {
-    if (!overlayHost.hasImageOverlay()) {
+    if (!ImageOverlay::hasOverlay(overlayHost)) {
         ASSERT_NOT_REACHED();
         clearDataDetectorHighlights();
         return;
@@ -58,7 +59,7 @@
 
     Vector<Ref<HTMLElement>> dataDetectorResultElements;
     for (auto& child : descendantsOfType<HTMLElement>(*overlayHost.userAgentShadowRoot())) {
-        if (child.isImageOverlayDataDetectorResult() && child.renderer())
+        if (ImageOverlay::isDataDetectorResult(child) && child.renderer())
             dataDetectorResultElements.append(child);
     }
 
@@ -190,7 +191,7 @@
     if (!elementUnderMouse && m_hostElementForDataDetectors && frame.document() != &m_hostElementForDataDetectors->document())
         return;
 
-    if (!elementUnderMouse || !HTMLElement::isInsideImageOverlay(*elementUnderMouse)) {
+    if (!elementUnderMouse || !ImageOverlay::isInsideOverlay(*elementUnderMouse)) {
         m_hostElementForDataDetectors = nullptr;
         uninstallPageOverlayIfNeeded();
         return;
@@ -205,7 +206,7 @@
     }
 
     Ref imageOverlayHost = downcast<HTMLElement>(*shadowHost);
-    if (!imageOverlayHost->hasImageOverlay()) {
+    if (!ImageOverlay::hasOverlay(imageOverlayHost.get())) {
         ASSERT_NOT_REACHED();
         m_hostElementForDataDetectors = nullptr;
         uninstallPageOverlayIfNeeded();

Modified: trunk/Source/WebCore/rendering/HitTestResult.cpp (285654 => 285655)


--- trunk/Source/WebCore/rendering/HitTestResult.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/rendering/HitTestResult.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -38,6 +38,7 @@
 #include "HTMLParserIdioms.h"
 #include "HTMLTextAreaElement.h"
 #include "HTMLVideoElement.h"
+#include "ImageOverlay.h"
 #include "PseudoElement.h"
 #include "Range.h"
 #include "RenderBlockFlow.h"
@@ -332,7 +333,7 @@
     if (!m_innerNonSharedNode)
         return nullptr;
 
-    if (HTMLElement::isInsideImageOverlay(*m_innerNonSharedNode))
+    if (ImageOverlay::isInsideOverlay(*m_innerNonSharedNode))
         return m_innerNonSharedNode->shadowHost();
 
     return m_innerNonSharedNode;
@@ -653,7 +654,7 @@
         return HitTestProgress::Continue;
 
     if ((request.disallowsUserAgentShadowContent() && node->isInUserAgentShadowTree())
-        || (request.disallowsUserAgentShadowContentExceptForImageOverlays() && !HTMLElement::isInsideImageOverlay(*node) && node->isInUserAgentShadowTree()))
+        || (request.disallowsUserAgentShadowContentExceptForImageOverlays() && !ImageOverlay::isInsideOverlay(*node) && node->isInUserAgentShadowTree()))
         node = node->document().ancestorNodeInThisScope(node);
 
     mutableListBasedTestResult().add(*node);

Modified: trunk/Source/WebCore/rendering/RenderImage.cpp (285654 => 285655)


--- trunk/Source/WebCore/rendering/RenderImage.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/rendering/RenderImage.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -45,6 +45,7 @@
 #include "HTMLMapElement.h"
 #include "HTMLNames.h"
 #include "HitTestResult.h"
+#include "ImageOverlay.h"
 #include "InlineIteratorInlineBox.h"
 #include "InlineIteratorLine.h"
 #include "Page.h"
@@ -140,7 +141,7 @@
 RenderImage::RenderImage(Element& element, RenderStyle&& style, StyleImage* styleImage, const float imageDevicePixelRatio)
     : RenderReplaced(element, WTFMove(style), IntSize())
     , m_imageResource(styleImage ? makeUnique<RenderImageResourceStyleImage>(*styleImage) : makeUnique<RenderImageResource>())
-    , m_hasImageOverlay(is<HTMLElement>(element) && downcast<HTMLElement>(element).hasImageOverlay())
+    , m_hasImageOverlay(is<HTMLElement>(element) && ImageOverlay::hasOverlay(downcast<HTMLElement>(element)))
     , m_imageDevicePixelRatio(imageDevicePixelRatio)
 {
     updateAltText();

Modified: trunk/Source/WebCore/testing/Internals.cpp (285654 => 285655)


--- trunk/Source/WebCore/testing/Internals.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebCore/testing/Internals.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -111,6 +111,7 @@
 #include "HitTestResult.h"
 #include "IDBRequest.h"
 #include "IDBTransaction.h"
+#include "ImageOverlay.h"
 #include "InspectorClient.h"
 #include "InspectorController.h"
 #include "InspectorDebuggableType.h"
@@ -5807,7 +5808,7 @@
         return;
 
 #if ENABLE(IMAGE_ANALYSIS)
-    downcast<HTMLElement>(element).updateWithTextRecognitionResult(TextRecognitionResult {
+    ImageOverlay::updateWithTextRecognitionResult(downcast<HTMLElement>(element), TextRecognitionResult {
         lines.map([] (auto& line) -> TextRecognitionLineData {
             return makeDataForLine(line);
         })

Modified: trunk/Source/WebKit/ChangeLog (285654 => 285655)


--- trunk/Source/WebKit/ChangeLog	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/ChangeLog	2021-11-11 21:52:01 UTC (rev 285655)
@@ -1,3 +1,31 @@
+2021-11-11  Wenson Hsieh  <[email protected]>
+
+        Move image overlay code out of HTMLElement and into a separate helper file
+        https://bugs.webkit.org/show_bug.cgi?id=232974
+
+        Reviewed by Antti Koivisto.
+
+        See WebCore/ChangeLog for more details.
+
+        * WebProcess/WebPage/Cocoa/WebPageCocoa.mm:
+        (WebKit::WebPage::dictionaryPopupInfoForRange):
+        * WebProcess/WebPage/FindController.cpp:
+        (WebKit::FindController::updateFindIndicator):
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::editorState const):
+        (WebKit::WebPage::findDataDetectionResultElementInImageOverlay):
+        (WebKit::WebPage::requestTextRecognition):
+        (WebKit::WebPage::updateWithTextRecognitionResult):
+        * WebProcess/WebPage/ios/FindControllerIOS.mm:
+        (WebKit::findTextIndicatorOptions):
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::insideImageOverlay):
+        (WebKit::rangeForPointInRootViewCoordinates):
+        (WebKit::hostVideoElementIgnoringImageOverlay):
+        (WebKit::elementPositionInformation):
+        * WebProcess/WebPage/mac/WebPageMac.mm:
+        (WebKit::WebPage::performImmediateActionHitTestAtLocation):
+
 2021-11-11  Ben Nham  <[email protected]>
 
         Log memory usage metadata when WebContent crosses critical or warning level memory thresholds

Modified: trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm (285654 => 285655)


--- trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/Cocoa/WebPageCocoa.mm	2021-11-11 21:52:01 UTC (rev 285655)
@@ -47,6 +47,7 @@
 #import <WebCore/HTMLOListElement.h>
 #import <WebCore/HTMLUListElement.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/ImageOverlay.h>
 #import <WebCore/NetworkExtensionContentFilter.h>
 #import <WebCore/NodeRenderStyle.h>
 #import <WebCore/PaymentCoordinator.h>
@@ -200,7 +201,7 @@
 #endif // PLATFORM(MAC)
 
     OptionSet<TextIndicatorOption> indicatorOptions { TextIndicatorOption::UseBoundingRectAndPaintAllContentForComplexRanges };
-    if (HTMLElement::isInsideImageOverlay(range))
+    if (ImageOverlay::isInsideOverlay(range))
         indicatorOptions.add({ TextIndicatorOption::PaintAllContent, TextIndicatorOption::PaintBackgrounds });
 
     if (presentationTransition == TextIndicatorPresentationTransition::BounceAndCrossfade)

Modified: trunk/Source/WebKit/WebProcess/WebPage/FindController.cpp (285654 => 285655)


--- trunk/Source/WebKit/WebProcess/WebPage/FindController.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/FindController.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -40,6 +40,7 @@
 #include <WebCore/FrameSelection.h>
 #include <WebCore/FrameView.h>
 #include <WebCore/GraphicsContext.h>
+#include <WebCore/ImageOverlay.h>
 #include <WebCore/Page.h>
 #include <WebCore/PageOverlayController.h>
 #include <WebCore/PathUtilities.h>
@@ -374,7 +375,7 @@
 bool FindController::updateFindIndicator(Frame& selectedFrame, bool isShowingOverlay, bool shouldAnimate)
 {
     OptionSet<TextIndicatorOption> textIndicatorOptions { TextIndicatorOption::IncludeMarginIfRangeMatchesSelection };
-    if (auto selectedRange = selectedFrame.selection().selection().range(); selectedRange && HTMLElement::isInsideImageOverlay(*selectedRange))
+    if (auto selectedRange = selectedFrame.selection().selection().range(); selectedRange && ImageOverlay::isInsideOverlay(*selectedRange))
         textIndicatorOptions.add({ TextIndicatorOption::PaintAllContent, TextIndicatorOption::PaintBackgrounds });
 
     auto indicator = TextIndicator::createWithSelectionInFrame(selectedFrame, textIndicatorOptions, shouldAnimate ? TextIndicatorPresentationTransition::Bounce : TextIndicatorPresentationTransition::None);

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (285654 => 285655)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-11-11 21:52:01 UTC (rev 285655)
@@ -202,6 +202,7 @@
 #include <WebCore/HistoryController.h>
 #include <WebCore/HistoryItem.h>
 #include <WebCore/HitTestResult.h>
+#include <WebCore/ImageOverlay.h>
 #include <WebCore/InspectorController.h>
 #include <WebCore/JSDOMExceptionHandling.h>
 #include <WebCore/JSDOMWindow.h>
@@ -1213,7 +1214,7 @@
 
     if (result.selectionIsRange) {
         auto selectionRange = selection.range();
-        result.selectionIsRangeInsideImageOverlay = selectionRange && HTMLElement::isInsideImageOverlay(*selectionRange);
+        result.selectionIsRangeInsideImageOverlay = selectionRange && ImageOverlay::isInsideOverlay(*selectionRange);
     }
 
     m_lastEditorStateWasContentEditable = result.isContentEditable ? EditorStateIsContentEditable::Yes : EditorStateIsContentEditable::No;
@@ -4121,7 +4122,7 @@
 {
     Vector<Ref<HTMLElement>> dataDetectorElements;
     for (auto& child : descendantsOfType<HTMLElement>(*imageOverlayHost.shadowRoot())) {
-        if (child.isImageOverlayDataDetectorResult())
+        if (ImageOverlay::isDataDetectorResult(child))
             dataDetectorElements.append(child);
     }
 
@@ -7497,7 +7498,7 @@
     if (corePage()->hasCachedTextRecognitionResult(htmlElement.get())) {
         if (completion) {
             RefPtr<Element> imageOverlayHost;
-            if (htmlElement->hasImageOverlay())
+            if (ImageOverlay::hasOverlay(htmlElement.get()))
                 imageOverlayHost = &element;
             completion(WTFMove(imageOverlayHost));
         }
@@ -7564,7 +7565,7 @@
             return;
 
         auto& htmlElement = downcast<HTMLElement>(*protectedElement);
-        htmlElement.updateWithTextRecognitionResult(result);
+        ImageOverlay::updateWithTextRecognitionResult(htmlElement, result);
 
         auto matchIndex = protectedPage->m_elementsPendingTextRecognition.findMatching([&] (auto& elementAndCompletionHandlers) {
             return elementAndCompletionHandlers.first == &htmlElement;
@@ -7573,7 +7574,7 @@
         if (matchIndex == notFound)
             return;
 
-        RefPtr imageOverlayHost = htmlElement.hasImageOverlay() ? &htmlElement : nullptr;
+        RefPtr imageOverlayHost = ImageOverlay::hasOverlay(htmlElement) ? &htmlElement : nullptr;
         for (auto& completionHandler : protectedPage->m_elementsPendingTextRecognition[matchIndex].second)
             completionHandler(imageOverlayHost.copyRef());
 
@@ -7589,7 +7590,7 @@
         return;
     }
 
-    downcast<HTMLElement>(*elementToUpdate).updateWithTextRecognitionResult(result);
+    ImageOverlay::updateWithTextRecognitionResult(downcast<HTMLElement>(*elementToUpdate), result);
     auto hitTestResult = corePage()->mainFrame().eventHandler().hitTestResultAtPoint(roundedIntPoint(location), {
         HitTestRequest::Type::ReadOnly,
         HitTestRequest::Type::Active,
@@ -7598,7 +7599,7 @@
 
     RefPtr nodeAtLocation = hitTestResult.innerNonSharedNode();
     auto updateResult = ([&] {
-        if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate || !HTMLElement::isInsideImageOverlay(*nodeAtLocation))
+        if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate || !ImageOverlay::isInsideOverlay(*nodeAtLocation))
             return TextRecognitionUpdateResult::NoText;
 
 #if ENABLE(DATA_DETECTION)
@@ -7606,7 +7607,7 @@
             return TextRecognitionUpdateResult::DataDetector;
 #endif
 
-        if (HTMLElement::isImageOverlayText(*nodeAtLocation))
+        if (ImageOverlay::isOverlayText(*nodeAtLocation))
             return TextRecognitionUpdateResult::Text;
 
         return TextRecognitionUpdateResult::NoText;

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/FindControllerIOS.mm (285654 => 285655)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/FindControllerIOS.mm	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/FindControllerIOS.mm	2021-11-11 21:52:01 UTC (rev 285655)
@@ -38,6 +38,7 @@
 #import <WebCore/Frame.h>
 #import <WebCore/FrameView.h>
 #import <WebCore/GraphicsContext.h>
+#import <WebCore/ImageOverlay.h>
 #import <WebCore/Page.h>
 #import <WebCore/PageOverlayController.h>
 #import <WebCore/PathUtilities.h>
@@ -54,7 +55,7 @@
 static OptionSet<TextIndicatorOption> findTextIndicatorOptions(const Frame& frame)
 {
     OptionSet<TextIndicatorOption> options { TextIndicatorOption::IncludeMarginIfRangeMatchesSelection, TextIndicatorOption::DoNotClipToVisibleRect };
-    if (auto selectedRange = frame.selection().selection().range(); selectedRange && HTMLElement::isInsideImageOverlay(*selectedRange))
+    if (auto selectedRange = frame.selection().selection().range(); selectedRange && ImageOverlay::isInsideOverlay(*selectedRange))
         options.add({ TextIndicatorOption::PaintAllContent, TextIndicatorOption::PaintBackgrounds });
     return options;
 };

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


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-11-11 21:52:01 UTC (rev 285655)
@@ -108,6 +108,7 @@
 #import <WebCore/HTMLVideoElement.h>
 #import <WebCore/HistoryItem.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/ImageOverlay.h>
 #import <WebCore/InputMode.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/LibWebRTCProvider.h>
@@ -1349,7 +1350,7 @@
 static bool insideImageOverlay(const VisiblePosition& position)
 {
     RefPtr container = position.deepEquivalent().containerNode();
-    return container && HTMLElement::isInsideImageOverlay(*container);
+    return container && ImageOverlay::isInsideOverlay(*container);
 }
 
 static std::optional<SimpleRange> expandForImageOverlay(const SimpleRange& range)
@@ -1586,7 +1587,7 @@
             range = makeSimpleRange(result, selectionEnd);
     }
     
-    if (range && HTMLElement::isInsideImageOverlay(*range))
+    if (range && ImageOverlay::isInsideOverlay(*range))
         return { expandForImageOverlay(*range), SelectionWasFlipped::No };
 
     return { range, selectionFlipped };
@@ -2805,7 +2806,7 @@
 
 static RefPtr<HTMLVideoElement> hostVideoElementIgnoringImageOverlay(Node& node)
 {
-    if (HTMLElement::isInsideImageOverlay(node))
+    if (ImageOverlay::isInsideOverlay(node))
         return { };
 
     if (is<HTMLVideoElement>(node))
@@ -2858,7 +2859,7 @@
 
     info.isElement = true;
     info.idAttribute = element.getIdAttribute();
-    info.isImageOverlayText = HTMLElement::isImageOverlayText(innerNonSharedNode);
+    info.isImageOverlayText = ImageOverlay::isOverlayText(innerNonSharedNode);
 
     info.title = element.attributeWithoutSynchronization(HTMLNames::titleAttr).string();
     if (linkElement && info.title.isEmpty())
@@ -2907,7 +2908,7 @@
 
 #if ENABLE(DATA_DETECTION)
     if (info.isImageOverlayText && innerNonSharedNode->shadowHost() == &element && is<HTMLElement>(element)) {
-        if (Ref htmlElement = downcast<HTMLElement>(element); htmlElement->hasImageOverlay())
+        if (Ref htmlElement = downcast<HTMLElement>(element); ImageOverlay::hasOverlay(htmlElement.get()))
             dataDetectorImageOverlayPositionInformation(htmlElement.get(), request, info);
     }
 #endif

Modified: trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm (285654 => 285655)


--- trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm	2021-11-11 21:29:00 UTC (rev 285654)
+++ trunk/Source/WebKit/WebProcess/WebPage/mac/WebPageMac.mm	2021-11-11 21:52:01 UTC (rev 285655)
@@ -73,6 +73,7 @@
 #import <WebCore/HTMLConverter.h>
 #import <WebCore/HTMLPlugInImageElement.h>
 #import <WebCore/HitTestResult.h>
+#import <WebCore/ImageOverlay.h>
 #import <WebCore/KeyboardEvent.h>
 #import <WebCore/MIMETypeRegistry.h>
 #import <WebCore/NetworkStorageSession.h>
@@ -885,7 +886,7 @@
 
     auto indicatorOptions = [&](const SimpleRange& range) {
         OptionSet<TextIndicatorOption> options { TextIndicatorOption::UseBoundingRectAndPaintAllContentForComplexRanges };
-        if (HTMLElement::isInsideImageOverlay(range))
+        if (ImageOverlay::isInsideOverlay(range))
             options.add({ TextIndicatorOption::PaintAllContent, TextIndicatorOption::PaintBackgrounds });
         return options;
     };
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to