1/*
2 *  Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
3 *  Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
4 *
5 *  This library is free software; you can redistribute it and/or
6 *  modify it under the terms of the GNU Lesser General Public
7 *  License as published by the Free Software Foundation; either
8 *  version 2 of the License, or (at your option) any later version.
9 *
10 *  This library is distributed in the hope that it will be useful,
11 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13 *  Lesser General Public License for more details.
14 *
15 *  You should have received a copy of the GNU Lesser General Public
16 *  License along with this library; if not, write to the Free Software
17 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 */
19
20#include "config.h"
21#include "JSPluginElementFunctions.h"
22
23#include "BridgeJSC.h"
24#include "HTMLNames.h"
25#include "HTMLPlugInElement.h"
26#include "JSHTMLElement.h"
27#include "PluginViewBase.h"
28
29using namespace JSC;
30
31namespace WebCore {
32
33using namespace Bindings;
34using namespace HTMLNames;
35
36// Runtime object support code for JSHTMLAppletElement, JSHTMLEmbedElement and JSHTMLObjectElement.
37
38static inline bool isPluginElement(Node* node)
39{
40    return node->hasTagName(objectTag) || node->hasTagName(embedTag) || node->hasTagName(appletTag);
41}
42
43Instance* pluginInstance(Node* node)
44{
45    if (!node)
46        return 0;
47    if (!isPluginElement(node))
48        return 0;
49
50    HTMLPlugInElement* plugInElement = static_cast<HTMLPlugInElement*>(node);
51    // The plugin element holds an owning reference, so we don't have to.
52    Instance* instance = plugInElement->getInstance().get();
53    if (!instance || !instance->rootObject())
54        return 0;
55    return instance;
56}
57
58static JSObject* pluginScriptObjectFromPluginViewBase(HTMLPlugInElement* pluginElement, JSGlobalObject* globalObject)
59{
60    Widget* pluginWidget = pluginElement->pluginWidget();
61    if (!pluginWidget)
62        return 0;
63
64    if (!pluginWidget->isPluginViewBase())
65        return 0;
66
67    PluginViewBase* pluginViewBase = static_cast<PluginViewBase*>(pluginWidget);
68    return pluginViewBase->scriptObject(globalObject);
69}
70
71static JSObject* pluginScriptObjectFromPluginViewBase(JSHTMLElement* jsHTMLElement)
72{
73    HTMLElement* element = jsHTMLElement->impl();
74    if (!isPluginElement(element))
75        return 0;
76
77    HTMLPlugInElement* pluginElement = static_cast<HTMLPlugInElement*>(element);
78    return pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject());
79}
80
81JSObject* pluginScriptObject(ExecState* exec, JSHTMLElement* jsHTMLElement)
82{
83    HTMLElement* element = jsHTMLElement->impl();
84    if (!isPluginElement(element))
85        return 0;
86
87    HTMLPlugInElement* pluginElement = static_cast<HTMLPlugInElement*>(element);
88
89    // First, see if we can ask the plug-in view for its script object.
90    if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()))
91        return scriptObject;
92
93    // Otherwise, fall back to getting the object from the instance.
94
95    // The plugin element holds an owning reference, so we don't have to.
96    Instance* instance = pluginElement->getInstance().get();
97    if (!instance || !instance->rootObject())
98        return 0;
99
100    return instance->createRuntimeObject(exec);
101}
102
103JSValue runtimeObjectPropertyGetter(ExecState* exec, JSValue slotBase, const Identifier& propertyName)
104{
105    JSHTMLElement* element = static_cast<JSHTMLElement*>(asObject(slotBase));
106    JSObject* scriptObject = pluginScriptObject(exec, element);
107    if (!scriptObject)
108        return jsUndefined();
109
110    return scriptObject->get(exec, propertyName);
111}
112
113bool runtimeObjectCustomGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot, JSHTMLElement* element)
114{
115    JSObject* scriptObject = pluginScriptObject(exec, element);
116    if (!scriptObject)
117        return false;
118
119    if (!scriptObject->hasProperty(exec, propertyName))
120        return false;
121    slot.setCustom(element, runtimeObjectPropertyGetter);
122    return true;
123}
124
125bool runtimeObjectCustomGetOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, JSHTMLElement* element)
126{
127    JSObject* scriptObject = pluginScriptObject(exec, element);
128    if (!scriptObject)
129        return false;
130    if (!scriptObject->hasProperty(exec, propertyName))
131        return false;
132    PropertySlot slot;
133    slot.setCustom(element, runtimeObjectPropertyGetter);
134    // While we don't know what the plugin allows, we do know that we prevent
135    // enumeration or deletion of properties, so we mark plugin properties
136    // as DontEnum | DontDelete
137    descriptor.setDescriptor(slot.getValue(exec, propertyName), DontEnum | DontDelete);
138    return true;
139}
140
141bool runtimeObjectCustomPut(ExecState* exec, const Identifier& propertyName, JSValue value, JSHTMLElement* element, PutPropertySlot& slot)
142{
143    JSObject* scriptObject = pluginScriptObject(exec, element);
144    if (!scriptObject)
145        return 0;
146    if (!scriptObject->hasProperty(exec, propertyName))
147        return false;
148    scriptObject->put(exec, propertyName, value, slot);
149    return true;
150}
151
152static EncodedJSValue JSC_HOST_CALL callPlugin(ExecState* exec)
153{
154    JSHTMLElement* element = static_cast<JSHTMLElement*>(exec->callee());
155
156    // Get the plug-in script object.
157    JSObject* scriptObject = pluginScriptObject(exec, element);
158    ASSERT(scriptObject);
159
160    size_t argumentCount = exec->argumentCount();
161    MarkedArgumentBuffer argumentList;
162    for (size_t i = 0; i < argumentCount; i++)
163        argumentList.append(exec->argument(i));
164
165    CallData callData;
166    CallType callType = getCallData(scriptObject, callData);
167    ASSERT(callType == CallTypeHost);
168
169    // Call the object.
170    JSValue result = call(exec, scriptObject, callType, callData, exec->hostThisValue(), argumentList);
171    return JSValue::encode(result);
172}
173
174CallType runtimeObjectGetCallData(JSHTMLElement* element, CallData& callData)
175{
176    // First, ask the plug-in view base for its runtime object.
177    if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(element)) {
178        CallData scriptObjectCallData;
179
180        if (scriptObject->getCallData(scriptObjectCallData) == CallTypeNone)
181            return CallTypeNone;
182
183        callData.native.function = callPlugin;
184        return CallTypeHost;
185    }
186
187    Instance* instance = pluginInstance(element->impl());
188    if (!instance || !instance->supportsInvokeDefaultMethod())
189        return CallTypeNone;
190    callData.native.function = callPlugin;
191    return CallTypeHost;
192}
193
194} // namespace WebCore
195