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 // TODO(koz): Merge this into EventBindings. | |
42 class ExtensionImpl : public ChromeV8Extension { | 43 class ExtensionImpl : public ChromeV8Extension { |
43 public: | 44 public: |
44 explicit ExtensionImpl(ExtensionDispatcher* dispatcher) | 45 // A map of event names to the number of contexts listening to that event. |
45 : ChromeV8Extension("extensions/event.js", | 46 // We notify the browser about event listeners when we transition between 0 |
46 IDR_EVENT_BINDINGS_JS, | 47 // and 1. |
47 dispatcher) { | 48 typedef std::map<std::string, int> EventListenerCounts; |
49 | |
50 ExtensionImpl(ExtensionDispatcher* dispatcher, | |
51 std::map<std::string, EventListenerCounts>* listener_counts) | |
52 : ChromeV8Extension(dispatcher), | |
53 listener_counts_(listener_counts) { | |
54 RouteStaticFunction("AttachEvent", &AttachEvent); | |
55 RouteStaticFunction("DetachEvent", &DetachEvent); | |
Matt Perry
2012/02/28 20:34:20
Both of these access the ExtensionImpl via GetFrom
koz (OOO until 15th September)
2012/03/01 03:41:56
Yes, that's right. I was planning on making those
| |
48 } | 56 } |
49 ~ExtensionImpl() {} | 57 ~ExtensionImpl() {} |
50 | 58 |
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. | 59 // Attach an event name to an object. |
62 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { | 60 static v8::Handle<v8::Value> AttachEvent(const v8::Arguments& args) { |
63 DCHECK(args.Length() == 1); | 61 DCHECK(args.Length() == 1); |
64 // TODO(erikkay) should enforce that event name is a string in the bindings | 62 // TODO(erikkay) should enforce that event name is a string in the bindings |
65 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); | 63 DCHECK(args[0]->IsString() || args[0]->IsUndefined()); |
66 | 64 |
67 if (args[0]->IsString()) { | 65 if (args[0]->IsString()) { |
68 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 66 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
69 const ChromeV8ContextSet& context_set = | 67 const ChromeV8ContextSet& context_set = |
70 self->extension_dispatcher()->v8_context_set(); | 68 self->extension_dispatcher()->v8_context_set(); |
71 ChromeV8Context* context = context_set.GetCurrent(); | 69 ChromeV8Context* context = context_set.GetCurrent(); |
72 CHECK(context); | 70 CHECK(context); |
73 std::string event_name(*v8::String::AsciiValue(args[0])); | 71 std::string event_name(*v8::String::AsciiValue(args[0])); |
74 | 72 |
75 if (!self->CheckCurrentContextAccessToExtensionAPI(event_name)) | 73 if (!self->CheckCurrentContextAccessToExtensionAPI(event_name)) |
76 return v8::Undefined(); | 74 return v8::Undefined(); |
77 | 75 |
78 EventListenerCounts& listener_counts = | 76 EventListenerCounts& listener_counts = |
79 self->listener_counts_[context->extension_id()]; | 77 (*(self->listener_counts_))[context->extension_id()]; |
80 if (++listener_counts[event_name] == 1) { | 78 if (++listener_counts[event_name] == 1) { |
81 content::RenderThread::Get()->Send( | 79 content::RenderThread::Get()->Send( |
82 new ExtensionHostMsg_AddListener(context->extension_id(), | 80 new ExtensionHostMsg_AddListener(context->extension_id(), |
83 event_name)); | 81 event_name)); |
84 } | 82 } |
85 | 83 |
86 // This is called the first time the page has added a listener. Since | 84 // 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 | 85 // the background page is the only lazy page, we know this is the first |
88 // time this listener has been registered. | 86 // time this listener has been registered. |
89 if (self->IsLazyBackgroundPage(context->extension_id())) { | 87 if (self->IsLazyBackgroundPage(context->extension_id())) { |
(...skipping 13 matching lines...) Expand all Loading... | |
103 | 101 |
104 if (args[0]->IsString() && args[1]->IsBoolean()) { | 102 if (args[0]->IsString() && args[1]->IsBoolean()) { |
105 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); | 103 ExtensionImpl* self = GetFromArguments<ExtensionImpl>(args); |
106 const ChromeV8ContextSet& context_set = | 104 const ChromeV8ContextSet& context_set = |
107 self->extension_dispatcher()->v8_context_set(); | 105 self->extension_dispatcher()->v8_context_set(); |
108 ChromeV8Context* context = context_set.GetCurrent(); | 106 ChromeV8Context* context = context_set.GetCurrent(); |
109 if (!context) | 107 if (!context) |
110 return v8::Undefined(); | 108 return v8::Undefined(); |
111 | 109 |
112 EventListenerCounts& listener_counts = | 110 EventListenerCounts& listener_counts = |
113 self->listener_counts_[context->extension_id()]; | 111 (*(self->listener_counts_))[context->extension_id()]; |
114 std::string event_name(*v8::String::AsciiValue(args[0])); | 112 std::string event_name(*v8::String::AsciiValue(args[0])); |
115 bool is_manual = args[1]->BooleanValue(); | 113 bool is_manual = args[1]->BooleanValue(); |
116 | 114 |
117 if (--listener_counts[event_name] == 0) { | 115 if (--listener_counts[event_name] == 0) { |
118 content::RenderThread::Get()->Send( | 116 content::RenderThread::Get()->Send( |
119 new ExtensionHostMsg_RemoveListener(context->extension_id(), | 117 new ExtensionHostMsg_RemoveListener(context->extension_id(), |
120 event_name)); | 118 event_name)); |
121 } | 119 } |
122 | 120 |
123 // DetachEvent is called when the last listener for the context is | 121 // DetachEvent is called when the last listener for the context is |
124 // removed. If the context is the background page, and it removes the | 122 // 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 | 123 // last listener manually, then we assume that it is no longer interested |
126 // in being awakened for this event. | 124 // in being awakened for this event. |
127 if (is_manual && self->IsLazyBackgroundPage(context->extension_id())) { | 125 if (is_manual && self->IsLazyBackgroundPage(context->extension_id())) { |
128 content::RenderThread::Get()->Send( | 126 content::RenderThread::Get()->Send( |
129 new ExtensionHostMsg_RemoveLazyListener(context->extension_id(), | 127 new ExtensionHostMsg_RemoveLazyListener(context->extension_id(), |
130 event_name)); | 128 event_name)); |
131 } | 129 } |
132 } | 130 } |
133 | 131 |
134 return v8::Undefined(); | 132 return v8::Undefined(); |
135 } | 133 } |
136 | 134 |
137 private: | 135 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 | 136 |
143 bool IsLazyBackgroundPage(const std::string& extension_id) { | 137 bool IsLazyBackgroundPage(const std::string& extension_id) { |
144 content::RenderView* render_view = GetCurrentRenderView(); | 138 content::RenderView* render_view = GetCurrentRenderView(); |
145 if (!render_view) | 139 if (!render_view) |
146 return false; | 140 return false; |
147 | 141 |
148 ExtensionHelper* helper = ExtensionHelper::Get(render_view); | 142 ExtensionHelper* helper = ExtensionHelper::Get(render_view); |
149 const ::Extension* extension = | 143 const ::Extension* extension = |
150 extension_dispatcher()->extensions()->GetByID(extension_id); | 144 extension_dispatcher()->extensions()->GetByID(extension_id); |
151 return (extension && !extension->background_page_persists() && | 145 return (extension && !extension->background_page_persists() && |
152 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); | 146 helper->view_type() == chrome::VIEW_TYPE_EXTENSION_BACKGROUND_PAGE); |
153 } | 147 } |
154 | 148 |
155 // A map of extension IDs to listener counts for that extension. | 149 std::map<std::string, ExtensionImpl::EventListenerCounts>* listener_counts_; |
156 std::map<std::string, EventListenerCounts> listener_counts_; | |
157 }; | 150 }; |
158 | 151 |
159 } // namespace | 152 } // namespace |
160 | 153 |
161 v8::Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { | 154 ChromeV8Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) { |
162 static v8::Extension* extension = new ExtensionImpl(dispatcher); | 155 // A map of extension IDs to listener counts for that extension. |
163 return extension; | 156 static std::map<std::string, ExtensionImpl::EventListenerCounts>* |
157 listener_counts = NULL; | |
158 if (!listener_counts) { | |
159 listener_counts = | |
160 new std::map<std::string, ExtensionImpl::EventListenerCounts>(); | |
161 } | |
162 return new ExtensionImpl(dispatcher, listener_counts); | |
Matt Perry
2012/02/28 20:34:20
I don't understand this set of changes. Why change
koz (OOO until 15th September)
2012/03/01 03:41:56
With this change ChromeV8Extensions are no longer
| |
164 } | 163 } |
OLD | NEW |