| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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/renderer/extensions/event_bindings.h" | 5 #include "chrome/renderer/extensions/event_bindings.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/bind.h" | 9 #include "base/bind.h" |
| 10 #include "base/basictypes.h" | 10 #include "base/basictypes.h" |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 65 // A map of extension IDs to filtered listener counts for that extension. | 65 // A map of extension IDs to filtered listener counts for that extension. |
| 66 base::LazyInstance<std::map<std::string, FilteredEventListenerCounts> > | 66 base::LazyInstance<std::map<std::string, FilteredEventListenerCounts> > |
| 67 g_filtered_listener_counts = LAZY_INSTANCE_INITIALIZER; | 67 g_filtered_listener_counts = LAZY_INSTANCE_INITIALIZER; |
| 68 | 68 |
| 69 base::LazyInstance<extensions::EventFilter> g_event_filter = | 69 base::LazyInstance<extensions::EventFilter> g_event_filter = |
| 70 LAZY_INSTANCE_INITIALIZER; | 70 LAZY_INSTANCE_INITIALIZER; |
| 71 | 71 |
| 72 // TODO(koz): Merge this into EventBindings. | 72 // TODO(koz): Merge this into EventBindings. |
| 73 class ExtensionImpl : public ChromeV8Extension { | 73 class ExtensionImpl : public ChromeV8Extension { |
| 74 public: | 74 public: |
| 75 explicit ExtensionImpl(Dispatcher* dispatcher, | 75 explicit ExtensionImpl(Dispatcher* dispatcher) |
| 76 v8::Handle<v8::Context> v8_context) | 76 : ChromeV8Extension(dispatcher) { |
| 77 : ChromeV8Extension(dispatcher, v8_context) { | |
| 78 RouteStaticFunction("AttachEvent", &AttachEvent); | 77 RouteStaticFunction("AttachEvent", &AttachEvent); |
| 79 RouteStaticFunction("DetachEvent", &DetachEvent); | 78 RouteStaticFunction("DetachEvent", &DetachEvent); |
| 80 RouteStaticFunction("AttachFilteredEvent", &AttachFilteredEvent); | 79 RouteStaticFunction("AttachFilteredEvent", &AttachFilteredEvent); |
| 81 RouteStaticFunction("DetachFilteredEvent", &DetachFilteredEvent); | 80 RouteStaticFunction("DetachFilteredEvent", &DetachFilteredEvent); |
| 82 RouteStaticFunction("MatchAgainstEventFilter", &MatchAgainstEventFilter); | 81 RouteStaticFunction("MatchAgainstEventFilter", &MatchAgainstEventFilter); |
| 83 } | 82 } |
| 84 | 83 |
| 85 virtual ~ExtensionImpl() {} | 84 virtual ~ExtensionImpl() {} |
| 86 | 85 |
| 87 // Attach an event name to an object. | 86 // Attach an event name to an object. |
| 88 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { | 87 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { |
| 89 DCHECK(args.Length() == 1); | 88 DCHECK(args.Length() == 1); |
| 90 // TODO(erikkay) should enforce that event name is a string in the bindings | 89 // TODO(erikkay) should enforce that event name is a string in the bindings |
| 91 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); | 90 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); |
| 92 | 91 |
| 93 if (args[0]->IsString()) { | 92 if (args[0]->IsString()) { |
| 94 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 93 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
| 95 std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); | 94 std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); |
| 96 Dispatcher* dispatcher = self->dispatcher(); | 95 Dispatcher* dispatcher = self->dispatcher(); |
| 97 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); | 96 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); |
| 98 ChromeV8Context* context = context_set.GetByV8Context(self->v8_context()); | 97 ChromeV8Context* context = context_set.GetCurrent(); |
| 99 CHECK(context); | 98 CHECK(context); |
| 100 | 99 |
| 101 if (!dispatcher->CheckContextAccessToExtensionAPI(event_name, context)) | 100 if (!dispatcher->CheckCurrentContextAccessToExtensionAPI(event_name)) |
| 102 return v8::Undefined(); | 101 return v8::Undefined(); |
| 103 | 102 |
| 104 std::string extension_id = context->GetExtensionID(); | 103 std::string extension_id = context->GetExtensionID(); |
| 105 EventListenerCounts& listener_counts = | 104 EventListenerCounts& listener_counts = |
| 106 g_listener_counts.Get()[extension_id]; | 105 g_listener_counts.Get()[extension_id]; |
| 107 if (++listener_counts[event_name] == 1) { | 106 if (++listener_counts[event_name] == 1) { |
| 108 content::RenderThread::Get()->Send( | 107 content::RenderThread::Get()->Send( |
| 109 new ExtensionHostMsg_AddListener(extension_id, event_name)); | 108 new ExtensionHostMsg_AddListener(extension_id, event_name)); |
| 110 } | 109 } |
| 111 | 110 |
| 112 // This is called the first time the page has added a listener. Since | 111 // This is called the first time the page has added a listener. Since |
| 113 // the background page is the only lazy page, we know this is the first | 112 // the background page is the only lazy page, we know this is the first |
| 114 // time this listener has been registered. | 113 // time this listener has been registered. |
| 115 if (IsLazyBackgroundPage(self->GetRenderView(), context->extension())) { | 114 if (IsLazyBackgroundPage(context->extension())) { |
| 116 content::RenderThread::Get()->Send( | 115 content::RenderThread::Get()->Send( |
| 117 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); | 116 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); |
| 118 } | 117 } |
| 119 } | 118 } |
| 120 return v8::Undefined(); | 119 return v8::Undefined(); |
| 121 } | 120 } |
| 122 | 121 |
| 123 static v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) { | 122 static v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) { |
| 124 DCHECK(args.Length() == 2); | 123 DCHECK(args.Length() == 2); |
| 125 // TODO(erikkay) should enforce that event name is a string in the bindings | 124 // TODO(erikkay) should enforce that event name is a string in the bindings |
| 126 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); | 125 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); |
| 127 | 126 |
| 128 if (args[0]->IsString() && args[1]->IsBoolean()) { | 127 if (args[0]->IsString() && args[1]->IsBoolean()) { |
| 129 std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); | 128 std::string event_name = *v8::String::AsciiValue(args[0]->ToString()); |
| 130 bool is_manual = args[1]->BooleanValue(); | 129 bool is_manual = args[1]->BooleanValue(); |
| 131 | 130 |
| 132 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 131 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
| 133 Dispatcher* dispatcher = self->dispatcher(); | 132 Dispatcher* dispatcher = self->dispatcher(); |
| 134 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); | 133 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); |
| 135 ChromeV8Context* context = context_set.GetByV8Context(self->v8_context()); | 134 ChromeV8Context* context = context_set.GetCurrent(); |
| 136 if (!context) | 135 if (!context) |
| 137 return v8::Undefined(); | 136 return v8::Undefined(); |
| 138 | 137 |
| 139 std::string extension_id = context->GetExtensionID(); | 138 std::string extension_id = context->GetExtensionID(); |
| 140 EventListenerCounts& listener_counts = | 139 EventListenerCounts& listener_counts = |
| 141 g_listener_counts.Get()[extension_id]; | 140 g_listener_counts.Get()[extension_id]; |
| 142 | 141 |
| 143 if (--listener_counts[event_name] == 0) { | 142 if (--listener_counts[event_name] == 0) { |
| 144 content::RenderThread::Get()->Send( | 143 content::RenderThread::Get()->Send( |
| 145 new ExtensionHostMsg_RemoveListener(extension_id, event_name)); | 144 new ExtensionHostMsg_RemoveListener(extension_id, event_name)); |
| 146 } | 145 } |
| 147 | 146 |
| 148 // DetachEvent is called when the last listener for the context is | 147 // DetachEvent is called when the last listener for the context is |
| 149 // removed. If the context is the background page, and it removes the | 148 // removed. If the context is the background page, and it removes the |
| 150 // last listener manually, then we assume that it is no longer interested | 149 // last listener manually, then we assume that it is no longer interested |
| 151 // in being awakened for this event. | 150 // in being awakened for this event. |
| 152 if (is_manual && IsLazyBackgroundPage(self->GetRenderView(), | 151 if (is_manual && IsLazyBackgroundPage(context->extension())) { |
| 153 context->extension())) { | |
| 154 content::RenderThread::Get()->Send( | 152 content::RenderThread::Get()->Send( |
| 155 new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name)); | 153 new ExtensionHostMsg_RemoveLazyListener(extension_id, event_name)); |
| 156 } | 154 } |
| 157 } | 155 } |
| 158 return v8::Undefined(); | 156 return v8::Undefined(); |
| 159 } | 157 } |
| 160 | 158 |
| 161 // MatcherID AttachFilteredEvent(string event_name, object filter) | 159 // MatcherID AttachFilteredEvent(string event_name, object filter) |
| 162 // event_name - Name of the event to attach. | 160 // event_name - Name of the event to attach. |
| 163 // filter - Which instances of the named event are we interested in. | 161 // filter - Which instances of the named event are we interested in. |
| 164 // returns the id assigned to the listener, which will be returned from calls | 162 // returns the id assigned to the listener, which will be returned from calls |
| 165 // to MatchAgainstEventFilter where this listener matches. | 163 // to MatchAgainstEventFilter where this listener matches. |
| 166 static v8::Handle<v8::Value> AttachFilteredEvent(const v8::Arguments& args) { | 164 static v8::Handle<v8::Value> AttachFilteredEvent(const v8::Arguments& args) { |
| 167 DCHECK_EQ(2, args.Length()); | 165 DCHECK_EQ(2, args.Length()); |
| 168 DCHECK(args[0]->IsString()); | 166 DCHECK(args[0]->IsString()); |
| 169 DCHECK(args[1]->IsObject()); | 167 DCHECK(args[1]->IsObject()); |
| 170 | 168 |
| 171 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 169 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
| 172 Dispatcher* dispatcher = self->dispatcher(); | 170 Dispatcher* dispatcher = self->dispatcher(); |
| 173 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); | 171 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); |
| 174 ChromeV8Context* context = context_set.GetByV8Context(self->v8_context()); | 172 ChromeV8Context* context = context_set.GetCurrent(); |
| 175 DCHECK(context); | 173 DCHECK(context); |
| 176 if (!context) | 174 if (!context) |
| 177 return v8::Integer::New(-1); | 175 return v8::Integer::New(-1); |
| 178 | 176 |
| 179 std::string event_name = *v8::String::AsciiValue(args[0]); | 177 std::string event_name = *v8::String::AsciiValue(args[0]); |
| 180 // This method throws an exception if it returns false. | 178 // This method throws an exception if it returns false. |
| 181 if (!dispatcher->CheckContextAccessToExtensionAPI(event_name, context)) | 179 if (!dispatcher->CheckCurrentContextAccessToExtensionAPI(event_name)) |
| 182 return v8::Undefined(); | 180 return v8::Undefined(); |
| 183 | 181 |
| 184 std::string extension_id = context->GetExtensionID(); | 182 std::string extension_id = context->GetExtensionID(); |
| 185 if (extension_id.empty()) | 183 if (extension_id.empty()) |
| 186 return v8::Integer::New(-1); | 184 return v8::Integer::New(-1); |
| 187 | 185 |
| 188 scoped_ptr<base::DictionaryValue> filter; | 186 scoped_ptr<base::DictionaryValue> filter; |
| 189 scoped_ptr<content::V8ValueConverter> converter( | 187 scoped_ptr<content::V8ValueConverter> converter( |
| 190 content::V8ValueConverter::create()); | 188 content::V8ValueConverter::create()); |
| 191 | 189 |
| 192 base::DictionaryValue* filter_dict = NULL; | 190 base::DictionaryValue* filter_dict = NULL; |
| 193 base::Value* filter_value = | 191 base::Value* filter_value = converter->FromV8Value(args[1]->ToObject(), |
| 194 converter->FromV8Value(args[1]->ToObject(), context->v8_context()); | 192 v8::Context::GetCurrent()); |
| 195 if (!filter_value) | 193 if (!filter_value) |
| 196 return v8::Integer::New(-1); | 194 return v8::Integer::New(-1); |
| 197 if (!filter_value->GetAsDictionary(&filter_dict)) { | 195 if (!filter_value->GetAsDictionary(&filter_dict)) { |
| 198 delete filter_value; | 196 delete filter_value; |
| 199 return v8::Integer::New(-1); | 197 return v8::Integer::New(-1); |
| 200 } | 198 } |
| 201 | 199 |
| 202 filter.reset(filter_dict); | 200 filter.reset(filter_dict); |
| 203 extensions::EventFilter& event_filter = g_event_filter.Get(); | 201 extensions::EventFilter& event_filter = g_event_filter.Get(); |
| 204 int id = event_filter.AddEventMatcher(event_name, ParseEventMatcher( | 202 int id = event_filter.AddEventMatcher(event_name, ParseEventMatcher( |
| 205 filter.get())); | 203 filter.get())); |
| 206 | 204 |
| 207 // Only send IPCs the first time a filter gets added. | 205 // Only send IPCs the first time a filter gets added. |
| 208 if (AddFilter(event_name, extension_id, filter.get())) { | 206 if (AddFilter(event_name, extension_id, filter.get())) { |
| 209 bool lazy = IsLazyBackgroundPage(self->GetRenderView(), | 207 bool lazy = IsLazyBackgroundPage(context->extension()); |
| 210 context->extension()); | |
| 211 content::RenderThread::Get()->Send( | 208 content::RenderThread::Get()->Send( |
| 212 new ExtensionHostMsg_AddFilteredListener(extension_id, event_name, | 209 new ExtensionHostMsg_AddFilteredListener(extension_id, event_name, |
| 213 *filter, lazy)); | 210 *filter, lazy)); |
| 214 } | 211 } |
| 215 | 212 |
| 216 return v8::Integer::New(id); | 213 return v8::Integer::New(id); |
| 217 } | 214 } |
| 218 | 215 |
| 219 // Add a filter to |event_name| in |extension_id|, returning true if it | 216 // Add a filter to |event_name| in |extension_id|, returning true if it |
| 220 // was the first filter for that event in that extension. | 217 // was the first filter for that event in that extension. |
| (...skipping 28 matching lines...) Expand all Loading... |
| 249 // manual - false if this is part of the extension unload process where all | 246 // manual - false if this is part of the extension unload process where all |
| 250 // listeners are automatically detached. | 247 // listeners are automatically detached. |
| 251 static v8::Handle<v8::Value> DetachFilteredEvent(const v8::Arguments& args) { | 248 static v8::Handle<v8::Value> DetachFilteredEvent(const v8::Arguments& args) { |
| 252 DCHECK_EQ(2, args.Length()); | 249 DCHECK_EQ(2, args.Length()); |
| 253 DCHECK(args[0]->IsInt32()); | 250 DCHECK(args[0]->IsInt32()); |
| 254 DCHECK(args[1]->IsBoolean()); | 251 DCHECK(args[1]->IsBoolean()); |
| 255 bool is_manual = args[1]->BooleanValue(); | 252 bool is_manual = args[1]->BooleanValue(); |
| 256 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 253 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
| 257 Dispatcher* dispatcher = self->dispatcher(); | 254 Dispatcher* dispatcher = self->dispatcher(); |
| 258 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); | 255 const ChromeV8ContextSet& context_set = dispatcher->v8_context_set(); |
| 259 ChromeV8Context* context = context_set.GetByV8Context(self->v8_context()); | 256 ChromeV8Context* context = context_set.GetCurrent(); |
| 260 if (!context) | 257 if (!context) |
| 261 return v8::Undefined(); | 258 return v8::Undefined(); |
| 262 | 259 |
| 263 std::string extension_id = context->GetExtensionID(); | 260 std::string extension_id = context->GetExtensionID(); |
| 264 if (extension_id.empty()) | 261 if (extension_id.empty()) |
| 265 return v8::Undefined(); | 262 return v8::Undefined(); |
| 266 | 263 |
| 267 int matcher_id = args[0]->Int32Value(); | 264 int matcher_id = args[0]->Int32Value(); |
| 268 extensions::EventFilter& event_filter = g_event_filter.Get(); | 265 extensions::EventFilter& event_filter = g_event_filter.Get(); |
| 269 extensions::EventMatcher* event_matcher = | 266 extensions::EventMatcher* event_matcher = |
| 270 event_filter.GetEventMatcher(matcher_id); | 267 event_filter.GetEventMatcher(matcher_id); |
| 271 | 268 |
| 272 const std::string& event_name = event_filter.GetEventName(matcher_id); | 269 const std::string& event_name = event_filter.GetEventName(matcher_id); |
| 273 | 270 |
| 274 // Only send IPCs the last time a filter gets removed. | 271 // Only send IPCs the last time a filter gets removed. |
| 275 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { | 272 if (RemoveFilter(event_name, extension_id, event_matcher->value())) { |
| 276 bool lazy = is_manual && IsLazyBackgroundPage(self->GetRenderView(), | 273 bool lazy = is_manual && IsLazyBackgroundPage(context->extension()); |
| 277 context->extension()); | |
| 278 content::RenderThread::Get()->Send( | 274 content::RenderThread::Get()->Send( |
| 279 new ExtensionHostMsg_RemoveFilteredListener(extension_id, event_name, | 275 new ExtensionHostMsg_RemoveFilteredListener(extension_id, event_name, |
| 280 *event_matcher->value(), | 276 *event_matcher->value(), |
| 281 lazy)); | 277 lazy)); |
| 282 } | 278 } |
| 283 | 279 |
| 284 event_filter.RemoveEventMatcher(matcher_id); | 280 event_filter.RemoveEventMatcher(matcher_id); |
| 285 | 281 |
| 286 return v8::Undefined(); | 282 return v8::Undefined(); |
| 287 } | 283 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 309 extensions::EventFilteringInfo info; | 305 extensions::EventFilteringInfo info; |
| 310 v8::Handle<v8::String> url(v8::String::New("url")); | 306 v8::Handle<v8::String> url(v8::String::New("url")); |
| 311 if (object->Has(url)) { | 307 if (object->Has(url)) { |
| 312 v8::Handle<v8::Value> url_value(object->Get(url)); | 308 v8::Handle<v8::Value> url_value(object->Get(url)); |
| 313 info.SetURL(GURL(*v8::String::AsciiValue(url_value))); | 309 info.SetURL(GURL(*v8::String::AsciiValue(url_value))); |
| 314 } | 310 } |
| 315 return info; | 311 return info; |
| 316 } | 312 } |
| 317 | 313 |
| 318 private: | 314 private: |
| 319 static bool IsLazyBackgroundPage(content::RenderView* render_view, | 315 static bool IsLazyBackgroundPage(const Extension* extension) { |
| 320 const Extension* extension) { | 316 content::RenderView* render_view = GetCurrentRenderView(); |
| 321 if (!render_view) | 317 if (!render_view) |
| 322 return false; | 318 return false; |
| 319 |
| 323 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | 320 ExtensionHelper* helper = ExtensionHelper::Get(render_view); |
| 324 return (extension && extension->has_lazy_background_page() && | 321 return (extension && extension->has_lazy_background_page() && |
| 325 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); | 322 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
| 326 } | 323 } |
| 327 | 324 |
| 328 static scoped_ptr<extensions::EventMatcher> ParseEventMatcher( | 325 static scoped_ptr<extensions::EventMatcher> ParseEventMatcher( |
| 329 base::DictionaryValue* filter_dict) { | 326 base::DictionaryValue* filter_dict) { |
| 330 return scoped_ptr<extensions::EventMatcher>(new extensions::EventMatcher( | 327 return scoped_ptr<extensions::EventMatcher>(new extensions::EventMatcher( |
| 331 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()))); | 328 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()))); |
| 332 } | 329 } |
| 333 }; | 330 }; |
| 334 | 331 |
| 335 } // namespace | 332 } // namespace |
| 336 | 333 |
| 337 // static | 334 // static |
| 338 ChromeV8Extension* EventBindings::Create(Dispatcher* dispatcher, | 335 ChromeV8Extension* EventBindings::Get(Dispatcher* dispatcher) { |
| 339 v8::Handle<v8::Context> context) { | 336 return new ExtensionImpl(dispatcher); |
| 340 return new ExtensionImpl(dispatcher, context); | |
| 341 } | 337 } |
| 342 | 338 |
| 343 } // namespace extensions | 339 } // namespace extensions |
| OLD | NEW |