Index: chrome/browser/extensions/api/automation_internal/automation_internal_api.cc |
diff --git a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc |
index 40e184bbf3b64d5776b523af8abb94ca9feb063d..e6c770ba90bfe1c1224a801a0da0d52fb554ff2d 100644 |
--- a/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc |
+++ b/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc |
@@ -7,6 +7,7 @@ |
#include <vector> |
#include "base/strings/string_number_conversions.h" |
+#include "base/strings/utf_string_conversions.h" |
#include "chrome/browser/extensions/api/automation_internal/automation_action_adapter.h" |
#include "chrome/browser/extensions/api/automation_internal/automation_util.h" |
#include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
@@ -19,9 +20,11 @@ |
#include "content/public/browser/ax_event_notification_details.h" |
#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/render_process_host.h" |
+#include "content/public/browser/render_view_host.h" |
#include "content/public/browser/render_widget_host.h" |
#include "content/public/browser/render_widget_host_view.h" |
#include "content/public/browser/web_contents.h" |
+#include "extensions/common/extension_messages.h" |
#include "extensions/common/permissions/permissions_data.h" |
#if defined(OS_CHROMEOS) |
@@ -41,6 +44,64 @@ const int kDesktopRoutingID = 0; |
const char kCannotRequestAutomationOnPage[] = |
"Cannot request automation tree on url \"*\". " |
"Extension manifest must request permission to access this host."; |
+const char kRendererDestroyed[] = "The tab was closed."; |
+ |
+class QuerySelectorHandler : public content::WebContentsObserver { |
Devlin
2014/10/28 21:05:09
document
aboxhall
2014/10/28 23:43:56
Done.
|
+ public: |
+ QuerySelectorHandler( |
+ content::WebContents* web_contents, |
+ int request_id, |
+ int acc_obj_id, |
+ base::string16& query, |
Devlin
2014/10/28 21:05:09
const
aboxhall
2014/10/28 23:43:55
Done.
|
+ extensions::AutomationInternalQuerySelectorFunction::Callback callback) |
Devlin
2014/10/28 21:05:09
const &
aboxhall
2014/10/28 23:43:56
I don't think this makes sense.
Devlin
2014/10/29 16:09:03
Sure it does - you can copy callbacks just like an
aboxhall
2014/10/29 16:35:19
I realise I'm making a copy, but I think that's th
aboxhall
2014/10/29 17:05:20
Ah right, but then I copy it again. Will fix.
Devlin
2014/10/29 17:05:36
One copy is good, but right now there could be two
|
+ : content::WebContentsObserver(web_contents), |
+ request_id_(request_id), |
+ callback_(callback) { |
+ content::RenderViewHost* rvh = web_contents->GetRenderViewHost(); |
+ rvh->Send(new ExtensionMsg_AutomationQuerySelector( |
+ rvh->GetRoutingID(), request_id, acc_obj_id, query)); |
+ } |
+ |
+ virtual ~QuerySelectorHandler() {} |
Devlin
2014/10/28 21:05:09
nit: ~QuerySelectorHandler() override {}
aboxhall
2014/10/28 23:43:55
Why override?
Devlin
2014/10/29 16:09:03
C++ 11 style. TL;DR: virtual + override is redund
aboxhall
2014/10/29 16:35:19
Got it, thanks. (https://groups.google.com/a/chrom
|
+ |
+ virtual bool OnMessageReceived(const IPC::Message& message) override { |
Devlin
2014/10/28 21:05:09
nit: no virtual (also for other methods)
aboxhall
2014/10/28 23:43:56
I don't understand; this is overriding a virtual m
Devlin
2014/10/29 16:09:03
See above - no virtual, just override. i.e.
bool
aboxhall
2014/10/29 16:35:19
Done.
|
+ if (message.type() != ExtensionHostMsg_AutomationQuerySelector_Result::ID) |
+ return false; |
+ |
+ // There may be several requests in flight; check that this response matches |
Devlin
2014/10/28 21:05:10
nit: End the sentence with a period.
aboxhall
2014/10/28 23:43:56
I don't think it's worth wrapping onto a new line.
Devlin
2014/10/29 16:09:03
Sadly, style rules. :/ (My personal preference wo
aboxhall
2014/10/29 16:35:19
I don't see it in the style guide. I don't think w
Devlin
2014/10/29 17:05:36
http://google-styleguide.googlecode.com/svn/trunk/
|
+ int unused_result_acc_obj_id; |
+ int message_request_id; |
+ PickleIterator iter(message); |
+ CHECK(message.ReadInt(&iter, &unused_result_acc_obj_id)); |
+ CHECK(message.ReadInt(&iter, &message_request_id)); |
Devlin
2014/10/28 21:05:09
I'm not super familiar with the inner workings of
aboxhall
2014/10/28 23:43:55
Good question. This was actually several flavours
|
+ |
+ if (message_request_id != request_id_) |
+ return false; |
+ |
+ IPC_BEGIN_MESSAGE_MAP(QuerySelectorHandler, message) |
+ IPC_MESSAGE_HANDLER(ExtensionHostMsg_AutomationQuerySelector_Result, |
+ OnQueryResponse) |
+ IPC_END_MESSAGE_MAP() |
+ return true; |
+ } |
+ |
+ virtual void WebContentsDestroyed() override { |
Devlin
2014/10/28 21:05:09
It's good that we watch the web contents, but shou
aboxhall
2014/10/28 23:43:56
I'm not sure; I copied this pattern from extension
|
+ callback_.Run(kRendererDestroyed, 0); |
+ delete this; |
+ } |
+ |
+ private: |
+ void OnQueryResponse(int request_id, |
+ const std::string& error, |
+ int result_acc_obj_id) { |
+ callback_.Run(error, result_acc_obj_id); |
+ delete this; |
+ } |
+ |
+ int request_id_; |
+ extensions::AutomationInternalQuerySelectorFunction::Callback callback_; |
Devlin
2014/10/28 21:05:09
Why not just put the class in extensions::?
aboxhall
2014/10/28 23:43:56
Which class?
Devlin
2014/10/29 16:09:03
QuerySelectorHandler. Basically, move the namespac
aboxhall
2014/10/29 16:35:19
Moved this into extensions:: below the const decla
|
+}; |
+ |
} // namespace |
namespace extensions { |
@@ -167,7 +228,7 @@ AutomationInternalEnableTabFunction::Run() { |
return RespondNow( |
ArgumentList(api::automation_internal::EnableTab::Results::Create( |
rfh->GetProcess()->GetID(), rfh->GetRoutingID()))); |
- } |
+} |
ExtensionFunction::ResponseAction |
AutomationInternalPerformActionFunction::Run() { |
@@ -251,4 +312,49 @@ AutomationInternalEnableDesktopFunction::Run() { |
#endif // defined(OS_CHROMEOS) |
} |
+// static |
+int AutomationInternalQuerySelectorFunction::query_request_id_counter_ = 0; |
Devlin
2014/10/28 21:05:09
why not put this in an anonymous namespace? Is it
aboxhall
2014/10/28 23:43:56
It's scoped and private to the class which uses it
Devlin
2014/10/29 16:09:03
Reduces the header import size by 0.000001%. :P M
aboxhall
2014/10/29 16:35:19
I don't feel particularly strongly, but I do think
|
+ |
+ExtensionFunction::ResponseAction |
+AutomationInternalQuerySelectorFunction::Run() { |
+ const AutomationInfo* automation_info = AutomationInfo::Get(extension()); |
+ EXTENSION_FUNCTION_VALIDATE(automation_info); |
+ |
+ using api::automation_internal::QuerySelector::Params; |
+ scoped_ptr<Params> params(Params::Create(*args_)); |
+ EXTENSION_FUNCTION_VALIDATE(params.get()); |
+ |
+ if (params->args.process_id == kDesktopProcessID && |
+ params->args.routing_id == kDesktopRoutingID) { |
+ return RespondNow( |
+ Error("querySelector queries may not be used on the desktop.")); |
+ } |
+ content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( |
+ params->args.process_id, params->args.routing_id); |
+ if (!rfh) |
+ return RespondNow(Error("querySelector query sent on destroyed node")); |
+ |
+ content::WebContents* contents = |
+ content::WebContents::FromRenderFrameHost(rfh); |
+ |
+ int request_id = query_request_id_counter_++; |
+ base::string16 selector = base::UTF8ToUTF16(params->args.selector); |
+ |
+ new QuerySelectorHandler( |
Devlin
2014/10/28 21:05:10
nit: comment that QuerySelectorHandler handles its
aboxhall
2014/10/28 23:43:56
Done.
|
+ contents, request_id, params->args.automation_node_id, selector, |
Devlin
2014/10/28 21:05:09
nit: one arg per line (even though it's long)
aboxhall
2014/10/28 23:43:56
This is how clang-format formats it, I'd rather le
Devlin
2014/10/29 16:09:03
Dang - they keep changing clang format's style (be
|
+ base::Bind(&AutomationInternalQuerySelectorFunction::OnResponse, this)); |
+ return RespondLater(); |
+} |
+ |
+void AutomationInternalQuerySelectorFunction::OnResponse( |
+ const std::string& error, |
+ int result_acc_obj_id) { |
+ if (!error.empty()) { |
+ Respond(Error(error)); |
+ return; |
+ } |
+ |
+ Respond(OneArgument(new base::FundamentalValue(result_acc_obj_id))); |
+} |
+ |
} // namespace extensions |