Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(185)

Side by Side Diff: chrome/renderer/extensions/event_bindings.cc

Issue 100214: Only send events to renderers that are listening to an event.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/renderer/extensions/event_bindings.h ('k') | chrome/test/render_view_test.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2009 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 "base/basictypes.h" 7 #include "base/basictypes.h"
8 #include "base/singleton.h" 8 #include "base/singleton.h"
9 #include "chrome/common/render_messages.h"
9 #include "chrome/renderer/extensions/bindings_utils.h" 10 #include "chrome/renderer/extensions/bindings_utils.h"
10 #include "chrome/renderer/extensions/event_bindings.h" 11 #include "chrome/renderer/extensions/event_bindings.h"
11 #include "chrome/renderer/js_only_v8_extensions.h" 12 #include "chrome/renderer/js_only_v8_extensions.h"
12 #include "chrome/renderer/render_thread.h" 13 #include "chrome/renderer/render_thread.h"
13 #include "grit/renderer_resources.h" 14 #include "grit/renderer_resources.h"
14 15
15 namespace { 16 namespace {
16 17
18 // Keep a local cache of RenderThread so that we can mock it out for unit tests.
19 static RenderThreadBase* render_thread = NULL;
20
21 static RenderThreadBase* GetRenderThread() {
22 return render_thread ? render_thread : RenderThread::current();
23 }
24
17 // Keep a list of contexts that have registered themselves with us. This lets 25 // Keep a list of contexts that have registered themselves with us. This lets
18 // us know where to dispatch events when we receive them. 26 // us know where to dispatch events when we receive them.
19 typedef std::list< v8::Persistent<v8::Context> > ContextList; 27 typedef std::list< v8::Persistent<v8::Context> > ContextList;
20 struct ExtensionData { 28 struct ExtensionData {
21 ContextList contexts; 29 ContextList contexts;
30 std::map<std::string, int> listener_count;
22 }; 31 };
23 ContextList& GetRegisteredContexts() { 32 ContextList& GetRegisteredContexts() {
24 return Singleton<ExtensionData>::get()->contexts; 33 return Singleton<ExtensionData>::get()->contexts;
25 } 34 }
35 int EventIncrementListenerCount(const std::string& event_name) {
36 ExtensionData *data = Singleton<ExtensionData>::get();
37 return ++(data->listener_count[event_name]);
38 }
39 int EventDecrementListenerCount(const std::string& event_name) {
40 ExtensionData *data = Singleton<ExtensionData>::get();
41 return --(data->listener_count[event_name]);
42 }
43
26 44
27 const char* kExtensionDeps[] = { JsonJsV8Extension::kName }; 45 const char* kExtensionDeps[] = { JsonJsV8Extension::kName };
28 const char* kContextAttachCount = "chromium.attachCount"; 46 const char* kContextAttachCount = "chromium.attachCount";
29 47
30 class ExtensionImpl : public v8::Extension { 48 class ExtensionImpl : public v8::Extension {
31 public: 49 public:
32 ExtensionImpl() 50 ExtensionImpl()
33 : v8::Extension(EventBindings::kName, 51 : v8::Extension(EventBindings::kName,
34 GetStringResource<IDR_EVENT_BINDINGS_JS>(), 52 GetStringResource<IDR_EVENT_BINDINGS_JS>(),
35 arraysize(kExtensionDeps), kExtensionDeps) { 53 arraysize(kExtensionDeps), kExtensionDeps) {
36 } 54 }
37 ~ExtensionImpl() {} 55 ~ExtensionImpl() {}
38 56
39 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction( 57 virtual v8::Handle<v8::FunctionTemplate> GetNativeFunction(
40 v8::Handle<v8::String> name) { 58 v8::Handle<v8::String> name) {
41 if (name->Equals(v8::String::New("AttachEvent"))) { 59 if (name->Equals(v8::String::New("AttachEvent"))) {
42 return v8::FunctionTemplate::New(AttachEvent); 60 return v8::FunctionTemplate::New(AttachEvent);
43 } else if (name->Equals(v8::String::New("DetachEvent"))) { 61 } else if (name->Equals(v8::String::New("DetachEvent"))) {
44 return v8::FunctionTemplate::New(DetachEvent); 62 return v8::FunctionTemplate::New(DetachEvent);
45 } 63 }
46 return v8::Handle<v8::FunctionTemplate>(); 64 return v8::Handle<v8::FunctionTemplate>();
47 } 65 }
48 66
49 // Attach an event name to an object. 67 // Attach an event name to an object.
50 // TODO(mpcomplete): I'm just using this to register the v8 Context right now.
51 // The idea is to eventually notify the browser about what events are being
52 // listened to, so it can dispatch appropriately.
53 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { 68 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) {
69 DCHECK(args.Length() == 1);
70 // TODO(erikkay) should enforce that event name is a string in the bindings
71 DCHECK(args[0]->IsString() || args[0]->IsUndefined());
72
54 v8::Persistent<v8::Context> context = 73 v8::Persistent<v8::Context> context =
55 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent()); 74 v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
56 v8::Local<v8::Object> global = context->Global(); 75 v8::Local<v8::Object> global = context->Global();
57 76
58 // Remember how many times this context has been attached, so we can 77 // Remember how many times this context has been attached, so we can
59 // register the context on first attach and unregister on last detach. 78 // register the context on first attach and unregister on last detach.
60 v8::Local<v8::Value> attach_count = global->GetHiddenValue( 79 v8::Local<v8::Value> attach_count = global->GetHiddenValue(
61 v8::String::New(kContextAttachCount)); 80 v8::String::New(kContextAttachCount));
62 int32_t account_count_value = 81 int32_t account_count_value =
63 (!attach_count.IsEmpty() && attach_count->IsNumber()) ? 82 (!attach_count.IsEmpty() && attach_count->IsNumber()) ?
64 attach_count->Int32Value() : 0; 83 attach_count->Int32Value() : 0;
65 if (account_count_value == 0) { 84 if (account_count_value == 0) {
66 // First time attaching. 85 // First time attaching.
67 GetRegisteredContexts().push_back(context); 86 GetRegisteredContexts().push_back(context);
68 context.MakeWeak(NULL, WeakContextCallback); 87 context.MakeWeak(NULL, WeakContextCallback);
69 } 88 }
70 global->SetHiddenValue( 89 global->SetHiddenValue(
71 v8::String::New(kContextAttachCount), 90 v8::String::New(kContextAttachCount),
72 v8::Integer::New(account_count_value + 1)); 91 v8::Integer::New(account_count_value + 1));
73 92
93 if (args[0]->IsString()) {
94 std::string event_name(*v8::String::AsciiValue(args[0]));
95 if (EventIncrementListenerCount(event_name) == 1) {
96 GetRenderThread()->Send(
97 new ViewHostMsg_ExtensionAddListener(event_name));
98 }
99 }
100
74 return v8::Undefined(); 101 return v8::Undefined();
75 } 102 }
76 103
77 static v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) { 104 static v8::Handle<v8::Value> DetachEvent(const v8::Arguments& args) {
105 DCHECK(args.Length() == 1);
106 // TODO(erikkay) should enforce that event name is a string in the bindings
107 DCHECK(args[0]->IsString() || args[0]->IsUndefined());
108
78 v8::Local<v8::Context> context = v8::Context::GetCurrent(); 109 v8::Local<v8::Context> context = v8::Context::GetCurrent();
79 v8::Local<v8::Object> global = context->Global(); 110 v8::Local<v8::Object> global = context->Global();
80 v8::Local<v8::Value> attach_count = global->GetHiddenValue( 111 v8::Local<v8::Value> attach_count = global->GetHiddenValue(
81 v8::String::New(kContextAttachCount)); 112 v8::String::New(kContextAttachCount));
82 DCHECK(!attach_count.IsEmpty() && attach_count->IsNumber()); 113 DCHECK(!attach_count.IsEmpty() && attach_count->IsNumber());
83 int32_t account_count_value = attach_count->Int32Value(); 114 int32_t account_count_value = attach_count->Int32Value();
84 DCHECK(account_count_value > 0); 115 DCHECK(account_count_value > 0);
85 if (account_count_value == 1) { 116 if (account_count_value == 1) {
86 // Clean up after last detach. 117 // Clean up after last detach.
87 UnregisterContext(context); 118 UnregisterContext(context);
88 } 119 }
89 global->SetHiddenValue( 120 global->SetHiddenValue(
90 v8::String::New(kContextAttachCount), 121 v8::String::New(kContextAttachCount),
91 v8::Integer::New(account_count_value - 1)); 122 v8::Integer::New(account_count_value - 1));
92 123
124 if (args[0]->IsString()) {
125 std::string event_name(*v8::String::AsciiValue(args[0]));
126 if (EventDecrementListenerCount(event_name) == 0) {
127 GetRenderThread()->Send(
128 new ViewHostMsg_ExtensionRemoveListener(event_name));
129 }
130 }
131
93 return v8::Undefined(); 132 return v8::Undefined();
94 } 133 }
95 134
96 // Called when a registered context is garbage collected. 135 // Called when a registered context is garbage collected.
97 static void UnregisterContext(v8::Handle<void> context) { 136 static void UnregisterContext(v8::Handle<void> context) {
98 ContextList& contexts = GetRegisteredContexts(); 137 ContextList& contexts = GetRegisteredContexts();
99 ContextList::iterator it = std::find(contexts.begin(), contexts.end(), 138 ContextList::iterator it = std::find(contexts.begin(), contexts.end(),
100 context); 139 context);
101 if (it == contexts.end()) { 140 if (it == contexts.end()) {
102 NOTREACHED(); 141 NOTREACHED();
(...skipping 12 matching lines...) Expand all
115 }; 154 };
116 155
117 } // namespace 156 } // namespace
118 157
119 const char* EventBindings::kName = "chrome/EventBindings"; 158 const char* EventBindings::kName = "chrome/EventBindings";
120 159
121 v8::Extension* EventBindings::Get() { 160 v8::Extension* EventBindings::Get() {
122 return new ExtensionImpl(); 161 return new ExtensionImpl();
123 } 162 }
124 163
164 // static
165 void EventBindings::SetRenderThread(RenderThreadBase* thread) {
166 render_thread = thread;
167 }
168
125 void EventBindings::CallFunction(const std::string& function_name, 169 void EventBindings::CallFunction(const std::string& function_name,
126 int argc, v8::Handle<v8::Value>* argv) { 170 int argc, v8::Handle<v8::Value>* argv) {
127 for (ContextList::iterator it = GetRegisteredContexts().begin(); 171 for (ContextList::iterator it = GetRegisteredContexts().begin();
128 it != GetRegisteredContexts().end(); ++it) { 172 it != GetRegisteredContexts().end(); ++it) {
129 DCHECK(!it->IsEmpty()); 173 DCHECK(!it->IsEmpty());
130 v8::Context::Scope context_scope(*it); 174 v8::Context::Scope context_scope(*it);
131 v8::Local<v8::Object> global = (*it)->Global(); 175 v8::Local<v8::Object> global = (*it)->Global();
132 176
133 v8::Local<v8::Script> script = v8::Script::Compile( 177 v8::Local<v8::Script> script = v8::Script::Compile(
134 v8::String::New(function_name.c_str())); 178 v8::String::New(function_name.c_str()));
135 v8::Local<v8::Value> function_obj = script->Run(); 179 v8::Local<v8::Value> function_obj = script->Run();
136 if (!function_obj->IsFunction()) 180 if (!function_obj->IsFunction())
137 continue; 181 continue;
138 182
139 v8::Local<v8::Function> function = 183 v8::Local<v8::Function> function =
140 v8::Local<v8::Function>::Cast(function_obj); 184 v8::Local<v8::Function>::Cast(function_obj);
141 if (!function.IsEmpty()) 185 if (!function.IsEmpty())
142 function->Call(v8::Object::New(), argc, argv); 186 function->Call(v8::Object::New(), argc, argv);
143 } 187 }
144 } 188 }
OLDNEW
« no previous file with comments | « chrome/renderer/extensions/event_bindings.h ('k') | chrome/test/render_view_test.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698