Title: [198738] trunk/Source
Revision
198738
Author
timo...@apple.com
Date
2016-03-28 08:57:23 -0700 (Mon, 28 Mar 2016)

Log Message

Web Automation: Add Automation protocol commands to resolve frames as handles

https://bugs.webkit.org/show_bug.cgi?id=155650
rdar://problem/25242422

Reviewed by Brian Burg.

Source/WebCore:

* page/DOMWindow.h: Marked focus() method as exported so WK2 can use them.
* page/FrameTree.h: Marked scopedChild() methods as exported so WK2 can use them.

Source/WebKit2:

* UIProcess/Automation/Automation.json:
Added resolveFrameHandle and resolveParentFrameHandle.

* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::webFrameProxyForHandle): Added.
(WebKit::WebAutomationSession::handleForWebFrameID): Added.
(WebKit::WebAutomationSession::handleForWebFrameProxy): Added.
(WebKit::WebAutomationSession::evaluateJavaScriptFunction): Use frame handles now.
(WebKit::WebAutomationSession::resolveChildFrameHandle): Added.
(WebKit::WebAutomationSession::didChildResolveFrame): Added.
(WebKit::WebAutomationSession::resolveParentFrameHandle): Added.
(WebKit::WebAutomationSession::didResolveParentFrame): Added.
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/Automation/WebAutomationSession.messages.in:
(DidResolveChildFrame): Added.
(DidResolveParentFrame): Added.

* WebProcess/Automation/WebAutomationSessionProxy.cpp:
(WebKit::WebAutomationSessionProxy::elementForNodeHandle): Added.
(WebKit::WebAutomationSessionProxy::resolveChildFrameWithOrdinal): Added.
(WebKit::WebAutomationSessionProxy::resolveChildFrameWithNodeHandle): Added.
(WebKit::WebAutomationSessionProxy::resolveChildFrameWithName): Added.
(WebKit::WebAutomationSessionProxy::resolveParentFrame): Added.
(WebKit::WebAutomationSessionProxy::focusFrame): Added.
* WebProcess/Automation/WebAutomationSessionProxy.h:
* WebProcess/Automation/WebAutomationSessionProxy.messages.in:
(ResolveChildFrameWithOrdinal): Added.
(ResolveChildFrameWithNodeHandle): Added.
(ResolveChildFrameWithName): Added.
(ResolveParentFrame): Added.
(FocusFrame): Added.

* WebProcess/Automation/WebAutomationSessionProxy.js:
(AutomationSessionProxy.prototype.nodeForIdentifier): Added.
Public method that eats the exception thrown by the private method.

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (198737 => 198738)


--- trunk/Source/WebCore/ChangeLog	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebCore/ChangeLog	2016-03-28 15:57:23 UTC (rev 198738)
@@ -1,3 +1,15 @@
+2016-03-18  Timothy Hatcher  <timo...@apple.com>
+
+        Web Automation: Add Automation protocol commands to resolve frames as handles
+
+        https://bugs.webkit.org/show_bug.cgi?id=155650
+        rdar://problem/25242422
+
+        Reviewed by Brian Burg.
+
+        * page/DOMWindow.h: Marked focus() method as exported so WK2 can use them.
+        * page/FrameTree.h: Marked scopedChild() methods as exported so WK2 can use them.
+
 2016-03-28  Konstantin Tokarev  <annu...@yandex.ru>
 
         Remove USE(TEXTURE_MAPPER) guards inside TextureMapper sources.

Modified: trunk/Source/WebCore/page/DOMWindow.h (198737 => 198738)


--- trunk/Source/WebCore/page/DOMWindow.h	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebCore/page/DOMWindow.h	2016-03-28 15:57:23 UTC (rev 198738)
@@ -160,7 +160,7 @@
 
         Element* frameElement() const;
 
-        void focus(bool allowFocus = false);
+        WEBCORE_EXPORT void focus(bool allowFocus = false);
         void focus(Document&);
         void blur();
         WEBCORE_EXPORT void close();

Modified: trunk/Source/WebCore/page/FrameTree.h (198737 => 198738)


--- trunk/Source/WebCore/page/FrameTree.h	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebCore/page/FrameTree.h	2016-03-28 15:57:23 UTC (rev 198738)
@@ -80,8 +80,8 @@
 
         WEBCORE_EXPORT Frame& top() const;
 
-        Frame* scopedChild(unsigned index) const;
-        Frame* scopedChild(const AtomicString& name) const;
+        WEBCORE_EXPORT Frame* scopedChild(unsigned index) const;
+        WEBCORE_EXPORT Frame* scopedChild(const AtomicString& name) const;
         unsigned scopedChildCount() const;
 
         unsigned indexInParent() const;

Modified: trunk/Source/WebKit2/ChangeLog (198737 => 198738)


--- trunk/Source/WebKit2/ChangeLog	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/ChangeLog	2016-03-28 15:57:23 UTC (rev 198738)
@@ -1,3 +1,48 @@
+2016-03-18  Timothy Hatcher  <timo...@apple.com>
+
+        Web Automation: Add Automation protocol commands to resolve frames as handles
+
+        https://bugs.webkit.org/show_bug.cgi?id=155650
+        rdar://problem/25242422
+
+        Reviewed by Brian Burg.
+
+        * UIProcess/Automation/Automation.json:
+        Added resolveFrameHandle and resolveParentFrameHandle.
+
+        * UIProcess/Automation/WebAutomationSession.cpp:
+        (WebKit::WebAutomationSession::webFrameProxyForHandle): Added.
+        (WebKit::WebAutomationSession::handleForWebFrameID): Added.
+        (WebKit::WebAutomationSession::handleForWebFrameProxy): Added.
+        (WebKit::WebAutomationSession::evaluateJavaScriptFunction): Use frame handles now.
+        (WebKit::WebAutomationSession::resolveChildFrameHandle): Added.
+        (WebKit::WebAutomationSession::didChildResolveFrame): Added.
+        (WebKit::WebAutomationSession::resolveParentFrameHandle): Added.
+        (WebKit::WebAutomationSession::didResolveParentFrame): Added.
+        * UIProcess/Automation/WebAutomationSession.h:
+        * UIProcess/Automation/WebAutomationSession.messages.in:
+        (DidResolveChildFrame): Added.
+        (DidResolveParentFrame): Added.
+
+        * WebProcess/Automation/WebAutomationSessionProxy.cpp:
+        (WebKit::WebAutomationSessionProxy::elementForNodeHandle): Added.
+        (WebKit::WebAutomationSessionProxy::resolveChildFrameWithOrdinal): Added.
+        (WebKit::WebAutomationSessionProxy::resolveChildFrameWithNodeHandle): Added.
+        (WebKit::WebAutomationSessionProxy::resolveChildFrameWithName): Added.
+        (WebKit::WebAutomationSessionProxy::resolveParentFrame): Added.
+        (WebKit::WebAutomationSessionProxy::focusFrame): Added.
+        * WebProcess/Automation/WebAutomationSessionProxy.h:
+        * WebProcess/Automation/WebAutomationSessionProxy.messages.in:
+        (ResolveChildFrameWithOrdinal): Added.
+        (ResolveChildFrameWithNodeHandle): Added.
+        (ResolveChildFrameWithName): Added.
+        (ResolveParentFrame): Added.
+        (FocusFrame): Added.
+
+        * WebProcess/Automation/WebAutomationSessionProxy.js:
+        (AutomationSessionProxy.prototype.nodeForIdentifier): Added.
+        Public method that eats the exception thrown by the private method.
+
 2016-03-17  Timothy Hatcher  <timo...@apple.com>
 
         Web Automation: Add Automation.evaluateJavaScriptFunction

Modified: trunk/Source/WebKit2/UIProcess/Automation/Automation.json (198737 => 198738)


--- trunk/Source/WebKit2/UIProcess/Automation/Automation.json	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/UIProcess/Automation/Automation.json	2016-03-28 15:57:23 UTC (rev 198738)
@@ -8,6 +8,16 @@
             "description": "An opaque identifier for a browsing context."
         },
         {
+            "id": "FrameHandle",
+            "type": "string",
+            "description": "An opaque identifier for a frame in a page."
+        },
+        {
+            "id": "NodeHandle",
+            "type": "string",
+            "description": "An opaque identifier for a node in a page."
+        },
+        {
             "id": "ErrorMessage",
             "type": "string",
             "description": "This enum contains predefined error messages that can be used to signal a well-defined error condition, such as a missing implementation, unknown window handle, and so forth. The backend signals one of these errors by using it as a prefix of the commands's error message (the errorString argument in generated C++ backend dispatchers). This will be reported to the frontend as a protocol error with a JSON-RPC error code of 'ServerError'. It is up to the frontend whether and how to deal with errors.",
@@ -15,8 +25,10 @@
                 "InternalError",
                 "_javascript_Error",
                 "WindowNotFound",
+                "FrameNotFound",
                 "NodeNotFound",
-                "NotImplemented"
+                "NotImplemented",
+                "MissingParameter"
             ]
         },
         {
@@ -64,9 +76,10 @@
         },
         {
             "name": "switchToBrowsingContext",
-            "description": "Activates the specified browsing context.",
+            "description": "Activates the specified browsing context and optional frame, which gives them focus (causing the 'focus' DOM event to fire, and 'blur' DOM event to fire for the previous browsing context and frame).",
             "parameters": [
-                { "name": "handle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context that should be made active." }
+                { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context that should be made focused." },
+                { "name": "frameHandle", "$ref": "FrameHandle", "optional": true, "description": "The handle for the frame that should be focused. Defaults to the main frame if omitted." }
             ]
         },
         {
@@ -102,8 +115,9 @@
             "name": "evaluateJavaScriptFunction",
             "description": "Evaluates a script function in a browsing context and calls it with the supplied arguments.",
             "parameters": [
-                { "name": "handle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context the script should be evaluated." },
-                { "name": "function", "type": "string", "description": "The script to evaluate in the browsing context. The script is expected to be a function declaration, or otherwise evaluate to a function result." },
+                { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context the script should be evaluated." },
+                { "name": "frameHandle", "$ref": "FrameHandle", "optional": true, "description": "The handle for the frame the script should be evaluated. The main frame is used if this parameter empty string or excluded." },
+                { "name": "function", "type": "string", "description": "The script to evaluate in the browsing context. It must be a function result." },
                 { "name": "arguments", "type": "array", "items": { "type": "string" }, "description": "The arguments to pass to the function when called. They will be parsed as JSON before calling the function." },
                 { "name": "expectsImplicitCallbackArgument", "type": "boolean", "description": "The function expects a callback function as the last argument. It is expected to call this callback with a result." }
             ],
@@ -111,6 +125,33 @@
                 { "name": "result", "type": "string", "description": "The result returned by the called function. It is JSON encoded after the function returns or calls the callback." }
             ],
             "async": true
+        },
+        {
+            "name": "resolveChildFrameHandle",
+            "description": "Determines the <code>FrameHandle</code> based on the ordinal, name or node handle of a child frame.",
+            "parameters": [
+                { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context in which to search for the frame." },
+                { "name": "frameHandle", "$ref": "FrameHandle", "optional": true, "description": "The handle for the frame in which to search for the frame. The main frame is used if this parameter empty string or excluded." },
+                { "name": "ordinal", "type": "integer", "optional": true, "description": "The ordinal of the child frame to resolve as a <code>FrameHandle</code>. This is analogous to 'window.frames[ordinal]' in _javascript_." },
+                { "name": "name", "type": "string", "optional": true, "description": "The name of the child frame to resolve as a <code>FrameHandle</code>. This is analogous to 'window.frames[name]' in _javascript_." },
+                { "name": "nodeHandle", "$ref": "NodeHandle", "optional": true, "description": "The handle of the child frame owner element to resolve as a <code>FrameHandle</code>." }
+            ],
+            "returns": [
+                { "name": "result", "$ref": "FrameHandle", "description": "The <code>FrameHandle</code> for the requested frame." }
+            ],
+            "async": true
+        },
+        {
+            "name": "resolveParentFrameHandle",
+            "description": "Determines the <code>FrameHandle</code> for the parent frame of the supplied <code>FrameHandle</code>.",
+            "parameters": [
+                { "name": "browsingContextHandle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context the frame is located." },
+                { "name": "frameHandle", "$ref": "FrameHandle", "description": "The handle for the frame that should resolve its parent frame." }
+            ],
+            "returns": [
+                { "name": "result", "$ref": "FrameHandle", "description": "The <code>FrameHandle</code> for the requested frame." }
+            ],
+            "async": true
         }
     ]
 }

Modified: trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp (198737 => 198738)


--- trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.cpp	2016-03-28 15:57:23 UTC (rev 198738)
@@ -125,25 +125,71 @@
     return WebProcessProxy::webPage(iter->value);
 }
 
-String WebAutomationSession::handleForWebPageProxy(WebPageProxy* webPageProxy)
+String WebAutomationSession::handleForWebPageProxy(const WebPageProxy& webPageProxy)
 {
-    auto iter = m_webPageHandleMap.find(webPageProxy->pageID());
+    auto iter = m_webPageHandleMap.find(webPageProxy.pageID());
     if (iter != m_webPageHandleMap.end())
         return iter->value;
 
-    String handle = WebCore::createCanonicalUUIDString().convertToASCIIUppercase();
+    String handle = "page-" + WebCore::createCanonicalUUIDString().convertToASCIIUppercase();
 
-    auto firstAddResult = m_webPageHandleMap.add(webPageProxy->pageID(), handle);
+    auto firstAddResult = m_webPageHandleMap.add(webPageProxy.pageID(), handle);
     RELEASE_ASSERT(firstAddResult.isNewEntry);
 
-    auto secondAddResult = m_handleWebPageMap.add(handle, webPageProxy->pageID());
+    auto secondAddResult = m_handleWebPageMap.add(handle, webPageProxy.pageID());
     RELEASE_ASSERT(secondAddResult.isNewEntry);
 
     return handle;
 }
 
-// Inspector::AutomationBackendDispatcherHandler API
+WebFrameProxy* WebAutomationSession::webFrameProxyForHandle(const String& handle, WebPageProxy& page)
+{
+    if (handle.isEmpty())
+        return page.mainFrame();
 
+    auto iter = m_handleWebFrameMap.find(handle);
+    if (iter == m_handleWebFrameMap.end())
+        return nullptr;
+
+    if (WebFrameProxy* frame = page.process().webFrame(iter->value))
+        return frame;
+
+    return nullptr;
+}
+
+String WebAutomationSession::handleForWebFrameID(uint64_t frameID)
+{
+    if (!frameID)
+        return emptyString();
+
+    for (auto& process : m_processPool->processes()) {
+        if (WebFrameProxy* frame = process->webFrame(frameID)) {
+            if (frame->isMainFrame())
+                return emptyString();
+            break;
+        }
+    }
+
+    auto iter = m_webFrameHandleMap.find(frameID);
+    if (iter != m_webFrameHandleMap.end())
+        return iter->value;
+
+    String handle = "frame-" + WebCore::createCanonicalUUIDString().convertToASCIIUppercase();
+
+    auto firstAddResult = m_webFrameHandleMap.add(frameID, handle);
+    RELEASE_ASSERT(firstAddResult.isNewEntry);
+
+    auto secondAddResult = m_handleWebFrameMap.add(handle, frameID);
+    RELEASE_ASSERT(secondAddResult.isNewEntry);
+
+    return handle;
+}
+
+String WebAutomationSession::handleForWebFrameProxy(const WebFrameProxy& webFrameProxy)
+{
+    return handleForWebFrameID(webFrameProxy.frameID());
+}
+
 void WebAutomationSession::getBrowsingContexts(Inspector::ErrorString& errorString, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Automation::BrowsingContext>>& contexts)
 {
     contexts = Inspector::Protocol::Array<Inspector::Protocol::Automation::BrowsingContext>::create();
@@ -153,10 +199,10 @@
             if (!page->isControlledByAutomation())
                 continue;
 
-            String handle = handleForWebPageProxy(page);
+            String handle = handleForWebPageProxy(*page);
 
             auto browsingContext = Inspector::Protocol::Automation::BrowsingContext::create()
-                .setHandle(handleForWebPageProxy(page))
+                .setHandle(handleForWebPageProxy(*page))
                 .setActive(m_activeBrowsingContextHandle == handle)
                 .setUrl(page->pageLoadState().activeURL())
                 .release();
@@ -173,7 +219,7 @@
         FAIL_WITH_PREDEFINED_ERROR_MESSAGE(WindowNotFound);
 
     context = Inspector::Protocol::Automation::BrowsingContext::create()
-        .setHandle(handleForWebPageProxy(page))
+        .setHandle(handleForWebPageProxy(*page))
         .setActive(m_activeBrowsingContextHandle == handle)
         .setUrl(page->pageLoadState().activeURL())
         .release();
@@ -189,7 +235,7 @@
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR_MESSAGE(InternalError);
 
-    m_activeBrowsingContextHandle = *handle = handleForWebPageProxy(page);
+    m_activeBrowsingContextHandle = *handle = handleForWebPageProxy(*page);
 }
 
 void WebAutomationSession::closeBrowsingContext(Inspector::ErrorString& errorString, const String& handle)
@@ -204,17 +250,21 @@
     page->closePage(false);
 }
 
-void WebAutomationSession::switchToBrowsingContext(Inspector::ErrorString& errorString, const String& handle)
+void WebAutomationSession::switchToBrowsingContext(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle)
 {
-    WebPageProxy* page = webPageProxyForHandle(handle);
+    WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR_MESSAGE(WindowNotFound);
 
-    m_activeBrowsingContextHandle = handle;
+    WebFrameProxy* frame = webFrameProxyForHandle(optionalFrameHandle ? *optionalFrameHandle : emptyString(), *page);
+    if (!frame)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(FrameNotFound);
 
-    // FIXME: Verify this is enough. We still might want to go through the AutomationSessionClient
-    // to get closer a user pressing focusing the window / page.
+    // FIXME: We don't need to track this in WK2. Remove in a follow up.
+    m_activeBrowsingContextHandle = browsingContextHandle;
+
     page->setFocus(true);
+    page->process().send(Messages::WebAutomationSessionProxy::FocusFrame(frame->frameID()), 0);
 }
 
 void WebAutomationSession::navigateBrowsingContext(Inspector::ErrorString& errorString, const String& handle, const String& url)
@@ -255,13 +305,16 @@
     page->reload(reloadFromOrigin, contentBlockersEnabled);
 }
 
-void WebAutomationSession::evaluateJavaScriptFunction(Inspector::ErrorString& errorString, const String& handle, const String& function, const Inspector::InspectorArray& arguments, bool expectsImplicitCallbackArgument, Ref<EvaluateJavaScriptFunctionCallback>&& callback)
+void WebAutomationSession::evaluateJavaScriptFunction(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const Inspector::InspectorArray& arguments, bool expectsImplicitCallbackArgument, Ref<EvaluateJavaScriptFunctionCallback>&& callback)
 {
-    // FIXME 24172439: This should be a frame handle, not a page handle. Change this once we have frame support.
-    WebPageProxy* page = webPageProxyForHandle(handle);
+    WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
     if (!page)
         FAIL_WITH_PREDEFINED_ERROR_MESSAGE(WindowNotFound);
 
+    WebFrameProxy* frame = webFrameProxyForHandle(optionalFrameHandle ? *optionalFrameHandle : emptyString(), *page);
+    if (!frame)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(FrameNotFound);
+
     Vector<String> argumentsVector;
     argumentsVector.reserveCapacity(arguments.length());
 
@@ -274,7 +327,7 @@
     uint64_t callbackID = m_nextEvaluateJavaScriptCallbackID++;
     m_evaluateJavaScriptFunctionCallbacks.set(callbackID, WTFMove(callback));
 
-    page->process().send(Messages::WebAutomationSessionProxy::EvaluateJavaScriptFunction(page->mainFrame()->frameID(), function, argumentsVector, expectsImplicitCallbackArgument, callbackID), 0);
+    page->process().send(Messages::WebAutomationSessionProxy::EvaluateJavaScriptFunction(frame->frameID(), function, argumentsVector, expectsImplicitCallbackArgument, callbackID), 0);
 }
 
 void WebAutomationSession::didEvaluateJavaScriptFunction(uint64_t callbackID, const String& result, const String& errorType)
@@ -290,4 +343,78 @@
         callback->sendSuccess(result);
 }
 
+void WebAutomationSession::resolveChildFrameHandle(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&& callback)
+{
+    if (!optionalOrdinal && !optionalName && !optionalNodeHandle)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(MissingParameter);
+
+    WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
+    if (!page)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(WindowNotFound);
+
+    WebFrameProxy* frame = webFrameProxyForHandle(optionalFrameHandle ? *optionalFrameHandle : emptyString(), *page);
+    if (!frame)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(FrameNotFound);
+
+    uint64_t callbackID = m_nextResolveFrameCallbackID++;
+    m_resolveChildFrameHandleCallbacks.set(callbackID, WTFMove(callback));
+
+    if (optionalNodeHandle) {
+        page->process().send(Messages::WebAutomationSessionProxy::ResolveChildFrameWithNodeHandle(frame->frameID(), *optionalNodeHandle, callbackID), 0);
+        return;
+    }
+
+    if (optionalName) {
+        page->process().send(Messages::WebAutomationSessionProxy::ResolveChildFrameWithName(frame->frameID(), *optionalName, callbackID), 0);
+        return;
+    }
+
+    if (optionalOrdinal) {
+        page->process().send(Messages::WebAutomationSessionProxy::ResolveChildFrameWithOrdinal(frame->frameID(), *optionalOrdinal, callbackID), 0);
+        return;
+    }
+
+    ASSERT_NOT_REACHED();
+}
+
+void WebAutomationSession::didResolveChildFrame(uint64_t callbackID, uint64_t frameID, const String& errorType)
+{
+    auto callback = m_resolveChildFrameHandleCallbacks.take(callbackID);
+    if (!callback)
+        return;
+
+    if (!errorType.isEmpty())
+        callback->sendFailure(errorType);
+    else
+        callback->sendSuccess(handleForWebFrameID(frameID));
+}
+
+void WebAutomationSession::resolveParentFrameHandle(Inspector::ErrorString& errorString, const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&& callback)
+{
+    WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
+    if (!page)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(WindowNotFound);
+
+    WebFrameProxy* frame = webFrameProxyForHandle(frameHandle, *page);
+    if (!frame)
+        FAIL_WITH_PREDEFINED_ERROR_MESSAGE(FrameNotFound);
+
+    uint64_t callbackID = m_nextResolveParentFrameCallbackID++;
+    m_resolveParentFrameHandleCallbacks.set(callbackID, WTFMove(callback));
+
+    page->process().send(Messages::WebAutomationSessionProxy::ResolveParentFrame(frame->frameID(), callbackID), 0);
+}
+
+void WebAutomationSession::didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType)
+{
+    auto callback = m_resolveParentFrameHandleCallbacks.take(callbackID);
+    if (!callback)
+        return;
+
+    if (!errorType.isEmpty())
+        callback->sendFailure(errorType);
+    else
+        callback->sendSuccess(handleForWebFrameID(frameID));
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h (198737 => 198738)


--- trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.h	2016-03-28 15:57:23 UTC (rev 198738)
@@ -47,6 +47,7 @@
 namespace WebKit {
 
 class WebAutomationSessionClient;
+class WebFrameProxy;
 class WebPageProxy;
 class WebProcessPool;
 
@@ -57,9 +58,6 @@
     , public Inspector::AutomationBackendDispatcherHandler
 {
 public:
-    typedef HashMap<uint64_t, String> WebPageHandleMap;
-    typedef HashMap<String, uint64_t> HandleWebPageMap;
-
     WebAutomationSession();
     ~WebAutomationSession();
 
@@ -68,8 +66,8 @@
     void setSessionIdentifier(const String& sessionIdentifier) { m_sessionIdentifier = sessionIdentifier; }
     String sessionIdentifier() const { return m_sessionIdentifier; }
 
-    WebKit::WebProcessPool* processPool() const { return m_processPool; }
-    void setProcessPool(WebKit::WebProcessPool*);
+    WebProcessPool* processPool() const { return m_processPool; }
+    void setProcessPool(WebProcessPool*);
 
 #if ENABLE(REMOTE_INSPECTOR)
     // Inspector::RemoteAutomationTarget API
@@ -84,37 +82,55 @@
     void getBrowsingContext(Inspector::ErrorString&, const String&, RefPtr<Inspector::Protocol::Automation::BrowsingContext>&) override;
     void createBrowsingContext(Inspector::ErrorString&, String*) override;
     void closeBrowsingContext(Inspector::ErrorString&, const String&) override;
-    void switchToBrowsingContext(Inspector::ErrorString&, const String&) override;
+    void switchToBrowsingContext(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle) override;
     void navigateBrowsingContext(Inspector::ErrorString&, const String& handle, const String& url) override;
     void goBackInBrowsingContext(Inspector::ErrorString&, const String&) override;
     void goForwardInBrowsingContext(Inspector::ErrorString&, const String&) override;
     void reloadBrowsingContext(Inspector::ErrorString&, const String&) override;
-    void evaluateJavaScriptFunction(Inspector::ErrorString&, const String& handle, const String& function, const Inspector::InspectorArray& arguments, bool expectsImplicitCallbackArgument, Ref<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>&&) override;
+    void evaluateJavaScriptFunction(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const String& function, const Inspector::InspectorArray& arguments, bool expectsImplicitCallbackArgument, Ref<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>&&) override;
+    void resolveChildFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String* optionalFrameHandle, const int* optionalOrdinal, const String* optionalName, const String* optionalNodeHandle, Ref<ResolveChildFrameHandleCallback>&&) override;
+    void resolveParentFrameHandle(Inspector::ErrorString&, const String& browsingContextHandle, const String& frameHandle, Ref<ResolveParentFrameHandleCallback>&&) override;
 
 private:
-    WebKit::WebPageProxy* webPageProxyForHandle(const String&);
-    String handleForWebPageProxy(WebKit::WebPageProxy*);
+    WebPageProxy* webPageProxyForHandle(const String&);
+    String handleForWebPageProxy(const WebPageProxy&);
 
+    WebFrameProxy* webFrameProxyForHandle(const String&, WebPageProxy&);
+    String handleForWebFrameID(uint64_t frameID);
+    String handleForWebFrameProxy(const WebFrameProxy&);
+
     // Implemented in generated WebAutomationSessionMessageReceiver.cpp
     void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&) override;
 
     // Called by WebAutomationSession messages
     void didEvaluateJavaScriptFunction(uint64_t callbackID, const String& result, const String& errorType);
+    void didResolveChildFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
+    void didResolveParentFrame(uint64_t callbackID, uint64_t frameID, const String& errorType);
 
-    WebKit::WebProcessPool* m_processPool { nullptr };
+    WebProcessPool* m_processPool { nullptr };
+
     std::unique_ptr<API::AutomationSessionClient> m_client;
     String m_sessionIdentifier { ASCIILiteral("Untitled Session") };
     Ref<Inspector::FrontendRouter> m_frontendRouter;
     Ref<Inspector::BackendDispatcher> m_backendDispatcher;
     Ref<Inspector::AutomationBackendDispatcher> m_domainDispatcher;
 
-    WebPageHandleMap m_webPageHandleMap;
-    HandleWebPageMap m_handleWebPageMap;
+    HashMap<uint64_t, String> m_webPageHandleMap;
+    HashMap<String, uint64_t> m_handleWebPageMap;
     String m_activeBrowsingContextHandle;
 
+    HashMap<uint64_t, String> m_webFrameHandleMap;
+    HashMap<String, uint64_t> m_handleWebFrameMap;
+
     uint64_t m_nextEvaluateJavaScriptCallbackID { 1 };
     HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::EvaluateJavaScriptFunctionCallback>> m_evaluateJavaScriptFunctionCallbacks;
 
+    uint64_t m_nextResolveFrameCallbackID { 1 };
+    HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveChildFrameHandleCallback>> m_resolveChildFrameHandleCallbacks;
+
+    uint64_t m_nextResolveParentFrameCallbackID { 1 };
+    HashMap<uint64_t, RefPtr<Inspector::AutomationBackendDispatcherHandler::ResolveParentFrameHandleCallback>> m_resolveParentFrameHandleCallbacks;
+
 #if ENABLE(REMOTE_INSPECTOR)
     Inspector::FrontendChannel* m_remoteChannel { nullptr };
 #endif

Modified: trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.messages.in (198737 => 198738)


--- trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.messages.in	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/UIProcess/Automation/WebAutomationSession.messages.in	2016-03-28 15:57:23 UTC (rev 198738)
@@ -22,4 +22,7 @@
 
 messages -> WebAutomationSession {
     DidEvaluateJavaScriptFunction(uint64_t callbackID, String result, String errorType)
+
+    DidResolveChildFrame(uint64_t callbackID, uint64_t frameID, String errorType)
+    DidResolveParentFrame(uint64_t callbackID, uint64_t frameID, String errorType)
 }

Modified: trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.cpp (198737 => 198738)


--- trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.cpp	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.cpp	2016-03-28 15:57:23 UTC (rev 198738)
@@ -33,9 +33,17 @@
 #include "WebFrame.h"
 #include "WebPage.h"
 #include "WebProcess.h"
+#include <_javascript_Core/APICast.h>
+#include <_javascript_Core/JSObject.h>
 #include <_javascript_Core/JSRetainPtr.h>
 #include <_javascript_Core/JSStringRefPrivate.h>
 #include <_javascript_Core/OpaqueJSString.h>
+#include <WebCore/DOMWindow.h>
+#include <WebCore/Frame.h>
+#include <WebCore/FrameTree.h>
+#include <WebCore/HTMLFrameElementBase.h>
+#include <WebCore/JSElement.h>
+#include <WebCore/MainFrame.h>
 #include <WebCore/UUID.h>
 
 namespace WebKit {
@@ -161,6 +169,33 @@
     return scriptObject;
 }
 
+WebCore::Element* WebAutomationSessionProxy::elementForNodeHandle(WebFrame& frame, const String& nodeHandle)
+{
+    // Don't use scriptObjectForFrame() since we can assume if the script object
+    // does not exist, there are no nodes mapped to handles. Using scriptObjectForFrame()
+    // will make a new script object if it can't find one, preventing us from returning fast.
+    JSObjectRef scriptObject = m_webFrameScriptObjectMap.get(frame.frameID());
+    if (!scriptObject)
+        return nullptr;
+
+    JSGlobalContextRef context = frame.jsContext();
+
+    JSValueRef functionArguments[] = {
+        toJSValue(context, nodeHandle)
+    };
+
+    JSValueRef result = callPropertyFunction(context, scriptObject, ASCIILiteral("nodeForIdentifier"), WTF_ARRAY_LENGTH(functionArguments), functionArguments, nullptr);
+    JSObjectRef element = JSValueToObject(context, result, nullptr);
+    if (!element)
+        return nullptr;
+
+    auto elementWrapper = JSC::jsDynamicCast<WebCore::JSElement*>(toJS(element));
+    if (!elementWrapper)
+        return nullptr;
+
+    return &elementWrapper->wrapped();
+}
+
 void WebAutomationSessionProxy::didClearWindowObjectForFrame(WebFrame& frame)
 {
     uint64_t frameID = frame.frameID();
@@ -239,4 +274,137 @@
     WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidEvaluateJavaScriptFunction(callbackID, result, errorType), 0);
 }
 
+void WebAutomationSessionProxy::resolveChildFrameWithOrdinal(uint64_t frameID, uint32_t ordinal, uint64_t callbackID)
+{
+    String frameNotFoundErrorType = Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
+
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Frame* coreFrame = frame->coreFrame();
+    if (!coreFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Frame* coreChildFrame = coreFrame->tree().scopedChild(ordinal);
+    if (!coreChildFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebFrame* childFrame = WebFrame::fromCoreFrame(*coreChildFrame);
+    if (!childFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, childFrame->frameID(), emptyString()), 0);
+}
+
+void WebAutomationSessionProxy::resolveChildFrameWithNodeHandle(uint64_t frameID, const String& nodeHandle, uint64_t callbackID)
+{
+    String frameNotFoundErrorType = Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
+
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Element* coreElement = elementForNodeHandle(*frame, nodeHandle);
+    if (!coreElement || !coreElement->isFrameElementBase()) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Frame* coreFrameFromElement = static_cast<WebCore::HTMLFrameElementBase*>(coreElement)->contentFrame();
+    if (!coreFrameFromElement) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebFrame* frameFromElement = WebFrame::fromCoreFrame(*coreFrameFromElement);
+    if (!frameFromElement) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, frameFromElement->frameID(), emptyString()), 0);
+}
+
+void WebAutomationSessionProxy::resolveChildFrameWithName(uint64_t frameID, const String& name, uint64_t callbackID)
+{
+    String frameNotFoundErrorType = Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
+
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Frame* coreFrame = frame->coreFrame();
+    if (!coreFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebCore::Frame* coreChildFrame = coreFrame->tree().scopedChild(name);
+    if (!coreChildFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebFrame* childFrame = WebFrame::fromCoreFrame(*coreChildFrame);
+    if (!childFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveChildFrame(callbackID, childFrame->frameID(), emptyString()), 0);
+}
+
+void WebAutomationSessionProxy::resolveParentFrame(uint64_t frameID, uint64_t callbackID)
+{
+    String frameNotFoundErrorType = Inspector::Protocol::getEnumConstantValue(Inspector::Protocol::Automation::ErrorMessage::FrameNotFound);
+
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveParentFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebFrame* parentFrame = frame->parentFrame();
+    if (!parentFrame) {
+        WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveParentFrame(callbackID, 0, frameNotFoundErrorType), 0);
+        return;
+    }
+
+    WebProcess::singleton().parentProcessConnection()->send(Messages::WebAutomationSession::DidResolveParentFrame(callbackID, parentFrame->frameID(), emptyString()), 0);
+}
+
+void WebAutomationSessionProxy::focusFrame(uint64_t frameID)
+{
+    WebFrame* frame = WebProcess::singleton().webFrame(frameID);
+    if (!frame)
+        return;
+
+    WebCore::Frame* coreFrame = frame->coreFrame();
+    if (!coreFrame)
+        return;
+
+    WebCore::Document* coreDocument = coreFrame->document();
+    if (!coreDocument)
+        return;
+
+    WebCore::DOMWindow* coreDOMWindow = coreDocument->domWindow();
+    if (!coreDOMWindow)
+        return;
+
+    coreDOMWindow->focus(true);
+}
+
 } // namespace WebKit

Modified: trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.h (198737 => 198738)


--- trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.h	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.h	2016-03-28 15:57:23 UTC (rev 198738)
@@ -29,6 +29,10 @@
 #include "Connection.h"
 #include <_javascript_Core/JSBase.h>
 
+namespace WebCore {
+class Element;
+}
+
 namespace WebKit {
 
 class WebFrame;
@@ -47,12 +51,18 @@
 
 private:
     JSObjectRef scriptObjectForFrame(WebFrame&);
+    WebCore::Element* elementForNodeHandle(WebFrame&, const String&);
 
     // Implemented in generated WebAutomationSessionProxyMessageReceiver.cpp
     void didReceiveMessage(IPC::Connection&, IPC::MessageDecoder&);
 
     // Called by WebAutomationSessionProxy messages
     void evaluateJavaScriptFunction(uint64_t frameID, const String& function, Vector<String> arguments, bool expectsImplicitCallbackArgument, uint64_t callbackID);
+    void resolveChildFrameWithOrdinal(uint64_t frameID, uint32_t ordinal, uint64_t callbackID);
+    void resolveChildFrameWithNodeHandle(uint64_t frameID, const String& nodeHandle, uint64_t callbackID);
+    void resolveChildFrameWithName(uint64_t frameID, const String& name, uint64_t callbackID);
+    void resolveParentFrame(uint64_t frameID, uint64_t callbackID);
+    void focusFrame(uint64_t frameID);
 
     String m_sessionIdentifier;
 

Modified: trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.js (198737 => 198738)


--- trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.js	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.js	2016-03-28 15:57:23 UTC (rev 198738)
@@ -56,6 +56,15 @@
             callback(functionValue.apply(null, argumentValues));
     }
 
+    nodeForIdentifier(identifier)
+    {
+        try {
+            return this._nodeForIdentifier(identifier);
+        } catch (error) {
+            return null;
+        }
+    }
+
     // Private
 
     _jsonParse(string)

Modified: trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.messages.in (198737 => 198738)


--- trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.messages.in	2016-03-28 15:57:06 UTC (rev 198737)
+++ trunk/Source/WebKit2/WebProcess/Automation/WebAutomationSessionProxy.messages.in	2016-03-28 15:57:23 UTC (rev 198738)
@@ -21,5 +21,12 @@
 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 messages -> WebAutomationSessionProxy {
-    EvaluateJavaScriptFunction(uint64_t frame, String function, Vector<String> arguments, bool expectsImplicitCallbackArgument, uint64_t callbackID)
+    EvaluateJavaScriptFunction(uint64_t frameID, String function, Vector<String> arguments, bool expectsImplicitCallbackArgument, uint64_t callbackID)
+
+    ResolveChildFrameWithOrdinal(uint64_t frameID, uint32_t ordinal, uint64_t callbackID)
+    ResolveChildFrameWithNodeHandle(uint64_t frameID, String nodeHandle, uint64_t callbackID)
+    ResolveChildFrameWithName(uint64_t frameID, String name, uint64_t callbackID)
+    ResolveParentFrame(uint64_t frameID, uint64_t callbackID)
+
+    FocusFrame(uint64_t frameID)
 }
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to