Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 "extensions/renderer/event_bindings.h" | 5 #include "extensions/renderer/event_bindings.h" |
| 6 | 6 |
| 7 #include <map> | 7 #include <map> |
| 8 #include <set> | 8 #include <set> |
| 9 #include <string> | 9 #include <string> |
| 10 #include <vector> | 10 #include <vector> |
| (...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 136 FilteredEventListenerCounts::iterator it = counts.find(event_name); | 136 FilteredEventListenerCounts::iterator it = counts.find(event_name); |
| 137 if (it == counts.end()) | 137 if (it == counts.end()) |
| 138 return false; | 138 return false; |
| 139 return 0 == it->second->Remove(*filter); | 139 return 0 == it->second->Remove(*filter); |
| 140 } | 140 } |
| 141 | 141 |
| 142 } // namespace | 142 } // namespace |
| 143 | 143 |
| 144 EventBindings::EventBindings(Dispatcher* dispatcher, ScriptContext* context) | 144 EventBindings::EventBindings(Dispatcher* dispatcher, ScriptContext* context) |
| 145 : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { | 145 : ObjectBackedNativeHandler(context), dispatcher_(dispatcher) { |
| 146 RouteFunction( | 146 RouteFunction("AttachEvent", base::Bind(&EventBindings::AttachEventHandler, |
| 147 "AttachEvent", | 147 base::Unretained(this))); |
| 148 base::Bind(&EventBindings::AttachEvent, base::Unretained(this))); | 148 RouteFunction("DetachEvent", base::Bind(&EventBindings::DetachEventHandler, |
| 149 RouteFunction( | 149 base::Unretained(this))); |
| 150 "DetachEvent", | |
| 151 base::Bind(&EventBindings::DetachEvent, base::Unretained(this))); | |
| 152 RouteFunction( | 150 RouteFunction( |
| 153 "AttachFilteredEvent", | 151 "AttachFilteredEvent", |
| 154 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); | 152 base::Bind(&EventBindings::AttachFilteredEvent, base::Unretained(this))); |
| 155 RouteFunction( | 153 RouteFunction( |
| 156 "DetachFilteredEvent", | 154 "DetachFilteredEvent", |
| 157 base::Bind(&EventBindings::DetachFilteredEvent, base::Unretained(this))); | 155 base::Bind(&EventBindings::DetachFilteredEvent, base::Unretained(this))); |
| 158 RouteFunction("MatchAgainstEventFilter", | 156 RouteFunction("MatchAgainstEventFilter", |
| 159 base::Bind(&EventBindings::MatchAgainstEventFilter, | 157 base::Bind(&EventBindings::MatchAgainstEventFilter, |
| 160 base::Unretained(this))); | 158 base::Unretained(this))); |
| 159 | |
| 160 // It's safe to use base::Unretained here because |context| will always | |
| 161 // outlive us. | |
| 162 context->AddInvalidateObserver( | |
| 163 base::Bind(&EventBindings::OnInvalidated, base::Unretained(this))); | |
| 161 } | 164 } |
| 162 | 165 |
| 163 EventBindings::~EventBindings() {} | 166 EventBindings::~EventBindings() {} |
| 164 | 167 |
| 165 // Attach an event name to an object. | 168 void EventBindings::AttachEventHandler( |
| 166 void EventBindings::AttachEvent( | |
| 167 const v8::FunctionCallbackInfo<v8::Value>& args) { | 169 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 168 CHECK_EQ(1, args.Length()); | 170 CHECK_EQ(1, args.Length()); |
| 169 CHECK(args[0]->IsString()); | 171 CHECK(args[0]->IsString()); |
| 172 AttachEvent(*v8::String::Utf8Value(args[0])); | |
| 173 } | |
| 170 | 174 |
| 171 std::string event_name = *v8::String::Utf8Value(args[0]); | 175 void EventBindings::AttachEvent(const std::string& event_name) { |
| 172 | 176 // This method throws an exception if it returns false. |
| 173 if (!dispatcher_->CheckContextAccessToExtensionAPI(event_name, context())) | 177 if (!dispatcher_->CheckContextAccessToExtensionAPI(event_name, context())) |
| 174 return; | 178 return; |
| 175 | 179 |
| 180 // Record the attachment for this context so that events can be detached when | |
| 181 // the context is destroyed. | |
| 182 // | |
| 183 // Ideally we'd CHECK that it's not already attached, however that's not | |
| 184 // possible because extension can create and attach events themselves. Very | |
|
Devlin
2015/04/10 18:10:40
nit: extensions
not at google - send to devlin
2015/04/10 18:39:01
Done.
| |
| 185 // silly, but that's the way it is. For an example of this, see | |
| 186 // chrome/test/data/extensions/api_test/events/background.js. | |
| 187 attached_event_names_.insert(event_name); | |
| 188 | |
| 176 const std::string& extension_id = context()->GetExtensionID(); | 189 const std::string& extension_id = context()->GetExtensionID(); |
| 177 if (IncrementEventListenerCount(context(), event_name) == 1) { | 190 if (IncrementEventListenerCount(context(), event_name) == 1) { |
| 178 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddListener( | 191 content::RenderThread::Get()->Send(new ExtensionHostMsg_AddListener( |
| 179 extension_id, context()->GetURL(), event_name)); | 192 extension_id, context()->GetURL(), event_name)); |
| 180 } | 193 } |
| 181 | 194 |
| 182 // This is called the first time the page has added a listener. Since | 195 // This is called the first time the page has added a listener. Since |
| 183 // the background page is the only lazy page, we know this is the first | 196 // the background page is the only lazy page, we know this is the first |
| 184 // time this listener has been registered. | 197 // time this listener has been registered. |
| 185 if (IsLazyBackgroundPage(context()->GetRenderView(), | 198 if (IsLazyBackgroundPage(context()->GetRenderView(), |
| 186 context()->extension())) { | 199 context()->extension())) { |
| 187 content::RenderThread::Get()->Send( | 200 content::RenderThread::Get()->Send( |
| 188 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); | 201 new ExtensionHostMsg_AddLazyListener(extension_id, event_name)); |
| 189 } | 202 } |
| 190 } | 203 } |
| 191 | 204 |
| 192 void EventBindings::DetachEvent( | 205 void EventBindings::DetachEventHandler( |
| 193 const v8::FunctionCallbackInfo<v8::Value>& args) { | 206 const v8::FunctionCallbackInfo<v8::Value>& args) { |
| 194 CHECK_EQ(2, args.Length()); | 207 CHECK_EQ(2, args.Length()); |
| 195 CHECK(args[0]->IsString()); | 208 CHECK(args[0]->IsString()); |
| 196 CHECK(args[1]->IsBoolean()); | 209 CHECK(args[1]->IsBoolean()); |
| 210 DetachEvent(*v8::String::Utf8Value(args[0]), args[1]->BooleanValue()); | |
| 211 } | |
| 197 | 212 |
| 198 std::string event_name = *v8::String::Utf8Value(args[0]); | 213 void EventBindings::DetachEvent(const std::string& event_name, bool is_manual) { |
| 199 bool is_manual = args[1]->BooleanValue(); | 214 // See comment in AttachEvent(). |
| 215 attached_event_names_.erase(event_name); | |
| 200 | 216 |
| 201 const std::string& extension_id = context()->GetExtensionID(); | 217 const std::string& extension_id = context()->GetExtensionID(); |
| 218 | |
| 202 if (DecrementEventListenerCount(context(), event_name) == 0) { | 219 if (DecrementEventListenerCount(context(), event_name) == 0) { |
| 203 content::RenderThread::Get()->Send(new ExtensionHostMsg_RemoveListener( | 220 content::RenderThread::Get()->Send(new ExtensionHostMsg_RemoveListener( |
| 204 extension_id, context()->GetURL(), event_name)); | 221 extension_id, context()->GetURL(), event_name)); |
| 205 } | 222 } |
| 206 | 223 |
| 207 // DetachEvent is called when the last listener for the context is | 224 // DetachEvent is called when the last listener for the context is |
| 208 // removed. If the context is the background page, and it removes the | 225 // removed. If the context is the background page, and it removes the |
| 209 // last listener manually, then we assume that it is no longer interested | 226 // last listener manually, then we assume that it is no longer interested |
| 210 // in being awakened for this event. | 227 // in being awakened for this event. |
| 211 if (is_manual && IsLazyBackgroundPage(context()->GetRenderView(), | 228 if (is_manual && IsLazyBackgroundPage(context()->GetRenderView(), |
| (...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 317 args.GetReturnValue().Set(array); | 334 args.GetReturnValue().Set(array); |
| 318 } | 335 } |
| 319 | 336 |
| 320 scoped_ptr<EventMatcher> EventBindings::ParseEventMatcher( | 337 scoped_ptr<EventMatcher> EventBindings::ParseEventMatcher( |
| 321 base::DictionaryValue* filter_dict) { | 338 base::DictionaryValue* filter_dict) { |
| 322 return scoped_ptr<EventMatcher>(new EventMatcher( | 339 return scoped_ptr<EventMatcher>(new EventMatcher( |
| 323 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()), | 340 scoped_ptr<base::DictionaryValue>(filter_dict->DeepCopy()), |
| 324 context()->GetRenderView()->GetRoutingID())); | 341 context()->GetRenderView()->GetRoutingID())); |
| 325 } | 342 } |
| 326 | 343 |
| 344 void EventBindings::OnInvalidated() { | |
| 345 // Detach all attached events that weren't attached. Iterate over a copy | |
| 346 // because it will be mutated. | |
| 347 std::set<std::string> attached_event_names_safe = attached_event_names_; | |
| 348 for (const std::string& event_name : attached_event_names_safe) { | |
| 349 DetachEvent(event_name, false /* is_manual */); | |
| 350 } | |
|
Devlin
2015/04/10 18:10:39
For kicks and grins, can we DCHECK(attached_event_
not at google - send to devlin
2015/04/10 18:39:01
Done.
| |
| 351 } | |
| 352 | |
| 327 } // namespace extensions | 353 } // namespace extensions |
| OLD | NEW |