Diff
Modified: trunk/Source/WebCore/platform/gtk/po/ChangeLog (216005 => 216006)
--- trunk/Source/WebCore/platform/gtk/po/ChangeLog 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebCore/platform/gtk/po/ChangeLog 2017-05-01 07:03:58 UTC (rev 216006)
@@ -1,3 +1,12 @@
+2017-05-01 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Add automation session API
+ https://bugs.webkit.org/show_bug.cgi?id=171428
+
+ Reviewed by Carlos Alberto Lopez Perez.
+
+ * POTFILES.in: Add WebKitAutomationSession.cpp.
+
2017-04-25 Carlos Garcia Campos <[email protected]>
[GTK] Add WebKitInspectorWindow to create inspector windows from local and remote inspector
Modified: trunk/Source/WebCore/platform/gtk/po/POTFILES.in (216005 => 216006)
--- trunk/Source/WebCore/platform/gtk/po/POTFILES.in 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebCore/platform/gtk/po/POTFILES.in 2017-05-01 07:03:58 UTC (rev 216006)
@@ -7,6 +7,7 @@
../../../WebKit2/Shared/gtk/WebErrorsGtk.cpp
../../../WebKit2/Shared/soup/WebErrorsSoup.cpp
../../../WebKit2/UIProcess/API/gtk/WebKitAuthenticationDialog.cpp
+../../../WebKit2/UIProcess/API/gtk/WebKitAutomationSession.cpp
../../../WebKit2/UIProcess/API/gtk/WebKitColorChooserRequest.cpp
../../../WebKit2/UIProcess/API/gtk/WebKitDownload.cpp
../../../WebKit2/UIProcess/API/gtk/WebKitEditorState.cpp
Modified: trunk/Source/WebKit2/ChangeLog (216005 => 216006)
--- trunk/Source/WebKit2/ChangeLog 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/ChangeLog 2017-05-01 07:03:58 UTC (rev 216006)
@@ -1,5 +1,51 @@
2017-05-01 Carlos Garcia Campos <[email protected]>
+ [GTK] Add automation session API
+ https://bugs.webkit.org/show_bug.cgi?id=171428
+
+ Reviewed by Carlos Alberto Lopez Perez.
+
+ Add new API to allow WebKitGTK+ to be controlled by automation. By default it's disabled, applications have to
+ explicitly call webkit_web_context_set_automation_allowed() to enabled it. When a new automation session is
+ requested, the signal WebKitWebContext::automation-started is emitted with a newly created
+ WebKitAutomationSession, similar to how WebKitWebContext::download-started works. The user should connect to it
+ have access to the WebKitAutomationSession and connect it its signals. When a new web view is requested to be
+ created in a WebKitAutomationSession, the signal WebKitAutomationSession::create-web-view is emitted. The user
+ should connect to it and return a WebKitWebView. The web views used for automation are special ones and need to
+ be created with the new WebKitWebView:is-controlled-by-automation construct property enabled, otherwise we will
+ refuse to create the requested browsing context.
+
+ * PlatformGTK.cmake:
+ * UIProcess/API/gtk/WebKitAutomationSession.cpp: Added.
+ (webkitAutomationSessionSetProperty):
+ (webkitAutomationSessionConstructed):
+ (webkit_automation_session_class_init):
+ (webkitAutomationSessionCreate):
+ (webkitAutomationSessionGetSession):
+ (webkit_automation_session_get_id):
+ * UIProcess/API/gtk/WebKitAutomationSession.h: Added.
+ * UIProcess/API/gtk/WebKitAutomationSessionPrivate.h: Added.
+ * UIProcess/API/gtk/WebKitWebContext.cpp:
+ (webkitWebContextConstructed):
+ (webkit_web_context_class_init):
+ (webkit_web_context_is_automation_allowed):
+ (webkit_web_context_set_automation_allowed):
+ (webkitWebContextCreatePageForWebView):
+ * UIProcess/API/gtk/WebKitWebContext.h:
+ * UIProcess/API/gtk/WebKitWebView.cpp:
+ (webkitWebViewConstructed):
+ (webkitWebViewSetProperty):
+ (webkitWebViewGetProperty):
+ (webkit_web_view_class_init):
+ (webkit_web_view_is_controlled_by_automation):
+ * UIProcess/API/gtk/WebKitWebView.h:
+ * UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt:
+ * UIProcess/API/gtk/docs/webkit2gtk-4.0.types:
+ * UIProcess/API/gtk/docs/webkit2gtk-docs.sgml:
+ * UIProcess/API/gtk/webkit2.h:
+
+2017-05-01 Carlos Garcia Campos <[email protected]>
+
Unreviewed. Fix GTK+ debug build after r216002.
* WebProcess/InjectedBundle/API/gtk/DOM/WebKitDOMClientRectList.cpp:
Modified: trunk/Source/WebKit2/PlatformGTK.cmake (216005 => 216006)
--- trunk/Source/WebKit2/PlatformGTK.cmake 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/PlatformGTK.cmake 2017-05-01 07:03:58 UTC (rev 216006)
@@ -124,6 +124,9 @@
UIProcess/API/gtk/WebKitAuthenticationRequest.cpp
UIProcess/API/gtk/WebKitAuthenticationRequest.h
UIProcess/API/gtk/WebKitAutocleanups.h
+ UIProcess/API/gtk/WebKitAutomationSession.cpp
+ UIProcess/API/gtk/WebKitAutomationSession.h
+ UIProcess/API/gtk/WebKitAutomationSessionPrivate.h
UIProcess/API/gtk/WebKitBackForwardList.cpp
UIProcess/API/gtk/WebKitBackForwardList.h
UIProcess/API/gtk/WebKitBackForwardListItem.cpp
@@ -533,6 +536,7 @@
${DERIVED_SOURCES_WEBKIT2GTK_API_DIR}/WebKitVersion.h
${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitAuthenticationRequest.h
${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitAutocleanups.h
+ ${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitAutomationSession.h
${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitBackForwardList.h
${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitBackForwardListItem.h
${WEBKIT2_DIR}/UIProcess/API/gtk/WebKitColorChooserRequest.h
Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.cpp (0 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.cpp (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.cpp 2017-05-01 07:03:58 UTC (rev 216006)
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+#include "WebKitAutomationSession.h"
+
+#include "APIAutomationSessionClient.h"
+#include "WebKitAutomationSessionPrivate.h"
+#include "WebKitPrivate.h"
+#include "WebKitWebView.h"
+#include "WebKitWebViewBasePrivate.h"
+#include <glib/gi18n-lib.h>
+#include <wtf/text/CString.h>
+
+using namespace WebKit;
+
+/**
+ * SECTION: WebKitAutomationSession
+ * @Short_description: Automation Session
+ * @Title: WebKitAutomationSession
+ *
+ * WebKitAutomationSession represents an automation session of a WebKitWebContext.
+ * When a new session is requested, a WebKitAutomationSession is created and the signal
+ * WebKitWebContext::automation-started is emitted with the WebKitAutomationSession as
+ * argument. Then, the automation client can request the session to create a new
+ * #WebKitWebView to interact with it. When this happens the signal #WebKitAutomationSession::create-web-view
+ * is emitted.
+ *
+ * Since: 2.18
+ */
+
+enum {
+ PROP_0,
+
+ PROP_ID
+};
+
+enum {
+ CREATE_WEB_VIEW,
+
+ LAST_SIGNAL
+};
+
+struct _WebKitAutomationSessionPrivate {
+ RefPtr<WebAutomationSession> session;
+ CString id;
+};
+
+static guint signals[LAST_SIGNAL] = { 0, };
+
+WEBKIT_DEFINE_TYPE(WebKitAutomationSession, webkit_automation_session, G_TYPE_OBJECT)
+
+class AutomationSessionClient final : public API::AutomationSessionClient {
+public:
+ explicit AutomationSessionClient(WebKitAutomationSession* session)
+ : m_session(session)
+ {
+ }
+
+private:
+ String sessionIdentifier() const override
+ {
+ return String::fromUTF8(m_session->priv->id.data());
+ }
+
+ WebPageProxy* didRequestNewWindow(WebAutomationSession&) override
+ {
+ WebKitWebView* webView = nullptr;
+ g_signal_emit(m_session, signals[CREATE_WEB_VIEW], 0, &webView);
+ if (!webView || !webkit_web_view_is_controlled_by_automation(webView))
+ return nullptr;
+
+ return webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(webView));
+ }
+
+ WebKitAutomationSession* m_session;
+};
+
+static void webkitAutomationSessionGetProperty(GObject* object, guint propID, GValue* value, GParamSpec* paramSpec)
+{
+ WebKitAutomationSession* session = WEBKIT_AUTOMATION_SESSION(object);
+
+ switch (propID) {
+ case PROP_ID:
+ g_value_set_string(value, session->priv->id.data());
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
+ }
+}
+
+static void webkitAutomationSessionSetProperty(GObject* object, guint propID, const GValue* value, GParamSpec* paramSpec)
+{
+ WebKitAutomationSession* session = WEBKIT_AUTOMATION_SESSION(object);
+
+ switch (propID) {
+ case PROP_ID:
+ session->priv->id = g_value_get_string(value);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, propID, paramSpec);
+ }
+}
+
+static void webkitAutomationSessionConstructed(GObject* object)
+{
+ WebKitAutomationSession* session = WEBKIT_AUTOMATION_SESSION(object);
+
+ G_OBJECT_CLASS(webkit_automation_session_parent_class)->constructed(object);
+
+ session->priv->session = adoptRef(new WebAutomationSession());
+ session->priv->session->setSessionIdentifier(String::fromUTF8(session->priv->id.data()));
+ session->priv->session->setClient(std::make_unique<AutomationSessionClient>(session));
+}
+
+static void webkit_automation_session_class_init(WebKitAutomationSessionClass* sessionClass)
+{
+ GObjectClass* gObjectClass = G_OBJECT_CLASS(sessionClass);
+ gObjectClass->get_property = webkitAutomationSessionGetProperty;
+ gObjectClass->set_property = webkitAutomationSessionSetProperty;
+ gObjectClass->constructed = webkitAutomationSessionConstructed;
+
+ /**
+ * WebKitAutomationSession:id:
+ *
+ * The session unique identifier.
+ *
+ * Since: 2.18
+ */
+ g_object_class_install_property(
+ gObjectClass,
+ PROP_ID,
+ g_param_spec_string(
+ "id",
+ _("Identifier"),
+ _("The automation session identifier"),
+ nullptr,
+ static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
+
+ /**
+ * WebKitAutomationSession::create-web-view:
+ * @session: a #WebKitAutomationSession
+ *
+ * This signal is emitted when the automation client requests a new
+ * browsing context to interact with it. The callback handler should
+ * return a #WebKitWebView created with #WebKitWebView:is-controlled-by-automation
+ * construct property enabled. The returned #WebKitWebView could be an existing
+ * web view or a new one created and added to a new tab or window.
+ *
+ * Returns: (transfer none): a #WebKitWebView widget.
+ *
+ * Since: 2.18
+ */
+ signals[CREATE_WEB_VIEW] = g_signal_new(
+ "create-web-view",
+ G_TYPE_FROM_CLASS(sessionClass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ nullptr, nullptr,
+ g_cclosure_marshal_generic,
+ WEBKIT_TYPE_WEB_VIEW, 0,
+ G_TYPE_NONE);
+}
+
+WebKitAutomationSession* webkitAutomationSessionCreate(const char* sessionID)
+{
+ return WEBKIT_AUTOMATION_SESSION(g_object_new(WEBKIT_TYPE_AUTOMATION_SESSION, "id", sessionID, nullptr));
+}
+
+WebAutomationSession& webkitAutomationSessionGetSession(WebKitAutomationSession* session)
+{
+ return *session->priv->session;
+}
+
+/**
+ * webkit_automation_session_get_id:
+ * @session: a #WebKitAutomationSession
+ *
+ * Get the unique identifier of a #WebKitAutomationSession
+ *
+ * Returns: the unique identifier of @session
+ *
+ * Since: 2.18
+ */
+const char* webkit_automation_session_get_id(WebKitAutomationSession* session)
+{
+ g_return_val_if_fail(WEBKIT_IS_AUTOMATION_SESSION(session), nullptr);
+ return session->priv->id.data();
+}
Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.h (0 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.h (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSession.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#if !defined(__WEBKIT2_H_INSIDE__) && !defined(WEBKIT2_COMPILATION)
+#error "Only <webkit2/webkit2.h> can be included directly."
+#endif
+
+#ifndef WebKitAutomationSession_h
+#define WebKitAutomationSession_h
+
+#include <glib-object.h>
+#include <webkit2/WebKitDefines.h>
+
+G_BEGIN_DECLS
+
+#define WEBKIT_TYPE_AUTOMATION_SESSION (webkit_automation_session_get_type())
+#define WEBKIT_AUTOMATION_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), WEBKIT_TYPE_AUTOMATION_SESSION, WebKitAutomationSession))
+#define WEBKIT_IS_AUTOMATION_SESSION(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), WEBKIT_TYPE_AUTOMATION_SESSION))
+#define WEBKIT_AUTOMATION_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), WEBKIT_TYPE_AUTOMATION_SESSION, WebKitAutomationSessionClass))
+#define WEBKIT_IS_AUTOMATION_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), WEBKIT_TYPE_AUTOMATION_SESSION))
+#define WEBKIT_AUTOMATION_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), WEBKIT_TYPE_AUTOMATION_SESSION, WebKitAutomationSessionClass))
+
+typedef struct _WebKitAutomationSession WebKitAutomationSession;
+typedef struct _WebKitAutomationSessionClass WebKitAutomationSessionClass;
+typedef struct _WebKitAutomationSessionPrivate WebKitAutomationSessionPrivate;
+
+struct _WebKitAutomationSession {
+ GObject parent;
+
+ WebKitAutomationSessionPrivate *priv;
+};
+
+struct _WebKitAutomationSessionClass {
+ GObjectClass parent_class;
+
+ void (*_webkit_reserved0) (void);
+ void (*_webkit_reserved1) (void);
+ void (*_webkit_reserved2) (void);
+ void (*_webkit_reserved3) (void);
+};
+
+WEBKIT_API GType
+webkit_automation_session_get_type (void);
+
+WEBKIT_API const char *
+webkit_automation_session_get_id (WebKitAutomationSession *session);
+
+G_END_DECLS
+
+#endif /* WebKitAutomationSession_h */
Added: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSessionPrivate.h (0 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSessionPrivate.h (rev 0)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitAutomationSessionPrivate.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#pragma once
+
+#include "WebAutomationSession.h"
+#include "WebKitAutomationSession.h"
+
+WebKitAutomationSession* webkitAutomationSessionCreate(const char* sessionID);
+WebKit::WebAutomationSession& webkitAutomationSessionGetSession(WebKitAutomationSession*);
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.cpp 2017-05-01 07:03:58 UTC (rev 216006)
@@ -20,6 +20,7 @@
#include "config.h"
#include "WebKitWebContext.h"
+#include "APIAutomationClient.h"
#include "APICustomProtocolManagerClient.h"
#include "APIDownloadClient.h"
#include "APIPageConfiguration.h"
@@ -27,8 +28,10 @@
#include "APIString.h"
#include "TextChecker.h"
#include "TextCheckerState.h"
+#include "WebAutomationSession.h"
#include "WebCertificateInfo.h"
#include "WebGeolocationManagerProxy.h"
+#include "WebKitAutomationSessionPrivate.h"
#include "WebKitCustomProtocolManagerClient.h"
#include "WebKitDownloadClient.h"
#include "WebKitDownloadPrivate.h"
@@ -51,6 +54,7 @@
#include "WebKitWebsiteDataManagerPrivate.h"
#include "WebNotificationManagerProxy.h"
#include "WebsiteDataType.h"
+#include <_javascript_Core/RemoteInspector.h>
#include <WebCore/FileSystem.h>
#include <WebCore/IconDatabase.h>
#include <WebCore/Language.h>
@@ -110,6 +114,7 @@
DOWNLOAD_STARTED,
INITIALIZE_WEB_EXTENSIONS,
INITIALIZE_NOTIFICATION_PERMISSIONS,
+ AUTOMATION_STARTED,
LAST_SIGNAL
};
@@ -150,6 +155,8 @@
typedef HashMap<String, RefPtr<WebKitURISchemeHandler> > URISchemeHandlerMap;
typedef HashMap<uint64_t, GRefPtr<WebKitURISchemeRequest> > URISchemeRequestMap;
+class WebKitAutomationClient;
+
struct _WebKitWebContextPrivate {
RefPtr<WebProcessPool> processPool;
bool clientsDetached;
@@ -180,11 +187,43 @@
CString localStorageDirectory;
#if ENABLE(REMOTE_INSPECTOR)
std::unique_ptr<RemoteInspectorProtocolHandler> remoteInspectorProtocolHandler;
+ std::unique_ptr<WebKitAutomationClient> automationClient;
+ GRefPtr<WebKitAutomationSession> automationSession;
+ bool automationAllowed;
#endif
};
static guint signals[LAST_SIGNAL] = { 0, };
+#if ENABLE(REMOTE_INSPECTOR)
+class WebKitAutomationClient final : Inspector::RemoteInspector::Client {
+public:
+ explicit WebKitAutomationClient(WebKitWebContext* context)
+ : m_webContext(context)
+ {
+ Inspector::RemoteInspector::singleton().setRemoteInspectorClient(this);
+ }
+
+ ~WebKitAutomationClient()
+ {
+ Inspector::RemoteInspector::singleton().setRemoteInspectorClient(nullptr);
+ }
+
+private:
+ bool remoteAutomationAllowed() const override { return m_webContext->priv->automationAllowed; }
+
+ void requestAutomationSession(const String& sessionIdentifier) override
+ {
+ ASSERT(!m_webContext->priv->automationSession);
+ m_webContext->priv->automationSession = adoptGRef(webkitAutomationSessionCreate(sessionIdentifier.utf8().data()));
+ m_webContext->priv->processPool->setAutomationSession(&webkitAutomationSessionGetSession(m_webContext->priv->automationSession.get()));
+ g_signal_emit(m_webContext, signals[AUTOMATION_STARTED], 0, m_webContext->priv->automationSession.get());
+ }
+
+ WebKitWebContext* m_webContext;
+};
+#endif // ENABLE(REMOTE_INSPECTOR)
+
WEBKIT_DEFINE_TYPE(WebKitWebContext, webkit_web_context, G_TYPE_OBJECT)
static const char* injectedBundleDirectory()
@@ -294,6 +333,7 @@
#endif
#if ENABLE(REMOTE_INSPECTOR)
priv->remoteInspectorProtocolHandler = std::make_unique<RemoteInspectorProtocolHandler>(webContext);
+ priv->automationClient = std::make_unique<WebKitAutomationClient>(webContext);
#endif
}
@@ -423,6 +463,27 @@
nullptr, nullptr,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
+
+ /**
+ * WebKitWebContext::automation-started:
+ * @context: the #WebKitWebContext
+ * @session: the #WebKitAutomationSession associated with this event
+ *
+ * This signal is emitted when a new automation request is made.
+ * Note that it will never be emitted if automation is not enabled in @context,
+ * see webkit_web_context_set_automation_allowed() for more details.
+ *
+ * Since: 2.18
+ */
+ signals[AUTOMATION_STARTED] =
+ g_signal_new("automation-started",
+ G_TYPE_FROM_CLASS(gObjectClass),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET(WebKitWebContextClass, automation_started),
+ nullptr, nullptr,
+ g_cclosure_marshal_VOID__OBJECT,
+ G_TYPE_NONE, 1,
+ WEBKIT_TYPE_AUTOMATION_SESSION);
}
static gpointer createDefaultWebContext(gpointer)
@@ -530,6 +591,49 @@
}
/**
+ * webkit_web_context_is_automation_allowed:
+ * @context: the #WebKitWebContext
+ *
+ * Get whether automation is allowed in @context.
+ * See also webkit_web_context_set_automation_allowed().
+ *
+ * Returns: %TRUE if automation is allowed or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_web_context_is_automation_allowed(WebKitWebContext* context)
+{
+ g_return_val_if_fail(WEBKIT_IS_WEB_CONTEXT(context), FALSE);
+
+ return context->priv->automationAllowed;
+}
+
+/**
+ * webkit_web_context_set_automation_allowed:
+ * @context: the #WebKitWebContext
+ * @allowed: value to set
+ *
+ * Set whether automation is allowed in @context. When automation is enabled the browser could
+ * be controlled by another process by requesting an automation session. When a new automation
+ * session is requested the signal #WebKitWebContext::automation-started is emitted.
+ * Automation is disabled by default, so you need to explicitly call this method passing %TRUE
+ * to enable it.
+ *
+ * Since: 2.18
+ */
+void webkit_web_context_set_automation_allowed(WebKitWebContext* context, gboolean allowed)
+{
+ g_return_if_fail(WEBKIT_IS_WEB_CONTEXT(context));
+
+ if (context->priv->automationAllowed == allowed)
+ return;
+ context->priv->automationAllowed = allowed;
+#if ENABLE(REMOTE_INSPECTOR)
+ Inspector::RemoteInspector::singleton().clientCapabilitiesDidChange();
+#endif
+}
+
+/**
* webkit_web_context_set_cache_model:
* @context: the #WebKitWebContext
* @cache_model: a #WebKitCacheModel
@@ -1501,6 +1605,7 @@
pageConfiguration->setPreferences(webkitSettingsGetPreferences(webkit_web_view_get_settings(webView)));
pageConfiguration->setRelatedPage(relatedView ? webkitWebViewBaseGetPage(WEBKIT_WEB_VIEW_BASE(relatedView)) : nullptr);
pageConfiguration->setUserContentController(userContentManager ? webkitUserContentManagerGetUserContentControllerProxy(userContentManager) : nullptr);
+ pageConfiguration->setControlledByAutomation(webkit_web_view_is_controlled_by_automation(webView));
WebKitWebsiteDataManager* manager = webkitWebViewGetWebsiteDataManager(webView);
if (!manager)
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebContext.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -25,6 +25,7 @@
#define WebKitWebContext_h
#include <glib-object.h>
+#include <webkit2/WebKitAutomationSession.h>
#include <webkit2/WebKitCookieManager.h>
#include <webkit2/WebKitDefines.h>
#include <webkit2/WebKitDownload.h>
@@ -145,16 +146,17 @@
struct _WebKitWebContextClass {
GObjectClass parent;
- void (* download_started) (WebKitWebContext *context,
- WebKitDownload *download);
- void (* initialize_web_extensions) (WebKitWebContext *context);
- void (* initialize_notification_permissions) (WebKitWebContext *context);
+ void (* download_started) (WebKitWebContext *context,
+ WebKitDownload *download);
+ void (* initialize_web_extensions) (WebKitWebContext *context);
+ void (* initialize_notification_permissions) (WebKitWebContext *context);
+ void (* automation_started) (WebKitWebContext *context,
+ WebKitAutomationSession *session);
void (*_webkit_reserved0) (void);
void (*_webkit_reserved1) (void);
void (*_webkit_reserved2) (void);
void (*_webkit_reserved3) (void);
- void (*_webkit_reserved4) (void);
};
WEBKIT_API GType
@@ -178,7 +180,13 @@
WEBKIT_API gboolean
webkit_web_context_is_ephemeral (WebKitWebContext *context);
+WEBKIT_API gboolean
+webkit_web_context_is_automation_allowed (WebKitWebContext *context);
+
WEBKIT_API void
+webkit_web_context_set_automation_allowed (WebKitWebContext *context,
+ gboolean allowed);
+WEBKIT_API void
webkit_web_context_set_cache_model (WebKitWebContext *context,
WebKitCacheModel cache_model);
WEBKIT_API WebKitCacheModel
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.cpp 2017-05-01 07:03:58 UTC (rev 216006)
@@ -155,6 +155,7 @@
PROP_IS_LOADING,
PROP_IS_PLAYING_AUDIO,
PROP_IS_EPHEMERAL,
+ PROP_IS_CONTROLLED_BY_AUTOMATION,
PROP_EDITABLE
};
@@ -180,6 +181,7 @@
CString activeURI;
bool isLoading;
bool isEphemeral;
+ bool isControlledByAutomation;
std::unique_ptr<PageLoadStateObserver> loadObserver;
@@ -667,6 +669,7 @@
if (priv->relatedView) {
priv->context = webkit_web_view_get_context(priv->relatedView);
priv->isEphemeral = webkit_web_view_is_ephemeral(priv->relatedView);
+ priv->isControlledByAutomation = webkit_web_view_is_controlled_by_automation(priv->relatedView);
} else if (!priv->context)
priv->context = webkit_web_context_get_default();
else if (!priv->isEphemeral)
@@ -739,6 +742,9 @@
case PROP_IS_EPHEMERAL:
webView->priv->isEphemeral = g_value_get_boolean(value);
break;
+ case PROP_IS_CONTROLLED_BY_AUTOMATION:
+ webView->priv->isControlledByAutomation = g_value_get_boolean(value);
+ break;
case PROP_EDITABLE:
webkit_web_view_set_editable(webView, g_value_get_boolean(value));
break;
@@ -785,6 +791,9 @@
case PROP_IS_EPHEMERAL:
g_value_set_boolean(value, webkit_web_view_is_ephemeral(webView));
break;
+ case PROP_IS_CONTROLLED_BY_AUTOMATION:
+ g_value_set_boolean(value, webkit_web_view_is_controlled_by_automation(webView));
+ break;
case PROP_EDITABLE:
g_value_set_boolean(value, webkit_web_view_is_editable(webView));
break;
@@ -1048,6 +1057,25 @@
static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
/**
+ * WebKitWebView:is-controlled-by-automation:
+ *
+ * Whether the #WebKitWebView is controlled by automation. This should only be used when
+ * creating a new #WebKitWebView as a response to #WebKitAutomationSession::create-web-view
+ * signal request.
+ *
+ * Since: 2.18
+ */
+ g_object_class_install_property(
+ gObjectClass,
+ PROP_IS_CONTROLLED_BY_AUTOMATION,
+ g_param_spec_boolean(
+ "is-controlled-by-automation",
+ "Is Controlled By Automation",
+ _("Whether the web view is crontrolled by automation"),
+ FALSE,
+ static_cast<GParamFlags>(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
+
+ /**
* WebKitWebView:editable:
*
* Whether the pages loaded inside #WebKitWebView are editable. For more
@@ -2317,6 +2345,25 @@
}
/**
+ * webkit_web_view_is_controlled_by_automation:
+ * @web_view: a #WebKitWebView
+ *
+ * Get whether a #WebKitWebView was created with #WebKitWebView:is-controlled-by-automation
+ * property enabled. Only #WebKitWebView<!-- -->s controlled by automation can be used in an
+ * automation session.
+ *
+ * Returns: %TRUE if @web_view is controlled by automation, or %FALSE otherwise.
+ *
+ * Since: 2.18
+ */
+gboolean webkit_web_view_is_controlled_by_automation(WebKitWebView* webView)
+{
+ g_return_val_if_fail(WEBKIT_IS_WEB_VIEW(webView), FALSE);
+
+ return webView->priv->isControlledByAutomation;
+}
+
+/**
* webkit_web_view_get_website_data_manager:
* @web_view: a #WebKitWebView
*
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/WebKitWebView.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -277,6 +277,9 @@
WEBKIT_API gboolean
webkit_web_view_is_ephemeral (WebKitWebView *web_view);
+WEBKIT_API gboolean
+webkit_web_view_is_controlled_by_automation (WebKitWebView *web_view);
+
WEBKIT_API WebKitWebsiteDataManager *
webkit_web_view_get_website_data_manager (WebKitWebView *web_view);
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0-sections.txt 2017-05-01 07:03:58 UTC (rev 216006)
@@ -33,6 +33,8 @@
webkit_web_context_new_ephemeral
webkit_web_context_new_with_website_data_manager
webkit_web_context_is_ephemeral
+webkit_web_context_is_automation_allowed
+webkit_web_context_set_automation_allowed
webkit_web_context_get_website_data_manager
webkit_web_context_get_cache_model
webkit_web_context_set_cache_model
@@ -161,6 +163,7 @@
webkit_web_view_new_with_settings
webkit_web_view_new_with_user_content_manager
webkit_web_view_is_ephemeral
+webkit_web_view_is_controlled_by_automation
webkit_web_view_get_context
webkit_web_view_get_user_content_manager
webkit_web_view_get_website_data_manager
@@ -1308,6 +1311,25 @@
</SECTION>
<SECTION>
+<FILE>WebKitAutomationSession</FILE>
+WebKitAutomationSession
+webkit_automation_session_get_id
+
+<SUBSECTION Private>
+WebKitAutomationSessionPrivate
+webkit_automation_session_get_type
+
+<SUBSECTION Standard>
+WebKitAutomationSessionClass
+WEBKIT_TYPE_AUTOMATION_SESSION
+WEBKIT_AUTOMATION_SESSION
+WEBKIT_IS_AUTOMATION_SESSION
+WEBKIT_AUTOMATION_SESSION_CLASS
+WEBKIT_IS_AUTOMATION_SESSION_CLASS
+WEBKIT_AUTOMATION_SESSION_GET_CLASS
+</SECTION>
+
+<SECTION>
<FILE>WebKitWebExtension</FILE>
WebKitWebExtension
WebKitWebExtensionInitializeFunction
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-4.0.types 2017-05-01 07:03:58 UTC (rev 216006)
@@ -35,3 +35,4 @@
webkit_console_message_get_type
webkit_web_view_session_state_get_type
webkit_print_custom_widget_get_type
+webkit_automation_session_get_type
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/docs/webkit2gtk-docs.sgml 2017-05-01 07:03:58 UTC (rev 216006)
@@ -56,6 +56,7 @@
<xi:include href=""
<xi:include href=""
<xi:include href=""
+ <xi:include href=""
</chapter>
<chapter>
@@ -118,5 +119,10 @@
<xi:include href="" /></xi:include>
</index>
+ <index id="api-index-2-18" role="2.18">
+ <title>Index of new symbols in 2.18</title>
+ <xi:include href="" /></xi:include>
+ </index>
+
<xi:include href="" /></xi:include>
</book>
Modified: trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h (216005 => 216006)
--- trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Source/WebKit2/UIProcess/API/gtk/webkit2.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -28,6 +28,7 @@
#define __WEBKIT2_H_INSIDE__
#include <webkit2/WebKitAuthenticationRequest.h>
+#include <webkit2/WebKitAutomationSession.h>
#include <webkit2/WebKitBackForwardList.h>
#include <webkit2/WebKitBackForwardListItem.h>
#include <webkit2/WebKitContextMenu.h>
Modified: trunk/Tools/ChangeLog (216005 => 216006)
--- trunk/Tools/ChangeLog 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Tools/ChangeLog 2017-05-01 07:03:58 UTC (rev 216006)
@@ -1,3 +1,32 @@
+2017-05-01 Carlos Garcia Campos <[email protected]>
+
+ [GTK] Add automation session API
+ https://bugs.webkit.org/show_bug.cgi?id=171428
+
+ Reviewed by Carlos Alberto Lopez Perez.
+
+ Add an automation mode to MiniBrowser using the new API and add a unit test too.
+
+ * MiniBrowser/gtk/BrowserWindow.c:
+ (webViewTitleChanged):
+ (webViewDecidePolicy):
+ (newTabCallback):
+ (openPrivateWindow):
+ (browserWindowFinalize):
+ (browser_window_init):
+ (browser_window_get_or_create_web_view_for_automation):
+ * MiniBrowser/gtk/BrowserWindow.h:
+ * MiniBrowser/gtk/main.c:
+ (createBrowserTab):
+ (createWebViewForAutomationCallback):
+ (automationStartedCallback):
+ (main):
+ * TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt:
+ * TestWebKitAPI/Tests/WebKit2Gtk/TestAutomationSession.cpp: Added.
+ (testAutomationSessionRequestSession):
+ (beforeAll):
+ (afterAll):
+
2017-04-30 Dan Bernstein <[email protected]>
[Cocoa] Have check-webkit-style advise against use of [get…Class() alloc]
Modified: trunk/Tools/MiniBrowser/gtk/BrowserWindow.c (216005 => 216006)
--- trunk/Tools/MiniBrowser/gtk/BrowserWindow.c 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Tools/MiniBrowser/gtk/BrowserWindow.c 2017-05-01 07:03:58 UTC (rev 216006)
@@ -76,7 +76,7 @@
static const gdouble maximumZoomLevel = 3;
static const gdouble defaultZoomLevel = 1;
static const gdouble zoomStep = 1.2;
-static gint windowCount = 0;
+static GList *windowList;
G_DEFINE_TYPE(BrowserWindow, browser_window, GTK_TYPE_WINDOW)
@@ -155,7 +155,9 @@
if (!title)
title = defaultWindowTitle;
char *privateTitle = NULL;
- if (webkit_web_view_is_ephemeral(webView))
+ if (webkit_web_view_is_controlled_by_automation(webView))
+ privateTitle = g_strdup_printf("[Automation] %s", title);
+ else if (webkit_web_view_is_ephemeral(webView))
privateTitle = g_strdup_printf("[Private] %s", title);
gtk_window_set_title(GTK_WINDOW(window), privateTitle ? privateTitle : title);
g_free(privateTitle);
@@ -355,6 +357,7 @@
"web-context", webkit_web_view_get_context(webView),
"settings", webkit_web_view_get_settings(webView),
"user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ "is-controlled-by-automation", webkit_web_view_is_controlled_by_automation(webView),
NULL));
browser_window_append_view(window, newWebView);
webkit_web_view_load_request(newWebView, webkit_navigation_action_get_request(navigationAction));
@@ -496,6 +499,7 @@
"web-context", webkit_web_view_get_context(webView),
"settings", webkit_web_view_get_settings(webView),
"user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ "is-controlled-by-automation", webkit_web_view_is_controlled_by_automation(webView),
NULL)));
gtk_notebook_set_current_page(GTK_NOTEBOOK(window->notebook), -1);
}
@@ -513,6 +517,7 @@
"settings", webkit_web_view_get_settings(webView),
"user-content-manager", webkit_web_view_get_user_content_manager(webView),
"is-ephemeral", TRUE,
+ "is-controlled-by-automation", webkit_web_view_is_controlled_by_automation(webView),
NULL));
GtkWidget *newWindow = browser_window_new(GTK_WINDOW(window), window->webContext);
browser_window_append_view(BROWSER_WINDOW(newWindow), newWebView);
@@ -662,9 +667,11 @@
g_free(window->sessionFile);
+ windowList = g_list_remove(windowList, window);
+
G_OBJECT_CLASS(browser_window_parent_class)->finalize(gObject);
- if (g_atomic_int_dec_and_test(&windowCount))
+ if (!windowList)
gtk_main_quit();
}
@@ -862,7 +869,7 @@
static void browser_window_init(BrowserWindow *window)
{
- g_atomic_int_inc(&windowCount);
+ windowList = g_list_append(windowList, window);
gtk_window_set_title(GTK_WINDOW(window), defaultWindowTitle);
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
@@ -1157,3 +1164,23 @@
webkit_web_view_set_background_color(webView, rgba);
}
+
+WebKitWebView *browser_window_get_or_create_web_view_for_automation(void)
+{
+ if (!windowList)
+ return NULL;
+
+ BrowserWindow *window = (BrowserWindow *)windowList->data;
+ WebKitWebView *webView = browser_tab_get_web_view(window->activeTab);
+ if (gtk_notebook_get_n_pages(GTK_NOTEBOOK(window->notebook)) == 1 && !webkit_web_view_get_uri(webView));
+ return webView;
+
+ WebKitWebView *newWebView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW,
+ "web-context", webkit_web_view_get_context(webView),
+ "settings", webkit_web_view_get_settings(webView),
+ "user-content-manager", webkit_web_view_get_user_content_manager(webView),
+ "is-controlled-by-automation", TRUE,
+ NULL));
+ browser_window_append_view(window, newWebView);
+ return newWebView;
+}
Modified: trunk/Tools/MiniBrowser/gtk/BrowserWindow.h (216005 => 216006)
--- trunk/Tools/MiniBrowser/gtk/BrowserWindow.h 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Tools/MiniBrowser/gtk/BrowserWindow.h 2017-05-01 07:03:58 UTC (rev 216006)
@@ -51,6 +51,7 @@
void browser_window_load_uri(BrowserWindow*, const char *uri);
void browser_window_load_session(BrowserWindow *, const char *sessionFile);
void browser_window_set_background_color(BrowserWindow*, GdkRGBA*);
+WebKitWebView* browser_window_get_or_create_web_view_for_automation(void);
G_END_DECLS
Modified: trunk/Tools/MiniBrowser/gtk/main.c (216005 => 216006)
--- trunk/Tools/MiniBrowser/gtk/main.c 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Tools/MiniBrowser/gtk/main.c 2017-05-01 07:03:58 UTC (rev 216006)
@@ -42,6 +42,7 @@
static const char *sessionFile;
static char *geometry;
static gboolean privateMode;
+static gboolean automationMode;
typedef enum {
MINI_BROWSER_ERROR_INVALID_ABOUT_PATH
@@ -67,6 +68,7 @@
"web-context", browser_window_get_web_context(window),
"settings", webkitSettings,
"user-content-manager", userContentManager,
+ "is-controlled-by-automation", automationMode,
NULL));
if (editorMode)
@@ -95,6 +97,7 @@
{ "session-file", 's', 0, G_OPTION_ARG_FILENAME, &sessionFile, "Session file", "FILE" },
{ "geometry", 'g', 0, G_OPTION_ARG_STRING, &geometry, "Set the size and position of the window (WIDTHxHEIGHT+X+Y)", "GEOMETRY" },
{ "private", 'p', 0, G_OPTION_ARG_NONE, &privateMode, "Run in private browsing mode", NULL },
+ { "automation", 0, 0, G_OPTION_ARG_NONE, &automationMode, "Run in automation mode", NULL },
{ G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &uriArguments, 0, "[URL…]" },
{ 0, 0, 0, 0, 0, 0, 0 }
};
@@ -448,6 +451,16 @@
}
}
+static GtkWidget *createWebViewForAutomationCallback(WebKitAutomationSession* session)
+{
+ return GTK_WIDGET(browser_window_get_or_create_web_view_for_automation());
+}
+
+static void automationStartedCallback(WebKitWebContext *webContext, WebKitAutomationSession *session)
+{
+ g_signal_connect(session, "create-web-view", G_CALLBACK(createWebViewForAutomationCallback), NULL);
+}
+
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
@@ -476,7 +489,7 @@
}
g_option_context_free (context);
- WebKitWebContext *webContext = privateMode ? webkit_web_context_new_ephemeral() : webkit_web_context_get_default();
+ WebKitWebContext *webContext = (privateMode || automationMode) ? webkit_web_context_new_ephemeral() : webkit_web_context_get_default();
const gchar *singleprocess = g_getenv("MINIBROWSER_SINGLEPROCESS");
webkit_web_context_set_process_model(webContext, (singleprocess && *singleprocess) ?
@@ -491,6 +504,9 @@
webkit_user_content_manager_register_script_message_handler(userContentManager, "aboutData");
g_signal_connect(userContentManager, "script-message-received::aboutData", G_CALLBACK(aboutDataScriptMessageReceivedCallback), webContext);
+ webkit_web_context_set_automation_allowed(webContext, automationMode);
+ g_signal_connect(webContext, "automation-started", G_CALLBACK(automationStartedCallback), NULL);
+
BrowserWindow *mainWindow = BROWSER_WINDOW(browser_window_new(NULL, webContext));
if (geometry)
gtk_window_parse_geometry(GTK_WINDOW(mainWindow), geometry);
@@ -517,7 +533,7 @@
if (!editorMode) {
if (sessionFile)
browser_window_load_session(mainWindow, sessionFile);
- else
+ else if (!automationMode)
webkit_web_view_load_uri(webView, BROWSER_DEFAULT_URL);
}
}
Modified: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt (216005 => 216006)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt 2017-05-01 07:02:07 UTC (rev 216005)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/CMakeLists.txt 2017-05-01 07:03:58 UTC (rev 216006)
@@ -97,6 +97,7 @@
ADD_WK2_TEST(InspectorTestServer InspectorTestServer.cpp)
ADD_WK2_TEST(TestAuthentication TestAuthentication.cpp)
+ADD_WK2_TEST(TestAutomationSession TestAutomationSession.cpp)
ADD_WK2_TEST(TestAutocleanups TestAutocleanups.cpp)
ADD_WK2_TEST(TestBackForwardList TestBackForwardList.cpp)
ADD_WK2_TEST(TestContextMenu TestContextMenu.cpp)
Added: trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutomationSession.cpp (0 => 216006)
--- trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutomationSession.cpp (rev 0)
+++ trunk/Tools/TestWebKitAPI/Tests/WebKit2Gtk/TestAutomationSession.cpp 2017-05-01 07:03:58 UTC (rev 216006)
@@ -0,0 +1,283 @@
+/*
+ * Copyright (C) 2017 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2,1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include "TestMain.h"
+#include <gio/gio.h>
+#include <wtf/UUID.h>
+#include <wtf/text/StringBuilder.h>
+
+class AutomationTest: public Test {
+public:
+ MAKE_GLIB_TEST_FIXTURE(AutomationTest);
+
+ AutomationTest()
+ : m_mainLoop(adoptGRef(g_main_loop_new(nullptr, TRUE)))
+ {
+ g_dbus_connection_new_for_address("tcp:host=127.0.0.1,port=2229",
+ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, nullptr, nullptr, [](GObject*, GAsyncResult* result, gpointer userData) {
+ GRefPtr<GDBusConnection> connection = adoptGRef(g_dbus_connection_new_for_address_finish(result, nullptr));
+ static_cast<AutomationTest*>(userData)->setConnection(WTFMove(connection));
+ }, this);
+ g_main_loop_run(m_mainLoop.get());
+ }
+
+ ~AutomationTest()
+ {
+ }
+
+ struct Target {
+ Target() = default;
+ Target(guint64 id, CString name, bool isPaired)
+ : id(id)
+ , name(name)
+ , isPaired(isPaired)
+ {
+ }
+
+ guint64 id { 0 };
+ CString name;
+ bool isPaired { false };
+ };
+
+ const GDBusInterfaceVTable s_interfaceVTable = {
+ // method_call
+ [](GDBusConnection* connection, const gchar* sender, const gchar* objectPath, const gchar* interfaceName, const gchar* methodName, GVariant* parameters, GDBusMethodInvocation* invocation, gpointer userData) {
+ auto* test = static_cast<AutomationTest*>(userData);
+ if (!g_strcmp0(methodName, "SetTargetList")) {
+ guint64 connectionID;
+ GUniqueOutPtr<GVariantIter> iter;
+ g_variant_get(parameters, "(ta(tsssb))", &connectionID, &iter.outPtr());
+ guint64 targetID;
+ const char* type;
+ const char* name;
+ const char* dummy;
+ gboolean isPaired;
+ while (g_variant_iter_loop(iter.get(), "(t&s&s&sb)", &targetID, &type, &name, &dummy, &isPaired)) {
+ if (!g_strcmp0(type, "Automation")) {
+ test->setTarget(connectionID, Target(targetID, name, isPaired));
+ break;
+ }
+ }
+ g_dbus_method_invocation_return_value(invocation, nullptr);
+ } else if (!g_strcmp0(methodName, "SendMessageToFrontend")) {
+ guint64 connectionID, targetID;
+ const char* message;
+ g_variant_get(parameters, "(tt&s)", &connectionID, &targetID, &message);
+ test->receivedMessage(connectionID, targetID, message);
+ g_dbus_method_invocation_return_value(invocation, nullptr);
+ }
+ },
+ // get_property
+ nullptr,
+ // set_property
+ nullptr,
+ };
+
+ void registerDBusObject()
+ {
+ static const char introspectionXML[] =
+ "<node>"
+ " <interface name='org.webkitgtk.RemoteInspectorClient'>"
+ " <method name='SetTargetList'>"
+ " <arg type='t' name='connectionID' direction='in'/>"
+ " <arg type='a(tsssb)' name='list' direction='in'/>"
+ " </method>"
+ " <method name='SendMessageToFrontend'>"
+ " <arg type='t' name='connectionID' direction='in'/>"
+ " <arg type='t' name='target' direction='in'/>"
+ " <arg type='s' name='message' direction='in'/>"
+ " </method>"
+ " </interface>"
+ "</node>";
+ static GDBusNodeInfo* introspectionData = nullptr;
+ if (!introspectionData)
+ introspectionData = g_dbus_node_info_new_for_xml(introspectionXML, nullptr);
+ g_dbus_connection_register_object(m_connection.get(), "/org/webkitgtk/RemoteInspectorClient", introspectionData->interfaces[0], &s_interfaceVTable, this, nullptr, nullptr);
+ }
+
+ void setConnection(GRefPtr<GDBusConnection>&& connection)
+ {
+ g_assert(G_IS_DBUS_CONNECTION(connection.get()));
+ m_connection = WTFMove(connection);
+ registerDBusObject();
+ g_main_loop_quit(m_mainLoop.get());
+ }
+
+ void setTarget(guint64 connectionID, Target&& target)
+ {
+ bool newConnection = !m_connectionID;
+ bool wasPaired = m_target.isPaired;
+ m_connectionID = connectionID;
+ m_target = WTFMove(target);
+ if (newConnection || (!wasPaired && m_target.isPaired))
+ g_main_loop_quit(m_mainLoop.get());
+ }
+
+ void receivedMessage(guint64 connectionID, guint64 targetID, const char* message)
+ {
+ g_assert(connectionID == m_connectionID);
+ g_assert(targetID == m_target.id);
+ m_message = message;
+ g_main_loop_quit(m_mainLoop.get());
+ }
+
+ void sendCommandToBackend(const String& command, const String& parameters = String())
+ {
+ static long sequenceID = 0;
+ StringBuilder messageBuilder;
+ messageBuilder.appendLiteral("{\"id\":");
+ messageBuilder.appendNumber(++sequenceID);
+ messageBuilder.appendLiteral(",\"method\":\"Automation.");
+ messageBuilder.append(command);
+ messageBuilder.append('"');
+ if (!parameters.isNull()) {
+ messageBuilder.appendLiteral(",\"params\":");
+ messageBuilder.append(parameters);
+ }
+ messageBuilder.append('}');
+ g_dbus_connection_call(m_connection.get(), nullptr, "/org/webkitgtk/Inspector", "org.webkitgtk.Inspector",
+ "SendMessageToBackend", g_variant_new("(tts)", m_connectionID, m_target.id, messageBuilder.toString().utf8().data()),
+ nullptr, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, nullptr, nullptr, nullptr);
+ }
+
+ static WebKitWebView* createWebViewCallback(WebKitAutomationSession* session, AutomationTest* test)
+ {
+ test->m_createWebViewWasCalled = true;
+ return test->m_webViewForAutomation;
+ }
+
+ void automationStarted(WebKitAutomationSession* session)
+ {
+ m_session = session;
+ assertObjectIsDeletedWhenTestFinishes(G_OBJECT(m_session));
+ }
+
+ static void automationStartedCallback(WebKitWebContext* webContext, WebKitAutomationSession* session, AutomationTest* test)
+ {
+ g_assert(webContext == test->m_webContext.get());
+ g_assert(WEBKIT_IS_AUTOMATION_SESSION(session));
+ test->automationStarted(session);
+ }
+
+ WebKitAutomationSession* requestSession(const char* sessionID)
+ {
+ auto signalID = g_signal_connect(m_webContext.get(), "automation-started", G_CALLBACK(automationStartedCallback), this);
+ g_dbus_connection_call(m_connection.get(), nullptr, "/org/webkitgtk/Inspector", "org.webkitgtk.Inspector",
+ "StartAutomationSession", g_variant_new("(s)", sessionID), nullptr, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, nullptr, nullptr, nullptr);
+ auto timeoutID = g_timeout_add(1000, [](gpointer userData) -> gboolean {
+ g_main_loop_quit(static_cast<GMainLoop*>(userData));
+ return G_SOURCE_REMOVE;
+ }, m_mainLoop.get());
+ g_main_loop_run(m_mainLoop.get());
+ if (!m_connectionID)
+ m_session = nullptr;
+ if (m_session && m_connectionID)
+ g_source_remove(timeoutID);
+ g_signal_handler_disconnect(m_webContext.get(), signalID);
+ return m_session;
+ }
+
+ void setupIfNeeded()
+ {
+ if (m_target.isPaired)
+ return;
+ g_assert(m_target.id);
+ g_dbus_connection_call(m_connection.get(), nullptr, "/org/webkitgtk/Inspector", "org.webkitgtk.Inspector",
+ "Setup", g_variant_new("(tt)", m_connectionID, m_target.id), nullptr, G_DBUS_CALL_FLAGS_NO_AUTO_START, -1, nullptr, nullptr, nullptr);
+ g_main_loop_run(m_mainLoop.get());
+ g_assert(m_target.isPaired);
+ }
+
+ bool createTopLevelBrowsingContext(WebKitWebView* webView)
+ {
+ setupIfNeeded();
+ m_webViewForAutomation = webView;
+ m_createWebViewWasCalled = false;
+ m_message = CString();
+ auto signalID = g_signal_connect(m_session, "create-web-view", G_CALLBACK(createWebViewCallback), this);
+ sendCommandToBackend("createBrowsingContext");
+ g_main_loop_run(m_mainLoop.get());
+ g_signal_handler_disconnect(m_session, signalID);
+ g_assert(m_createWebViewWasCalled);
+ g_assert(!m_message.isNull());
+ m_webViewForAutomation = nullptr;
+
+ if (strstr(m_message.data(), "The remote session failed to create a new browsing context"))
+ return false;
+ if (strstr(m_message.data(), "handle"))
+ return true;
+ return false;
+ }
+
+ GRefPtr<GMainLoop> m_mainLoop;
+ GRefPtr<GDBusConnection> m_connection;
+ WebKitAutomationSession* m_session;
+ guint64 m_connectionID { 0 };
+ Target m_target;
+
+ WebKitWebView* m_webViewForAutomation { nullptr };
+ bool m_createWebViewWasCalled { false };
+ CString m_message;
+};
+
+static void testAutomationSessionRequestSession(AutomationTest* test, gconstpointer)
+{
+ String sessionID = createCanonicalUUIDString();
+ // WebKitAutomationSession::automation-started is never emitted if automation is not enabled.
+ g_assert(!webkit_web_context_is_automation_allowed(test->m_webContext.get()));
+ auto* session = test->requestSession(sessionID.utf8().data());
+ g_assert(!session);
+
+ webkit_web_context_set_automation_allowed(test->m_webContext.get(), TRUE);
+ g_assert(webkit_web_context_is_automation_allowed(test->m_webContext.get()));
+ session = test->requestSession(sessionID.utf8().data());
+ g_assert_cmpstr(webkit_automation_session_get_id(session), ==, sessionID.utf8().data());
+ g_assert_cmpuint(test->m_target.id, >, 0);
+ ASSERT_CMP_CSTRING(test->m_target.name, ==, sessionID.utf8());
+ g_assert(!test->m_target.isPaired);
+
+ // Will fail to create a browsing context when not creating a web view (or not handling the signal).
+ g_assert(!test->createTopLevelBrowsingContext(nullptr));
+
+ // Will also fail if the web view is not controlled by automation.
+ GRefPtr<WebKitWebView> webView = WEBKIT_WEB_VIEW(webkit_web_view_new_with_context(test->m_webContext.get()));
+ g_assert(!webkit_web_view_is_controlled_by_automation(webView.get()));
+ g_assert(!test->createTopLevelBrowsingContext(webView.get()));
+
+ // And will work with a proper web view.
+ webView = WEBKIT_WEB_VIEW(g_object_new(WEBKIT_TYPE_WEB_VIEW, "web-context", test->m_webContext.get(), "is-controlled-by-automation", TRUE, nullptr));
+ g_assert(webkit_web_view_is_controlled_by_automation(webView.get()));
+ g_assert(test->createTopLevelBrowsingContext(webView.get()));
+
+ webkit_web_context_set_automation_allowed(test->m_webContext.get(), FALSE);
+}
+
+void beforeAll()
+{
+ g_setenv("WEBKIT_INSPECTOR_SERVER", "127.0.0.1:2229", TRUE);
+
+ AutomationTest::add("WebKitAutomationSession", "request-session", testAutomationSessionRequestSession);
+}
+
+void afterAll()
+{
+ g_unsetenv("WEBKIT_INSPECTOR_SERVER");
+}