Skip to content

Commit

Permalink
Merge r222256 - WebDriver: Implement commands to get and set the wind…
Browse files Browse the repository at this point in the history
…ow rect

https://bugs.webkit.org/show_bug.cgi?id=177134

Reviewed by Brian Burg.

We are currently implementing the selenium legacy ones, we should implement the w3c ones instead.

https://w3c.github.io/webdriver/webdriver-spec.html#resizing-and-positioning-windows

* Session.cpp:
(WebDriver::Session::getToplevelBrowsingContextRect): Helper to get the window rect. This is used by both get
and set window rect commands.
(WebDriver::Session::moveToplevelBrowsingContextwindow): Helper to ask automation to move the window.
(WebDriver::Session::resizeToplevelBrowsingContextwindow): Helper to ask automation to resize the window.
(WebDriver::Session::getWindowRect): Handle prompts and then call getToplevelBrowsingContextRect().
(WebDriver::Session::setWindowRect): Handle prompts and then move and resize the window according to the given
parameters and finish the operation calling getToplevelBrowsingContextRect().
* Session.h:
* WebDriverService.cpp:
(WebDriver::WebDriverService::getWindowRect): Ask the session to get the window rect.
(WebDriver::valueAsNumberInRange): Helper to check a value is a valid number in the given range.
(WebDriver::WebDriverService::setWindowRect): Get and check size and position from parameters and then ask the
session to set the window rect.
* WebDriverService.h:
  • Loading branch information
carlosgcampos committed Oct 16, 2017
1 parent 4c29fe5 commit e4edc25
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 96 deletions.
27 changes: 27 additions & 0 deletions Source/WebDriver/ChangeLog
@@ -1,3 +1,30 @@
2017-09-19 Carlos Garcia Campos <cgarcia@igalia.com>

WebDriver: Implement commands to get and set the window rect
https://bugs.webkit.org/show_bug.cgi?id=177134

Reviewed by Brian Burg.

We are currently implementing the selenium legacy ones, we should implement the w3c ones instead.

https://w3c.github.io/webdriver/webdriver-spec.html#resizing-and-positioning-windows

* Session.cpp:
(WebDriver::Session::getToplevelBrowsingContextRect): Helper to get the window rect. This is used by both get
and set window rect commands.
(WebDriver::Session::moveToplevelBrowsingContextwindow): Helper to ask automation to move the window.
(WebDriver::Session::resizeToplevelBrowsingContextwindow): Helper to ask automation to resize the window.
(WebDriver::Session::getWindowRect): Handle prompts and then call getToplevelBrowsingContextRect().
(WebDriver::Session::setWindowRect): Handle prompts and then move and resize the window according to the given
parameters and finish the operation calling getToplevelBrowsingContextRect().
* Session.h:
* WebDriverService.cpp:
(WebDriver::WebDriverService::getWindowRect): Ask the session to get the window rect.
(WebDriver::valueAsNumberInRange): Helper to check a value is a valid number in the given range.
(WebDriver::WebDriverService::setWindowRect): Get and check size and position from parameters and then ask the
session to set the window rect.
* WebDriverService.h:

2017-09-19 Carlos Garcia Campos <cgarcia@igalia.com>

WebDriver: wrong response in case of errors
Expand Down
127 changes: 83 additions & 44 deletions Source/WebDriver/Session.cpp
Expand Up @@ -636,13 +636,8 @@ void Session::switchToParentFrame(Function<void (CommandResult&&)>&& completionH
});
}

void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHandler)
void Session::getToplevelBrowsingContextRect(Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
return;
}

RefPtr<InspectorObject> parameters = InspectorObject::create();
parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
Expand All @@ -656,26 +651,37 @@ void Session::getWindowPosition(Function<void (CommandResult&&)>&& completionHan
return;
}
RefPtr<InspectorObject> windowOrigin;
if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)) {
double x, y;
if (!browsingContext->getObject(ASCIILiteral("windowOrigin"), windowOrigin)
|| !windowOrigin->getDouble(ASCIILiteral("x"), x)
|| !windowOrigin->getDouble(ASCIILiteral("y"), y)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
return;
}
completionHandler(CommandResult::success(WTFMove(windowOrigin)));
RefPtr<InspectorObject> windowSize;
double width, height;
if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)
|| !windowSize->getDouble(ASCIILiteral("width"), width)
|| !windowSize->getDouble(ASCIILiteral("height"), width)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
return;
}
auto windowRect = InspectorObject::create();
windowRect->setDouble(ASCIILiteral("x"), x);
windowRect->setDouble(ASCIILiteral("y"), y);
windowRect->setDouble(ASCIILiteral("width"), width);
windowRect->setDouble(ASCIILiteral("height"), height);
completionHandler(CommandResult::success(WTFMove(windowRect)));
});
}

void Session::setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&& completionHandler)
void Session::moveToplevelBrowsingContextWindow(double x, double y, Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
return;
}

RefPtr<InspectorObject> parameters = InspectorObject::create();
parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
RefPtr<InspectorObject> windowOrigin = InspectorObject::create();
windowOrigin->setInteger("x", windowX);
windowOrigin->setInteger("y", windowY);
windowOrigin->setDouble("x", x);
windowOrigin->setDouble("y", y);
parameters->setObject(ASCIILiteral("origin"), WTFMove(windowOrigin));
m_host->sendCommandToBackend(ASCIILiteral("moveWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
if (response.isError) {
Expand All @@ -686,53 +692,86 @@ void Session::setWindowPosition(int windowX, int windowY, Function<void (Command
});
}

void Session::getWindowSize(Function<void (CommandResult&&)>&& completionHandler)
void Session::resizeToplevelBrowsingContextWindow(double width, double height, Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
return;
}

RefPtr<InspectorObject> parameters = InspectorObject::create();
parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
m_host->sendCommandToBackend(ASCIILiteral("getBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
if (response.isError || !response.responseObject) {
RefPtr<InspectorObject> windowSize = InspectorObject::create();
windowSize->setDouble("width", width);
windowSize->setDouble("height", height);
parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
if (response.isError) {
completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
return;
}
RefPtr<InspectorObject> browsingContext;
if (!response.responseObject->getObject(ASCIILiteral("context"), browsingContext)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
return;
}
RefPtr<InspectorObject> windowSize;
if (!browsingContext->getObject(ASCIILiteral("windowSize"), windowSize)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::UnknownError));
completionHandler(CommandResult::success());
});
}

void Session::getWindowRect(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;
}
completionHandler(CommandResult::success(WTFMove(windowSize)));
getToplevelBrowsingContextRect(WTFMove(completionHandler));
});
}

void Session::setWindowSize(int windowWidth, int windowHeight, Function<void (CommandResult&&)>&& completionHandler)
void Session::setWindowRect(std::optional<double> x, std::optional<double> y, std::optional<double> width, std::optional<double> height, Function<void (CommandResult&&)>&& completionHandler)
{
if (!m_toplevelBrowsingContext) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::NoSuchWindow));
return;
}

RefPtr<InspectorObject> parameters = InspectorObject::create();
parameters->setString(ASCIILiteral("handle"), m_toplevelBrowsingContext.value());
RefPtr<InspectorObject> windowSize = InspectorObject::create();
windowSize->setInteger("width", windowWidth);
windowSize->setInteger("height", windowHeight);
parameters->setObject(ASCIILiteral("size"), WTFMove(windowSize));
m_host->sendCommandToBackend(ASCIILiteral("resizeWindowOfBrowsingContext"), WTFMove(parameters), [this, protectedThis = makeRef(*this), completionHandler = WTFMove(completionHandler)](SessionHost::CommandResponse&& response) {
if (response.isError) {
completionHandler(CommandResult::fail(WTFMove(response.responseObject)));
handleUserPrompts([this, x, y, width, height, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
if (result.isError()) {
completionHandler(WTFMove(result));
return;
}
completionHandler(CommandResult::success());

if (width && height) {
resizeToplevelBrowsingContextWindow(width.value(), height.value(), [this, x, y, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
if (result.isError()) {
completionHandler(WTFMove(result));
return;
}
if (!x || !y) {
getToplevelBrowsingContextRect(WTFMove(completionHandler));
return;
}

moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
if (result.isError()) {
completionHandler(WTFMove(result));
return;
}
getToplevelBrowsingContextRect(WTFMove(completionHandler));
});
});
return;
}

if (x && y) {
moveToplevelBrowsingContextWindow(x.value(), y.value(), [this, completionHandler = WTFMove(completionHandler)](CommandResult&& result) mutable {
if (result.isError()) {
completionHandler(WTFMove(result));
return;
}
getToplevelBrowsingContextRect(WTFMove(completionHandler));
});
return;
}

getToplevelBrowsingContextRect(WTFMove(completionHandler));
});
}

Expand Down
10 changes: 6 additions & 4 deletions Source/WebDriver/Session.h
Expand Up @@ -87,10 +87,8 @@ class Session : public RefCounted<Session> {
void getWindowHandles(Function<void (CommandResult&&)>&&);
void switchToFrame(RefPtr<Inspector::InspectorValue>&&, Function<void (CommandResult&&)>&&);
void switchToParentFrame(Function<void (CommandResult&&)>&&);
void getWindowPosition(Function<void (CommandResult&&)>&&);
void setWindowPosition(int windowX, int windowY, Function<void (CommandResult&&)>&&);
void getWindowSize(Function<void (CommandResult&&)>&&);
void setWindowSize(int windowWidth, int windowHeight, 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 findElements(const String& strategy, const String& selector, FindElementsMode, const String& rootElementID, Function<void (CommandResult&&)>&&);
void isElementSelected(const String& elementID, Function<void (CommandResult&&)>&&);
void getElementText(const String& elementID, Function<void (CommandResult&&)>&&);
Expand Down Expand Up @@ -123,6 +121,10 @@ class Session : public RefCounted<Session> {
void closeTopLevelBrowsingContext(const String& toplevelBrowsingContext, Function<void (CommandResult&&)>&&);
void closeAllToplevelBrowsingContexts(const String& toplevelBrowsingContext, Function<void (CommandResult&&)>&&);

void getToplevelBrowsingContextRect(Function<void (CommandResult&&)>&&);
void moveToplevelBrowsingContextWindow(double x, double y, Function<void (CommandResult&&)>&&);
void resizeToplevelBrowsingContextWindow(double width, double height, Function<void (CommandResult&&)>&&);

std::optional<String> pageLoadStrategyString() const;

void handleUserPrompts(Function<void (CommandResult&&)>&&);
Expand Down
102 changes: 58 additions & 44 deletions Source/WebDriver/WebDriverService.cpp
Expand Up @@ -118,12 +118,8 @@ const WebDriverService::Command WebDriverService::s_commands[] = {
{ HTTPMethod::Get, "/session/$sessionId/window/handles", &WebDriverService::getWindowHandles },
{ HTTPMethod::Post, "/session/$sessionId/frame", &WebDriverService::switchToFrame },
{ HTTPMethod::Post, "/session/$sessionId/frame/parent", &WebDriverService::switchToParentFrame },

// FIXME: Not in the spec, but still used by Selenium.
{ HTTPMethod::Get, "/session/$sessionId/window/position", &WebDriverService::getWindowPosition },
{ HTTPMethod::Post, "/session/$sessionId/window/position", &WebDriverService::setWindowPosition },
{ HTTPMethod::Get, "/session/$sessionId/window/size", &WebDriverService::getWindowSize },
{ HTTPMethod::Post, "/session/$sessionId/window/size", &WebDriverService::setWindowSize },
{ HTTPMethod::Get, "/session/$sessionId/window/rect", &WebDriverService::getWindowRect },
{ HTTPMethod::Post, "/session/$sessionId/window/rect", &WebDriverService::setWindowRect },

{ HTTPMethod::Post, "/session/$sessionId/element", &WebDriverService::findElement },
{ HTTPMethod::Post, "/session/$sessionId/elements", &WebDriverService::findElements },
Expand Down Expand Up @@ -799,58 +795,76 @@ void WebDriverService::getWindowHandle(RefPtr<InspectorObject>&& parameters, Fun
session->getWindowHandle(WTFMove(completionHandler));
}

void WebDriverService::getWindowPosition(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
void WebDriverService::getWindowRect(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
// §10.7.1 Get Window Rect.
// https://w3c.github.io/webdriver/webdriver-spec.html#get-window-rect
if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
session->getWindowPosition(WTFMove(completionHandler));
session->getWindowRect(WTFMove(completionHandler));
}

void WebDriverService::setWindowPosition(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
static std::optional<double> valueAsNumberInRange(const InspectorValue& value, double minAllowed = 0, double maxAllowed = INT_MAX)
{
auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
if (!session)
return;

int windowX;
if (!parameters->getInteger(ASCIILiteral("x"), windowX)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
double number;
if (!value.asDouble(number))
return std::nullopt;

int windowY;
if (!parameters->getInteger(ASCIILiteral("y"), windowY)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
if (std::isnan(number) || std::isinf(number))
return std::nullopt;

session->setWindowPosition(windowX, windowY, WTFMove(completionHandler));
}
if (number < minAllowed || number > maxAllowed)
return std::nullopt;

void WebDriverService::getWindowSize(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
session->getWindowSize(WTFMove(completionHandler));
return number;
}

void WebDriverService::setWindowSize(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
void WebDriverService::setWindowRect(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
{
auto session = findSessionOrCompleteWithError(*parameters, completionHandler);
if (!session)
return;

int windowWidth;
if (!parameters->getInteger(ASCIILiteral("width"), windowWidth)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
// §10.7.2 Set Window Rect.
// https://w3c.github.io/webdriver/webdriver-spec.html#set-window-rect
RefPtr<InspectorValue> value;
std::optional<double> width;
if (parameters->getValue(ASCIILiteral("width"), value)) {
if (auto number = valueAsNumberInRange(*value))
width = number;
else if (!value->isNull()) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
}

int windowHeight;
if (!parameters->getInteger(ASCIILiteral("height"), windowHeight)) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
std::optional<double> height;
if (parameters->getValue(ASCIILiteral("height"), value)) {
if (auto number = valueAsNumberInRange(*value))
height = number;
else if (!value->isNull()) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
}
std::optional<double> x;
if (parameters->getValue(ASCIILiteral("x"), value)) {
if (auto number = valueAsNumberInRange(*value, INT_MIN))
x = number;
else if (!value->isNull()) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
}
std::optional<double> y;
if (parameters->getValue(ASCIILiteral("y"), value)) {
if (auto number = valueAsNumberInRange(*value, INT_MIN))
y = number;
else if (!value->isNull()) {
completionHandler(CommandResult::fail(CommandResult::ErrorCode::InvalidArgument));
return;
}
}

session->setWindowSize(windowWidth, windowHeight, WTFMove(completionHandler));
// FIXME: If the remote end does not support the Set Window Rect command for the current
// top-level browsing context for any reason, return error with error code unsupported operation.

if (auto session = findSessionOrCompleteWithError(*parameters, completionHandler))
session->setWindowRect(x, y, width, height, WTFMove(completionHandler));
}

void WebDriverService::closeWindow(RefPtr<InspectorObject>&& parameters, Function<void (CommandResult&&)>&& completionHandler)
Expand Down

0 comments on commit e4edc25

Please sign in to comment.