| // Copyright (c) 2006-2008 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 "webkit/activex_shim/dispatch_object.h" |
| |
| #include <algorithm> |
| #include <string> |
| #include <vector> |
| |
| #include "base/logging.h" |
| #include "webkit/activex_shim/activex_util.h" |
| #include "webkit/activex_shim/npp_impl.h" |
| |
| using std::string; |
| using std::wstring; |
| |
| namespace activex_shim { |
| |
| // Used when the browser asks for scriptable object. |
| static NPClass npclass = { |
| 1, // NP_CLASS_STRUCT_VERSION, |
| NPAllocate, |
| NPDeallocate, |
| NPInvalidate, |
| NPHasMethod, |
| NPInvoke, |
| NPInvokeDefault, |
| NPHasProperty, |
| NPGetProperty, |
| NPSetProperty, |
| NPRemoveProperty |
| }; |
| |
| DispatchObject::DispatchObject(DispatchObject* root) |
| : npobject_(NULL), |
| root_(root), |
| deleting_spawned_children_(false) { |
| } |
| |
| DispatchObject::~DispatchObject() { |
| if (npobject_) { |
| // We are gone, but the NPObject may still be there. So remove |
| // the reference to myself to avoid future trouble. |
| npobject_->dispatch_object = NULL; |
| } |
| } |
| |
| NPObject* DispatchObject::GetScriptableNPObject() { |
| if (npobject_ == NULL) { |
| npobject_ = static_cast<DispatchNPObject*>(NPAllocate(&npclass)); |
| } else { |
| // If it is requesting the object again, we should just return the |
| // object with increased reference count. |
| g_browser->retainobject(npobject_); |
| } |
| return npobject_; |
| } |
| |
| NPObject* DispatchObject::NPAllocate(NPClass* cls) { |
| DispatchNPObject* obj = new DispatchNPObject(); |
| obj->_class = cls; |
| obj->referenceCount = 1; |
| obj->dispatch_object = this; |
| return obj; |
| } |
| |
| void DispatchObject::NPInvalidate() { |
| } |
| |
| void DispatchObject::OnDeallocateObject(DispatchNPObject* obj) { |
| DCHECK_EQ(obj, npobject_); |
| if (obj == npobject_) { |
| // Just null our reference so that we won't accidentally access it |
| // during destruction. |
| npobject_ = NULL; |
| if (NPObjectOwnsMe()) { |
| delete this; |
| } |
| } |
| } |
| |
| bool DispatchObject::NPHasMethod(NPIdentifier name) { |
| wstring wname; |
| if (!NPIdentifierToWString(name, &wname)) |
| return false; |
| return DispIsMethodOrProperty(GetDispatch(), wname.c_str(), true); |
| } |
| |
| bool DispatchObject::NPHasProperty(NPIdentifier name) { |
| wstring wname; |
| if (!NPIdentifierToWString(name, &wname)) |
| return false; |
| return DispIsMethodOrProperty(GetDispatch(), wname.c_str(), false); |
| // Here is another way. But the problem is it can not distiguish between |
| // method and property. |
| // DISPID dispid; |
| // if (GetDispID(npobj->dispatch_object->GetDispatch(), wname.c_str(), &dispid)) |
| // return true; |
| } |
| |
| bool DispatchObject::NPInvoke(NPIdentifier name, const NPVariant* args, |
| uint32_t argCount, NPVariant* result) { |
| wstring wname; |
| if (!NPIdentifierToWString(name, &wname)) |
| return false; |
| std::vector<ScopedVariant> vars; |
| ScopedVariant vtres; |
| bool res = false; |
| do { |
| if (argCount > 0) { |
| vars.resize(argCount); |
| unsigned int i; |
| for (i = 0; i < argCount; i++) { |
| // Note that we need to reverse the order of arguments for |
| // IDispatch::Invoke. |
| if (!NPVariantToVariant(&args[argCount - i - 1], &vars[i])) |
| break; |
| } |
| if (i < argCount) |
| break; |
| } |
| if (!DispInvoke(GetDispatch(), wname.c_str(), |
| argCount > 0 ? &vars[0] : NULL, |
| argCount, &vtres)) |
| break; |
| if (!VariantToNPVariant(this, &vtres, result)) |
| break; |
| res = true; |
| } while (false); |
| return res; |
| } |
| |
| bool DispatchObject::NPInvokeDefault(const NPVariant* args, uint32_t argCount, |
| NPVariant* result) { |
| return false; |
| } |
| |
| bool DispatchObject::NPGetProperty(NPIdentifier name, NPVariant* variant) { |
| wstring wname; |
| if (!NPIdentifierToWString(name, &wname)) |
| return false; |
| ScopedVariant result; |
| if (!DispInvoke(GetDispatch(), wname.c_str(), NULL, 0, &result)) |
| return false; |
| if (!VariantToNPVariant(this, &result, variant)) |
| return false; |
| return true; |
| } |
| |
| bool DispatchObject::NPSetProperty(NPIdentifier name, const NPVariant* variant) { |
| wstring wname; |
| if (!NPIdentifierToWString(name, &wname)) |
| return false; |
| ScopedVariant rvalue; |
| if (!NPVariantToVariant(variant, &rvalue)) |
| return false; |
| if (!DispSetProperty(GetDispatch(), wname.c_str(), rvalue)) |
| return false; |
| return true; |
| } |
| |
| bool DispatchObject::NPRemoveProperty(NPIdentifier propertyName) { |
| return false; |
| } |
| |
| void DispatchObject::AddSpawned(DispatchObject* obj) { |
| // I myself must be the root. |
| DCHECK(root_ == NULL); |
| spawned_children_.push_back(obj); |
| } |
| |
| void DispatchObject::RemoveSpawned(DispatchObject* obj) { |
| // This is to avoid problem when the root object is calling ReleaseSpawned to |
| // delete all spawned children. |
| if (deleting_spawned_children_) |
| return; |
| DCHECK(root_ == NULL); |
| SpawnedChildrenList::iterator it = std::find(spawned_children_.begin(), |
| spawned_children_.end(), obj); |
| if (it == spawned_children_.end()) { |
| DCHECK(false); |
| return; |
| } |
| spawned_children_.erase(it); |
| } |
| |
| void DispatchObject::ReleaseSpawned() { |
| DCHECK(root_ == NULL); |
| deleting_spawned_children_ = true; |
| for (SpawnedChildrenList::iterator it = spawned_children_.begin(); |
| it != spawned_children_.end(); ++it) |
| delete *it; |
| deleting_spawned_children_ = false; |
| spawned_children_.clear(); |
| } |
| |
| SpawnedDispatchObject::SpawnedDispatchObject(IDispatch* dispatch, |
| DispatchObject* root) |
| : DispatchObject(root), |
| dispatch_(dispatch) { |
| if (dispatch) |
| dispatch->AddRef(); |
| DCHECK(root != NULL); |
| root->AddSpawned(this); |
| } |
| |
| SpawnedDispatchObject::~SpawnedDispatchObject() { |
| if (dispatch_) |
| dispatch_->Release(); |
| DCHECK(root_ != NULL); |
| root_->RemoveSpawned(this); |
| } |
| |
| /////////////////////////////////////////////////////////////////////////////// |
| // Scripting object functions implementation. |
| |
| NPObject* NPAllocate(NPP npp, NPClass* theClass) { |
| DispatchObject* dispatch_object = static_cast<DispatchObject*>(npp->pdata); |
| return dispatch_object->NPAllocate(theClass); |
| } |
| |
| void NPDeallocate(NPObject* obj) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| // The dispatch_object could be well gone before the NPObject is released. |
| if (npobj->dispatch_object != NULL) { |
| npobj->dispatch_object->OnDeallocateObject(npobj); |
| } |
| delete npobj; |
| } |
| |
| void NPInvalidate(NPObject* obj) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return; |
| npobj->dispatch_object->NPInvalidate(); |
| } |
| |
| bool NPHasMethod(NPObject* obj, NPIdentifier name) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPHasMethod(name); |
| } |
| |
| bool NPInvoke(NPObject* obj, NPIdentifier name, const NPVariant* args, |
| uint32_t argCount, NPVariant* result) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPInvoke(name, args, argCount, result); |
| } |
| |
| bool NPInvokeDefault(NPObject* obj, const NPVariant* args, uint32_t argCount, |
| NPVariant* result) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPInvokeDefault(args, argCount, result); |
| } |
| |
| bool NPHasProperty(NPObject* obj, NPIdentifier name) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPHasProperty(name); |
| } |
| |
| bool NPGetProperty(NPObject* obj, NPIdentifier name, NPVariant* variant) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPGetProperty(name, variant); |
| } |
| |
| bool NPSetProperty(NPObject* obj, NPIdentifier name, const NPVariant* variant) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPSetProperty(name, variant); |
| } |
| |
| bool NPRemoveProperty(NPObject* obj, NPIdentifier name) { |
| DispatchNPObject* npobj = static_cast<DispatchNPObject*>(obj); |
| if (npobj->dispatch_object == NULL) |
| return false; |
| return npobj->dispatch_object->NPRemoveProperty(name); |
| } |
| |
| } // namespace activex_shim |