/* * 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 "Event.h" #include "EventNames.h" #include "Frame.h" #include "GCController.h" #include "HTMLPlugInElement.h" #include "JSDocument.h" #include "NP_jsobject.h" #include "Page.h" #include "PageGroup.h" #include "ScriptSourceCode.h" #include "ScriptValue.h" #include "Settings.h" #include "XSSAuditor.h" #include "npruntime_impl.h" #include "runtime_root.h" #include #include using namespace JSC; namespace WebCore { ScriptController::ScriptController(Frame* frame) : m_frame(frame) , m_handlerLineNumber(0) , m_sourceURL(0) , m_processingTimerCallback(false) , m_paused(false) , m_allowPopupsFromPlugin(false) #if ENABLE(NETSCAPE_PLUGIN_API) , m_windowScriptNPObject(0) #endif #if PLATFORM(MAC) , m_windowScriptObject(0) #endif , m_XSSAuditor(new XSSAuditor(frame)) { #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) { const SourceCode& jsSourceCode = sourceCode.jsSourceCode(); String sourceURL = jsSourceCode.provider()->url(); if (sourceURL.isNull() && !m_XSSAuditor->canEvaluateJavaScriptURL(sourceCode.source())) { // This JavaScript URL is not safe to be evaluated. return JSValue(); } if (!sourceURL.isNull() && !m_XSSAuditor->canEvaluate(sourceCode.source())) { // This script is not safe to be evaluated. return JSValue(); } // evaluate code. Returns the JS return value or 0 // if there was none, an error occured or the type couldn't be converted. 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; m_sourceURL = &sourceURL; JSLock lock(SilenceAssertionsOnly); RefPtr protect = m_frame; m_windowShell->window()->globalData()->timeoutChecker.start(); Completion comp = JSC::evaluate(exec, exec->dynamicGlobalObject()->globalScopeChain(), jsSourceCode, m_windowShell); m_windowShell->window()->globalData()->timeoutChecker.stop(); // Evaluating the JavaScript could cause the frame to be deallocated // so we start the keep alive timer here. m_frame->keepAlive(); if (comp.complType() == Normal || comp.complType() == ReturnValue) { m_sourceURL = savedSourceURL; return comp.value(); } if (comp.complType() == Throw || comp.complType() == Interrupted) reportException(exec, comp.value()); m_sourceURL = savedSourceURL; return JSValue(); } void ScriptController::clearWindowShell() { if (!m_windowShell) return; JSLock lock(SilenceAssertionsOnly); // Clear the debugger from the current window before setting the new window. attachDebugger(0); m_windowShell->window()->willRemoveFromWindowShell(); 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(); } void ScriptController::initScript() { if (m_windowShell) return; JSLock lock(SilenceAssertionsOnly); 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 m_allowPopupsFromPlugin || 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 || // 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