Index: chrome/browser/extensions/api/automation_internal/automation_event_router.cc |
diff --git a/chrome/browser/extensions/api/automation_internal/automation_event_router.cc b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..019d365d26b621bc8931d2f5afe0744d3f33136f |
--- /dev/null |
+++ b/chrome/browser/extensions/api/automation_internal/automation_event_router.cc |
@@ -0,0 +1,132 @@ |
+// Copyright 2015 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. |
+ |
+#include "chrome/browser/extensions/api/automation_internal/automation_event_router.h" |
+ |
+#include <string> |
+#include <utility> |
+ |
+#include "base/stl_util.h" |
+#include "base/values.h" |
+#include "chrome/browser/accessibility/ax_tree_id_registry.h" |
+#include "chrome/common/extensions/api/automation_internal.h" |
+#include "chrome/common/extensions/chrome_extension_messages.h" |
+#include "content/public/browser/notification_service.h" |
+#include "content/public/browser/notification_source.h" |
+#include "content/public/browser/notification_types.h" |
+#include "content/public/browser/render_process_host.h" |
+#include "extensions/browser/event_router.h" |
+#include "ui/accessibility/ax_enums.h" |
+#include "ui/accessibility/ax_node_data.h" |
+ |
+namespace extensions { |
+ |
+struct AutomationListener { |
+ int routing_id; |
+ int process_id; |
+ bool desktop; |
+ std::set<int> tree_ids; |
+}; |
+ |
+// static |
+AutomationEventRouter* AutomationEventRouter::GetInstance() { |
+ return Singleton<AutomationEventRouter, |
+ LeakySingletonTraits<AutomationEventRouter>>::get(); |
+} |
+ |
+AutomationEventRouter::AutomationEventRouter() { |
+ registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
+ content::NotificationService::AllBrowserContextsAndSources()); |
+ registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
+ content::NotificationService::AllBrowserContextsAndSources()); |
+} |
+ |
+AutomationEventRouter::~AutomationEventRouter() { |
+ STLDeleteContainerPairSecondPointers(listener_map_.begin(), |
+ listener_map_.end()); |
+} |
+ |
+void AutomationEventRouter::AddListener( |
+ ExtensionId extension_id, |
+ int ax_tree_id, |
+ int process_id, |
+ int routing_id, |
+ bool desktop) { |
+ auto iter = listener_map_.find(extension_id); |
+ AutomationListener* listener; |
not at google - send to devlin
2015/06/02 23:59:24
it's nice to initialize pointers to nullptr
dmazzoni
2015/06/04 20:07:39
Done.
|
+ if (iter != listener_map_.end()) { |
+ listener = iter->second; |
not at google - send to devlin
2015/06/02 23:59:24
What happens if the listener that is already there
dmazzoni
2015/06/04 20:07:39
OK, I tried to clarify it. I realized it was a mis
|
+ } else { |
+ listener = new AutomationListener(); |
+ listener->routing_id = routing_id; |
+ listener->process_id = process_id; |
+ listener->desktop = desktop; |
+ listener_map_.insert(std::make_pair(extension_id, listener)); |
not at google - send to devlin
2015/06/02 23:59:24
I would have thought that listener_map_[extension_
dmazzoni
2015/06/04 20:07:39
Doesn't compile, but moot as I simplified it.
|
+ } |
+ listener->tree_ids.insert(ax_tree_id); |
+} |
+ |
+void AutomationEventRouter::DispatchAccessibilityEventToAutomation( |
+ const ExtensionMsg_AccessibilityEventParams& params) { |
+ for (auto iter = listener_map_.begin(); |
+ iter != listener_map_.end(); |
+ ++iter) { |
not at google - send to devlin
2015/06/02 23:59:24
You can use a range-based for loop here, I think?
dmazzoni
2015/06/04 20:07:39
Done.
|
+ AutomationListener* listener = iter->second; |
+ if (!listener->desktop && |
+ listener->tree_ids.find(params.tree_id) == listener->tree_ids.end()) { |
+ continue; |
+ } |
+ |
+ content::RenderProcessHost* rph = |
+ content::RenderProcessHost::FromID(listener->process_id); |
+ rph->Send( |
+ new ExtensionMsg_AccessibilityEvent(listener->routing_id, params)); |
+ } |
+} |
+ |
+void AutomationEventRouter::DispatchTreeDestroyedEventToAutomation( |
+ int process_id, |
+ int routing_id, |
+ content::BrowserContext* browser_context) { |
+ int tree_id = AXTreeIDRegistry::GetInstance()->GetOrCreateAXTreeID( |
+ process_id, routing_id); |
+ |
+ std::string event_name( |
+ api::automation_internal::OnAccessibilityTreeDestroyed::kEventName); |
+ scoped_ptr<base::ListValue> args( |
+ api::automation_internal::OnAccessibilityTreeDestroyed::Create(tree_id)); |
+ if (browser_context && EventRouter::Get(browser_context)) { |
not at google - send to devlin
2015/06/02 23:59:24
Checking for |browser_context| here implies it can
dmazzoni
2015/06/04 20:07:39
Hmmm, I can't see a good reason why. The caller sh
|
+ scoped_ptr<Event> event(new Event(event_name, args.Pass())); |
+ event->restrict_to_browser_context = browser_context; |
+ EventRouter::Get(browser_context)->BroadcastEvent(event.Pass()); |
+ } |
+ AXTreeIDRegistry::GetInstance()->RemoveAXTreeID(tree_id); |
+} |
+ |
+void AutomationEventRouter::Observe( |
+ int type, |
+ const content::NotificationSource& source, |
+ const content::NotificationDetails& details) { |
+ if (type != content::NOTIFICATION_RENDERER_PROCESS_TERMINATED && |
+ type != content::NOTIFICATION_RENDERER_PROCESS_CLOSED) { |
+ NOTREACHED(); |
+ return; |
+ } |
+ |
+ content::RenderProcessHost* rph = |
+ content::Source<content::RenderProcessHost>(source).ptr(); |
+ int process_id = rph->GetID(); |
+ |
+ auto iter = listener_map_.begin(); |
+ while (iter != listener_map_.end()) { |
+ auto temp = iter; |
not at google - send to devlin
2015/06/02 23:59:24
apologies for nit, but for what it's worth I've mo
dmazzoni
2015/06/04 20:07:39
Thanks, that's cleaner.
|
+ iter++; |
+ if (temp->second->process_id == process_id) { |
+ delete temp->second; |
+ listener_map_.erase(temp); |
+ } |
+ } |
+} |
+ |
+} // namespace extensions |