Add WebKit Legacy SPI to retrieve editable elements in rect
authordbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Nov 2019 20:50:02 +0000 (20:50 +0000)
committerdbates@webkit.org <dbates@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Nov 2019 20:50:02 +0000 (20:50 +0000)
https://bugs.webkit.org/show_bug.cgi?id=204006
<rdar://problem/57024093>

Reviewed by Wenson Hsieh.

Source/WebCore:

Extract code to retrieve the editable elements inside a specified rect from WebKit
to WebCore so that it can be shared by both Modern WebKit and Legacy WebKit.

* page/Page.cpp:
(WebCore::isEditableTextInputElement):
(WebCore::Page::editableElementsInRect const):
* page/Page.h:

Source/WebKit:

Write WebPage::textInputContextsInRect() in terms of Page::editableElementsInRect().
Also make use of Element::clientRect() instead of elementRectInRootViewCoordinates(),
which duplicates what the former does.

* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::textInputContextsInRect): Write in terms of Page::editableElementsInRect().
(WebKit::WebPage::contextForElement const): Use Element::clientRect() which does what
elementRectInRootViewCoordinates() does.
(WebKit::elementRectInRootViewCoordinates): Deleted.
(WebKit::isEditableTextInputElement): Deleted.

Source/WebKitLegacy/mac:

Add SPI to retrieve all the editable elements in a rect.

* WebView/WebView.mm:
(-[WebView _editableElementsInRect:]): Added.
* WebView/WebViewPrivate.h:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@252254 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebCore/ChangeLog
Source/WebCore/page/Page.cpp
Source/WebCore/page/Page.h
Source/WebKit/ChangeLog
Source/WebKit/WebProcess/WebPage/WebPage.cpp
Source/WebKitLegacy/mac/ChangeLog
Source/WebKitLegacy/mac/WebView/WebView.mm
Source/WebKitLegacy/mac/WebView/WebViewPrivate.h

index 4f2ca9a..96d5483 100644 (file)
@@ -1,3 +1,19 @@
+2019-11-08  Daniel Bates  <dabates@apple.com>
+
+        Add WebKit Legacy SPI to retrieve editable elements in rect
+        https://bugs.webkit.org/show_bug.cgi?id=204006
+        <rdar://problem/57024093>
+
+        Reviewed by Wenson Hsieh.
+
+        Extract code to retrieve the editable elements inside a specified rect from WebKit
+        to WebCore so that it can be shared by both Modern WebKit and Legacy WebKit.
+
+        * page/Page.cpp:
+        (WebCore::isEditableTextInputElement):
+        (WebCore::Page::editableElementsInRect const):
+        * page/Page.h:
+
 2019-11-08  Antoine Quint  <graouts@apple.com>
 
         [Web Animations] Use a keyframe effect stack to resolve animations on an element
index 38701dd..b146cac 100644 (file)
@@ -62,6 +62,8 @@
 #include "FullscreenManager.h"
 #include "HTMLElement.h"
 #include "HTMLMediaElement.h"
+#include "HTMLTextAreaElement.h"
+#include "HTMLTextFormControlElement.h"
 #include "HistoryController.h"
 #include "HistoryItem.h"
 #include "InspectorClient.h"
 #include "VoidCallback.h"
 #include "WheelEventDeltaFilter.h"
 #include "Widget.h"
+#include <wtf/Deque.h>
 #include <wtf/FileSystem.h>
 #include <wtf/RefCountedLeakCounter.h>
 #include <wtf/StdLibExtras.h>
@@ -912,6 +915,45 @@ void Page::unmarkAllTextMatches()
     } while (frame);
 }
 
+static bool isEditableTextInputElement(const Element& element)
+{
+    if (is<HTMLTextFormControlElement>(element)) {
+        if (!element.isTextField() && !is<HTMLTextAreaElement>(element))
+            return false;
+        return downcast<HTMLTextFormControlElement>(element).isInnerTextElementEditable();
+    }
+    return element.isRootEditableElement();
+}
+
+Vector<Ref<Element>> Page::editableElementsInRect(const FloatRect& searchRectInRootViewCoordinates) const
+{
+    Vector<Ref<Element>> result;
+    for (auto* frame = &mainFrame(); frame; frame = frame->tree().traverseNext()) {
+        auto* document = frame->document();
+        if (!document)
+            continue;
+
+        Deque<Node*> nodesToSearch;
+        nodesToSearch.append(document);
+        while (!nodesToSearch.isEmpty()) {
+            auto* node = nodesToSearch.takeFirst();
+
+            // It is possible to have nested text input contexts (e.g. <input type='text'> inside contenteditable) but
+            // in this case we just take the outermost context and skip the rest.
+            if (!is<Element>(node) || !isEditableTextInputElement(downcast<Element>(*node))) {
+                for (auto* child = node->firstChild(); child; child = child->nextSibling())
+                    nodesToSearch.append(child);
+                continue;
+            }
+
+            auto& element = downcast<Element>(*node);
+            if (searchRectInRootViewCoordinates.intersects(element.clientRect()))
+                result.append(element);
+        }
+    }
+    return result;
+}
+
 const VisibleSelection& Page::selection() const
 {
     return focusController().focusedOrMainFrame().selection().selection();
index ea2b7d2..b4f144e 100644 (file)
@@ -717,6 +717,8 @@ public:
 
     void configureLoggingChannel(const String&, WTFLogChannelState, WTFLogLevel);
 
+    WEBCORE_EXPORT Vector<Ref<Element>> editableElementsInRect(const FloatRect&) const;
+
 private:
     struct Navigation {
         RegistrableDomain domain;
index 275caf6..c8ac15d 100644 (file)
@@ -1,3 +1,22 @@
+2019-11-08  Daniel Bates  <dabates@apple.com>
+
+        Add WebKit Legacy SPI to retrieve editable elements in rect
+        https://bugs.webkit.org/show_bug.cgi?id=204006
+        <rdar://problem/57024093>
+
+        Reviewed by Wenson Hsieh.
+
+        Write WebPage::textInputContextsInRect() in terms of Page::editableElementsInRect().
+        Also make use of Element::clientRect() instead of elementRectInRootViewCoordinates(),
+        which duplicates what the former does.
+
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::textInputContextsInRect): Write in terms of Page::editableElementsInRect().
+        (WebKit::WebPage::contextForElement const): Use Element::clientRect() which does what
+        elementRectInRootViewCoordinates() does.
+        (WebKit::elementRectInRootViewCoordinates): Deleted.
+        (WebKit::isEditableTextInputElement): Deleted.
+
 2019-11-06  Jiewen Tan  <jiewen_tan@apple.com>
 
         [WebAuthn] Return NotAllowedError immediately for UI cancellations
index ff8f204..8247480 100644 (file)
 #include <WebCore/HTMLPlugInElement.h>
 #include <WebCore/HTMLPlugInImageElement.h>
 #include <WebCore/HTMLSelectElement.h>
-#include <WebCore/HTMLTextAreaElement.h>
 #include <WebCore/HTMLTextFormControlElement.h>
 #include <WebCore/HTMLUListElement.h>
 #include <WebCore/HistoryController.h>
@@ -6691,69 +6690,19 @@ void WebPage::updateInputContextAfterBlurringAndRefocusingElementIfNeeded(Elemen
 
 #endif // !PLATFORM(IOS_FAMILY)
 
-static IntRect elementRectInRootViewCoordinates(const Element& element, const Frame& frame)
-{
-    auto* view = frame.view();
-    if (!view)
-        return { };
-
-    auto* renderer = element.renderer();
-    if (!renderer)
-        return { };
-
-    return view->contentsToRootView(renderer->absoluteBoundingBoxRect());
-}
-
-static bool isEditableTextInputElement(Element& element)
-{
-    if (is<HTMLTextFormControlElement>(element)) {
-        if (!element.isTextField() && !is<HTMLTextAreaElement>(element))
-            return false;
-        return downcast<HTMLTextFormControlElement>(element).isInnerTextElementEditable();
-    }
-
-    return element.isRootEditableElement();
-}
-
 void WebPage::textInputContextsInRect(WebCore::FloatRect searchRect, CompletionHandler<void(const Vector<WebCore::ElementContext>&)>&& completionHandler)
 {
-    Vector<WebCore::ElementContext> textInputContexts;
-
-    for (Frame* frame = &m_page->mainFrame(); frame; frame = frame->tree().traverseNext()) {
-        Document* document = frame->document();
-        if (!document)
-            continue;
-
-        Deque<Node*> nodesToSearch;
-        nodesToSearch.append(document);
-        while (!nodesToSearch.isEmpty()) {
-            auto node = nodesToSearch.takeFirst();
-
-            // It is possible to have nested text input contexts (e.g. <input type='text'> inside contenteditable) but
-            // in this case we just take the outermost context and skip the rest.
-            if (!is<Element>(*node) || !isEditableTextInputElement(downcast<Element>(*node))) {
-                for (auto* child = node->firstChild(); child; child = child->nextSibling())
-                    nodesToSearch.append(child);
-                continue;
-            }
-
-            auto& element = downcast<Element>(*node);
+    auto contexts = m_page->editableElementsInRect(searchRect).map([&] (const auto& element) {
+        auto& document = element->document();
 
-            IntRect elementRect = elementRectInRootViewCoordinates(element, *frame);
-            if (!searchRect.intersects(elementRect))
-                continue;
-
-            WebCore::ElementContext context;
-            context.webPageIdentifier = m_identifier;
-            context.documentIdentifier = document->identifier();
-            context.elementIdentifier = document->identifierForElement(element);
-            context.boundingRect = elementRect;
-
-            textInputContexts.append(context);
-        }
-    }
-
-    completionHandler(textInputContexts);
+        WebCore::ElementContext context;
+        context.webPageIdentifier = m_identifier;
+        context.documentIdentifier = document.identifier();
+        context.elementIdentifier = document.identifierForElement(element);
+        context.boundingRect = element->clientRect();
+        return context;
+    });
+    completionHandler(contexts);
 }
 
 void WebPage::focusTextInputContext(const WebCore::ElementContext& textInputContext, CompletionHandler<void(bool)>&& completionHandler)
@@ -6791,7 +6740,7 @@ Optional<WebCore::ElementContext> WebPage::contextForElement(WebCore::Element& e
     if (!frame)
         return WTF::nullopt;
 
-    return WebCore::ElementContext { elementRectInRootViewCoordinates(element, *frame), m_identifier, document.identifier(), document.identifierForElement(element) };
+    return WebCore::ElementContext { element.clientRect(), m_identifier, document.identifier(), document.identifierForElement(element) };
 }
 
 void WebPage::startTextManipulations(Vector<WebCore::TextManipulationController::ExclusionRule>&& exclusionRules, CompletionHandler<void()>&& completionHandler)
index 824b40f..30a3ef2 100644 (file)
@@ -1,3 +1,17 @@
+2019-11-08  Daniel Bates  <dabates@apple.com>
+
+        Add WebKit Legacy SPI to retrieve editable elements in rect
+        https://bugs.webkit.org/show_bug.cgi?id=204006
+        <rdar://problem/57024093>
+
+        Reviewed by Wenson Hsieh.
+
+        Add SPI to retrieve all the editable elements in a rect.
+
+        * WebView/WebView.mm:
+        (-[WebView _editableElementsInRect:]): Added.
+        * WebView/WebViewPrivate.h:
+
 2019-11-04  Alex Christensen  <achristensen@webkit.org>
 
         REGRESSION(r243947) Epson software updater fails to install new version
index cdff099..13efc27 100644 (file)
@@ -10131,6 +10131,7 @@ static NSTextAlignment nsTextAlignmentFromRenderStyle(const WebCore::RenderStyle
 @end
 
 #if PLATFORM(IOS_FAMILY)
+
 @implementation WebView (WebViewIOSPDF)
 
 + (Class)_getPDFRepresentationClass
@@ -10158,6 +10159,25 @@ static NSTextAlignment nsTextAlignmentFromRenderStyle(const WebCore::RenderStyle
 }
 
 @end
+
+@implementation WebView (WebViewIOSAdditions)
+
+- (NSArray<DOMElement *> *)_editableElementsInRect:(CGRect)rect
+{
+    auto* page = core(self);
+    if (!page)
+        return @[];
+    auto coreElements = page->editableElementsInRect(rect);
+    if (coreElements.isEmpty())
+        return @[];
+    auto result = adoptNS([[NSMutableArray alloc] initWithCapacity:coreElements.size()]);
+    for (auto& coreElement : coreElements)
+        [result addObject:kit(coreElement.ptr())];
+    return result.autorelease();
+}
+
+@end
+
 #endif
 
 @implementation WebView (WebViewFullScreen)
index 9874655..79d042b 100644 (file)
@@ -1075,6 +1075,7 @@ typedef struct WebEdgeInsets {
 @end
 
 #if TARGET_OS_IPHONE
+
 @interface WebView (WebViewIOSPDF)
 + (Class)_getPDFRepresentationClass;
 + (void)_setPDFRepresentationClass:(Class)pdfRepresentationClass;
@@ -1082,6 +1083,11 @@ typedef struct WebEdgeInsets {
 + (Class)_getPDFViewClass;
 + (void)_setPDFViewClass:(Class)pdfViewClass;
 @end
+
+@interface WebView (WebViewIOSAdditions)
+- (NSArray<DOMElement *> *)_editableElementsInRect:(CGRect)rect;
+@end
+
 #endif
 
 @interface NSObject (WebViewFrameLoadDelegatePrivate)