2 * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
3 * Copyright (C) 2001 Peter Kelly (pmk@post.com)
4 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "ScriptController.h"
25 #include "DOMWindow.h"
28 #include "EventNames.h"
30 #include "FrameLoader.h"
31 #include "GCController.h"
32 #include "JSDOMWindow.h"
33 #include "JSDocument.h"
34 #include "JSEventListener.h"
35 #include "npruntime_impl.h"
36 #include "NP_jsobject.h"
38 #include "PageGroup.h"
39 #include "runtime_root.h"
40 #include "ScriptSourceCode.h"
41 #include "ScriptValue.h"
44 #include <runtime/Completion.h>
45 #include <debugger/Debugger.h>
46 #include <runtime/JSLock.h>
48 #include "HTMLPlugInElement.h"
54 ScriptController::ScriptController(Frame* frame)
58 , m_processingTimerCallback(false)
60 #if ENABLE(NETSCAPE_PLUGIN_API)
61 , m_windowScriptNPObject(0)
64 , m_windowScriptObject(0)
67 #if PLATFORM(MAC) && ENABLE(MAC_JAVA_BRIDGE)
68 static bool initializedJavaJSBindings;
69 if (!initializedJavaJSBindings) {
70 initializedJavaJSBindings = true;
76 ScriptController::~ScriptController()
81 // It's likely that releasing the global object has created a lot of garbage.
82 gcController().garbageCollectSoon();
85 disconnectPlatformScriptObjects();
88 ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode)
90 // evaluate code. Returns the JS return value or 0
91 // if there was none, an error occured or the type couldn't be converted.
93 const SourceCode& jsSourceCode = sourceCode.jsSourceCode();
96 // inlineCode is true for <a href="javascript:doSomething()">
97 // and false for <script>doSomething()</script>. Check if it has the
98 // expected value in all cases.
99 // See smart window.open policy for where this is used.
100 ExecState* exec = m_windowShell->window()->globalExec();
101 const String* savedSourceURL = m_sourceURL;
102 String sourceURL = jsSourceCode.provider()->url();
103 m_sourceURL = &sourceURL;
107 // Evaluating the JavaScript could cause the frame to be deallocated
108 // so we start the keep alive timer here.
109 m_frame->keepAlive();
111 m_windowShell->window()->globalData()->timeoutChecker.start();
112 Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, m_windowShell);
113 m_windowShell->window()->globalData()->timeoutChecker.stop();
115 if (comp.complType() == Normal || comp.complType() == ReturnValue) {
116 m_sourceURL = savedSourceURL;
120 if (comp.complType() == Throw || comp.complType() == Interrupted)
121 reportException(exec, comp.value());
123 m_sourceURL = savedSourceURL;
127 void ScriptController::clearWindowShell()
133 m_windowShell->window()->clear();
134 m_liveFormerWindows.add(m_windowShell->window());
135 m_windowShell->setWindow(m_frame->domWindow());
136 if (Page* page = m_frame->page()) {
137 attachDebugger(page->debugger());
138 m_windowShell->window()->setProfileGroup(page->group().identifier());
141 // There is likely to be a lot of garbage now.
142 gcController().garbageCollectSoon();
145 PassRefPtr<EventListener> ScriptController::createInlineEventListener(const String& functionName, const String& code, Node* node)
147 initScriptIfNeeded();
149 return JSLazyEventListener::create(JSLazyEventListener::HTMLLazyEventListener, functionName, code, m_windowShell->window(), node, m_handlerLineno);
153 PassRefPtr<EventListener> ScriptController::createSVGEventHandler(const String& functionName, const String& code, Node* node)
155 initScriptIfNeeded();
157 return JSLazyEventListener::create(JSLazyEventListener::SVGLazyEventListener, functionName, code, m_windowShell->window(), node, m_handlerLineno);
161 void ScriptController::initScript()
168 m_windowShell = new JSDOMWindowShell(m_frame->domWindow());
171 if (Page* page = m_frame->page()) {
172 attachDebugger(page->debugger());
173 m_windowShell->window()->setProfileGroup(page->group().identifier());
176 m_frame->loader()->dispatchWindowObjectAvailable();
179 bool ScriptController::processingUserGesture() const
181 return processingUserGestureEvent() || isJavaScriptAnchorNavigation();
184 bool ScriptController::processingUserGestureEvent() const
189 if (Event* event = m_windowShell->window()->currentEvent()) {
190 const AtomicString& type = event->type();
192 type == eventNames().clickEvent || type == eventNames().mousedownEvent ||
193 type == eventNames().mouseupEvent || type == eventNames().dblclickEvent ||
195 type == eventNames().keydownEvent || type == eventNames().keypressEvent ||
196 type == eventNames().keyupEvent ||
197 // other accepted events
198 type == eventNames().selectEvent || type == eventNames().changeEvent ||
199 type == eventNames().focusEvent || type == eventNames().blurEvent ||
200 type == eventNames().submitEvent)
207 // FIXME: This seems like an insufficient check to verify a click on a javascript: anchor.
208 bool ScriptController::isJavaScriptAnchorNavigation() const
210 // This is the <a href="javascript:window.open('...')> case -> we let it through
211 if (m_sourceURL && m_sourceURL->isNull() && !m_processingTimerCallback)
214 // This is the <script>window.open(...)</script> case or a timer callback -> block it
218 bool ScriptController::anyPageIsProcessingUserGesture() const
220 Page* page = m_frame->page();
224 const HashSet<Page*>& pages = page->group().pages();
225 HashSet<Page*>::const_iterator end = pages.end();
226 for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) {
227 for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) {
228 if (frame->script()->processingUserGesture())
236 bool ScriptController::isEnabled()
238 Settings* settings = m_frame->settings();
239 return (settings && settings->isJavaScriptEnabled());
242 void ScriptController::attachDebugger(JSC::Debugger* debugger)
248 debugger->attach(m_windowShell->window());
249 else if (JSC::Debugger* currentDebugger = m_windowShell->window()->debugger())
250 currentDebugger->detach(m_windowShell->window());
253 void ScriptController::updateDocument()
255 if (!m_frame->document())
260 m_windowShell->window()->updateDocument();
261 HashSet<JSDOMWindow*>::iterator end = m_liveFormerWindows.end();
262 for (HashSet<JSDOMWindow*>::iterator it = m_liveFormerWindows.begin(); it != end; ++it)
263 (*it)->updateDocument();
266 void ScriptController::updateSecurityOrigin()
268 // Our bindings do not do anything in this case.
271 Bindings::RootObject* ScriptController::bindingRootObject()
276 if (!m_bindingRootObject) {
278 m_bindingRootObject = Bindings::RootObject::create(0, globalObject());
280 return m_bindingRootObject.get();
283 PassRefPtr<Bindings::RootObject> ScriptController::createRootObject(void* nativeHandle)
285 RootObjectMap::iterator it = m_rootObjects.find(nativeHandle);
286 if (it != m_rootObjects.end())
289 RefPtr<Bindings::RootObject> rootObject = Bindings::RootObject::create(nativeHandle, globalObject());
291 m_rootObjects.set(nativeHandle, rootObject);
292 return rootObject.release();
295 #if ENABLE(NETSCAPE_PLUGIN_API)
296 NPObject* ScriptController::windowScriptNPObject()
298 if (!m_windowScriptNPObject) {
300 // JavaScript is enabled, so there is a JavaScript window object.
301 // Return an NPObject bound to the window object.
302 JSC::JSLock lock(false);
303 JSObject* win = windowShell()->window();
305 Bindings::RootObject* root = bindingRootObject();
306 m_windowScriptNPObject = _NPN_CreateScriptObject(0, win, root);
308 // JavaScript is not enabled, so we cannot bind the NPObject to the JavaScript window object.
309 // Instead, we create an NPObject of a different class, one which is not bound to a JavaScript object.
310 m_windowScriptNPObject = _NPN_CreateNoScriptObject();
314 return m_windowScriptNPObject;
317 NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin)
319 JSObject* object = jsObjectForPluginElement(plugin);
321 return _NPN_CreateNoScriptObject();
323 // Wrap the JSObject in an NPObject
324 return _NPN_CreateScriptObject(0, object, bindingRootObject());
328 JSObject* ScriptController::jsObjectForPluginElement(HTMLPlugInElement* plugin)
330 // Can't create JSObjects when JavaScript is disabled
334 // Create a JSObject bound to this element
336 ExecState* exec = globalObject()->globalExec();
337 JSValuePtr jsElementValue = toJS(exec, plugin);
338 if (!jsElementValue || !jsElementValue.isObject())
341 return jsElementValue.getObject();
345 void ScriptController::updatePlatformScriptObjects()
349 void ScriptController::disconnectPlatformScriptObjects()
354 void ScriptController::cleanupScriptObjectsForPlugin(void* nativeHandle)
356 RootObjectMap::iterator it = m_rootObjects.find(nativeHandle);
358 if (it == m_rootObjects.end())
361 it->second->invalidate();
362 m_rootObjects.remove(it);
365 void ScriptController::clearScriptObjects()
369 RootObjectMap::const_iterator end = m_rootObjects.end();
370 for (RootObjectMap::const_iterator it = m_rootObjects.begin(); it != end; ++it)
371 it->second->invalidate();
373 m_rootObjects.clear();
375 if (m_bindingRootObject) {
376 m_bindingRootObject->invalidate();
377 m_bindingRootObject = 0;
380 #if ENABLE(NETSCAPE_PLUGIN_API)
381 if (m_windowScriptNPObject) {
382 // Call _NPN_DeallocateObject() instead of _NPN_ReleaseObject() so that we don't leak if a plugin fails to release the window
383 // script object properly.
384 // This shouldn't cause any problems for plugins since they should have already been stopped and destroyed at this point.
385 _NPN_DeallocateObject(m_windowScriptNPObject);
386 m_windowScriptNPObject = 0;
391 } // namespace WebCore