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