ScriptController.cpp [plain text]
#include "config.h"
#include "ScriptController.h"
#include "PlatformBridge.h"
#include "Document.h"
#include "DOMWindow.h"
#include "Event.h"
#include "EventListener.h"
#include "EventNames.h"
#include "Frame.h"
#include "FrameLoaderClient.h"
#include "Node.h"
#include "NotImplemented.h"
#include "npruntime_impl.h"
#include "npruntime_priv.h"
#include "NPV8Object.h"
#include "ScriptSourceCode.h"
#include "Settings.h"
#include "UserGestureIndicator.h"
#include "V8Binding.h"
#include "V8BindingState.h"
#include "V8DOMWindow.h"
#include "V8Event.h"
#include "V8HTMLEmbedElement.h"
#include "V8IsolatedContext.h"
#include "V8NPObject.h"
#include "V8Proxy.h"
#include "Widget.h"
#include "XSSAuditor.h"
#include <wtf/StdLibExtras.h>
#include <wtf/text/CString.h>
namespace WebCore {
void ScriptController::initializeThreading()
{
static bool initializedThreading = false;
if (!initializedThreading) {
WTF::initializeThreading();
WTF::initializeMainThread();
initializedThreading = true;
}
}
void ScriptController::setFlags(const char* string, int length)
{
v8::V8::SetFlagsFromString(string, length);
}
Frame* ScriptController::retrieveFrameForEnteredContext()
{
return V8Proxy::retrieveFrameForEnteredContext();
}
Frame* ScriptController::retrieveFrameForCurrentContext()
{
return V8Proxy::retrieveFrameForCurrentContext();
}
bool ScriptController::isSafeScript(Frame* target)
{
return V8BindingSecurity::canAccessFrame(V8BindingState::Only(), target, true);
}
void ScriptController::gcProtectJSWrapper(void* domObject)
{
V8GCController::gcProtect(domObject);
}
void ScriptController::gcUnprotectJSWrapper(void* domObject)
{
V8GCController::gcUnprotect(domObject);
}
ScriptController::ScriptController(Frame* frame)
: m_frame(frame)
, m_sourceURL(0)
, m_inExecuteScript(false)
, m_processingTimerCallback(false)
, m_paused(false)
, m_proxy(new V8Proxy(frame))
#if ENABLE(NETSCAPE_PLUGIN_API)
, m_windowScriptNPObject(0)
#endif
, m_XSSAuditor(new XSSAuditor(frame))
{
}
ScriptController::~ScriptController()
{
m_proxy->disconnectFrame();
}
void ScriptController::clearScriptObjects()
{
PluginObjectMap::iterator it = m_pluginObjects.begin();
for (; it != m_pluginObjects.end(); ++it) {
_NPN_UnregisterObject(it->second);
_NPN_ReleaseObject(it->second);
}
m_pluginObjects.clear();
#if ENABLE(NETSCAPE_PLUGIN_API)
if (m_windowScriptNPObject) {
_NPN_DeallocateObject(m_windowScriptNPObject);
m_windowScriptNPObject = 0;
}
#endif
}
void ScriptController::updateSecurityOrigin()
{
m_proxy->windowShell()->updateSecurityOrigin();
}
void ScriptController::updatePlatformScriptObjects()
{
notImplemented();
}
bool ScriptController::processingUserGesture(DOMWrapperWorld*) const
{
Frame* activeFrame = V8Proxy::retrieveFrameForEnteredContext();
if (!activeFrame)
return UserGestureIndicator::processingUserGesture();
V8Proxy* activeProxy = activeFrame->script()->proxy();
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(activeFrame);
if (v8Context.IsEmpty())
return true;
v8::Context::Scope scope(v8Context);
v8::Handle<v8::Object> global = v8Context->Global();
v8::Handle<v8::Value> jsEvent = global->Get(v8::String::NewSymbol("event"));
Event* event = V8DOMWrapper::isValidDOMObject(jsEvent) ? V8Event::toNative(v8::Handle<v8::Object>::Cast(jsEvent)) : 0;
if (event) {
if (!UserGestureIndicator::processingUserGesture())
return false;
const AtomicString& type = event->type();
bool eventOk =
type == eventNames().clickEvent || type == eventNames().mousedownEvent || type == eventNames().mouseupEvent || type == eventNames().dblclickEvent
|| type == eventNames().keydownEvent || type == eventNames().keypressEvent || type == eventNames().keyupEvent
|| type == eventNames().selectEvent || type == eventNames().changeEvent || type == eventNames().focusEvent || type == eventNames().blurEvent || type == eventNames().submitEvent;
if (eventOk)
return true;
} else if (m_sourceURL && m_sourceURL->isNull() && !activeProxy->timerCallback()) {
return true;
}
return false;
}
bool ScriptController::anyPageIsProcessingUserGesture() const
{
return processingUserGesture();
}
void ScriptController::evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>& sources)
{
m_proxy->evaluateInIsolatedWorld(worldID, sources, 0);
}
void ScriptController::evaluateInIsolatedWorld(unsigned worldID, const Vector<ScriptSourceCode>& sources, int extensionGroup)
{
m_proxy->evaluateInIsolatedWorld(worldID, sources, extensionGroup);
}
ScriptValue ScriptController::evaluate(const ScriptSourceCode& sourceCode, ShouldAllowXSS shouldAllowXSS)
{
String sourceURL = sourceCode.url();
const String* savedSourceURL = m_sourceURL;
m_sourceURL = &sourceURL;
if (!shouldAllowXSS && !m_XSSAuditor->canEvaluate(sourceCode.source())) {
return ScriptValue();
}
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_proxy->frame());
if (v8Context.IsEmpty())
return ScriptValue();
v8::Context::Scope scope(v8Context);
RefPtr<Frame> protect(m_frame);
v8::Local<v8::Value> object = m_proxy->evaluate(sourceCode, 0);
m_frame->keepAlive();
m_sourceURL = savedSourceURL;
if (object.IsEmpty() || object->IsUndefined())
return ScriptValue();
return ScriptValue(object);
}
void ScriptController::setEventHandlerLineNumber(int lineNumber)
{
m_proxy->setEventHandlerLineNumber(lineNumber);
}
void ScriptController::finishedWithEvent(Event* event)
{
m_proxy->finishedWithEvent(event);
}
void ScriptController::bindToWindowObject(Frame* frame, const String& key, NPObject* object)
{
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(frame);
if (v8Context.IsEmpty())
return;
v8::Context::Scope scope(v8Context);
v8::Handle<v8::Object> value = createV8ObjectForNPObject(object, 0);
v8::Handle<v8::Object> global = v8Context->Global();
global->Set(v8String(key), value);
}
void ScriptController::collectGarbage()
{
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_proxy->frame());
if (v8Context.IsEmpty())
return;
v8::Context::Scope scope(v8Context);
m_proxy->evaluate(ScriptSourceCode("if (window.gc) void(gc());"), 0);
}
void ScriptController::lowMemoryNotification()
{
v8::V8::LowMemoryNotification();
}
bool ScriptController::haveInterpreter() const
{
return m_proxy->windowShell()->isContextInitialized();
}
PassScriptInstance ScriptController::createScriptInstanceForWidget(Widget* widget)
{
ASSERT(widget);
if (widget->isFrameView())
return 0;
NPObject* npObject = PlatformBridge::pluginScriptableObject(widget);
if (!npObject)
return 0;
v8::Local<v8::Object> wrapper = createV8ObjectForNPObject(npObject, 0);
m_pluginObjects.set(widget, npObject);
return V8ScriptInstance::create(wrapper);
}
void ScriptController::cleanupScriptObjectsForPlugin(Widget* nativeHandle)
{
PluginObjectMap::iterator it = m_pluginObjects.find(nativeHandle);
if (it == m_pluginObjects.end())
return;
_NPN_UnregisterObject(it->second);
_NPN_ReleaseObject(it->second);
m_pluginObjects.remove(it);
}
void ScriptController::getAllWorlds(Vector<DOMWrapperWorld*>& worlds)
{
worlds.append(mainThreadNormalWorld());
}
void ScriptController::evaluateInWorld(const ScriptSourceCode& source,
DOMWrapperWorld* world)
{
Vector<ScriptSourceCode> sources;
sources.append(source);
evaluateInIsolatedWorld(0, sources);
}
static NPObject* createNoScriptObject()
{
notImplemented();
return 0;
}
static NPObject* createScriptObject(Frame* frame)
{
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(frame);
if (v8Context.IsEmpty())
return createNoScriptObject();
v8::Context::Scope scope(v8Context);
DOMWindow* window = frame->domWindow();
v8::Handle<v8::Value> global = toV8(window);
ASSERT(global->IsObject());
return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(global), window);
}
NPObject* ScriptController::windowScriptNPObject()
{
if (m_windowScriptNPObject)
return m_windowScriptNPObject;
if (canExecuteScripts(NotAboutToExecuteScript)) {
m_windowScriptNPObject = createScriptObject(m_frame);
_NPN_RegisterObject(m_windowScriptNPObject, 0);
} else {
m_windowScriptNPObject = createNoScriptObject();
}
return m_windowScriptNPObject;
}
NPObject* ScriptController::createScriptObjectForPluginElement(HTMLPlugInElement* plugin)
{
if (!canExecuteScripts(NotAboutToExecuteScript))
return createNoScriptObject();
v8::HandleScope handleScope;
v8::Handle<v8::Context> v8Context = V8Proxy::mainWorldContext(m_frame);
if (v8Context.IsEmpty())
return createNoScriptObject();
v8::Context::Scope scope(v8Context);
DOMWindow* window = m_frame->domWindow();
v8::Handle<v8::Value> v8plugin = toV8(static_cast<HTMLEmbedElement*>(plugin));
if (!v8plugin->IsObject())
return createNoScriptObject();
return npCreateV8ScriptObject(0, v8::Handle<v8::Object>::Cast(v8plugin), window);
}
void ScriptController::clearWindowShell()
{
m_proxy->clearForNavigation();
}
void ScriptController::attachDebugger(void*)
{
notImplemented();
}
void ScriptController::updateDocument()
{
m_proxy->windowShell()->updateDocument();
}
}