WebDriver: implement maximize, minimize and fullscreen window commands
authorcarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 May 2018 08:54:37 +0000 (08:54 +0000)
committercarlosgc@webkit.org <carlosgc@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Thu, 24 May 2018 08:54:37 +0000 (08:54 +0000)
https://bugs.webkit.org/show_bug.cgi?id=180398

Reviewed by Brian Burg.

Source/WebDriver:

* CMakeLists.txt: Add EnterFullscreen.js to the build.
* Session.cpp:
(WebDriver::Session::maximizeWindow):
(WebDriver::Session::minimizeWindow):
(WebDriver::Session::fullscreenWindow):
* Session.h:
* WebDriverService.cpp:
(WebDriver::WebDriverService::maximizeWindow):
(WebDriver::WebDriverService::minimizeWindow):
(WebDriver::WebDriverService::fullscreenWindow):
* WebDriverService.h:

Source/WebKit:

* UIProcess/API/APIAutomationSessionClient.h:
(API::AutomationSessionClient::requestMaximizeWindowOfPage): Added to allow clients maximize the window.
* UIProcess/API/glib/WebKitAutomationSession.cpp:
* UIProcess/API/glib/WebKitWebViewPrivate.h:
* UIProcess/API/gtk/WebKitWebViewGtk.cpp:
(WindowStateEvent::WindowStateEvent): Struct to handle window state events.
(WindowStateEvent::~WindowStateEvent): Complete the event.
(WindowStateEvent::complete): Call the completion handler is not called already.
(windowStateEventCallback): Handle window state event changes.
(webkitWebViewMaximizeWindow): Try to maximize the window and wait for the event.
(webkitWebViewMinimizeWindow): Try to minimize the window and wait for the event.
(webkitWebViewRestoreWindow): Try to unmaximize or unminimize the window and wait for the event.
* UIProcess/API/wpe/WebKitWebViewWPE.cpp:
(webkitWebViewMaximizeWindow):
(webkitWebViewMinimizeWindow):
(webkitWebViewRestoreWindow):
* UIProcess/Automation/Automation.json:
* UIProcess/Automation/WebAutomationSession.cpp:
(WebKit::WebAutomationSession::maximizeWindowOfBrowsingContext): Exit fullscreen, restore the window and then
maximize it.
(WebKit::WebAutomationSession::maximizeWindowForPage): Ask the client to maximize the window of page.
* UIProcess/Automation/WebAutomationSession.h:
* UIProcess/Automation/atoms/EnterFullscreen.js:
(enterFullscreen): Return early if fullscreen is disabled or if window is already in fullscreen.

Tools:

* Scripts/webkitpy/port/xvfbdriver.py:
(XvfbDriver._setup_environ_for_test): Set UNDER_XVFB environment variable when running under Xvfb.

WebDriverTests:

Remove expectations for tests that are passing now.

* TestExpectations.json:

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

20 files changed:
Source/WebDriver/CMakeLists.txt
Source/WebDriver/ChangeLog
Source/WebDriver/Session.cpp
Source/WebDriver/Session.h
Source/WebDriver/WebDriverService.cpp
Source/WebDriver/WebDriverService.h
Source/WebKit/ChangeLog
Source/WebKit/UIProcess/API/APIAutomationSessionClient.h
Source/WebKit/UIProcess/API/glib/WebKitAutomationSession.cpp
Source/WebKit/UIProcess/API/glib/WebKitWebViewPrivate.h
Source/WebKit/UIProcess/API/gtk/WebKitWebViewGtk.cpp
Source/WebKit/UIProcess/API/wpe/WebKitWebViewWPE.cpp
Source/WebKit/UIProcess/Automation/Automation.json
Source/WebKit/UIProcess/Automation/WebAutomationSession.cpp
Source/WebKit/UIProcess/Automation/WebAutomationSession.h
Source/WebKit/UIProcess/Automation/atoms/EnterFullscreen.js
Tools/ChangeLog
Tools/Scripts/webkitpy/port/xvfbdriver.py
WebDriverTests/ChangeLog
WebDriverTests/TestExpectations.json

index 8bb1077..0768ae9 100644 (file)
@@ -22,6 +22,7 @@ set(WebDriver_LIBRARIES
 set(WebDriver_SCRIPTS
     ${WEBKIT_DIR}/UIProcess/Automation/atoms/ElementAttribute.js
     ${WEBKIT_DIR}/UIProcess/Automation/atoms/ElementDisplayed.js
+    ${WEBKIT_DIR}/UIProcess/Automation/atoms/EnterFullscreen.js
     ${WEBKIT_DIR}/UIProcess/Automation/atoms/FindNodes.js
     ${WEBKIT_DIR}/UIProcess/Automation/atoms/FormElementClear.js
     ${WEBKIT_DIR}/UIProcess/Automation/atoms/FormSubmit.js
index b2ff0df..2f29533 100644 (file)
@@ -1,3 +1,22 @@
+2018-05-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        WebDriver: implement maximize, minimize and fullscreen window commands
+        https://bugs.webkit.org/show_bug.cgi?id=180398
+
+        Reviewed by Brian Burg.
+
+        * CMakeLists.txt: Add EnterFullscreen.js to the build.
+        * Session.cpp:
+        (WebDriver::Session::maximizeWindow):
+        (WebDriver::Session::minimizeWindow):
+        (WebDriver::Session::fullscreenWindow):
+        * Session.h:
+        * WebDriverService.cpp:
+        (WebDriver::WebDriverService::maximizeWindow):
+        (WebDriver::WebDriverService::minimizeWindow):
+        (WebDriver::WebDriverService::fullscreenWindow):
+        * WebDriverService.h:
+
 2018-05-23  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         [GTK] WebDriver: implement AutomationSessionClient::didDisconnectFromRemote
index 3d95ab4..5335696 100644 (file)
@@ -774,6 +774,96 @@ void Session::setWindowRect(std::optional<double> x, std::optional<double> y, st
     });
 }
 
+void Session::maximizeWindow(Function<void (CommandResult&&)>&& completionHandler)
+{
+    if (!m_toplevelBrowsingContext) {
+        completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
+        return;
+    }
+
+    handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+        if (result.isError()) {
+            completionHandler(WTFMove(result));
+            return;
+        }
+
+        RefPtr<JSON::Object> parameters = JSON::Object::create();
+        parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
+        m_host->sendCommandToBackend(ASCIILiteral("maximizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (SessionHost::CommandResponse&& response) mutable {
+            if (response.isError) {
+                completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
+                return;
+            }
+            getToplevelBrowsingContextRect(WTFMove(completionHandler));
+        });
+    });
+}
+
+void Session::minimizeWindow(Function<void (CommandResult&&)>&& completionHandler)
+{
+    if (!m_toplevelBrowsingContext) {
+        completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
+        return;
+    }
+
+    handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+        if (result.isError()) {
+            completionHandler(WTFMove(result));
+            return;
+        }
+
+        RefPtr<JSON::Object> parameters = JSON::Object::create();
+        parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
+        m_host->sendCommandToBackend(ASCIILiteral("hideWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)] (SessionHost::CommandResponse&& response) mutable {
+            if (response.isError) {
+                completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
+                return;
+            }
+            getToplevelBrowsingContextRect(WTFMove(completionHandler));
+        });
+    });
+}
+
+void Session::fullscreenWindow(Function<void (CommandResult&&)>&& completionHandler)
+{
+    if (!m_toplevelBrowsingContext) {
+        completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
+        return;
+    }
+
+    handleUserPrompts([this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
+        if (result.isError()) {
+            completionHandler(WTFMove(result));
+            return;
+        }
+
+        RefPtr<JSON::Object> parameters = JSON::Object::create();
+        parameters->setString(ASCIILiteral("browsingContextHandle"), m_toplevelBrowsingContext.value());
+        parameters->setString(ASCIILiteral("function"), EnterFullscreenJavaScript);
+        parameters->setArray(ASCIILiteral("arguments"), JSON::Array::create());
+        parameters->setBoolean(ASCIILiteral("expectsImplicitCallbackArgument"), true);
+        m_host->sendCommandToBackend(ASCIILiteral("evaluateJavaScriptFunction"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) mutable {
+            if (response.isError || !response.responseObject) {
+                completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
+                return;
+            }
+
+            String valueString;
+            if (!response.responseObject->getString(ASCIILiteral("result"), valueString)) {
+                completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
+                return;
+            }
+            RefPtr<JSON::Value> resultValue;
+            if (!JSON::Value::parseJSON(valueString, resultValue)) {
+                completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
+                return;
+            }
+
+            getToplevelBrowsingContextRect(WTFMove(completionHandler));
+        });
+    });
+}
+
 RefPtr<JSON::Object> Session::createElement(RefPtr<JSON::Value>&& value)
 {
     RefPtr<JSON::Object> valueObject;
index ec6430a..72ab07d 100644 (file)
@@ -90,6 +90,9 @@ public:
     void switchToParentFrame(Function<void (CommandResult&&)>&&);
     void getWindowRect(Function<void (CommandResult&&)>&&);
     void setWindowRect(std::optional<double> x, std::optional<double> y, std::optional<double> width, std::optional<double> height, Function<void (CommandResult&&)>&&);
+    void maximizeWindow(Function<void (CommandResult&&)>&&);
+    void minimizeWindow(Function<void (CommandResult&&)>&&);
+    void fullscreenWindow(Function<void (CommandResult&&)>&&);
     void findElements(const String& strategy, const String& selector, FindElementsMode, const String& rootElementID, Function<void (CommandResult&&)>&&);
     void getActiveElement(Function<void (CommandResult&&)>&&);
     void isElementSelected(const String& elementID, Function<void (CommandResult&&)>&&);
index ee3fc6e..38d19e4 100644 (file)
@@ -122,6 +122,9 @@ const WebDriverService::Command WebDriverService::s_commands[] = {
     { HTTPMethod::Post, "/session/$sessionId/frame/parent", &WebDriverService::switchToParentFrame },
     { HTTPMethod::Get, "/session/$sessionId/window/rect", &WebDriverService::getWindowRect },
     { HTTPMethod::Post, "/session/$sessionId/window/rect", &WebDriverService::setWindowRect },
+    { HTTPMethod::Post, "/session/$sessionId/window/maximize", &WebDriverService::maximizeWindow },
+    { HTTPMethod::Post, "/session/$sessionId/window/minimize", &WebDriverService::minimizeWindow },
+    { HTTPMethod::Post, "/session/$sessionId/window/fullscreen", &WebDriverService::fullscreenWindow },
 
     { HTTPMethod::Post, "/session/$sessionId/element", &WebDriverService::findElement },
     { HTTPMethod::Post, "/session/$sessionId/elements", &WebDriverService::findElements },
@@ -968,6 +971,30 @@ void WebDriverService::setWindowRect(RefPtr<JSON::Object>&& parameters, Function
         m_session->setWindowRect(x, y, width, height, WTFMove(completionHandler));
 }
 
+void WebDriverService::maximizeWindow(RefPtr<JSON::Object>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
+{
+    // §10.7.3 Maximize Window
+    // https://w3c.github.io/webdriver/#maximize-window
+    if (findSessionOrCompleteWithError(*parameters, completionHandler))
+        m_session->maximizeWindow(WTFMove(completionHandler));
+}
+
+void WebDriverService::minimizeWindow(RefPtr<JSON::Object>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
+{
+    // §10.7.4 Minimize Window
+    // https://w3c.github.io/webdriver/#minimize-window
+    if (findSessionOrCompleteWithError(*parameters, completionHandler))
+        m_session->minimizeWindow(WTFMove(completionHandler));
+}
+
+void WebDriverService::fullscreenWindow(RefPtr<JSON::Object>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
+{
+    // §10.7.5 Fullscreen Window
+    // https://w3c.github.io/webdriver/#fullscreen-window
+    if (findSessionOrCompleteWithError(*parameters, completionHandler))
+        m_session->fullscreenWindow(WTFMove(completionHandler));
+}
+
 void WebDriverService::closeWindow(RefPtr<JSON::Object>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
 {
     // §10.2 Close Window.
index 7ea45bd..4d6878e 100644 (file)
@@ -79,6 +79,9 @@ private:
     void switchToParentFrame(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     void getWindowRect(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     void setWindowRect(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
+    void maximizeWindow(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
+    void minimizeWindow(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
+    void fullscreenWindow(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     void findElement(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     void findElements(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
     void findElementFromElement(RefPtr<JSON::Object>&&, Function<void (CommandResult&&)>&&);
index 25b3002..628389b 100644 (file)
@@ -1,3 +1,35 @@
+2018-05-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        WebDriver: implement maximize, minimize and fullscreen window commands
+        https://bugs.webkit.org/show_bug.cgi?id=180398
+
+        Reviewed by Brian Burg.
+
+        * UIProcess/API/APIAutomationSessionClient.h:
+        (API::AutomationSessionClient::requestMaximizeWindowOfPage): Added to allow clients maximize the window.
+        * UIProcess/API/glib/WebKitAutomationSession.cpp:
+        * UIProcess/API/glib/WebKitWebViewPrivate.h:
+        * UIProcess/API/gtk/WebKitWebViewGtk.cpp:
+        (WindowStateEvent::WindowStateEvent): Struct to handle window state events.
+        (WindowStateEvent::~WindowStateEvent): Complete the event.
+        (WindowStateEvent::complete): Call the completion handler is not called already.
+        (windowStateEventCallback): Handle window state event changes.
+        (webkitWebViewMaximizeWindow): Try to maximize the window and wait for the event.
+        (webkitWebViewMinimizeWindow): Try to minimize the window and wait for the event.
+        (webkitWebViewRestoreWindow): Try to unmaximize or unminimize the window and wait for the event.
+        * UIProcess/API/wpe/WebKitWebViewWPE.cpp:
+        (webkitWebViewMaximizeWindow):
+        (webkitWebViewMinimizeWindow):
+        (webkitWebViewRestoreWindow):
+        * UIProcess/Automation/Automation.json:
+        * UIProcess/Automation/WebAutomationSession.cpp:
+        (WebKit::WebAutomationSession::maximizeWindowOfBrowsingContext): Exit fullscreen, restore the window and then
+        maximize it.
+        (WebKit::WebAutomationSession::maximizeWindowForPage): Ask the client to maximize the window of page.
+        * UIProcess/Automation/WebAutomationSession.h:
+        * UIProcess/Automation/atoms/EnterFullscreen.js:
+        (enterFullscreen): Return early if fullscreen is disabled or if window is already in fullscreen.
+
 2018-05-23  Eric Carlson  <eric.carlson@apple.com>
 
         Avoid loading AVFoundation to check supported MIME types if possible
index 8076e44..bfc5ee3 100644 (file)
@@ -54,6 +54,7 @@ public:
     virtual String sessionIdentifier() const { return String(); }
     virtual void didDisconnectFromRemote(WebKit::WebAutomationSession&) { }
     virtual void requestNewPageWithOptions(WebKit::WebAutomationSession&, AutomationSessionBrowsingContextOptions, CompletionHandler<void(WebKit::WebPageProxy*)>&& completionHandler) { completionHandler(nullptr); }
+    virtual void requestMaximizeWindowOfPage(WebKit::WebAutomationSession&, WebKit::WebPageProxy&, CompletionHandler<void()>&& completionHandler) { completionHandler(); }
     virtual void requestHideWindowOfPage(WebKit::WebAutomationSession&, WebKit::WebPageProxy&, CompletionHandler<void()>&& completionHandler) { completionHandler(); }
     virtual void requestRestoreWindowOfPage(WebKit::WebAutomationSession&, WebKit::WebPageProxy&, CompletionHandler<void()>&& completionHandler) { completionHandler(); }
     virtual void requestSwitchToPage(WebKit::WebAutomationSession&, WebKit::WebPageProxy&, CompletionHandler<void()>&& completionHandler) { completionHandler(); }
index a12249f..0bd3832 100644 (file)
@@ -97,6 +97,30 @@ private:
             completionHandler(&webkitWebViewGetPage(webView));
     }
 
+    void requestMaximizeWindowOfPage(WebAutomationSession&, WebPageProxy& page, CompletionHandler<void()>&& completionHandler) override
+    {
+        if (auto* webView = webkitWebContextGetWebViewForPage(m_session->priv->webContext, &page))
+            webkitWebViewMaximizeWindow(webView, WTFMove(completionHandler));
+        else
+            completionHandler();
+    }
+
+    void requestHideWindowOfPage(WebAutomationSession&, WebPageProxy& page, CompletionHandler<void()>&& completionHandler) override
+    {
+        if (auto* webView = webkitWebContextGetWebViewForPage(m_session->priv->webContext, &page))
+            webkitWebViewMinimizeWindow(webView, WTFMove(completionHandler));
+        else
+            completionHandler();
+    }
+
+    void requestRestoreWindowOfPage(WebAutomationSession&, WebPageProxy& page, CompletionHandler<void()>&& completionHandler) override
+    {
+        if (auto* webView = webkitWebContextGetWebViewForPage(m_session->priv->webContext, &page))
+            webkitWebViewRestoreWindow(webView, WTFMove(completionHandler));
+        else
+            completionHandler();
+    }
+
     bool isShowingJavaScriptDialogOnPage(WebAutomationSession&, WebPageProxy& page) override
     {
         auto* webView = webkitWebContextGetWebViewForPage(m_session->priv->webContext, &page);
index 3605a91..51ee3b0 100644 (file)
@@ -36,6 +36,7 @@
 #include "WebPageProxy.h"
 #include <WebCore/IntRect.h>
 #include <WebCore/LinkIcon.h>
+#include <wtf/CompletionHandler.h>
 #include <wtf/text/CString.h>
 
 void webkitWebViewCreatePage(WebKitWebView*, Ref<API::PageConfiguration>&&);
@@ -74,6 +75,9 @@ WebKitWebResource* webkitWebViewGetLoadingWebResource(WebKitWebView*, uint64_t r
 void webKitWebViewDidReceiveSnapshot(WebKitWebView*, uint64_t callbackID, WebKit::WebImage*);
 #endif
 void webkitWebViewRemoveLoadingWebResource(WebKitWebView*, uint64_t resourceIdentifier);
+void webkitWebViewMaximizeWindow(WebKitWebView*, CompletionHandler<void()>&&);
+void webkitWebViewMinimizeWindow(WebKitWebView*, CompletionHandler<void()>&&);
+void webkitWebViewRestoreWindow(WebKitWebView*, CompletionHandler<void()>&&);
 void webkitWebViewEnterFullScreen(WebKitWebView*);
 void webkitWebViewExitFullScreen(WebKitWebView*);
 void webkitWebViewPopulateContextMenu(WebKitWebView*, const Vector<WebKit::WebContextMenuItemData>& proposedMenu, const WebKit::WebHitTestResultData&, GVariant*);
index c12eda0..9bc7520 100644 (file)
@@ -25,6 +25,8 @@
 #include "WebKitWebViewBasePrivate.h"
 #include "WebKitWebViewPrivate.h"
 #include <WebCore/GtkUtilities.h>
+#include <WebCore/PlatformDisplay.h>
+#include <WebCore/PlatformScreen.h>
 #include <glib/gi18n-lib.h>
 #include <gtk/gtk.h>
 
@@ -104,6 +106,154 @@ gboolean webkitWebViewRunFileChooser(WebKitWebView* webView, WebKitFileChooserRe
     return TRUE;
 }
 
+struct WindowStateEvent {
+    enum class Type { Maximize, Minimize, Restore };
+
+    WindowStateEvent(Type type, CompletionHandler<void()>&& completionHandler)
+        : type(type)
+        , completionHandler(WTFMove(completionHandler))
+        , completeTimer(RunLoop::main(), this, &WindowStateEvent::complete)
+    {
+        // Complete the event if not done after one second.
+        completeTimer.startOneShot(1_s);
+    }
+
+    ~WindowStateEvent()
+    {
+        complete();
+    }
+
+    void complete()
+    {
+        if (auto handler = std::exchange(completionHandler, nullptr))
+            handler();
+    }
+
+    Type type;
+    CompletionHandler<void()> completionHandler;
+    RunLoop::Timer<WindowStateEvent> completeTimer;
+};
+
+static const char* gWindowStateEventID = "wk-window-state-event";
+
+static gboolean windowStateEventCallback(GtkWidget* window, GdkEventWindowState* event, WebKitWebView* view)
+{
+    auto* state = static_cast<WindowStateEvent*>(g_object_get_data(G_OBJECT(view), gWindowStateEventID));
+    if (!state) {
+        g_signal_handlers_disconnect_by_func(window, reinterpret_cast<gpointer>(windowStateEventCallback), view);
+        return FALSE;
+    }
+
+    bool eventCompleted = false;
+    switch (state->type) {
+    case WindowStateEvent::Type::Maximize:
+        if (event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED)
+            eventCompleted = true;
+        break;
+    case WindowStateEvent::Type::Minimize:
+        if ((event->new_window_state & GDK_WINDOW_STATE_ICONIFIED) || !gtk_widget_get_mapped(window))
+            eventCompleted = true;
+        break;
+    case WindowStateEvent::Type::Restore:
+        if (!(event->new_window_state & GDK_WINDOW_STATE_MAXIMIZED) && !(event->new_window_state & GDK_WINDOW_STATE_ICONIFIED))
+            eventCompleted = true;
+        break;
+    }
+
+    if (eventCompleted) {
+        g_signal_handlers_disconnect_by_func(window, reinterpret_cast<gpointer>(windowStateEventCallback), view);
+        g_object_set_data(G_OBJECT(view), gWindowStateEventID, nullptr);
+    }
+
+    return FALSE;
+}
+
+void webkitWebViewMaximizeWindow(WebKitWebView* view, CompletionHandler<void()>&& completionHandler)
+{
+    auto* topLevel = gtk_widget_get_toplevel(GTK_WIDGET(view));
+    if (!gtk_widget_is_toplevel(topLevel)) {
+        completionHandler();
+        return;
+    }
+
+    auto* window = GTK_WINDOW(topLevel);
+    if (gtk_window_is_maximized(window)) {
+        completionHandler();
+        return;
+    }
+
+    g_object_set_data_full(G_OBJECT(view), gWindowStateEventID, new WindowStateEvent(WindowStateEvent::Type::Maximize, WTFMove(completionHandler)), [](gpointer userData) {
+        delete static_cast<WindowStateEvent*>(userData);
+    });
+    g_signal_connect_object(window, "window-state-event", G_CALLBACK(windowStateEventCallback), view, G_CONNECT_AFTER);
+    gtk_window_maximize(window);
+#if ENABLE(DEVELOPER_MODE)
+    // Xvfb doesn't support maximize, so we resize the window to the screen size.
+    if (WebCore::PlatformDisplay::sharedDisplay().type() == WebCore::PlatformDisplay::Type::X11) {
+        const char* underXvfb = g_getenv("UNDER_XVFB");
+        if (!g_strcmp0(underXvfb, "yes")) {
+            auto screenRect = WebCore::screenAvailableRect(nullptr);
+            gtk_window_move(window, screenRect.x(), screenRect.y());
+            gtk_window_resize(window, screenRect.width(), screenRect.height());
+        }
+    }
+#endif
+    gtk_widget_show(topLevel);
+}
+
+void webkitWebViewMinimizeWindow(WebKitWebView* view, CompletionHandler<void()>&& completionHandler)
+{
+    auto* topLevel = gtk_widget_get_toplevel(GTK_WIDGET(view));
+    if (!gtk_widget_is_toplevel(topLevel)) {
+        completionHandler();
+        return;
+    }
+
+    auto* window = GTK_WINDOW(topLevel);
+    g_object_set_data_full(G_OBJECT(view), gWindowStateEventID, new WindowStateEvent(WindowStateEvent::Type::Minimize, WTFMove(completionHandler)), [](gpointer userData) {
+        delete static_cast<WindowStateEvent*>(userData);
+    });
+    g_signal_connect_object(window, "window-state-event", G_CALLBACK(windowStateEventCallback), view, G_CONNECT_AFTER);
+    gtk_window_iconify(window);
+    gtk_widget_hide(topLevel);
+}
+
+void webkitWebViewRestoreWindow(WebKitWebView* view, CompletionHandler<void()>&& completionHandler)
+{
+    auto* topLevel = gtk_widget_get_toplevel(GTK_WIDGET(view));
+    if (!gtk_widget_is_toplevel(topLevel)) {
+        completionHandler();
+        return;
+    }
+
+    auto* window = GTK_WINDOW(topLevel);
+    if (gtk_widget_get_mapped(topLevel) && !gtk_window_is_maximized(window)) {
+        completionHandler();
+        return;
+    }
+
+    g_object_set_data_full(G_OBJECT(view), gWindowStateEventID, new WindowStateEvent(WindowStateEvent::Type::Restore, WTFMove(completionHandler)), [](gpointer userData) {
+        delete static_cast<WindowStateEvent*>(userData);
+    });
+    g_signal_connect_object(window, "window-state-event", G_CALLBACK(windowStateEventCallback), view, G_CONNECT_AFTER);
+    if (gtk_window_is_maximized(window))
+        gtk_window_unmaximize(window);
+    if (!gtk_widget_get_mapped(topLevel))
+        gtk_window_deiconify(window);
+#if ENABLE(DEVELOPER_MODE)
+    // Xvfb doesn't support maximize, so we resize the window to the default size.
+    if (WebCore::PlatformDisplay::sharedDisplay().type() == WebCore::PlatformDisplay::Type::X11) {
+        const char* underXvfb = g_getenv("UNDER_XVFB");
+        if (!g_strcmp0(underXvfb, "yes")) {
+            int x, y;
+            gtk_window_get_default_size(window, &x, &y);
+            gtk_window_resize(window, x, y);
+        }
+    }
+#endif
+    gtk_widget_show(topLevel);
+}
+
 /**
  * webkit_web_view_new:
  *
index 4958e7b..a3495e8 100644 (file)
@@ -37,6 +37,21 @@ gboolean webkitWebViewRunFileChooser(WebKitWebView*, WebKitFileChooserRequest*)
     return FALSE;
 }
 
+void webkitWebViewMaximizeWindow(WebKitWebView*, CompletionHandler<void()>&& completionHandler)
+{
+    completionHandler();
+}
+
+void webkitWebViewMinimizeWindow(WebKitWebView*, CompletionHandler<void()>&& completionHandler)
+{
+    completionHandler();
+}
+
+void webkitWebViewRestoreWindow(WebKitWebView*, CompletionHandler<void()>&& completionHandler)
+{
+    completionHandler();
+}
+
 /**
  * webkit_web_view_new:
  * @backend: (transfer full): a #WebKitWebViewBackend
index 42556b5..78ee2ac 100644 (file)
             "async": true
         },
         {
+            "name": "maximizeWindowOfBrowsingContext",
+            "description": "Causes the window of the specified browsing context to be maximized. This command implicitly exits fullscreen mode.",
+            "parameters": [
+                { "name": "handle", "$ref": "BrowsingContextHandle", "description": "The handle for the browsing context whose window should be maximized." }
+            ],
+            "async": true
+        },
+        {
             "name": "hideWindowOfBrowsingContext",
             "description": "Causes the window of the specified browsing context to be hidden/minimized/iconified. This command implicitly exits fullscreen mode.",
             "parameters": [
index b9b4ddc..455fa42 100644 (file)
@@ -525,6 +525,22 @@ void WebAutomationSession::loadTimerFired()
     respondToPendingPageNavigationCallbacksWithTimeout(m_pendingEagerNavigationInBrowsingContextCallbacksPerPage);
 }
 
+void WebAutomationSession::maximizeWindowOfBrowsingContext(const String& browsingContextHandle, Ref<MaximizeWindowOfBrowsingContextCallback>&& callback)
+{
+    auto* page = webPageProxyForHandle(browsingContextHandle);
+    if (!page)
+        ASYNC_FAIL_WITH_PREDEFINED_ERROR(WindowNotFound);
+
+    exitFullscreenWindowForPage(*page, [this, protectedThis = makeRef(*this), callback = WTFMove(callback), page = makeRefPtr(page)]() mutable {
+        auto& webPage = *page;
+        restoreWindowForPage(webPage, [this, callback = WTFMove(callback), page = WTFMove(page)]() mutable {
+            maximizeWindowForPage(*page, [callback = WTFMove(callback)]() {
+                callback->sendSuccess();
+            });
+        });
+    });
+}
+
 void WebAutomationSession::hideWindowOfBrowsingContext(const String& browsingContextHandle, Ref<HideWindowOfBrowsingContextCallback>&& callback)
 {
     WebPageProxy* page = webPageProxyForHandle(browsingContextHandle);
@@ -568,6 +584,11 @@ void WebAutomationSession::restoreWindowForPage(WebPageProxy& page, WTF::Complet
     m_client->requestRestoreWindowOfPage(*this, page, WTFMove(completionHandler));
 }
 
+void WebAutomationSession::maximizeWindowForPage(WebPageProxy& page, WTF::CompletionHandler<void()>&& completionHandler)
+{
+    m_client->requestMaximizeWindowOfPage(*this, page, WTFMove(completionHandler));
+}
+
 void WebAutomationSession::hideWindowForPage(WebPageProxy& page, WTF::CompletionHandler<void()>&& completionHandler)
 {
     m_client->requestHideWindowOfPage(*this, page, WTFMove(completionHandler));
index 3ffe3b3..12b7335 100644 (file)
@@ -151,6 +151,7 @@ public:
     void closeBrowsingContext(Inspector::ErrorString&, const String&) final;
     void switchToBrowsingContext(const String& browsingContextHandle, const String* optionalFrameHandle, Ref<SwitchToBrowsingContextCallback>&&) final;
     void setWindowFrameOfBrowsingContext(const String& handle, const JSON::Object* origin, const JSON::Object* size, Ref<SetWindowFrameOfBrowsingContextCallback>&&) final;
+    void maximizeWindowOfBrowsingContext(const String& handle, Ref<MaximizeWindowOfBrowsingContextCallback>&&) final;
     void hideWindowOfBrowsingContext(const String& handle, Ref<HideWindowOfBrowsingContextCallback>&&) final;
     void navigateBrowsingContext(const String& handle, const String& url, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<NavigateBrowsingContextCallback>&&) override;
     void goBackInBrowsingContext(const String&, const String* optionalPageLoadStrategyString, const int* optionalPageLoadTimeout, Ref<GoBackInBrowsingContextCallback>&&) override;
@@ -213,6 +214,7 @@ private:
 
     void exitFullscreenWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
     void restoreWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
+    void maximizeWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
     void hideWindowForPage(WebPageProxy&, WTF::CompletionHandler<void()>&&);
 
     // Implemented in generated WebAutomationSessionMessageReceiver.cpp.
index 0e946e6..57451c6 100644 (file)
 function enterFullscreen() {
 
     let callback = arguments[0];
-    if (!document.webkitFullscreenEnabled)
+    if (!document.webkitFullscreenEnabled) {
         callback(false);
+        return;
+    }
+
+    if (document.webkitIsFullScreen) {
+        callback(true);
+        return;
+    }
 
     let fullscreenChangeListener, fullscreenErrorListener;
     fullscreenChangeListener = (e) => {
index dc3693c..fbee6d5 100644 (file)
@@ -1,3 +1,13 @@
+2018-05-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        WebDriver: implement maximize, minimize and fullscreen window commands
+        https://bugs.webkit.org/show_bug.cgi?id=180398
+
+        Reviewed by Brian Burg.
+
+        * Scripts/webkitpy/port/xvfbdriver.py:
+        (XvfbDriver._setup_environ_for_test): Set UNDER_XVFB environment variable when running under Xvfb.
+
 2018-05-24  Xabier Rodriguez Calvar  <calvaris@igalia.com>
 
         [GStreamer] Save some time disabling some compile options in the dependencies
index ab33d3a..99121d0 100644 (file)
@@ -98,6 +98,7 @@ class XvfbDriver(Driver):
 
         # We must do this here because the DISPLAY number depends on _worker_number
         environment['DISPLAY'] = ":%d" % display_id
+        environment['UNDER_XVFB'] = 'yes'
         environment['GDK_BACKEND'] = 'x11'
         environment['LOCAL_RESOURCE_ROOT'] = self._port.layout_tests_dir()
         if self._driver_tempdir is not None:
index 98ecc3e..714278e 100644 (file)
@@ -1,3 +1,14 @@
+2018-05-24  Carlos Garcia Campos  <cgarcia@igalia.com>
+
+        WebDriver: implement maximize, minimize and fullscreen window commands
+        https://bugs.webkit.org/show_bug.cgi?id=180398
+
+        Reviewed by Brian Burg.
+
+        Remove expectations for tests that are passing now.
+
+        * TestExpectations.json:
+
 2018-05-21  Carlos Garcia Campos  <cgarcia@igalia.com>
 
         Unreviewed gardening. Update several test expectations.
index c725b13..2757587 100644 (file)
             }
         }
     },
-    "imported/selenium/py/test/selenium/webdriver/common/window_tests.py": {
-        "subtests": {
-            "testShouldMaximizeTheWindow": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_should_fullscreen_the_current_window": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_should_minimize_the_current_window": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            }
-        }
-    },
     "imported/w3c/webdriver/tests/actions/key.py": {
         "subtests": {
             "test_single_printable_key_sends_correct_events[\\xe0-]": {
             }
         }
     },
-    "imported/w3c/webdriver/tests/maximize_window/maximize.py": {
-        "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-    },
-    "imported/w3c/webdriver/tests/maximize_window/user_prompts.py": {
-        "subtests": {
-            "test_handle_prompt_accept": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_handle_prompt_missing_value": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            }
-        }
-    },
     "imported/w3c/webdriver/tests/execute_script/json_serialize_windowproxy.py": {
         "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180397"}}
     },
             }
         }
     },
-    "imported/w3c/webdriver/tests/fullscreen_window/fullscreen.py": {
-        "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-    },
-    "imported/w3c/webdriver/tests/fullscreen_window/user_prompts.py": {
-        "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}},
-        "subtests": {
-            "test_handle_prompt_dismiss_and_notify": {
-                "expected": {"all": {"status": ["PASS"]}}
-            },
-            "test_handle_prompt_accept_and_notify": {
-                "expected": {"all": {"status": ["PASS"]}}
-            },
-            "test_handle_prompt_ignore": {
-                "expected": {"all": {"status": ["PASS"]}}
-            }
-        }
-    },
-    "imported/w3c/webdriver/tests/minimize_window/minimize.py": {
-        "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-    },
-    "imported/w3c/webdriver/tests/minimize_window/user_prompts.py": {
-        "subtests": {
-            "test_handle_prompt_accept": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_handle_prompt_missing_value": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            }
-        }
-    },
     "imported/w3c/webdriver/tests/set_window_rect/set.py": {
         "subtests": {
-            "test_fully_exit_fullscreen": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_restore_from_minimized": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
-            "test_restore_from_maximized": {
-                "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180398"}}
-            },
             "test_negative_x_y": {
                 "expected": {"all": {"status": ["FAIL"], "bug": "webkit.org/b/180418"}}
             }