DOM timer throttling for hidden plugins
[WebKit-https.git] / Source / WebCore / bindings / js / JSPluginElementFunctions.cpp
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
29 using namespace JSC;
30
31 namespace WebCore {
32
33 using namespace Bindings;
34 using namespace HTMLNames;
35
36 // JavaScript access to plug-in-exported properties for JSHTMLAppletElement, JSHTMLEmbedElement and JSHTMLObjectElement.
37
38 static inline bool isPluginElement(HTMLElement& element)
39 {
40     return element.hasTagName(objectTag) || element.hasTagName(embedTag) || element.hasTagName(appletTag);
41 }
42
43 Instance* pluginInstance(HTMLElement& element)
44 {
45     // The plugin element holds an owning reference, so we don't have to.
46     if (!isPluginElement(element))
47         return 0;
48     Instance* instance = toHTMLPlugInElement(element).getInstance().get();
49     if (!instance || !instance->rootObject())
50         return 0;
51     return instance;
52 }
53
54 static JSObject* pluginScriptObjectFromPluginViewBase(HTMLPlugInElement& pluginElement, JSGlobalObject* globalObject)
55 {
56     Widget* pluginWidget = pluginElement.pluginWidget();
57     if (!pluginWidget)
58         return 0;
59     
60     if (!pluginWidget->isPluginViewBase())
61         return 0;
62
63     PluginViewBase* pluginViewBase = toPluginViewBase(pluginWidget);
64     return pluginViewBase->scriptObject(globalObject);
65 }
66
67 static JSObject* pluginScriptObjectFromPluginViewBase(JSHTMLElement* jsHTMLElement)
68 {
69     HTMLElement& element = jsHTMLElement->impl();
70     if (!isPluginElement(element))
71         return 0;
72
73     HTMLPlugInElement& pluginElement = toHTMLPlugInElement(element);
74     return pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject());
75 }
76
77 JSObject* pluginScriptObject(ExecState* exec, JSHTMLElement* jsHTMLElement)
78 {
79     HTMLElement& element = jsHTMLElement->impl();
80     if (!isPluginElement(element))
81         return 0;
82
83     HTMLPlugInElement& pluginElement = toHTMLPlugInElement(element);
84
85     // Choke point for script/plugin interaction; notify DOMTimer of the event.
86     DOMTimer::scriptDidInteractWithPlugin(pluginElement);
87
88     // First, see if the element has a plug-in replacement with a script.
89     if (JSObject* scriptObject = pluginElement.scriptObjectForPluginReplacement())
90         return scriptObject;
91     
92     // Next, see if we can ask the plug-in view for its script object.
93     if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(pluginElement, jsHTMLElement->globalObject()))
94         return scriptObject;
95
96     // Otherwise, fall back to getting the object from the instance.
97
98     // The plugin element holds an owning reference, so we don't have to.
99     Instance* instance = pluginElement.getInstance().get();
100     if (!instance || !instance->rootObject())
101         return 0;
102
103     return instance->createRuntimeObject(exec);
104 }
105     
106 EncodedJSValue pluginElementPropertyGetter(ExecState* exec, JSObject*, EncodedJSValue thisValue, PropertyName propertyName)
107 {
108
109     JSHTMLElement* thisObject = jsDynamicCast<JSHTMLElement*>(JSValue::decode(thisValue));
110     if (!thisObject)
111         return throwVMTypeError(exec);
112     JSObject* scriptObject = pluginScriptObject(exec, thisObject);
113     if (!scriptObject)
114         return JSValue::encode(jsUndefined());
115     
116     return JSValue::encode(scriptObject->get(exec, propertyName));
117 }
118
119 bool pluginElementCustomGetOwnPropertySlot(ExecState* exec, PropertyName propertyName, PropertySlot& slot, JSHTMLElement* element)
120 {
121     JSObject* scriptObject = pluginScriptObject(exec, element);
122     if (!scriptObject)
123         return false;
124
125     if (!scriptObject->hasProperty(exec, propertyName))
126         return false;
127     slot.setCustom(element, DontDelete | DontEnum, pluginElementPropertyGetter);
128     return true;
129 }
130
131 bool pluginElementCustomPut(ExecState* exec, PropertyName propertyName, JSValue value, JSHTMLElement* element, PutPropertySlot& slot)
132 {
133     JSObject* scriptObject = pluginScriptObject(exec, element);
134     if (!scriptObject)
135         return 0;
136     if (!scriptObject->hasProperty(exec, propertyName))
137         return false;
138     scriptObject->methodTable()->put(scriptObject, exec, propertyName, value, slot);
139     return true;
140 }
141
142 static EncodedJSValue JSC_HOST_CALL callPlugin(ExecState* exec)
143 {
144     JSHTMLElement* element = jsCast<JSHTMLElement*>(exec->callee());
145
146     // Get the plug-in script object.
147     JSObject* scriptObject = pluginScriptObject(exec, element);
148     ASSERT(scriptObject);
149
150     size_t argumentCount = exec->argumentCount();
151     MarkedArgumentBuffer argumentList;
152     for (size_t i = 0; i < argumentCount; i++)
153         argumentList.append(exec->argument(i));
154
155     CallData callData;
156     CallType callType = getCallData(scriptObject, callData);
157     ASSERT(callType == CallTypeHost);
158
159     // Call the object.
160     JSValue result = call(exec, scriptObject, callType, callData, exec->thisValue(), argumentList);
161     return JSValue::encode(result);
162 }
163
164 CallType pluginElementGetCallData(JSHTMLElement* element, CallData& callData)
165 {
166     // First, ask the plug-in view base for its runtime object.
167     if (JSObject* scriptObject = pluginScriptObjectFromPluginViewBase(element)) {
168         CallData scriptObjectCallData;
169         
170         if (scriptObject->methodTable()->getCallData(scriptObject, scriptObjectCallData) == CallTypeNone)
171             return CallTypeNone;
172
173         callData.native.function = callPlugin;
174         return CallTypeHost;
175     }
176     
177     Instance* instance = pluginInstance(element->impl());
178     if (!instance || !instance->supportsInvokeDefaultMethod())
179         return CallTypeNone;
180     callData.native.function = callPlugin;
181     return CallTypeHost;
182 }
183
184 } // namespace WebCore