/* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ #include "config.h" #include "ScriptController.h" #include "Console.h" #include "DOMWindow.h" #include "Document.h" #include "Event.h" #include "EventNames.h" #include "Frame.h" #include "FrameLoader.h" #include "GCController.h" #include "JSDOMWindow.h" #include "JSDocument.h" #include "JSEventListener.h" #include "npruntime_impl.h" #include "NP_jsobject.h" #include "Page.h" #include "PageGroup.h" #include "runtime_root.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "Settings.h" #include #include #include #if ENABLE(NETSCAPE_PLUGIN_API) #include "HTMLPlugInElement.h" #endif using namespace JSC; namespace WebCore { ScriptController::ScriptController(Frame* frame) : m_frame(frame) , m_handlerLineno(0) , m_sourceURL(0) , m_processingTimerCallback(false) , m_paused(false) #if ENABLE(NETSCAPE_PLUGIN_API) , m_windowScriptNPObject(0) #endif #if PLATFORM(MAC) , m_windowScriptObject(0) #endif { #if PLATFORM(MAC) && ENABLE(MAC_JAVA_BRIDGE) static bool initializedJavaJSBindings; if (!initializedJavaJSBindings) { initializedJavaJSBindings = true; initJavaJSBindings(); } #endif } ScriptController::~ScriptController() { if (m_windowShell) { m_windowShell = 0; // It's likely that releasing the global object has created a lot of garbage. gcController().garbageCollectSoon(); } disconnectPlatformScriptObjects(); } ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode) { // evaluate code. Returns the JS return value or 0 // if there was none, an error occured or the type couldn't be converted. const SourceCode& jsSourceCode = sourceCode.jsSourceCode(); initScriptIfNeeded(); // inlineCode is true for // and false for . Check if it has the // expected value in all cases. // See smart window.open policy for where this is used. ExecState* exec = m_windowShell->window()->globalExec(); const String* savedSourceURL = m_sourceURL; String sourceURL = jsSourceCode.provider()->url(); m_sourceURL = &sourceURL; JSLock lock(false); // Evaluating the JavaScript could cause the frame to be deallocated // so we start the keep alive timer here. m_frame->keepAlive(); m_windowShell->window()->startTimeoutCheck(); Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, m_windowShell); m_windowShell->window()->stopTimeoutCheck(); if (comp.complType() == Normal || comp.complType() == ReturnValue) { m_sourceURL = savedSourceURL; return comp.value(); } if (comp.complType() == Throw) reportException(exec, comp.value()); m_sourceURL = savedSourceURL; return noValue(); } void ScriptController::clearWindowShell() { if (!m_windowShell) return; JSLock lock(false); m_windowShell->window()->clear(); m_windowShell->setWindow(m_frame->domWindow()); if (Page* page = m_frame->page()) { attachDebugger(page->debugger()); m_windowShell->window()->setProfileGroup(page->group().identifier()); } // There is likely to be a lot of garbage now. gcController().garbageCollectSoon(); } PassRefPtr ScriptController::createInlineEventListener(const String& functionName, const String& code, Node* node) { initScriptIfNeeded(); JSLock lock(false); return JSLazyEventListener::create(JSLazyEventListener::HTMLLazyEventListener, functionName, code, m_windowShell->window(), node, m_handlerLineno); } #if ENABLE(SVG) PassRefPtr ScriptController::createSVGEventHandler(const String& functionName, const String& code, Node* node) { initScriptIfNeeded(); JSLock lock(false); return JSLazyEventListener::create(JSLazyEventListener::SVGLazyEventListener, functionName, code, m_windowShell->window(), node, m_handlerLineno); } #endif void ScriptController::initScript() { if (m_windowShell) return; JSLock lock(false); m_windowShell = new JSDOMWindowShell(m_frame->domWindow()); m_windowShell->window()->updateDocument(); if (Page* page = m_frame->page()) { attachDebugger(page->debugger()); m_windowShell->window()->setProfileGroup(page->group().identifier()); } m_frame->loader()->dispatchWindowObjectAvailable(); } bool ScriptController::processingUserGesture() const { return processingUserGestureEvent() || isJavaScriptAnchorNavigation(); } bool ScriptController::processingUserGestureEvent() const { if (!m_windowShell) return false; if (Event* event = m_windowShell->window()->currentEvent()) { const AtomicString& type = event->type(); if ( // mouse events type == eventNames().clickEvent || type == eventNames().mousedownEvent || type == eventNames().mouseupEvent || type == eventNames().dblclickEvent || // keyboard events type == eventNames().keydownEvent || type == eventNames().keypressEvent || type == eventNames().keyupEvent || #if ENABLE(TOUCH_EVENTS) // Android // touch events type == eventNames().touchstartEvent || type == eventNames().touchmoveEvent || type == eventNames().touchendEvent || type == eventNames().touchcancelEvent || #endif // other accepted events type == eventNames().selectEvent || type == eventNames().changeEvent || type == eventNames().focusEvent || type == eventNames().blurEvent || type == eventNames().submitEvent) return true; } return false; } // FIXME: This seems like an insufficient check to verify a click on a javascript: anchor. bool ScriptController::isJavaScriptAnchorNavigation() const { // This is the