Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(51)

Side by Side Diff: chrome/browser/extensions/api/automation_internal/automation_internal_api.cc

Issue 655273005: Implement AutomationNode.querySelector(). (Closed) Base URL: https://chromium.googlesource.com/chromium/src@master
Patch Set: Use assertEq instead of assertTrue in testQuerySelectorFromRemovedNode() Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h" 5 #include "chrome/browser/extensions/api/automation_internal/automation_internal_ api.h"
6 6
7 #include <vector> 7 #include <vector>
8 8
9 #include "base/strings/string_number_conversions.h" 9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/utf_string_conversions.h"
10 #include "chrome/browser/extensions/api/automation_internal/automation_action_ad apter.h" 11 #include "chrome/browser/extensions/api/automation_internal/automation_action_ad apter.h"
11 #include "chrome/browser/extensions/api/automation_internal/automation_util.h" 12 #include "chrome/browser/extensions/api/automation_internal/automation_util.h"
12 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 13 #include "chrome/browser/extensions/api/tabs/tabs_constants.h"
13 #include "chrome/browser/extensions/extension_tab_util.h" 14 #include "chrome/browser/extensions/extension_tab_util.h"
14 #include "chrome/browser/profiles/profile.h" 15 #include "chrome/browser/profiles/profile.h"
15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser.h"
16 #include "chrome/browser/ui/tabs/tab_strip_model.h" 17 #include "chrome/browser/ui/tabs/tab_strip_model.h"
17 #include "chrome/common/extensions/api/automation_internal.h" 18 #include "chrome/common/extensions/api/automation_internal.h"
18 #include "chrome/common/extensions/manifest_handlers/automation.h" 19 #include "chrome/common/extensions/manifest_handlers/automation.h"
19 #include "content/public/browser/ax_event_notification_details.h" 20 #include "content/public/browser/ax_event_notification_details.h"
20 #include "content/public/browser/render_frame_host.h" 21 #include "content/public/browser/render_frame_host.h"
21 #include "content/public/browser/render_process_host.h" 22 #include "content/public/browser/render_process_host.h"
23 #include "content/public/browser/render_view_host.h"
22 #include "content/public/browser/render_widget_host.h" 24 #include "content/public/browser/render_widget_host.h"
23 #include "content/public/browser/render_widget_host_view.h" 25 #include "content/public/browser/render_widget_host_view.h"
24 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
27 #include "extensions/common/extension_messages.h"
25 #include "extensions/common/permissions/permissions_data.h" 28 #include "extensions/common/permissions/permissions_data.h"
26 29
27 #if defined(OS_CHROMEOS) 30 #if defined(OS_CHROMEOS)
28 #include "chrome/browser/ui/ash/accessibility/automation_manager_ash.h" 31 #include "chrome/browser/ui/ash/accessibility/automation_manager_ash.h"
29 #endif 32 #endif
30 33
31 namespace extensions { 34 namespace extensions {
32 class AutomationWebContentsObserver; 35 class AutomationWebContentsObserver;
33 } // namespace extensions 36 } // namespace extensions
34 37
35 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver); 38 DEFINE_WEB_CONTENTS_USER_DATA_KEY(extensions::AutomationWebContentsObserver);
36 39
40 namespace extensions {
41
37 namespace { 42 namespace {
38 const int kDesktopProcessID = 0; 43 const int kDesktopProcessID = 0;
39 const int kDesktopRoutingID = 0; 44 const int kDesktopRoutingID = 0;
40 45
41 const char kCannotRequestAutomationOnPage[] = 46 const char kCannotRequestAutomationOnPage[] =
42 "Cannot request automation tree on url \"*\". " 47 "Cannot request automation tree on url \"*\". "
43 "Extension manifest must request permission to access this host."; 48 "Extension manifest must request permission to access this host.";
44 } // namespace 49 const char kRendererDestroyed[] = "The tab was closed.";
45 50
46 namespace extensions { 51 // Handles sending and receiving IPCs for a single querySelector request. On
52 // creation, sends the request IPC, and is destroyed either when the response is
53 // received or the renderer is destroyed.
54 class QuerySelectorHandler : public content::WebContentsObserver {
55 public:
56 QuerySelectorHandler(
57 content::WebContents* web_contents,
58 int request_id,
59 int acc_obj_id,
60 const base::string16& query,
61 const extensions::AutomationInternalQuerySelectorFunction::Callback&
62 callback)
63 : content::WebContentsObserver(web_contents),
64 request_id_(request_id),
65 callback_(callback) {
66 content::RenderViewHost* rvh = web_contents->GetRenderViewHost();
67 rvh->Send(new ExtensionMsg_AutomationQuerySelector(
68 rvh->GetRoutingID(), request_id, acc_obj_id, query));
69 }
70
71 ~QuerySelectorHandler() override {}
72
73 bool OnMessageReceived(const IPC::Message& message) override {
74 if (message.type() != ExtensionHostMsg_AutomationQuerySelector_Result::ID)
75 return false;
76
77 // There may be several requests in flight; check this response matches.
78 int message_request_id = 0;
79 PickleIterator iter(message);
80 CHECK(message.ReadInt(&iter, &message_request_id));
81
82 if (message_request_id != request_id_)
83 return false;
84
85 IPC_BEGIN_MESSAGE_MAP(QuerySelectorHandler, message)
86 IPC_MESSAGE_HANDLER(ExtensionHostMsg_AutomationQuerySelector_Result,
87 OnQueryResponse)
88 IPC_END_MESSAGE_MAP()
89 return true;
90 }
91
92 void WebContentsDestroyed() override {
93 callback_.Run(kRendererDestroyed, 0);
94 delete this;
95 }
96
97 private:
98 void OnQueryResponse(int request_id,
99 const std::string& error,
100 int result_acc_obj_id) {
101 callback_.Run(error, result_acc_obj_id);
102 delete this;
103 }
104
105 int request_id_;
106 const extensions::AutomationInternalQuerySelectorFunction::Callback callback_;
107 };
47 108
48 bool CanRequestAutomation(const Extension* extension, 109 bool CanRequestAutomation(const Extension* extension,
49 const AutomationInfo* automation_info, 110 const AutomationInfo* automation_info,
50 const content::WebContents* contents) { 111 const content::WebContents* contents) {
51 if (automation_info->desktop) 112 if (automation_info->desktop)
52 return true; 113 return true;
53 114
54 const GURL& url = contents->GetURL(); 115 const GURL& url = contents->GetURL();
55 // TODO(aboxhall): check for webstore URL 116 // TODO(aboxhall): check for webstore URL
56 if (automation_info->matches.MatchesURL(url)) 117 if (automation_info->matches.MatchesURL(url))
57 return true; 118 return true;
58 119
59 int tab_id = ExtensionTabUtil::GetTabId(contents); 120 int tab_id = ExtensionTabUtil::GetTabId(contents);
60 content::RenderProcessHost* process = contents->GetRenderProcessHost(); 121 content::RenderProcessHost* process = contents->GetRenderProcessHost();
61 int process_id = process ? process->GetID() : -1; 122 int process_id = process ? process->GetID() : -1;
62 std::string unused_error; 123 std::string unused_error;
63 return extension->permissions_data()->CanAccessPage( 124 return extension->permissions_data()->CanAccessPage(
64 extension, url, url, tab_id, process_id, &unused_error); 125 extension, url, url, tab_id, process_id, &unused_error);
65 } 126 }
66 127
128 // Helper class that implements an action adapter for a |RenderFrameHost|.
129 class RenderFrameHostActionAdapter : public AutomationActionAdapter {
130 public:
131 explicit RenderFrameHostActionAdapter(content::RenderFrameHost* rfh)
132 : rfh_(rfh) {}
133
134 virtual ~RenderFrameHostActionAdapter() {}
135
136 // AutomationActionAdapter implementation.
137 void DoDefault(int32 id) override { rfh_->AccessibilityDoDefaultAction(id); }
138
139 void Focus(int32 id) override { rfh_->AccessibilitySetFocus(id); }
140
141 void MakeVisible(int32 id) override {
142 rfh_->AccessibilityScrollToMakeVisible(id, gfx::Rect());
143 }
144
145 void SetSelection(int32 id, int32 start, int32 end) override {
146 rfh_->AccessibilitySetTextSelection(id, start, end);
147 }
148
149 private:
150 content::RenderFrameHost* rfh_;
151
152 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostActionAdapter);
153 };
154
155 } // namespace
156
67 // Helper class that receives accessibility data from |WebContents|. 157 // Helper class that receives accessibility data from |WebContents|.
68 class AutomationWebContentsObserver 158 class AutomationWebContentsObserver
69 : public content::WebContentsObserver, 159 : public content::WebContentsObserver,
70 public content::WebContentsUserData<AutomationWebContentsObserver> { 160 public content::WebContentsUserData<AutomationWebContentsObserver> {
71 public: 161 public:
72 ~AutomationWebContentsObserver() override {} 162 ~AutomationWebContentsObserver() override {}
73 163
74 // content::WebContentsObserver overrides. 164 // content::WebContentsObserver overrides.
75 void AccessibilityEventReceived( 165 void AccessibilityEventReceived(
76 const std::vector<content::AXEventNotificationDetails>& details) 166 const std::vector<content::AXEventNotificationDetails>& details)
(...skipping 17 matching lines...) Expand all
94 AutomationWebContentsObserver( 184 AutomationWebContentsObserver(
95 content::WebContents* web_contents) 185 content::WebContents* web_contents)
96 : content::WebContentsObserver(web_contents), 186 : content::WebContentsObserver(web_contents),
97 browser_context_(web_contents->GetBrowserContext()) {} 187 browser_context_(web_contents->GetBrowserContext()) {}
98 188
99 content::BrowserContext* browser_context_; 189 content::BrowserContext* browser_context_;
100 190
101 DISALLOW_COPY_AND_ASSIGN(AutomationWebContentsObserver); 191 DISALLOW_COPY_AND_ASSIGN(AutomationWebContentsObserver);
102 }; 192 };
103 193
104 // Helper class that implements an action adapter for a |RenderFrameHost|.
105 class RenderFrameHostActionAdapter : public AutomationActionAdapter {
106 public:
107 explicit RenderFrameHostActionAdapter(content::RenderFrameHost* rfh)
108 : rfh_(rfh) {}
109
110 virtual ~RenderFrameHostActionAdapter() {}
111
112 // AutomationActionAdapter implementation.
113 void DoDefault(int32 id) override { rfh_->AccessibilityDoDefaultAction(id); }
114
115 void Focus(int32 id) override { rfh_->AccessibilitySetFocus(id); }
116
117 void MakeVisible(int32 id) override {
118 rfh_->AccessibilityScrollToMakeVisible(id, gfx::Rect());
119 }
120
121 void SetSelection(int32 id, int32 start, int32 end) override {
122 rfh_->AccessibilitySetTextSelection(id, start, end);
123 }
124
125 private:
126 content::RenderFrameHost* rfh_;
127
128 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostActionAdapter);
129 };
130
131 ExtensionFunction::ResponseAction 194 ExtensionFunction::ResponseAction
132 AutomationInternalEnableTabFunction::Run() { 195 AutomationInternalEnableTabFunction::Run() {
133 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 196 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
134 EXTENSION_FUNCTION_VALIDATE(automation_info); 197 EXTENSION_FUNCTION_VALIDATE(automation_info);
135 198
136 using api::automation_internal::EnableTab::Params; 199 using api::automation_internal::EnableTab::Params;
137 scoped_ptr<Params> params(Params::Create(*args_)); 200 scoped_ptr<Params> params(Params::Create(*args_));
138 EXTENSION_FUNCTION_VALIDATE(params.get()); 201 EXTENSION_FUNCTION_VALIDATE(params.get());
139 content::WebContents* contents = NULL; 202 content::WebContents* contents = NULL;
140 if (params->tab_id.get()) { 203 if (params->tab_id.get()) {
(...skipping 19 matching lines...) Expand all
160 223
161 if (!CanRequestAutomation(extension(), automation_info, contents)) { 224 if (!CanRequestAutomation(extension(), automation_info, contents)) {
162 return RespondNow( 225 return RespondNow(
163 Error(kCannotRequestAutomationOnPage, contents->GetURL().spec())); 226 Error(kCannotRequestAutomationOnPage, contents->GetURL().spec()));
164 } 227 }
165 AutomationWebContentsObserver::CreateForWebContents(contents); 228 AutomationWebContentsObserver::CreateForWebContents(contents);
166 contents->EnableTreeOnlyAccessibilityMode(); 229 contents->EnableTreeOnlyAccessibilityMode();
167 return RespondNow( 230 return RespondNow(
168 ArgumentList(api::automation_internal::EnableTab::Results::Create( 231 ArgumentList(api::automation_internal::EnableTab::Results::Create(
169 rfh->GetProcess()->GetID(), rfh->GetRoutingID()))); 232 rfh->GetProcess()->GetID(), rfh->GetRoutingID())));
170 } 233 }
171 234
172 ExtensionFunction::ResponseAction 235 ExtensionFunction::ResponseAction
173 AutomationInternalPerformActionFunction::Run() { 236 AutomationInternalPerformActionFunction::Run() {
174 const AutomationInfo* automation_info = AutomationInfo::Get(extension()); 237 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
175 EXTENSION_FUNCTION_VALIDATE(automation_info && automation_info->interact); 238 EXTENSION_FUNCTION_VALIDATE(automation_info && automation_info->interact);
176 239
177 using api::automation_internal::PerformAction::Params; 240 using api::automation_internal::PerformAction::Params;
178 scoped_ptr<Params> params(Params::Create(*args_)); 241 scoped_ptr<Params> params(Params::Create(*args_));
179 EXTENSION_FUNCTION_VALIDATE(params.get()); 242 EXTENSION_FUNCTION_VALIDATE(params.get());
180 243
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
244 if (!automation_info || !automation_info->desktop) 307 if (!automation_info || !automation_info->desktop)
245 return RespondNow(Error("desktop permission must be requested")); 308 return RespondNow(Error("desktop permission must be requested"));
246 309
247 AutomationManagerAsh::GetInstance()->Enable(browser_context()); 310 AutomationManagerAsh::GetInstance()->Enable(browser_context());
248 return RespondNow(NoArguments()); 311 return RespondNow(NoArguments());
249 #else 312 #else
250 return RespondNow(Error("getDesktop is unsupported by this platform")); 313 return RespondNow(Error("getDesktop is unsupported by this platform"));
251 #endif // defined(OS_CHROMEOS) 314 #endif // defined(OS_CHROMEOS)
252 } 315 }
253 316
317 // static
318 int AutomationInternalQuerySelectorFunction::query_request_id_counter_ = 0;
319
320 ExtensionFunction::ResponseAction
321 AutomationInternalQuerySelectorFunction::Run() {
322 const AutomationInfo* automation_info = AutomationInfo::Get(extension());
323 EXTENSION_FUNCTION_VALIDATE(automation_info);
324
325 using api::automation_internal::QuerySelector::Params;
326 scoped_ptr<Params> params(Params::Create(*args_));
327 EXTENSION_FUNCTION_VALIDATE(params.get());
328
329 if (params->args.process_id == kDesktopProcessID &&
330 params->args.routing_id == kDesktopRoutingID) {
331 return RespondNow(
332 Error("querySelector queries may not be used on the desktop."));
333 }
334 content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(
335 params->args.process_id, params->args.routing_id);
336 if (!rfh)
337 return RespondNow(Error("querySelector query sent on destroyed tree."));
338
339 content::WebContents* contents =
340 content::WebContents::FromRenderFrameHost(rfh);
341
342 int request_id = query_request_id_counter_++;
343 base::string16 selector = base::UTF8ToUTF16(params->args.selector);
Devlin 2014/10/31 22:11:28 #include "base/strings/string16.h"
aboxhall 2014/10/31 23:06:48 Done.
344
345 // QuerySelectorHandler handles IPCs and deletes itself on completion.
346 new QuerySelectorHandler(
347 contents, request_id, params->args.automation_node_id, selector,
348 base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this));
349
350 return RespondLater();
351 }
352
353 void AutomationInternalQuerySelectorFunction::OnResponse(
354 const std::string& error,
355 int result_acc_obj_id) {
356 if (!error.empty()) {
357 Respond(Error(error));
358 return;
359 }
360
361 Respond(OneArgument(new base::FundamentalValue(result_acc_obj_id)));
362 }
363
254 } // namespace extensions 364 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698