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

Side by Side Diff: chrome_frame/np_event_listener.cc

Issue 218019: Initial import of the Chrome Frame codebase. Integration in chrome.gyp coming... (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 11 years, 3 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_frame/np_event_listener.h ('k') | chrome_frame/np_proxy_service.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
3 // found in the LICENSE file.
4
5 #include "chrome_frame/np_event_listener.h"
6
7 #include "base/string_util.h"
8
9 #include "third_party/xulrunner-sdk/win/include/string/nsEmbedString.h"
10 #include "third_party/xulrunner-sdk/win/include/dom/nsIDOMElement.h"
11 #include "third_party/xulrunner-sdk/win/include/dom/nsIDOMEventTarget.h"
12 #include "third_party/xulrunner-sdk/win/include/dom/nsIDOMEvent.h"
13
14 #include "chrome_frame/scoped_ns_ptr_win.h"
15 #include "chrome_frame/ns_associate_iid_win.h"
16
17 ASSOCIATE_IID(NS_IDOMELEMENT_IID_STR, nsIDOMElement);
18 ASSOCIATE_IID(NS_IDOMNODE_IID_STR, nsIDOMNode);
19 ASSOCIATE_IID(NS_IDOMEVENTTARGET_IID_STR, nsIDOMEventTarget);
20 ASSOCIATE_IID(NS_IDOMEVENTLISTENER_IID_STR, nsIDOMEventListener);
21
22 DomEventListener::DomEventListener(NpEventDelegate* delegate)
23 : NpEventListenerBase<DomEventListener>(delegate) {
24 }
25
26 DomEventListener::~DomEventListener() {
27 }
28
29 // We implement QueryInterface etc ourselves in order to avoid
30 // extra dependencies brought on by the NS_IMPL_* macros.
31 NS_IMETHODIMP DomEventListener::QueryInterface(REFNSIID iid, void** ptr) {
32 DCHECK(thread_id_ == ::GetCurrentThreadId());
33 nsresult res = NS_NOINTERFACE;
34
35 if (memcmp(&iid, &__uuidof(nsIDOMEventListener), sizeof(nsIID)) == 0 ||
36 memcmp(&iid, &__uuidof(nsISupports), sizeof(nsIID)) == 0) {
37 *ptr = static_cast<nsIDOMEventListener*>(this);
38 AddRef();
39 res = NS_OK;
40 }
41
42 return res;
43 }
44
45 NS_IMETHODIMP DomEventListener::HandleEvent(nsIDOMEvent *event) {
46 DCHECK(thread_id_ == ::GetCurrentThreadId());
47 DCHECK(event);
48
49 nsEmbedString tag;
50 event->GetType(tag);
51 delegate_->OnEvent(WideToUTF8(tag.get()).c_str());
52
53 return NS_OK;
54 }
55
56 bool DomEventListener::Subscribe(NPP instance,
57 const char* event_names[],
58 int event_name_count) {
59 DCHECK(event_names);
60 DCHECK(event_name_count > 0);
61
62 ScopedNsPtr<nsIDOMElement> element;
63 bool ret = GetObjectElement(instance, element.Receive());
64 if (ret) {
65 ScopedNsPtr<nsIDOMEventTarget> target;
66 target.QueryFrom(element);
67 if (target) {
68 for (int i = 0; i < event_name_count && ret; ++i) {
69 nsEmbedString name(ASCIIToWide(event_names[i]).c_str());
70 // See NPObjectEventListener::Subscribe (below) for a note on why
71 // we set the useCapture parameter to PR_FALSE.
72 nsresult res = target->AddEventListener(name, this, PR_FALSE);
73 DCHECK(res == NS_OK) << "AddEventListener: " << event_names[i];
74 ret = NS_SUCCEEDED(res);
75 }
76 } else {
77 DLOG(ERROR) << "failed to get nsIDOMEventTarget";
78 ret = false;
79 }
80 }
81
82 return ret;
83 }
84
85 bool DomEventListener::Unsubscribe(NPP instance,
86 const char* event_names[],
87 int event_name_count) {
88 DCHECK(event_names);
89 DCHECK(event_name_count > 0);
90
91 ScopedNsPtr<nsIDOMElement> element;
92 bool ret = GetObjectElement(instance, element.Receive());
93 if (ret) {
94 ScopedNsPtr<nsIDOMEventTarget> target;
95 target.QueryFrom(element);
96 if (target) {
97 for (int i = 0; i < event_name_count && ret; ++i) {
98 nsEmbedString name(ASCIIToWide(event_names[i]).c_str());
99 nsresult res = target->RemoveEventListener(name, this, PR_FALSE);
100 DCHECK(res == NS_OK) << "RemoveEventListener: " << event_names[i];
101 ret = NS_SUCCEEDED(res) && ret;
102 }
103 } else {
104 DLOG(ERROR) << "failed to get nsIDOMEventTarget";
105 ret = false;
106 }
107 }
108
109 return ret;
110 }
111
112 bool DomEventListener::GetObjectElement(NPP instance, nsIDOMElement** element) {
113 DCHECK(element);
114
115 ScopedNsPtr<nsIDOMElement> elem;
116 // Fetching the dom element works in Firefox, but is not implemented
117 // in webkit.
118 npapi::GetValue(instance, NPNVDOMElement, elem.Receive());
119 if (!elem.get()) {
120 DLOG(INFO) << "Failed to get NPNVDOMElement";
121 return false;
122 }
123
124 nsEmbedString tag;
125 nsresult res = elem->GetTagName(tag);
126 if (NS_SUCCEEDED(res)) {
127 if (LowerCaseEqualsASCII(tag.get(), tag.get() + tag.Length(), "embed")) {
128 ScopedNsPtr<nsIDOMNode> parent;
129 elem->GetParentNode(parent.Receive());
130 if (parent) {
131 elem.Release();
132 res = parent.QueryInterface(elem.Receive());
133 DCHECK(NS_SUCCEEDED(res));
134 }
135 }
136 } else {
137 NOTREACHED() << " GetTagName";
138 }
139
140 *element = elem.Detach();
141
142 return *element != NULL;
143 }
144
145 ///////////////////////////////////
146 // NPObjectEventListener
147
148 NPObjectEventListener::NPObjectEventListener(NpEventDelegate* delegate)
149 : NpEventListenerBase<NPObjectEventListener>(delegate) {
150 }
151
152 NPObjectEventListener::~NPObjectEventListener() {
153 DLOG_IF(ERROR, npo_.get() == NULL);
154 }
155
156 NPObject* NPObjectEventListener::GetObjectElement(NPP instance) {
157 NPObject* object = NULL;
158 // We can't trust the return value from getvalue.
159 // In Opera, the return value can be false even though the correct
160 // object is returned.
161 npapi::GetValue(instance, NPNVPluginElementNPObject, &object);
162
163 if (object) {
164 NPIdentifier* ids = GetCachedStringIds();
165 NPVariant var;
166 if (npapi::GetProperty(instance, object, ids[TAG_NAME], &var)) {
167 DCHECK(NPVARIANT_IS_STRING(var));
168 const NPString& np_tag = NPVARIANT_TO_STRING(var);
169 std::string tag(np_tag.UTF8Characters, np_tag.UTF8Length);
170 npapi::ReleaseVariantValue(&var);
171
172 if (lstrcmpiA(tag.c_str(), "embed") == 0) {
173 // We've got the <embed> element but we really want
174 // the <object> element.
175 if (npapi::GetProperty(instance, object, ids[PARENT_ELEMENT], &var)) {
176 DCHECK(NPVARIANT_IS_OBJECT(var));
177 npapi::ReleaseObject(object);
178 object = NPVARIANT_TO_OBJECT(var);
179 }
180 } else {
181 DLOG(INFO) << __FUNCTION__ << " got " << tag;
182 }
183 } else {
184 DLOG(INFO) << __FUNCTION__ << " failed to get the element's tag";
185 }
186 } else {
187 DLOG(WARNING) << __FUNCTION__ << " failed to get NPNVPluginElementNPObject";
188 }
189
190 return object;
191 }
192
193 // Implementation of NpEventListener
194 bool NPObjectEventListener::Subscribe(NPP instance,
195 const char* event_names[],
196 int event_name_count) {
197 DCHECK(event_names);
198 DCHECK(event_name_count > 0);
199 DCHECK(npo_.get() == NULL);
200
201 ScopedNpObject<> plugin_element(GetObjectElement(instance));
202 if (!plugin_element.get())
203 return false;
204
205 // This object seems to be getting leaked :-(
206 bool ret = false;
207 npo_.Attach(reinterpret_cast<Npo*>(
208 npapi::CreateObject(instance, PluginClass())));
209
210 if (!npo_.get()) {
211 NOTREACHED() << "createobject";
212 } else {
213 npo_->Initialize(this);
214 ret = true;
215
216 NPIdentifier* ids = GetCachedStringIds();
217
218 NPVariant args[3];
219 OBJECT_TO_NPVARIANT(npo_, args[1]);
220 // We don't want to set 'capture' (last parameter) to true.
221 // If we do, then in Opera, we'll simply not get callbacks unless
222 // the target <object> or <embed> element we're syncing with has its
223 // on[event] property assigned to some function handler. weird.
224 // Ideally though we'd like to set capture to true since we'd like to
225 // only be triggered for this particular object (and not for bubbling
226 // events, but alas it's not meant to be.
227 BOOLEAN_TO_NPVARIANT(false, args[2]);
228 for (int i = 0; i < event_name_count; ++i) {
229 ScopedNpVariant result;
230 STRINGZ_TO_NPVARIANT(event_names[i], args[0]);
231 ret = npapi::Invoke(instance, plugin_element, ids[ADD_EVENT_LISTENER],
232 args, arraysize(args), &result) && ret;
233 if (!ret) {
234 DLOG(WARNING) << __FUNCTION__ << " invoke failed for "
235 << event_names[i];
236 break;
237 }
238 }
239 }
240
241 return ret;
242 }
243
244 bool NPObjectEventListener::Unsubscribe(NPP instance,
245 const char* event_names[],
246 int event_name_count) {
247 DCHECK(event_names);
248 DCHECK(event_name_count > 0);
249 DCHECK(npo_.get() != NULL);
250
251 ScopedNpObject<> plugin_element(GetObjectElement(instance));
252 if (!plugin_element.get())
253 return false;
254
255 NPIdentifier* ids = GetCachedStringIds();
256
257 NPVariant args[3];
258 OBJECT_TO_NPVARIANT(npo_, args[1]);
259 BOOLEAN_TO_NPVARIANT(false, args[2]);
260 for (int i = 0; i < event_name_count; ++i) {
261 // TODO(tommi): look into why chrome isn't releasing the reference
262 // count here. As it stands the reference count doesn't go down
263 // and as a result, the NPO gets leaked.
264 ScopedNpVariant result;
265 STRINGZ_TO_NPVARIANT(event_names[i], args[0]);
266 bool ret = npapi::Invoke(instance, plugin_element,
267 ids[REMOVE_EVENT_LISTENER], args, arraysize(args), &result);
268 DLOG_IF(ERROR, !ret) << __FUNCTION__ << " invoke: " << ret;
269 }
270
271 npo_.Free();
272
273 return true;
274 }
275
276 void NPObjectEventListener::HandleEvent(Npo* npo, NPObject* event) {
277 DCHECK(npo);
278 DCHECK(event);
279
280 NPIdentifier* ids = GetCachedStringIds();
281 ScopedNpVariant result;
282 bool ret = npapi::GetProperty(npo->npp(), event, ids[TYPE], &result);
283 DCHECK(ret) << "getproperty(type)";
284 if (ret) {
285 DCHECK(NPVARIANT_IS_STRING(result));
286 // Opera doesn't zero terminate its utf8 strings.
287 const NPString& type = NPVARIANT_TO_STRING(result);
288 std::string zero_terminated(type.UTF8Characters, type.UTF8Length);
289 DLOG(INFO) << "handleEvent: " << zero_terminated;
290 delegate_->OnEvent(zero_terminated.c_str());
291 }
292 }
293
294 NPClass* NPObjectEventListener::PluginClass() {
295 static NPClass _np_class = {
296 NP_CLASS_STRUCT_VERSION,
297 reinterpret_cast<NPAllocateFunctionPtr>(AllocateObject),
298 reinterpret_cast<NPDeallocateFunctionPtr>(DeallocateObject),
299 NULL, // invalidate
300 reinterpret_cast<NPHasMethodFunctionPtr>(HasMethod),
301 reinterpret_cast<NPInvokeFunctionPtr>(Invoke),
302 NULL, // InvokeDefault,
303 NULL, // HasProperty,
304 NULL, // GetProperty,
305 NULL, // SetProperty,
306 NULL // construct
307 };
308
309 return &_np_class;
310 }
311
312 bool NPObjectEventListener::HasMethod(NPObjectEventListener::Npo* npo,
313 NPIdentifier name) {
314 NPIdentifier* ids = GetCachedStringIds();
315 if (name == ids[HANDLE_EVENT])
316 return true;
317
318 return false;
319 }
320
321 bool NPObjectEventListener::Invoke(NPObjectEventListener::Npo* npo,
322 NPIdentifier name, const NPVariant* args,
323 uint32_t arg_count, NPVariant* result) {
324 NPIdentifier* ids = GetCachedStringIds();
325 if (name != ids[HANDLE_EVENT])
326 return false;
327
328 if (arg_count != 1 || !NPVARIANT_IS_OBJECT(args[0])) {
329 NOTREACHED();
330 } else {
331 NPObject* ev = NPVARIANT_TO_OBJECT(args[0]);
332 npo->listener()->HandleEvent(npo, ev);
333 }
334
335 return true;
336 }
337
338 NPObject* NPObjectEventListener::AllocateObject(NPP instance,
339 NPClass* class_name) {
340 return new Npo(instance);
341 }
342
343 void NPObjectEventListener::DeallocateObject(NPObjectEventListener::Npo* npo) {
344 delete npo;
345 }
346
347 NPIdentifier* NPObjectEventListener::GetCachedStringIds() {
348 static NPIdentifier _identifiers[IDENTIFIER_COUNT] = {0};
349 if (!_identifiers[0]) {
350 const NPUTF8* identifier_names[] = {
351 "handleEvent",
352 "type",
353 "addEventListener",
354 "removeEventListener",
355 "tagName",
356 "parentElement",
357 };
358 COMPILE_ASSERT(arraysize(identifier_names) == arraysize(_identifiers),
359 mismatched_array_size);
360 npapi::GetStringIdentifiers(identifier_names, IDENTIFIER_COUNT,
361 _identifiers);
362 for (int i = 0; i < IDENTIFIER_COUNT; ++i) {
363 DCHECK(_identifiers[i] != 0);
364 }
365 }
366 return _identifiers;
367 }
OLDNEW
« no previous file with comments | « chrome_frame/np_event_listener.h ('k') | chrome_frame/np_proxy_service.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698