diff options
author | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-25 21:13:10 +0000 |
---|---|---|
committer | benwells@chromium.org <benwells@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-06-25 21:13:10 +0000 |
commit | 327828249838e5ddac21ba9ed35c1856e71fdec6 (patch) | |
tree | 42df000d06d301dc94eb092d0166ea3e80c72788 /chrome/renderer | |
parent | 4998b1d57f4b06385ca968321282a54697bb595d (diff) | |
download | chromium_src-327828249838e5ddac21ba9ed35c1856e71fdec6.zip chromium_src-327828249838e5ddac21ba9ed35c1856e71fdec6.tar.gz chromium_src-327828249838e5ddac21ba9ed35c1856e71fdec6.tar.bz2 |
Revert 143896 - Filtered events.
(Reverting as it breaks platform app's onLaunched event dispatch).
Makes web_navigation events support filters, eg:
chrome.webNavigation.onBeforeCommitted.addListener(callback, {url: [{hostSuffix: 'google.com'}]});
Now callback will only be called when the event has a URL with a host suffix of google.com.
BUG=121479
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=143872
Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=143874
Review URL: https://chromiumcodereview.appspot.com/10514013
TBR=koz@chromium.org
Review URL: https://chromiumcodereview.appspot.com/10661038
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@144013 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r-- | chrome/renderer/extensions/event_bindings.cc | 225 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_bindings.h | 7 | ||||
-rw-r--r-- | chrome/renderer/extensions/event_unittest.cc | 154 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_dispatcher.cc | 5 | ||||
-rw-r--r-- | chrome/renderer/extensions/extension_dispatcher.h | 9 | ||||
-rw-r--r-- | chrome/renderer/resources/extensions/event.js | 220 |
6 files changed, 80 insertions, 540 deletions
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc index 06d9dbc..94a0203 100644 --- a/chrome/renderer/extensions/event_bindings.cc +++ b/chrome/renderer/extensions/event_bindings.cc @@ -6,15 +6,11 @@ #include <vector> -#include "base/bind.h" #include "base/basictypes.h" #include "base/lazy_instance.h" -#include "base/memory/scoped_ptr.h" #include "base/message_loop.h" #include "chrome/common/extensions/extension_messages.h" #include "chrome/common/extensions/extension_set.h" -#include "chrome/common/extensions/event_filter.h" -#include "chrome/common/extensions/value_counter.h" #include "chrome/common/url_constants.h" #include "chrome/common/view_type.h" #include "chrome/renderer/extensions/chrome_v8_context.h" @@ -25,7 +21,6 @@ #include "chrome/renderer/extensions/extension_helper.h" #include "chrome/renderer/extensions/user_script_slave.h" #include "content/public/renderer/render_thread.h" -#include "content/public/renderer/v8_value_converter.h" #include "googleurl/src/gurl.h" #include "grit/renderer_resources.h" #include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h" @@ -53,57 +48,33 @@ typedef std::map<std::string, int> EventListenerCounts; base::LazyInstance<std::map<std::string, EventListenerCounts> > g_listener_counts = LAZY_INSTANCE_INITIALIZER; -// A map of event names to a (filter -> count) map. The map is used to keep -// track of which filters are in effect for which events. -// We notify the browser about filtered event listeners when we transition -// between 0 and 1. -typedef std::map<std::string, linked_ptr<extensions::ValueCounter> > - FilteredEventListenerCounts; - -// A map of extension IDs to filtered listener counts for that extension. -base::LazyInstance<std::map<std::string, FilteredEventListenerCounts> > - g_filtered_listener_counts = LAZY_INSTANCE_INITIALIZER; - // TODO(koz): Merge this into EventBindings. class ExtensionImpl : public ChromeV8Extension { public: - ExtensionImpl(ExtensionDispatcher* dispatcher, - extensions::EventFilter* event_filter) - : ChromeV8Extension(dispatcher), - event_filter_(event_filter) { - RouteFunction("AttachEvent", - base::Bind(&ExtensionImpl::AttachEvent, - base::Unretained(this))); - RouteFunction("DetachEvent", - base::Bind(&ExtensionImpl::DetachEvent, - base::Unretained(this))); - RouteFunction("AttachFilteredEvent", - base::Bind(&ExtensionImpl::AttachFilteredEvent, - base::Unretained(this))); - RouteFunction("DetachFilteredEvent", - base::Bind(&ExtensionImpl::DetachFilteredEvent, - base::Unretained(this))); - RouteFunction("MatchAgainstEventFilter", - base::Bind(&ExtensionImpl::MatchAgainstEventFilter, - base::Unretained(this))); + explicit ExtensionImpl(ExtensionDispatcher* dispatcher) + : ChromeV8Extension(dispatcher) { + RouteStaticFunction("AttachEvent", &AttachEvent); + RouteStaticFunction("DetachEvent", &DetachEvent); } ~ExtensionImpl() {} // Attach an event name to an object. - v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { + static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { DCHECK(args.Length() == 1); // TODO(erikkay) should enforce that event name is a string in the bindings DCHECK(args[0]->IsString() || args[0]->IsUndefined()); if (args[0]->IsString()) { - std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); + ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); const ChromeV8ContextSet& context_set = - extension_dispatcher()->v8_context_set(); + self->extension_dispatcher()->v8_context_set(); ChromeV8Context* context = context_set.GetCurrent(); CHECK(context); + std::string event_name(*v8::String::AsciiValue(args[0])); - if (!extension_dispatcher()->CheckCurrentContextAccessToExtensionAPI( + ExtensionDispatcher* extension_dispatcher = self->extension_dispatcher(); + if (!extension_dispatcher->CheckCurrentContextAccessToExtensionAPI( event_name)) return v8::Undefined(); @@ -118,25 +89,24 @@ class ExtensionImpl : public ChromeV8Extension { // This is called the first time the page has added a listener. Since // the background page is the only lazy page, we know this is the first // time this listener has been registered. - if (IsLazyBackgroundPage(context->extension())) { + if (self->IsLazyBackgroundPage(context->extension())) { content::RenderThread::Get()->Send( new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); } } + return v8::Undefined(); } - v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) { + static v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) { DCHECK(args.Length() == 2); // TODO(erikkay) should enforce that event name is a string in the bindings DCHECK(args[0]->IsString() || args[0]->IsUndefined()); if (args[0]->IsString() && args[1]->IsBoolean()) { - std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); - bool is_manual = args[1]->BooleanValue(); - + ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); const ChromeV8ContextSet& context_set = - extension_dispatcher()->v8_context_set(); + self->extension_dispatcher()->v8_context_set(); ChromeV8Context* context = context_set.GetCurrent(); if (!context) return v8::Undefined(); @@ -144,6 +114,8 @@ class ExtensionImpl : public ChromeV8Extension { std::string extension_id = context->GetExtensionID(); EventListenerCounts& listener_counts = g_listener_counts.Get()[extension_id]; + std::string event_name(*v8::String::AsciiValue(args[0])); + bool is_manual = args[1]->BooleanValue(); if (--listener_counts[event_name] == 0) { content::RenderThread::Get()->Send( @@ -154,164 +126,17 @@ class ExtensionImpl : public ChromeV8Extension { // removed. If the context is the background page, and it removes the // last listener manually, then we assume that it is no longer interested // in being awakened for this event. - if (is_manual && IsLazyBackgroundPage(context->extension())) { + if (is_manual && self->IsLazyBackgroundPage(context->extension())) { content::RenderThread::Get()->Send( new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name)); } } - return v8::Undefined(); - } - - // MatcherID AttachFilteredEvent(string event_name, object filter) - // event_name - Name of the event to attach. - // filter - Which instances of the named event are we interested in. - // returns the id assigned to the listener, which will be returned from calls - // to MatchAgainstEventFilter where this listener matches. - v8::Handle<v8::Value> AttachFilteredEvent(const v8::Arguments& args) { - DCHECK_EQ(2, args.Length()); - DCHECK(args[0]->IsString()); - DCHECK(args[1]->IsObject()); - - const ChromeV8ContextSet& context_set = - extension_dispatcher()->v8_context_set(); - ChromeV8Context* context = context_set.GetCurrent(); - DCHECK(context); - if (!context) - return v8::Integer::New(-1); - - std::string event_name = *v8::String::AsciiValue(args[0]); - // This method throws an exception if it returns false. - if (!extension_dispatcher()->CheckCurrentContextAccessToExtensionAPI( - event_name)) - return v8::Undefined(); - - std::string extension_id = context->GetExtensionID(); - if (extension_id.empty()) - return v8::Integer::New(-1); - - scoped_ptr<base::DictionaryValue> filter; - scoped_ptr<content::V8ValueConverter> converter( - content::V8ValueConverter::create()); - - base::DictionaryValue* filter_dict = NULL; - base::Value* filter_value = converter->FromV8Value(args[1]->ToObject(), - v8::Context::GetCurrent()); - if (!filter_value->GetAsDictionary(&filter_dict)) { - delete filter_value; - return v8::Integer::New(-1); - } - - filter.reset(filter_dict); - int id = event_filter_->AddEventMatcher(event_name, ParseEventMatcher( - filter.get())); - - // Only send IPCs the first time a filter gets added. - if (AddFilter(event_name, extension_id, filter.get())) { - bool lazy = IsLazyBackgroundPage(context->extension()); - content::RenderThread::Get()->Send( - new ExtensionHostMsg_AddFilteredListener(extension_id, event_name, - *filter, lazy)); - } - - return v8::Integer::New(id); - } - - // Add a filter to |event_name| in |extension_id|, returning true if it - // was the first filter for that event in that extension. - bool AddFilter(const std::string& event_name, - const std::string& extension_id, - base::DictionaryValue* filter) { - FilteredEventListenerCounts& counts = - g_filtered_listener_counts.Get()[extension_id]; - FilteredEventListenerCounts::iterator it = counts.find(event_name); - if (it == counts.end()) - counts[event_name].reset(new extensions::ValueCounter); - - int result = counts[event_name]->Add(*filter); - return 1 == result; - } - - // Remove a filter from |event_name| in |extension_id|, returning true if it - // was the last filter for that event in that extension. - bool RemoveFilter(const std::string& event_name, - const std::string& extension_id, - base::DictionaryValue* filter) { - FilteredEventListenerCounts& counts = - g_filtered_listener_counts.Get()[extension_id]; - FilteredEventListenerCounts::iterator it = counts.find(event_name); - if (it == counts.end()) - return false; - return 0 == it->second->Remove(*filter); - } - - // void DetachFilteredEvent(int id, bool manual) - // id - Id of the event to detach. - // manual - false if this is part of the extension unload process where all - // listeners are automatically detached. - v8::Handle<v8::Value> DetachFilteredEvent(const v8::Arguments& args) { - DCHECK_EQ(2, args.Length()); - DCHECK(args[0]->IsInt32()); - DCHECK(args[1]->IsBoolean()); - bool is_manual = args[1]->BooleanValue(); - const ChromeV8ContextSet& context_set = - extension_dispatcher()->v8_context_set(); - ChromeV8Context* context = context_set.GetCurrent(); - if (!context) - return v8::Undefined(); - - std::string extension_id = context->GetExtensionID(); - if (extension_id.empty()) - return v8::Undefined(); - - int matcher_id = args[0]->Int32Value(); - extensions::EventMatcher* event_matcher = - event_filter_->GetEventMatcher(matcher_id); - - const std::string& event_name = event_filter_->GetEventName(matcher_id); - - // Only send IPCs the last time a filter gets removed. - if (RemoveFilter(event_name, extension_id, event_matcher->value())) { - bool lazy = is_manual && IsLazyBackgroundPage(context->extension()); - content::RenderThread::Get()->Send( - new ExtensionHostMsg_RemoveFilteredListener(extension_id, event_name, - *event_matcher->value(), - lazy)); - } - - event_filter_->RemoveEventMatcher(matcher_id); return v8::Undefined(); } - v8::Handle<v8::Value> MatchAgainstEventFilter(const v8::Arguments& args) { - typedef std::set<extensions::EventFilter::MatcherID> MatcherIDs; - - std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); - extensions::EventFilteringInfo info = ParseFromObject(args[1]->ToObject()); - MatcherIDs matched_event_filters = event_filter_->MatchEvent( - event_name, info); - v8::Handle<v8::Array> array(v8::Array::New(matched_event_filters.size())); - int i = 0; - for (MatcherIDs::iterator it = matched_event_filters.begin(); - it != matched_event_filters.end(); ++it) { - array->Set(v8::Integer::New(i++), v8::Integer::New(*it)); - } - return array; - } - - extensions::EventFilteringInfo ParseFromObject( - v8::Handle<v8::Object> object) { - extensions::EventFilteringInfo info; - v8::Handle<v8::String> url(v8::String::New("url")); - if (object->Has(url)) { - v8::Handle<v8::Value> url_value(object->Get(url)); - info.SetURL(GURL(*v8::String::AsciiValue(url_value))); - } - return info; - } - private: - extensions::EventFilter* event_filter_; + bool IsLazyBackgroundPage(const Extension* extension) { content::RenderView* render_view = GetCurrentRenderView(); if (!render_view) @@ -321,18 +146,10 @@ class ExtensionImpl : public ChromeV8Extension { return (extension && extension->has_lazy_background_page() && helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); } - - scoped_ptr<extensions::EventMatcher> ParseEventMatcher( - base::DictionaryValue* filter_dict) { - return scoped_ptr<extensions::EventMatcher>(new extensions::EventMatcher( - scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()))); - } }; } // namespace -// static -ChromeV8Extension* EventBindings::Get(ExtensionDispatcher* dispatcher, - extensions::EventFilter* event_filter) { - return new ExtensionImpl(dispatcher, event_filter); +ChromeV8Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { + return new ExtensionImpl(dispatcher); } diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h index 17b32d5..baa2004 100644 --- a/chrome/renderer/extensions/event_bindings.h +++ b/chrome/renderer/extensions/event_bindings.h @@ -9,10 +9,6 @@ class ChromeV8Extension; class ExtensionDispatcher; -namespace extensions { -class EventFilter; -} - namespace v8 { class Extension; } @@ -20,8 +16,7 @@ class Extension; // This class deals with the javascript bindings related to Event objects. class EventBindings { public: - static ChromeV8Extension* Get(ExtensionDispatcher* dispatcher, - extensions::EventFilter* event_filter); + static ChromeV8Extension* Get(ExtensionDispatcher* dispatcher); }; #endif // CHROME_RENDERER_EXTENSIONS_EVENT_BINDINGS_H_ diff --git a/chrome/renderer/extensions/event_unittest.cc b/chrome/renderer/extensions/event_unittest.cc index 4b0619f..947d3e8 100644 --- a/chrome/renderer/extensions/event_unittest.cc +++ b/chrome/renderer/extensions/event_unittest.cc @@ -22,41 +22,13 @@ class EventUnittest : public ModuleSystemTest { OverrideNativeHandler("event_bindings", "var assert = requireNative('assert');" "var attachedListeners = exports.attachedListeners = {};" - "var attachedFilteredListeners = " - " exports.attachedFilteredListeners = {};" - "var nextId = 0;" - "var idToName = {};" - "exports.AttachEvent = function(eventName) {" " assert.AssertFalse(!!attachedListeners[eventName]);" " attachedListeners[eventName] = 1;" "};" - "exports.DetachEvent = function(eventName) {" " assert.AssertTrue(!!attachedListeners[eventName]);" " delete attachedListeners[eventName];" - "};" - - "exports.IsEventAttached = function(eventName) {" - " return !!attachedListeners[eventName];" - "};" - - "exports.AttachFilteredEvent = function(name, filters) {" - " var id = nextId++;" - " idToName[id] = name;" - " attachedFilteredListeners[name] =" - " attachedFilteredListeners[name] || [];" - " attachedFilteredListeners[name][id] = filters;" - " return id;" - "};" - - "exports.DetachFilteredEvent = function(id, manual) {" - " var i = attachedFilteredListeners[idToName[id]].indexOf(id);" - " attachedFilteredListeners[idToName[id]].splice(i, 1);" - "};" - - "exports.HasFilteredListener = function(name) {" - " return attachedFilteredListeners[name].length;" "};"); OverrideNativeHandler("chrome_hidden", "var chromeHidden = {};" @@ -90,39 +62,6 @@ TEST_F(EventUnittest, AddRemoveTwoListeners) { module_system_->Require("test"); } -TEST_F(EventUnittest, OnUnloadDetachesAllListeners) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var assert = requireNative('assert');" - "var event = require('event');" - "var eventBindings = requireNative('event_bindings');" - "var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();" - "var myEvent = new event.Event('named-event');" - "var cb1 = function() {};" - "var cb2 = function() {};" - "myEvent.addListener(cb1);" - "myEvent.addListener(cb2);" - "chromeHidden.dispatchOnUnload();" - "assert.AssertFalse(!!eventBindings.attachedListeners['named-event']);"); - module_system_->Require("test"); -} - -TEST_F(EventUnittest, OnUnloadDetachesAllListenersEvenDupes) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var assert = requireNative('assert');" - "var event = require('event');" - "var eventBindings = requireNative('event_bindings');" - "var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();" - "var myEvent = new event.Event('named-event');" - "var cb1 = function() {};" - "myEvent.addListener(cb1);" - "myEvent.addListener(cb1);" - "chromeHidden.dispatchOnUnload();" - "assert.AssertFalse(!!eventBindings.attachedListeners['named-event']);"); - module_system_->Require("test"); -} - TEST_F(EventUnittest, EventsThatSupportRulesMustHaveAName) { ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); RegisterModule("test", @@ -153,97 +92,4 @@ TEST_F(EventUnittest, NamedEventDispatch) { module_system_->Require("test"); } -TEST_F(EventUnittest, AddListenerWithFiltersThrowsErrorByDefault) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var event = require('event');" - "var assert = requireNative('assert');" - "var e = new event.Event('myevent');" - "var filter = [{" - " url: {hostSuffix: 'google.com'}," - "}];" - "var caught = false;" - "try {" - " e.addListener(function() {}, filter);" - "} catch (e) {" - " caught = true;" - "}" - "assert.AssertTrue(caught);"); - module_system_->Require("test"); -} - -TEST_F(EventUnittest, FilteredEventsAttachment) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var event = require('event');" - "var assert = requireNative('assert');" - "var bindings = requireNative('event_bindings');" - "var eventOpts = {supportsListeners: true, supportsFilters: true};" - "var e = new event.Event('myevent', undefined, eventOpts);" - "var cb = function() {};" - "var filters = {url: [{hostSuffix: 'google.com'}]};" - "e.addListener(cb, filters);" - "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" - "e.removeListener(cb);" - "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); - module_system_->Require("test"); -} - -TEST_F(EventUnittest, DetachFilteredEvent) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var event = require('event');" - "var assert = requireNative('assert');" - "var bindings = requireNative('event_bindings');" - "var eventOpts = {supportsListeners: true, supportsFilters: true};" - "var e = new event.Event('myevent', undefined, eventOpts);" - "var cb1 = function() {};" - "var cb2 = function() {};" - "var filters = {url: [{hostSuffix: 'google.com'}]};" - "e.addListener(cb1, filters);" - "e.addListener(cb2, filters);" - "e.detach_();" - "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); - module_system_->Require("test"); -} - -TEST_F(EventUnittest, AttachAndRemoveSameFilteredEventListener) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var event = require('event');" - "var assert = requireNative('assert');" - "var bindings = requireNative('event_bindings');" - "var eventOpts = {supportsListeners: true, supportsFilters: true};" - "var e = new event.Event('myevent', undefined, eventOpts);" - "var cb = function() {};" - "var filters = {url: [{hostSuffix: 'google.com'}]};" - "e.addListener(cb, filters);" - "e.addListener(cb, filters);" - "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" - "e.removeListener(cb);" - "assert.AssertTrue(bindings.HasFilteredListener('myevent'));" - "e.removeListener(cb);" - "assert.AssertFalse(bindings.HasFilteredListener('myevent'));"); - module_system_->Require("test"); -} - -TEST_F(EventUnittest, AddingFilterWithUrlFieldNotAListThrowsException) { - ModuleSystem::NativesEnabledScope natives_enabled_scope(module_system_.get()); - RegisterModule("test", - "var event = require('event');" - "var assert = requireNative('assert');" - "var eventOpts = {supportsListeners: true, supportsFilters: true};" - "var e = new event.Event('myevent', undefined, eventOpts);" - "var cb = function() {};" - "var filters = {url: {hostSuffix: 'google.com'}};" - "var caught = false;" - "try {" - " e.addListener(cb, filters);" - "} catch (e) {" - " caught = true;" - "}" - "assert.AssertTrue(caught);"); - module_system_->Require("test"); -} - } // namespace diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc index 9a60e06..35fe9af 100644 --- a/chrome/renderer/extensions/extension_dispatcher.cc +++ b/chrome/renderer/extensions/extension_dispatcher.cc @@ -233,8 +233,7 @@ ExtensionDispatcher::ExtensionDispatcher() webrequest_adblock_plus_(false), webrequest_other_(false), source_map_(&ResourceBundle::GetSharedInstance()), - chrome_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN), - event_filter_(new extensions::EventFilter) { + chrome_channel_(chrome::VersionInfo::CHANNEL_UNKNOWN) { const CommandLine& command_line = *(CommandLine::ForCurrentProcess()); is_extension_process_ = command_line.HasSwitch(switches::kExtensionProcess) || @@ -491,7 +490,7 @@ bool ExtensionDispatcher::AllowScriptExtension( void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system, ChromeV8Context* context) { module_system->RegisterNativeHandler("event_bindings", - scoped_ptr<NativeHandler>(EventBindings::Get(this, event_filter_.get()))); + scoped_ptr<NativeHandler>(EventBindings::Get(this))); module_system->RegisterNativeHandler("miscellaneous_bindings", scoped_ptr<NativeHandler>(MiscellaneousBindings::Get(this))); module_system->RegisterNativeHandler("apiDefinitions", diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h index 4947f48..ea2f9c1 100644 --- a/chrome/renderer/extensions/extension_dispatcher.h +++ b/chrome/renderer/extensions/extension_dispatcher.h @@ -13,7 +13,6 @@ #include "base/shared_memory.h" #include "base/timer.h" #include "content/public/renderer/render_process_observer.h" -#include "chrome/common/extensions/event_filter.h" #include "chrome/common/extensions/extension_set.h" #include "chrome/common/extensions/features/feature.h" #include "chrome/renderer/extensions/chrome_v8_context.h" @@ -29,10 +28,6 @@ class URLPattern; class UserScriptSlave; struct ExtensionMsg_Loaded_Params; -namespace extensions { -class FilteredEventRouter; -} - namespace WebKit { class WebFrame; } @@ -263,10 +258,6 @@ class ExtensionDispatcher : public content::RenderProcessObserver { // TODO(aa): Remove when we can restrict non-permission APIs to dev-only. int chrome_channel_; - // Routes events to the appropriate listener taking into consideration event - // filters. - scoped_ptr<extensions::EventFilter> event_filter_; - DISALLOW_COPY_AND_ASSIGN(ExtensionDispatcher); }; diff --git a/chrome/renderer/resources/extensions/event.js b/chrome/renderer/resources/extensions/event.js index 4b784ad..a6d6363 100644 --- a/chrome/renderer/resources/extensions/event.js +++ b/chrome/renderer/resources/extensions/event.js @@ -5,9 +5,6 @@ var eventBindingsNatives = requireNative('event_bindings'); var AttachEvent = eventBindingsNatives.AttachEvent; var DetachEvent = eventBindingsNatives.DetachEvent; - var AttachFilteredEvent = eventBindingsNatives.AttachFilteredEvent; - var DetachFilteredEvent = eventBindingsNatives.DetachFilteredEvent; - var MatchAgainstEventFilter = eventBindingsNatives.MatchAgainstEventFilter; var sendRequest = require('sendRequest').sendRequest; var utils = require('utils'); var validate = require('schemaUtils').validate; @@ -78,85 +75,6 @@ }; })(); - // A map of event names to the event object that is registered to that name. - var attachedNamedEvents = {}; - - // An array of all attached event objects, used for detaching on unload. - var allAttachedEvents = []; - - // A map of functions that massage event arguments before they are dispatched. - // Key is event name, value is function. - var eventArgumentMassagers = {}; - - // Handles adding/removing/dispatching listeners for unfiltered events. - var UnfilteredAttachmentStrategy = function(event) { - this.event_ = event; - }; - - UnfilteredAttachmentStrategy.prototype.onAddedListener = - function(listener) { - // Only attach / detach on the first / last listener removed. - if (this.event_.listeners_.length == 0) - AttachEvent(this.event_.eventName_); - }; - - UnfilteredAttachmentStrategy.prototype.onRemovedListener = - function(listener) { - if (this.event_.listeners_.length == 0) - this.detach(true); - }; - - UnfilteredAttachmentStrategy.prototype.detach = function(manual) { - DetachEvent(this.event_.eventName_, manual); - }; - - UnfilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { - return this.event_.listeners_; - }; - - var FilteredAttachmentStrategy = function(event) { - this.event_ = event; - this.listenerMap_ = {}; - }; - - FilteredAttachmentStrategy.idToEventMap = {}; - - FilteredAttachmentStrategy.prototype.onAddedListener = function(listener) { - var id = AttachFilteredEvent(this.event_.eventName_, - listener.filters || {}); - if (id == -1) - throw new Error("Can't add listener"); - listener.id = id; - this.listenerMap_[id] = listener; - FilteredAttachmentStrategy.idToEventMap[id] = this.event_; - }; - - FilteredAttachmentStrategy.prototype.onRemovedListener = function(listener) { - this.detachListener(listener, true); - }; - - FilteredAttachmentStrategy.prototype.detachListener = - function(listener, manual) { - if (listener.id == undefined) - throw new Error("listener.id undefined - '" + listener + "'"); - var id = listener.id; - delete this.listenerMap_[id]; - delete FilteredAttachmentStrategy.idToEventMap[id]; - DetachFilteredEvent(id, manual); - }; - - FilteredAttachmentStrategy.prototype.detach = function(manual) { - for (var i in this.listenerMap_) - this.detachListener(this.listenerMap_[i], manual); - }; - - FilteredAttachmentStrategy.prototype.getListenersByIDs = function(ids) { - var result = []; - for (var i = 0; i < ids.length; i++) - result.push(this.listenerMap_[ids[i]]); - return result; - }; - // Event object. If opt_eventName is provided, this object represents // the unique instance of that named event, and dispatching an event // with that name will route through this object's listeners. Note that @@ -174,20 +92,11 @@ this.eventName_ = opt_eventName; this.listeners_ = []; this.eventOptions_ = opt_eventOptions || - {supportsFilters: false, - supportsListeners: true, - supportsRules: false, - }; + {"supportsListeners": true, "supportsRules": false}; if (this.eventOptions_.supportsRules && !opt_eventName) throw new Error("Events that support rules require an event name."); - if (this.eventOptions_.supportsFilters) { - this.attachmentStrategy_ = new FilteredAttachmentStrategy(this); - } else { - this.attachmentStrategy_ = new UnfilteredAttachmentStrategy(this); - } - // Validate event arguments (the data that is passed to the callbacks) // if we are in debug. if (opt_argSchemas && @@ -206,6 +115,16 @@ } }; + // A map of event names to the event object that is registered to that name. + var attachedNamedEvents = {}; + + // An array of all attached event objects, used for detaching on unload. + var allAttachedEvents = []; + + // A map of functions that massage event arguments before they are dispatched. + // Key is event name, value is function. + var eventArgumentMassagers = {}; + chromeHidden.Event = {}; chromeHidden.Event.registerArgumentMassager = function(name, fn) { @@ -217,12 +136,7 @@ // Dispatches a named event with the given JSON array, which is deserialized // before dispatch. The JSON array is the list of arguments that will be // sent with the event callback. - chromeHidden.Event.dispatchJSON = function(name, args, filteringInfo) { - var listenerIDs = null; - - if (filteringInfo) { - listenerIDs = MatchAgainstEventFilter(name, filteringInfo); - } + chromeHidden.Event.dispatchJSON = function(name, args) { if (attachedNamedEvents[name]) { if (args) { // TODO(asargent): This is an antiquity. Until all callers of @@ -234,18 +148,8 @@ if (eventArgumentMassagers[name]) eventArgumentMassagers[name](args); } - - var event = attachedNamedEvents[name]; - var result; - // TODO(koz): We have to do this differently for unfiltered events (which - // have listenerIDs = null) because some bindings write over - // event.dispatch (eg: experimental.app.custom_bindings.js) and so expect - // events to go through it. These places need to be fixed so that they - // expect a listenerIDs parameter. - if (listenerIDs) - result = event.dispatch_(args, listenerIDs); - else - result = event.dispatch.apply(event, args); + var result = attachedNamedEvents[name].dispatch.apply( + attachedNamedEvents[name], args); if (result && result.validationErrors) return result.validationErrors; } @@ -266,34 +170,13 @@ }; // Registers a callback to be called when this event is dispatched. - chrome.Event.prototype.addListener = function(cb, filters) { + chrome.Event.prototype.addListener = function(cb) { if (!this.eventOptions_.supportsListeners) throw new Error("This event does not support listeners."); - if (filters) { - if (!this.eventOptions_.supportsFilters) - throw new Error("This event does not support filters."); - if (filters.url && !(filters.url instanceof Array)) - throw new Error("filters.url should be an array"); - } - var listener = {callback: cb, filters: filters}; - this.attach_(listener); - this.listeners_.push(listener); - }; - - chrome.Event.prototype.attach_ = function(listener) { - this.attachmentStrategy_.onAddedListener(listener); if (this.listeners_.length == 0) { - allAttachedEvents[allAttachedEvents.length] = this; - if (!this.eventName_) - return; - - if (attachedNamedEvents[this.eventName_]) { - throw new Error("chrome.Event '" + this.eventName_ + - "' is already attached."); - } - - attachedNamedEvents[this.eventName_] = this; + this.attach_(); } + this.listeners_.push(cb); }; // Unregisters a callback. @@ -305,22 +188,9 @@ return; } - var removedListener = this.listeners_.splice(idx, 1)[0]; - this.attachmentStrategy_.onRemovedListener(removedListener); - + this.listeners_.splice(idx, 1); if (this.listeners_.length == 0) { - var i = allAttachedEvents.indexOf(this); - if (i >= 0) - delete allAttachedEvents[i]; - if (!this.eventName_) - return; - - if (!attachedNamedEvents[this.eventName_]) { - throw new Error("chrome.Event '" + this.eventName_ + - "' is not attached."); - } - - delete attachedNamedEvents[this.eventName_]; + this.detach_(true); } }; @@ -342,7 +212,7 @@ // found. chrome.Event.prototype.findListener_ = function(cb) { for (var i = 0; i < this.listeners_.length; i++) { - if (this.listeners_[i].callback == cb) { + if (this.listeners_[i] == cb) { return i; } } @@ -350,21 +220,21 @@ return -1; }; - chrome.Event.prototype.dispatch_ = function(args, listenerIDs) { + // Dispatches this event object to all listeners, passing all supplied + // arguments to this function each listener. + chrome.Event.prototype.dispatch = function(varargs) { if (!this.eventOptions_.supportsListeners) throw new Error("This event does not support listeners."); + var args = Array.prototype.slice.call(arguments); var validationErrors = this.validateEventArgs_(args); if (validationErrors) { console.error(validationErrors); return {validationErrors: validationErrors}; } - - var listeners = this.attachmentStrategy_.getListenersByIDs(listenerIDs); - var results = []; - for (var i = 0; i < listeners.length; i++) { + for (var i = 0; i < this.listeners_.length; i++) { try { - var result = listeners[i].callback.apply(null, args); + var result = this.listeners_[i].apply(null, args); if (result !== undefined) results.push(result); } catch (e) { @@ -374,17 +244,39 @@ } if (results.length) return {results: results}; - } + }; - // Dispatches this event object to all listeners, passing all supplied - // arguments to this function each listener. - chrome.Event.prototype.dispatch = function(varargs) { - return this.dispatch_(Array.prototype.slice.call(arguments), undefined); + // Attaches this event object to its name. Only one object can have a given + // name. + chrome.Event.prototype.attach_ = function() { + AttachEvent(this.eventName_); + allAttachedEvents[allAttachedEvents.length] = this; + if (!this.eventName_) + return; + + if (attachedNamedEvents[this.eventName_]) { + throw new Error("chrome.Event '" + this.eventName_ + + "' is already attached."); + } + + attachedNamedEvents[this.eventName_] = this; }; // Detaches this event object from its name. - chrome.Event.prototype.detach_ = function() { - this.attachmentStrategy_.detach(false); + chrome.Event.prototype.detach_ = function(manual) { + var i = allAttachedEvents.indexOf(this); + if (i >= 0) + delete allAttachedEvents[i]; + DetachEvent(this.eventName_, manual); + if (!this.eventName_) + return; + + if (!attachedNamedEvents[this.eventName_]) { + throw new Error("chrome.Event '" + this.eventName_ + + "' is not attached."); + } + + delete attachedNamedEvents[this.eventName_]; }; chrome.Event.prototype.destroy_ = function() { @@ -471,7 +363,7 @@ for (var i = 0; i < allAttachedEvents.length; ++i) { var event = allAttachedEvents[i]; if (event) - event.detach_(); + event.detach_(false); } }; |