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/basictypes.h" | 9 #include "base/basictypes.h" |
10 #include "base/lazy_instance.h" | 10 #include "base/lazy_instance.h" |
(...skipping 21 matching lines...) Expand all Loading... |
32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" | 32 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
33 #include "v8/include/v8.h" | 33 #include "v8/include/v8.h" |
34 | 34 |
35 using WebKit::WebFrame; | 35 using WebKit::WebFrame; |
36 using WebKit::WebSecurityOrigin; | 36 using WebKit::WebSecurityOrigin; |
37 using WebKit::WebURL; | 37 using WebKit::WebURL; |
38 using content::RenderThread; | 38 using content::RenderThread; |
39 | 39 |
40 namespace { | 40 namespace { |
41 | 41 |
| 42 // A map of event names to the number of contexts listening to that event. |
| 43 // We notify the browser about event listeners when we transition between 0 |
| 44 // and 1. |
| 45 typedef std::map<std::string, int> EventListenerCounts; |
| 46 |
| 47 // A map of extension IDs to listener counts for that extension. |
| 48 base::LazyInstance<std::map<std::string, EventListenerCounts> > |
| 49 g_listener_counts = LAZY_INSTANCE_INITIALIZER; |
| 50 |
| 51 // TODO(koz): Merge this into EventBindings. |
42 class ExtensionImpl : public ChromeV8Extension { | 52 class ExtensionImpl : public ChromeV8Extension { |
43 public: | 53 public: |
| 54 |
44 explicit ExtensionImpl(ExtensionDispatcher* dispatcher) | 55 explicit ExtensionImpl(ExtensionDispatcher* dispatcher) |
45 : ChromeV8Extension("extensions/event.js", | 56 : ChromeV8Extension(dispatcher) { |
46 IDR_EVENT_BINDINGS_JS, | 57 RouteStaticFunction("AttachEvent", &AttachEvent); |
47 dispatcher) { | 58 RouteStaticFunction("DetachEvent", &DetachEvent); |
48 } | 59 } |
49 ~ExtensionImpl() {} | 60 ~ExtensionImpl() {} |
50 | 61 |
51 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( | |
52 v8::Handle<v8::String> name) { | |
53 if (name->Equals(v8::String::New("AttachEvent"))) { | |
54 return v8::FunctionTemplate::New(AttachEvent, v8::External::New(this)); | |
55 } else if (name->Equals(v8::String::New("DetachEvent"))) { | |
56 return v8::FunctionTemplate::New(DetachEvent, v8::External::New(this)); | |
57 } | |
58 return ChromeV8Extension::GetNativeFunction(name); | |
59 } | |
60 | |
61 // Attach an event name to an object. | 62 // Attach an event name to an object. |
62 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { | 63 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { |
63 DCHECK(args.Length() == 1); | 64 DCHECK(args.Length() == 1); |
64 // TODO(erikkay) should enforce that event name is a string in the bindings | 65 // TODO(erikkay) should enforce that event name is a string in the bindings |
65 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); | 66 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); |
66 | 67 |
67 if (args[0]->IsString()) { | 68 if (args[0]->IsString()) { |
68 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 69 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
69 const ChromeV8ContextSet& context_set = | 70 const ChromeV8ContextSet& context_set = |
70 self->extension_dispatcher()->v8_context_set(); | 71 self->extension_dispatcher()->v8_context_set(); |
71 ChromeV8Context* context = context_set.GetCurrent(); | 72 ChromeV8Context* context = context_set.GetCurrent(); |
72 CHECK(context); | 73 CHECK(context); |
73 std::string event_name(*v8::String::AsciiValue(args[0])); | 74 std::string event_name(*v8::String::AsciiValue(args[0])); |
74 | 75 |
75 if (!self->CheckCurrentContextAccessToExtensionAPI(event_name)) | 76 if (!self->CheckCurrentContextAccessToExtensionAPI(event_name)) |
76 return v8::Undefined(); | 77 return v8::Undefined(); |
77 | 78 |
78 EventListenerCounts& listener_counts = | 79 EventListenerCounts& listener_counts = |
79 self->listener_counts_[context->extension_id()]; | 80 g_listener_counts.Get()[context->extension_id()]; |
80 if (++listener_counts[event_name] == 1) { | 81 if (++listener_counts[event_name] == 1) { |
81 content::RenderThread::Get()->Send( | 82 content::RenderThread::Get()->Send( |
82 new ExtensionHostMsg_AddListener(context->extension_id(), | 83 new ExtensionHostMsg_AddListener(context->extension_id(), |
83 event_name)); | 84 event_name)); |
84 } | 85 } |
85 | 86 |
86 // This is called the first time the page has added a listener. Since | 87 // This is called the first time the page has added a listener. Since |
87 // the background page is the only lazy page, we know this is the first | 88 // the background page is the only lazy page, we know this is the first |
88 // time this listener has been registered. | 89 // time this listener has been registered. |
89 if (self->IsLazyBackgroundPage(context->extension_id())) { | 90 if (self->IsLazyBackgroundPage(context->extension_id())) { |
(...skipping 13 matching lines...) Expand all Loading... |
103 | 104 |
104 if (args[0]->IsString() && args[1]->IsBoolean()) { | 105 if (args[0]->IsString() && args[1]->IsBoolean()) { |
105 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 106 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
106 const ChromeV8ContextSet& context_set = | 107 const ChromeV8ContextSet& context_set = |
107 self->extension_dispatcher()->v8_context_set(); | 108 self->extension_dispatcher()->v8_context_set(); |
108 ChromeV8Context* context = context_set.GetCurrent(); | 109 ChromeV8Context* context = context_set.GetCurrent(); |
109 if (!context) | 110 if (!context) |
110 return v8::Undefined(); | 111 return v8::Undefined(); |
111 | 112 |
112 EventListenerCounts& listener_counts = | 113 EventListenerCounts& listener_counts = |
113 self->listener_counts_[context->extension_id()]; | 114 g_listener_counts.Get()[context->extension_id()]; |
114 std::string event_name(*v8::String::AsciiValue(args[0])); | 115 std::string event_name(*v8::String::AsciiValue(args[0])); |
115 bool is_manual = args[1]->BooleanValue(); | 116 bool is_manual = args[1]->BooleanValue(); |
116 | 117 |
117 if (--listener_counts[event_name] == 0) { | 118 if (--listener_counts[event_name] == 0) { |
118 content::RenderThread::Get()->Send( | 119 content::RenderThread::Get()->Send( |
119 new ExtensionHostMsg_RemoveListener(context->extension_id(), | 120 new ExtensionHostMsg_RemoveListener(context->extension_id(), |
120 event_name)); | 121 event_name)); |
121 } | 122 } |
122 | 123 |
123 // DetachEvent is called when the last listener for the context is | 124 // DetachEvent is called when the last listener for the context is |
124 // removed. If the context is the background page, and it removes the | 125 // removed. If the context is the background page, and it removes the |
125 // last listener manually, then we assume that it is no longer interested | 126 // last listener manually, then we assume that it is no longer interested |
126 // in being awakened for this event. | 127 // in being awakened for this event. |
127 if (is_manual && self->IsLazyBackgroundPage(context->extension_id())) { | 128 if (is_manual && self->IsLazyBackgroundPage(context->extension_id())) { |
128 content::RenderThread::Get()->Send( | 129 content::RenderThread::Get()->Send( |
129 new ExtensionHostMsg_RemoveLazyListener(context->extension_id(), | 130 new ExtensionHostMsg_RemoveLazyListener(context->extension_id(), |
130 event_name)); | 131 event_name)); |
131 } | 132 } |
132 } | 133 } |
133 | 134 |
134 return v8::Undefined(); | 135 return v8::Undefined(); |
135 } | 136 } |
136 | 137 |
137 private: | 138 private: |
138 // A map of event names to the number of contexts listening to that event. | |
139 // We notify the browser about event listeners when we transition between 0 | |
140 // and 1. | |
141 typedef std::map<std::string, int> EventListenerCounts; | |
142 | 139 |
143 bool IsLazyBackgroundPage(const std::string& extension_id) { | 140 bool IsLazyBackgroundPage(const std::string& extension_id) { |
144 content::RenderView* render_view = GetCurrentRenderView(); | 141 content::RenderView* render_view = GetCurrentRenderView(); |
145 if (!render_view) | 142 if (!render_view) |
146 return false; | 143 return false; |
147 | 144 |
148 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | 145 ExtensionHelper* helper = ExtensionHelper::Get(render_view); |
149 const ::Extension* extension = | 146 const ::Extension* extension = |
150 extension_dispatcher()->extensions()->GetByID(extension_id); | 147 extension_dispatcher()->extensions()->GetByID(extension_id); |
151 return (extension && !extension->background_page_persists() && | 148 return (extension && !extension->background_page_persists() && |
152 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); | 149 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
153 } | 150 } |
154 | |
155 // A map of extension IDs to listener counts for that extension. | |
156 std::map<std::string, EventListenerCounts> listener_counts_; | |
157 }; | 151 }; |
158 | 152 |
159 } // namespace | 153 } // namespace |
160 | 154 |
161 v8::Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { | 155 ChromeV8Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { |
162 static v8::Extension* extension = new ExtensionImpl(dispatcher); | 156 return new ExtensionImpl(dispatcher); |
163 return extension; | |
164 } | 157 } |
OLD | NEW |