/*
* Copyright (C) 2010 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "NPJSObject.h"
#include "JSNPObject.h"
#include "NPRuntimeObjectMap.h"
#include "NPRuntimeUtilities.h"
#include "PluginView.h"
#include <JavaScriptCore/JSLock.h>
#include <JavaScriptCore/JSObject.h>
#include <WebCore/Frame.h>
#include <WebCore/IdentifierRep.h>
#include <WebCore/NotImplemented.h>
#include <wtf/text/WTFString.h>
using namespace JSC;
using namespace WebCore;
namespace WebKit {
NPJSObject* NPJSObject::create(JSGlobalData& globalData, NPRuntimeObjectMap* objectMap, JSObject* jsObject)
{
// We should never have a JSNPObject inside an NPJSObject.
ASSERT(!jsObject->inherits(&JSNPObject::s_info));
NPJSObject* npJSObject = toNPJSObject(createNPObject(0, npClass()));
npJSObject->initialize(globalData, objectMap, jsObject);
return npJSObject;
}
NPJSObject::NPJSObject()
: m_objectMap(0)
{
}
NPJSObject::~NPJSObject()
{
m_objectMap->npJSObjectDestroyed(this);
}
bool NPJSObject::isNPJSObject(NPObject* npObject)
{
return npObject->_class == npClass();
}
void NPJSObject::initialize(JSGlobalData& globalData, NPRuntimeObjectMap* objectMap, JSObject* jsObject)
{
ASSERT(!m_objectMap);
ASSERT(!m_jsObject);
m_objectMap = objectMap;
m_jsObject.set(globalData, jsObject);
}
static Identifier identifierFromIdentifierRep(ExecState* exec, IdentifierRep* identifierRep)
{
ASSERT(identifierRep->isString());
const char* string = identifierRep->string();
int length = strlen(string);
return Identifier(exec, String::fromUTF8WithLatin1Fallback(string, length).impl());
}
bool NPJSObject::hasMethod(NPIdentifier methodName)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
if (!identifierRep->isString())
return false;
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
JSValue value = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
exec->clearException();
CallData callData;
return getCallData(value, callData) != CallTypeNone;
}
bool NPJSObject::invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(methodName);
if (!identifierRep->isString())
return false;
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
JSValue function = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
}
bool NPJSObject::invokeDefault(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
JSValue function = m_jsObject.get();
return invoke(exec, m_objectMap->globalObject(), function, arguments, argumentCount, result);
}
bool NPJSObject::hasProperty(NPIdentifier identifier)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(identifier);
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
bool result;
if (identifierRep->isString())
result = m_jsObject->hasProperty(exec, identifierFromIdentifierRep(exec, identifierRep));
else
result = m_jsObject->hasProperty(exec, identifierRep->number());
exec->clearException();
return result;
}
bool NPJSObject::getProperty(NPIdentifier propertyName, NPVariant* result)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
JSValue jsResult;
if (identifierRep->isString())
jsResult = m_jsObject->get(exec, identifierFromIdentifierRep(exec, identifierRep));
else
jsResult = m_jsObject->get(exec, identifierRep->number());
m_objectMap->convertJSValueToNPVariant(exec, jsResult, *result);
exec->clearException();
return true;
}
bool NPJSObject::setProperty(NPIdentifier propertyName, const NPVariant* value)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
JSValue jsValue = m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), *value);
if (identifierRep->isString()) {
PutPropertySlot slot;
m_jsObject->put(exec, identifierFromIdentifierRep(exec, identifierRep), jsValue, slot);
} else
m_jsObject->put(exec, identifierRep->number(), jsValue);
exec->clearException();
return true;
}
bool NPJSObject::removeProperty(NPIdentifier propertyName)
{
IdentifierRep* identifierRep = static_cast<IdentifierRep*>(propertyName);
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
if (identifierRep->isString()) {
Identifier identifier = identifierFromIdentifierRep(exec, identifierRep);
if (!m_jsObject->hasProperty(exec, identifier)) {
exec->clearException();
return false;
}
m_jsObject->deleteProperty(exec, identifier);
} else {
if (!m_jsObject->hasProperty(exec, identifierRep->number())) {
exec->clearException();
return false;
}
m_jsObject->deleteProperty(exec, identifierRep->number());
}
exec->clearException();
return true;
}
bool NPJSObject::enumerate(NPIdentifier** identifiers, uint32_t* identifierCount)
{
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
PropertyNameArray propertyNames(exec);
m_jsObject->getPropertyNames(exec, propertyNames);
NPIdentifier* nameIdentifiers = npnMemNewArray<NPIdentifier>(propertyNames.size());
for (size_t i = 0; i < propertyNames.size(); ++i)
nameIdentifiers[i] = static_cast<NPIdentifier>(IdentifierRep::get(propertyNames[i].ustring().utf8().data()));
*identifiers = nameIdentifiers;
*identifierCount = propertyNames.size();
return true;
}
bool NPJSObject::construct(const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
ExecState* exec = m_objectMap->globalExec();
if (!exec)
return false;
JSLock lock(SilenceAssertionsOnly);
ConstructData constructData;
ConstructType constructType = getConstructData(m_jsObject.get(), constructData);
if (constructType == ConstructTypeNone)
return false;
// Convert the passed in arguments.
MarkedArgumentBuffer argumentList;
for (uint32_t i = 0; i < argumentCount; ++i)
argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, m_objectMap->globalObject(), arguments[i]));
exec->globalData().timeoutChecker.start();
JSValue value = JSC::construct(exec, m_jsObject.get(), constructType, constructData, argumentList);
exec->globalData().timeoutChecker.stop();
// Convert and return the new object.
m_objectMap->convertJSValueToNPVariant(exec, value, *result);
exec->clearException();
return true;
}
bool NPJSObject::invoke(ExecState* exec, JSGlobalObject* globalObject, JSValue function, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
CallData callData;
CallType callType = getCallData(function, callData);
if (callType == CallTypeNone)
return false;
// Convert the passed in arguments.
MarkedArgumentBuffer argumentList;
for (uint32_t i = 0; i < argumentCount; ++i)
argumentList.append(m_objectMap->convertNPVariantToJSValue(exec, globalObject, arguments[i]));
exec->globalData().timeoutChecker.start();
JSValue value = JSC::call(exec, function, callType, callData, m_jsObject.get(), argumentList);
exec->globalData().timeoutChecker.stop();
// Convert and return the result of the function call.
m_objectMap->convertJSValueToNPVariant(exec, value, *result);
exec->clearException();
return true;
}
NPClass* NPJSObject::npClass()
{
static NPClass npClass = {
NP_CLASS_STRUCT_VERSION,
NP_Allocate,
NP_Deallocate,
0,
NP_HasMethod,
NP_Invoke,
NP_InvokeDefault,
NP_HasProperty,
NP_GetProperty,
NP_SetProperty,
NP_RemoveProperty,
NP_Enumerate,
NP_Construct
};
return &npClass;
}
NPObject* NPJSObject::NP_Allocate(NPP npp, NPClass*)
{
ASSERT_UNUSED(npp, !npp);
return new NPJSObject;
}
void NPJSObject::NP_Deallocate(NPObject* npObject)
{
NPJSObject* npJSObject = toNPJSObject(npObject);
delete npJSObject;
}
bool NPJSObject::NP_HasMethod(NPObject* npObject, NPIdentifier methodName)
{
return toNPJSObject(npObject)->hasMethod(methodName);
}
bool NPJSObject::NP_Invoke(NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
return toNPJSObject(npObject)->invoke(methodName, arguments, argumentCount, result);
}
bool NPJSObject::NP_InvokeDefault(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
return toNPJSObject(npObject)->invokeDefault(arguments, argumentCount, result);
}
bool NPJSObject::NP_HasProperty(NPObject* npObject, NPIdentifier propertyName)
{
return toNPJSObject(npObject)->hasProperty(propertyName);
}
bool NPJSObject::NP_GetProperty(NPObject* npObject, NPIdentifier propertyName, NPVariant* result)
{
return toNPJSObject(npObject)->getProperty(propertyName, result);
}
bool NPJSObject::NP_SetProperty(NPObject* npObject, NPIdentifier propertyName, const NPVariant* value)
{
return toNPJSObject(npObject)->setProperty(propertyName, value);
}
bool NPJSObject::NP_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
{
return toNPJSObject(npObject)->removeProperty(propertyName);
}
bool NPJSObject::NP_Enumerate(NPObject* npObject, NPIdentifier** identifiers, uint32_t* identifierCount)
{
return toNPJSObject(npObject)->enumerate(identifiers, identifierCount);
}
bool NPJSObject::NP_Construct(NPObject* npObject, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
{
return toNPJSObject(npObject)->construct(arguments, argumentCount, result);
}
} // namespace WebKit