JSPluginElementFunctions.cpp [plain text]
#include "config.h"
#include "JSPluginElementFunctions.h"
#include "BridgeJSC.h"
#include "HTMLNames.h"
#include "HTMLPlugInElement.h"
#include "JSHTMLElement.h"
#include "PluginViewBase.h"
namespace WebCore {
using namespace JSC;
using namespace Bindings;
using namespace HTMLNames;
static JSC_DECLARE_HOST_FUNCTION(callPlugin);
static JSC_DECLARE_CUSTOM_GETTER(pluginElementPropertyGetter);
Instance* pluginInstance(HTMLElement& element)
{
if (!is<HTMLPlugInElement>(element))
return nullptr;
auto* instance = downcast<HTMLPlugInElement>(element).bindingsInstance();
if (!instance || !instance->rootObject())
return nullptr;
return instance;
}
static JSObject* pluginScriptObjectFromPluginViewBase(HTMLPlugInElement& pluginElement, JSGlobalObject* globalObject)
{
Widget* pluginWidget = pluginElement.pluginWidget();
if (!is<PluginViewBase>(pluginWidget))
return nullptr;
return downcast<PluginViewBase>(*pluginWidget).scriptObject(globalObject);
}
static JSObject* pluginScriptObjectFromPluginViewBase(JSHTMLElement* jsHTMLElement)
{
HTMLElement& element = jsHTMLElement->wrapped();
if (!is<HTMLPlugInElement>(element))
return nullptr;
HTMLPlugInElement& pluginElement = downcast<HTMLPlugInElement>(element);
return pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject());
}
JSObject* pluginScriptObject(JSGlobalObject* lexicalGlobalObject, JSHTMLElement* jsHTMLElement)
{
HTMLElement& element = jsHTMLElement->wrapped();
if (!is<HTMLPlugInElement>(element))
return nullptr;
auto& pluginElement = downcast<HTMLPlugInElement>(element);
DOMTimer::scriptDidInteractWithPlugin(pluginElement);
if (auto* scriptObject = pluginElement.scriptObjectForPluginReplacement())
return scriptObject;
if (auto* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()))
return scriptObject;
auto* instance = pluginElement.bindingsInstance();
if (!instance || !instance->rootObject())
return nullptr;
return instance->createRuntimeObject(lexicalGlobalObject);
}
JSC_DEFINE_CUSTOM_GETTER(pluginElementPropertyGetter, (JSGlobalObject* lexicalGlobalObject, EncodedJSValue thisValue, PropertyName propertyName))
{
VM& vm = lexicalGlobalObject->vm();
auto scope = DECLARE_THROW_SCOPE(vm);
JSHTMLElement* thisObject = jsDynamicCast<JSHTMLElement*>(vm, JSValue::decode(thisValue));
if (!thisObject)
return throwVMTypeError(lexicalGlobalObject, scope);
JSObject* scriptObject = pluginScriptObject(lexicalGlobalObject, thisObject);
if (!scriptObject)
return JSValue::encode(jsUndefined());
return JSValue::encode(scriptObject->get(lexicalGlobalObject, propertyName));
}
bool pluginElementCustomGetOwnPropertySlot(JSHTMLElement* element, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, PropertySlot& slot)
{
slot.setIsTaintedByOpaqueObject();
if (!element->globalObject()->world().isNormal()) {
JSC::JSValue proto = element->getPrototypeDirect(lexicalGlobalObject->vm());
if (proto.isObject() && JSC::jsCast<JSC::JSObject*>(asObject(proto))->hasProperty(lexicalGlobalObject, propertyName))
return false;
}
if (slot.isVMInquiry()) {
slot.setValue(element, static_cast<unsigned>(JSC::PropertyAttribute::None), jsUndefined());
return false; }
JSObject* scriptObject = pluginScriptObject(lexicalGlobalObject, element);
if (!scriptObject)
return false;
if (!scriptObject->hasProperty(lexicalGlobalObject, propertyName))
return false;
slot.setCustom(element, JSC::PropertyAttribute::DontDelete | JSC::PropertyAttribute::DontEnum, pluginElementPropertyGetter);
return true;
}
bool pluginElementCustomPut(JSHTMLElement* element, JSGlobalObject* lexicalGlobalObject, PropertyName propertyName, JSValue value, PutPropertySlot& slot, bool& putResult)
{
JSObject* scriptObject = pluginScriptObject(lexicalGlobalObject, element);
if (!scriptObject)
return false;
if (!scriptObject->hasProperty(lexicalGlobalObject, propertyName))
return false;
putResult = scriptObject->methodTable(lexicalGlobalObject->vm())->put(scriptObject, lexicalGlobalObject, propertyName, value, slot);
return true;
}
JSC_DEFINE_HOST_FUNCTION(callPlugin, (JSGlobalObject* lexicalGlobalObject, CallFrame* callFrame))
{
JSHTMLElement* element = jsCast<JSHTMLElement*>(callFrame->jsCallee());
JSObject* scriptObject = pluginScriptObject(lexicalGlobalObject, element);
ASSERT(scriptObject);
size_t argumentCount = callFrame->argumentCount();
MarkedArgumentBuffer argumentList;
for (size_t i = 0; i < argumentCount; i++)
argumentList.append(callFrame->argument(i));
ASSERT(!argumentList.hasOverflowed());
auto callData = getCallData(lexicalGlobalObject->vm(), scriptObject);
ASSERT(callData.type == CallData::Type::Native);
JSValue result = call(lexicalGlobalObject, scriptObject, callData, callFrame->thisValue(), argumentList);
return JSValue::encode(result);
}
CallData pluginElementCustomGetCallData(JSHTMLElement* element)
{
CallData callData;
if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(element)) {
VM& vm = scriptObject->vm();
auto scriptObjectCallData = getCallData(vm, scriptObject);
if (scriptObjectCallData.type != CallData::Type::None) {
callData.type = CallData::Type::Native;
callData.native.function = callPlugin;
}
} else {
Instance* instance = pluginInstance(element->wrapped());
if (instance && instance->supportsInvokeDefaultMethod()) {
callData.type = CallData::Type::Native;
callData.native.function = callPlugin;
}
}
return callData;
}
}