blob: 461cea31214b10b8bd53e0e043621bf2f8501acd [file] [log] [blame]
// 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