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

Unified 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome_frame/np_event_listener.h ('k') | chrome_frame/np_proxy_service.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome_frame/np_event_listener.cc
===================================================================
--- chrome_frame/np_event_listener.cc (revision 0)
+++ chrome_frame/np_event_listener.cc (revision 0)
@@ -0,0 +1,367 @@
+// Copyright (c) 2009 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome_frame/np_event_listener.h"
+
+#include "base/string_util.h"
+
+#include "third_party/xulrunner-sdk/win/include/string/nsEmbedString.h"
+#include "third_party/xulrunner-sdk/win/include/dom/nsIDOMElement.h"
+#include "third_party/xulrunner-sdk/win/include/dom/nsIDOMEventTarget.h"
+#include "third_party/xulrunner-sdk/win/include/dom/nsIDOMEvent.h"
+
+#include "chrome_frame/scoped_ns_ptr_win.h"
+#include "chrome_frame/ns_associate_iid_win.h"
+
+ASSOCIATE_IID(NS_IDOMELEMENT_IID_STR, nsIDOMElement);
+ASSOCIATE_IID(NS_IDOMNODE_IID_STR, nsIDOMNode);
+ASSOCIATE_IID(NS_IDOMEVENTTARGET_IID_STR, nsIDOMEventTarget);
+ASSOCIATE_IID(NS_IDOMEVENTLISTENER_IID_STR, nsIDOMEventListener);
+
+DomEventListener::DomEventListener(NpEventDelegate* delegate)
+ : NpEventListenerBase<DomEventListener>(delegate) {
+}
+
+DomEventListener::~DomEventListener() {
+}
+
+// We implement QueryInterface etc ourselves in order to avoid
+// extra dependencies brought on by the NS_IMPL_* macros.
+NS_IMETHODIMP DomEventListener::QueryInterface(REFNSIID iid, void** ptr) {
+ DCHECK(thread_id_ == ::GetCurrentThreadId());
+ nsresult res = NS_NOINTERFACE;
+
+ if (memcmp(&iid, &__uuidof(nsIDOMEventListener), sizeof(nsIID)) == 0 ||
+ memcmp(&iid, &__uuidof(nsISupports), sizeof(nsIID)) == 0) {
+ *ptr = static_cast<nsIDOMEventListener*>(this);
+ AddRef();
+ res = NS_OK;
+ }
+
+ return res;
+}
+
+NS_IMETHODIMP DomEventListener::HandleEvent(nsIDOMEvent *event) {
+ DCHECK(thread_id_ == ::GetCurrentThreadId());
+ DCHECK(event);
+
+ nsEmbedString tag;
+ event->GetType(tag);
+ delegate_->OnEvent(WideToUTF8(tag.get()).c_str());
+
+ return NS_OK;
+}
+
+bool DomEventListener::Subscribe(NPP instance,
+ const char* event_names[],
+ int event_name_count) {
+ DCHECK(event_names);
+ DCHECK(event_name_count > 0);
+
+ ScopedNsPtr<nsIDOMElement> element;
+ bool ret = GetObjectElement(instance, element.Receive());
+ if (ret) {
+ ScopedNsPtr<nsIDOMEventTarget> target;
+ target.QueryFrom(element);
+ if (target) {
+ for (int i = 0; i < event_name_count && ret; ++i) {
+ nsEmbedString name(ASCIIToWide(event_names[i]).c_str());
+ // See NPObjectEventListener::Subscribe (below) for a note on why
+ // we set the useCapture parameter to PR_FALSE.
+ nsresult res = target->AddEventListener(name, this, PR_FALSE);
+ DCHECK(res == NS_OK) << "AddEventListener: " << event_names[i];
+ ret = NS_SUCCEEDED(res);
+ }
+ } else {
+ DLOG(ERROR) << "failed to get nsIDOMEventTarget";
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+bool DomEventListener::Unsubscribe(NPP instance,
+ const char* event_names[],
+ int event_name_count) {
+ DCHECK(event_names);
+ DCHECK(event_name_count > 0);
+
+ ScopedNsPtr<nsIDOMElement> element;
+ bool ret = GetObjectElement(instance, element.Receive());
+ if (ret) {
+ ScopedNsPtr<nsIDOMEventTarget> target;
+ target.QueryFrom(element);
+ if (target) {
+ for (int i = 0; i < event_name_count && ret; ++i) {
+ nsEmbedString name(ASCIIToWide(event_names[i]).c_str());
+ nsresult res = target->RemoveEventListener(name, this, PR_FALSE);
+ DCHECK(res == NS_OK) << "RemoveEventListener: " << event_names[i];
+ ret = NS_SUCCEEDED(res) && ret;
+ }
+ } else {
+ DLOG(ERROR) << "failed to get nsIDOMEventTarget";
+ ret = false;
+ }
+ }
+
+ return ret;
+}
+
+bool DomEventListener::GetObjectElement(NPP instance, nsIDOMElement** element) {
+ DCHECK(element);
+
+ ScopedNsPtr<nsIDOMElement> elem;
+ // Fetching the dom element works in Firefox, but is not implemented
+ // in webkit.
+ npapi::GetValue(instance, NPNVDOMElement, elem.Receive());
+ if (!elem.get()) {
+ DLOG(INFO) << "Failed to get NPNVDOMElement";
+ return false;
+ }
+
+ nsEmbedString tag;
+ nsresult res = elem->GetTagName(tag);
+ if (NS_SUCCEEDED(res)) {
+ if (LowerCaseEqualsASCII(tag.get(), tag.get() + tag.Length(), "embed")) {
+ ScopedNsPtr<nsIDOMNode> parent;
+ elem->GetParentNode(parent.Receive());
+ if (parent) {
+ elem.Release();
+ res = parent.QueryInterface(elem.Receive());
+ DCHECK(NS_SUCCEEDED(res));
+ }
+ }
+ } else {
+ NOTREACHED() << " GetTagName";
+ }
+
+ *element = elem.Detach();
+
+ return *element != NULL;
+}
+
+///////////////////////////////////
+// NPObjectEventListener
+
+NPObjectEventListener::NPObjectEventListener(NpEventDelegate* delegate)
+ : NpEventListenerBase<NPObjectEventListener>(delegate) {
+}
+
+NPObjectEventListener::~NPObjectEventListener() {
+ DLOG_IF(ERROR, npo_.get() == NULL);
+}
+
+NPObject* NPObjectEventListener::GetObjectElement(NPP instance) {
+ NPObject* object = NULL;
+ // We can't trust the return value from getvalue.
+ // In Opera, the return value can be false even though the correct
+ // object is returned.
+ npapi::GetValue(instance, NPNVPluginElementNPObject, &object);
+
+ if (object) {
+ NPIdentifier* ids = GetCachedStringIds();
+ NPVariant var;
+ if (npapi::GetProperty(instance, object, ids[TAG_NAME], &var)) {
+ DCHECK(NPVARIANT_IS_STRING(var));
+ const NPString& np_tag = NPVARIANT_TO_STRING(var);
+ std::string tag(np_tag.UTF8Characters, np_tag.UTF8Length);
+ npapi::ReleaseVariantValue(&var);
+
+ if (lstrcmpiA(tag.c_str(), "embed") == 0) {
+ // We've got the <embed> element but we really want
+ // the <object> element.
+ if (npapi::GetProperty(instance, object, ids[PARENT_ELEMENT], &var)) {
+ DCHECK(NPVARIANT_IS_OBJECT(var));
+ npapi::ReleaseObject(object);
+ object = NPVARIANT_TO_OBJECT(var);
+ }
+ } else {
+ DLOG(INFO) << __FUNCTION__ << " got " << tag;
+ }
+ } else {
+ DLOG(INFO) << __FUNCTION__ << " failed to get the element's tag";
+ }
+ } else {
+ DLOG(WARNING) << __FUNCTION__ << " failed to get NPNVPluginElementNPObject";
+ }
+
+ return object;
+}
+
+// Implementation of NpEventListener
+bool NPObjectEventListener::Subscribe(NPP instance,
+ const char* event_names[],
+ int event_name_count) {
+ DCHECK(event_names);
+ DCHECK(event_name_count > 0);
+ DCHECK(npo_.get() == NULL);
+
+ ScopedNpObject<> plugin_element(GetObjectElement(instance));
+ if (!plugin_element.get())
+ return false;
+
+ // This object seems to be getting leaked :-(
+ bool ret = false;
+ npo_.Attach(reinterpret_cast<Npo*>(
+ npapi::CreateObject(instance, PluginClass())));
+
+ if (!npo_.get()) {
+ NOTREACHED() << "createobject";
+ } else {
+ npo_->Initialize(this);
+ ret = true;
+
+ NPIdentifier* ids = GetCachedStringIds();
+
+ NPVariant args[3];
+ OBJECT_TO_NPVARIANT(npo_, args[1]);
+ // We don't want to set 'capture' (last parameter) to true.
+ // If we do, then in Opera, we'll simply not get callbacks unless
+ // the target <object> or <embed> element we're syncing with has its
+ // on[event] property assigned to some function handler. weird.
+ // Ideally though we'd like to set capture to true since we'd like to
+ // only be triggered for this particular object (and not for bubbling
+ // events, but alas it's not meant to be.
+ BOOLEAN_TO_NPVARIANT(false, args[2]);
+ for (int i = 0; i < event_name_count; ++i) {
+ ScopedNpVariant result;
+ STRINGZ_TO_NPVARIANT(event_names[i], args[0]);
+ ret = npapi::Invoke(instance, plugin_element, ids[ADD_EVENT_LISTENER],
+ args, arraysize(args), &result) && ret;
+ if (!ret) {
+ DLOG(WARNING) << __FUNCTION__ << " invoke failed for "
+ << event_names[i];
+ break;
+ }
+ }
+ }
+
+ return ret;
+}
+
+bool NPObjectEventListener::Unsubscribe(NPP instance,
+ const char* event_names[],
+ int event_name_count) {
+ DCHECK(event_names);
+ DCHECK(event_name_count > 0);
+ DCHECK(npo_.get() != NULL);
+
+ ScopedNpObject<> plugin_element(GetObjectElement(instance));
+ if (!plugin_element.get())
+ return false;
+
+ NPIdentifier* ids = GetCachedStringIds();
+
+ NPVariant args[3];
+ OBJECT_TO_NPVARIANT(npo_, args[1]);
+ BOOLEAN_TO_NPVARIANT(false, args[2]);
+ for (int i = 0; i < event_name_count; ++i) {
+ // TODO(tommi): look into why chrome isn't releasing the reference
+ // count here. As it stands the reference count doesn't go down
+ // and as a result, the NPO gets leaked.
+ ScopedNpVariant result;
+ STRINGZ_TO_NPVARIANT(event_names[i], args[0]);
+ bool ret = npapi::Invoke(instance, plugin_element,
+ ids[REMOVE_EVENT_LISTENER], args, arraysize(args), &result);
+ DLOG_IF(ERROR, !ret) << __FUNCTION__ << " invoke: " << ret;
+ }
+
+ npo_.Free();
+
+ return true;
+}
+
+void NPObjectEventListener::HandleEvent(Npo* npo, NPObject* event) {
+ DCHECK(npo);
+ DCHECK(event);
+
+ NPIdentifier* ids = GetCachedStringIds();
+ ScopedNpVariant result;
+ bool ret = npapi::GetProperty(npo->npp(), event, ids[TYPE], &result);
+ DCHECK(ret) << "getproperty(type)";
+ if (ret) {
+ DCHECK(NPVARIANT_IS_STRING(result));
+ // Opera doesn't zero terminate its utf8 strings.
+ const NPString& type = NPVARIANT_TO_STRING(result);
+ std::string zero_terminated(type.UTF8Characters, type.UTF8Length);
+ DLOG(INFO) << "handleEvent: " << zero_terminated;
+ delegate_->OnEvent(zero_terminated.c_str());
+ }
+}
+
+NPClass* NPObjectEventListener::PluginClass() {
+ static NPClass _np_class = {
+ NP_CLASS_STRUCT_VERSION,
+ reinterpret_cast<NPAllocateFunctionPtr>(AllocateObject),
+ reinterpret_cast<NPDeallocateFunctionPtr>(DeallocateObject),
+ NULL, // invalidate
+ reinterpret_cast<NPHasMethodFunctionPtr>(HasMethod),
+ reinterpret_cast<NPInvokeFunctionPtr>(Invoke),
+ NULL, // InvokeDefault,
+ NULL, // HasProperty,
+ NULL, // GetProperty,
+ NULL, // SetProperty,
+ NULL // construct
+ };
+
+ return &_np_class;
+}
+
+bool NPObjectEventListener::HasMethod(NPObjectEventListener::Npo* npo,
+ NPIdentifier name) {
+ NPIdentifier* ids = GetCachedStringIds();
+ if (name == ids[HANDLE_EVENT])
+ return true;
+
+ return false;
+}
+
+bool NPObjectEventListener::Invoke(NPObjectEventListener::Npo* npo,
+ NPIdentifier name, const NPVariant* args,
+ uint32_t arg_count, NPVariant* result) {
+ NPIdentifier* ids = GetCachedStringIds();
+ if (name != ids[HANDLE_EVENT])
+ return false;
+
+ if (arg_count != 1 || !NPVARIANT_IS_OBJECT(args[0])) {
+ NOTREACHED();
+ } else {
+ NPObject* ev = NPVARIANT_TO_OBJECT(args[0]);
+ npo->listener()->HandleEvent(npo, ev);
+ }
+
+ return true;
+}
+
+NPObject* NPObjectEventListener::AllocateObject(NPP instance,
+ NPClass* class_name) {
+ return new Npo(instance);
+}
+
+void NPObjectEventListener::DeallocateObject(NPObjectEventListener::Npo* npo) {
+ delete npo;
+}
+
+NPIdentifier* NPObjectEventListener::GetCachedStringIds() {
+ static NPIdentifier _identifiers[IDENTIFIER_COUNT] = {0};
+ if (!_identifiers[0]) {
+ const NPUTF8* identifier_names[] = {
+ "handleEvent",
+ "type",
+ "addEventListener",
+ "removeEventListener",
+ "tagName",
+ "parentElement",
+ };
+ COMPILE_ASSERT(arraysize(identifier_names) == arraysize(_identifiers),
+ mismatched_array_size);
+ npapi::GetStringIdentifiers(identifier_names, IDENTIFIER_COUNT,
+ _identifiers);
+ for (int i = 0; i < IDENTIFIER_COUNT; ++i) {
+ DCHECK(_identifiers[i] != 0);
+ }
+ }
+ return _identifiers;
+}
« 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