blob: e4e26ad7b5eb718a0c16da43ddaa3854c7596df4 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_
#define COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_
#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "components/autofill_assistant/browser/batch_element_checker.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_dom.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_input.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_network.h"
#include "components/autofill_assistant/browser/devtools/devtools/domains/types_runtime.h"
#include "components/autofill_assistant/browser/devtools/devtools_client.h"
#include "components/autofill_assistant/browser/rectf.h"
#include "components/autofill_assistant/browser/selector.h"
namespace autofill {
class AutofillProfile;
class CreditCard;
} // namespace autofill
namespace content {
class WebContents;
class RenderFrameHost;
} // namespace content
namespace autofill {
struct FormData;
struct FormFieldData;
}
namespace autofill_assistant {
// Controller to interact with the web pages.
//
// WARNING: Accessing or modifying page elements must be run in sequence: wait
// until the result of the first operation has been given to the callback before
// starting a new operation.
//
// TODO(crbug.com/806868): Figure out the reason for this limitation and fix it.
// Also, consider structuring the WebController to make it easier to run
// multiple operations, whether in sequence or in parallel.
class WebController {
public:
// Create web controller for a given |web_contents|.
static std::unique_ptr<WebController> CreateForWebContents(
content::WebContents* web_contents);
// |web_contents| must outlive this web controller.
WebController(content::WebContents* web_contents,
std::unique_ptr<DevtoolsClient> devtools_client);
virtual ~WebController();
// Returns the last committed URL of the associated |web_contents_|.
virtual const GURL& GetUrl();
// Load |url| in the current tab. Returns immediately, before the new page has
// been loaded.
virtual void LoadURL(const GURL& url);
// Perform a mouse left button click or a touch tap on the element given by
// |selector| and return the result through callback.
virtual void ClickOrTapElement(const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Fill the address form given by |selector| with the given address
// |profile|.
virtual void FillAddressForm(const autofill::AutofillProfile* profile,
const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Fill the card form given by |selector| with the given |card| and its
// |cvc|.
virtual void FillCardForm(std::unique_ptr<autofill::CreditCard> card,
const base::string16& cvc,
const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Select the option given by |selector| and the value of the option to be
// picked.
virtual void SelectOption(const Selector& selector,
const std::string& selected_option,
base::OnceCallback<void(bool)> callback);
// Highlight an element given by |selector|.
virtual void HighlightElement(const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Focus on element given by |selector|.
virtual void FocusElement(const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Set the |value| of field |selector| and return the result through
// |callback|. If |simulate_key_presses| is true, the value will be set by
// clicking the field and then simulating key presses, otherwise the `value`
// attribute will be set directly.
virtual void SetFieldValue(const Selector& selector,
const std::string& value,
bool simulate_key_presses,
base::OnceCallback<void(bool)> callback);
// Set the |value| of the |attribute| of the element given by |selector|.
virtual void SetAttribute(const Selector& selector,
const std::vector<std::string>& attribute,
const std::string& value,
base::OnceCallback<void(bool)> callback);
// Sets the keyboard focus to |selector| and inputs the specified UTF-8
// characters in the specified order.
// Returns the result through |callback|.
virtual void SendKeyboardInput(const Selector& selector,
const std::vector<std::string>& utf8_chars,
base::OnceCallback<void(bool)> callback);
// Return the outerHTML of |selector|.
virtual void GetOuterHtml(
const Selector& selector,
base::OnceCallback<void(bool, const std::string&)> callback);
// Create a helper for checking element existence and field value.
virtual std::unique_ptr<BatchElementChecker> CreateBatchElementChecker();
// Gets the position of the element identified by the selector.
//
// If unsuccessful, the callback gets (false, 0, 0, 0, 0).
//
// If successful, the callback gets (true, left, top, right, bottom), with
// coordinates expressed as numbers between 0 and 1, relative to the width or
// height of the visible viewport.
virtual void GetElementPosition(
const Selector& selector,
base::OnceCallback<void(bool, const RectF&)> callback);
// Functions to set, get and expire the Autofill Assistant cookie used to
// detect when Autofill Assistant has been used on a domain before.
virtual void SetCookie(const std::string& domain,
base::OnceCallback<void(bool)> callback);
virtual void HasCookie(base::OnceCallback<void(bool)> callback);
virtual void ClearCookie();
protected:
friend class BatchElementChecker;
// Checks an element for:
//
// kExistenceCheck: Checks whether at least one element given by |selector|
// exists on the web page.
//
// kVisibilityCheck: Checks whether at least on element given by |selector|
// is visible on the web page.
//
// Normally done through BatchElementChecker.
virtual void ElementCheck(ElementCheckType type,
const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Get the value of |selector| and return the result through |callback|. The
// returned value might be false, if the element cannot be found, true and the
// empty string in case of error or empty value.
//
// Normally done through BatchElementChecker.
virtual void GetFieldValue(
const Selector& selector,
base::OnceCallback<void(bool, const std::string&)> callback);
private:
friend class WebControllerBrowserTest;
// Helper class to get element's position when is stable and the frame it
// belongs finished visual update.
class ElementPositionGetter {
public:
ElementPositionGetter();
~ElementPositionGetter();
// |devtools_client| must outlive this class which is guarantteed by the
// owner of this class.
void Start(content::RenderFrameHost* frame_host,
DevtoolsClient* devtools_client,
std::string element_object_id,
base::OnceCallback<void(int, int)> callback);
private:
void OnVisualStateUpdatedCallback(bool state);
void GetAndWaitBoxModelStable(DevtoolsClient* devtools_client,
std::string object_id,
int point_x,
int point_y,
int remaining_rounds);
void OnGetBoxModelForStableCheck(
DevtoolsClient* devtools_client,
std::string object_id,
int point_x,
int point_y,
int remaining_rounds,
std::unique_ptr<dom::GetBoxModelResult> result);
void OnScrollIntoView(
DevtoolsClient* devtools_client,
std::string object_id,
int point_x,
int point_y,
int remaining_rounds,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnResult(int x, int y);
base::OnceCallback<void(int, int)> callback_;
bool visual_state_updated_;
base::WeakPtrFactory<ElementPositionGetter> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(ElementPositionGetter);
};
// Perform a mouse left button click on the element given by |selector| and
// return the result through callback.
void ClickElement(const Selector& selector,
base::OnceCallback<void(bool)> callback);
// Perform a touch tap on the element given by |selector| and return the
// result through callback.
void TapElement(const Selector& selector,
base::OnceCallback<void(bool)> callback);
struct FindElementResult {
FindElementResult() = default;
~FindElementResult() = default;
// The render frame host contains the element.
content::RenderFrameHost* container_frame_host;
// The selector index in the given selectors corresponding to the container
// frame. Zero indicates the element is in main frame or the first element
// is the container frame selector. Compare main frame with the above
// |container_frame_host| to distinguish them.
size_t container_frame_selector_index;
// The object id of the element.
std::string object_id;
};
using FindElementCallback =
base::OnceCallback<void(std::unique_ptr<FindElementResult>)>;
struct FillFormInputData {
FillFormInputData();
~FillFormInputData();
// Data for filling address form.
std::unique_ptr<autofill::AutofillProfile> profile;
// Data for filling card form.
std::unique_ptr<autofill::CreditCard> card;
base::string16 cvc;
};
void OnFindElementForClickOrTap(base::OnceCallback<void(bool)> callback,
bool is_a_click,
std::unique_ptr<FindElementResult> result);
void OnFindElementForTap(base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> result);
void ClickOrTapElement(std::unique_ptr<FindElementResult> target_element,
bool is_a_click,
base::OnceCallback<void(bool)> callback);
void OnScrollIntoView(std::unique_ptr<FindElementResult> target_element,
base::OnceCallback<void(bool)> callback,
bool is_a_click,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void TapOrClickOnCoordinates(
std::unique_ptr<ElementPositionGetter> element_position_getter,
base::OnceCallback<void(bool)> callback,
bool is_a_click,
int x,
int y);
void OnDispatchPressMouseEvent(
base::OnceCallback<void(bool)> callback,
int x,
int y,
std::unique_ptr<input::DispatchMouseEventResult> result);
void OnDispatchReleaseMouseEvent(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<input::DispatchMouseEventResult> result);
void OnDispatchTouchEventStart(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<input::DispatchTouchEventResult> result);
void OnDispatchTouchEventEnd(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<input::DispatchTouchEventResult> result);
void OnFindElementForCheck(ElementCheckType check_type,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> result);
void OnGetBoxModelForVisible(base::OnceCallback<void(bool)> callback,
std::unique_ptr<dom::GetBoxModelResult> result);
// Find the element given by |selector|. If multiple elements match
// |selector| and if |strict_mode| is false, return the first one that is
// found. Otherwise if |strict-mode| is true, do not return any.
void FindElement(const Selector& selector,
bool strict_mode,
FindElementCallback callback);
void OnGetDocumentElement(const Selector& selector,
bool strict_mode,
FindElementCallback callback,
std::unique_ptr<runtime::EvaluateResult> result);
void RecursiveFindElement(const std::string& object_id,
size_t index,
const Selector& selector,
bool strict_mode,
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback);
void OnQuerySelectorAll(
size_t index,
const Selector& selector,
bool strict_mode,
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnDescribeNodeForPseudoElement(
dom::PseudoType pseudo_type,
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback,
std::unique_ptr<dom::DescribeNodeResult> result);
void OnResolveNodeForPseudoElement(
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback,
std::unique_ptr<dom::ResolveNodeResult> result);
void OnDescribeNode(const std::string& object_id,
size_t index,
const Selector& selector,
bool strict_mode,
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback,
std::unique_ptr<dom::DescribeNodeResult> result);
void OnResolveNode(size_t index,
const Selector& selector,
bool strict_mode,
std::unique_ptr<FindElementResult> element_result,
FindElementCallback callback,
std::unique_ptr<dom::ResolveNodeResult> result);
content::RenderFrameHost* FindCorrespondingRenderFrameHost(
std::string name,
std::string document_url);
void OnResult(bool result, base::OnceCallback<void(bool)> callback);
void OnResult(bool exists,
const std::string& result,
base::OnceCallback<void(bool, const std::string&)> callback);
void OnFindElementForFillingForm(
std::unique_ptr<FillFormInputData> data_to_autofill,
const Selector& selector,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnGetFormAndFieldDataForFillingForm(
std::unique_ptr<FillFormInputData> data_to_autofill,
base::OnceCallback<void(bool)> callback,
content::RenderFrameHost* container_frame_host,
const autofill::FormData& form_data,
const autofill::FormFieldData& form_field);
void OnFindElementForFocusElement(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnFocusElement(base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSelectOption(
const std::string& selected_option,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnSelectOption(base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForHighlightElement(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnHighlightElement(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForGetFieldValue(
base::OnceCallback<void(bool, const std::string&)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnGetValueAttribute(
base::OnceCallback<void(bool, const std::string&)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void InternalSetFieldValue(const Selector& selector,
const std::string& value,
base::OnceCallback<void(bool)> callback);
void OnClearFieldForSendKeyboardInput(
const Selector& selector,
const std::vector<std::string>& utf8_chars,
base::OnceCallback<void(bool)> callback,
bool clear_status);
void OnClickElementForSendKeyboardInput(
const std::vector<std::string>& utf8_chars,
base::OnceCallback<void(bool)> callback,
bool click_status);
void DispatchKeyboardTextDownEvent(const std::vector<std::string>& utf8_chars,
size_t index,
base::OnceCallback<void(bool)> callback);
void DispatchKeyboardTextUpEvent(const std::vector<std::string>& utf8_chars,
size_t index,
base::OnceCallback<void(bool)> callback);
void OnFindElementForSetAttribute(
const std::vector<std::string>& attribute,
const std::string& value,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnSetAttribute(base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSendKeyboardInput(
const Selector& selector,
const std::vector<std::string>& utf8_chars,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnPressKeyboard(int key_code,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForSetFieldValue(
const std::string& value,
base::OnceCallback<void(bool)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnSetValueAttribute(
base::OnceCallback<void(bool)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForGetOuterHtml(
base::OnceCallback<void(bool, const std::string&)> callback,
std::unique_ptr<FindElementResult> element_result);
void OnGetOuterHtml(
base::OnceCallback<void(bool, const std::string&)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
void OnFindElementForPosition(
base::OnceCallback<void(bool, const RectF&)> callback,
std::unique_ptr<FindElementResult> result);
void OnGetElementPositionResult(
base::OnceCallback<void(bool, const RectF&)> callback,
std::unique_ptr<runtime::CallFunctionOnResult> result);
// Creates a new instance of DispatchKeyEventParams for the specified type and
// text.
using DispatchKeyEventParamsPtr =
std::unique_ptr<autofill_assistant::input::DispatchKeyEventParams>;
static DispatchKeyEventParamsPtr CreateKeyEventParamsFromText(
autofill_assistant::input::DispatchKeyEventType type,
const std::string& text);
void OnSetCookie(base::OnceCallback<void(bool)> callback,
std::unique_ptr<network::SetCookieResult> result);
void OnHasCookie(base::OnceCallback<void(bool)> callback,
std::unique_ptr<network::GetCookiesResult> result);
// Weak pointer is fine here since it must outlive this web controller, which
// is guaranteed by the owner of this object.
content::WebContents* web_contents_;
std::unique_ptr<DevtoolsClient> devtools_client_;
base::WeakPtrFactory<WebController> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(WebController);
};
} // namespace autofill_assistant
#endif // COMPONENTS_AUTOFILL_ASSISTANT_BROWSER_WEB_CONTROLLER_H_