/* * Copyright (C) 2009, 2011 Google Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above * copyright notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * Neither the name of Google Inc. nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "V8Window.h" #include "V8HTMLCollection.h" #include "V8Node.h" #include "bindings/v8/BindingSecurity.h" #include "bindings/v8/ExceptionMessages.h" #include "bindings/v8/ExceptionState.h" #include "bindings/v8/ScheduledAction.h" #include "bindings/v8/ScriptController.h" #include "bindings/v8/ScriptSourceCode.h" #include "bindings/v8/SerializedScriptValue.h" #include "bindings/v8/V8Binding.h" #include "bindings/v8/V8EventListener.h" #include "bindings/v8/V8EventListenerList.h" #include "bindings/v8/V8GCForContextDispose.h" #include "bindings/v8/V8HiddenPropertyName.h" #include "bindings/v8/V8Utilities.h" #include "core/dom/ExceptionCode.h" #include "core/dom/MessagePort.h" #include "core/html/HTMLCollection.h" #include "core/html/HTMLDocument.h" #include "core/inspector/ScriptCallStack.h" #include "core/loader/FrameLoadRequest.h" #include "core/loader/FrameLoader.h" #include "core/frame/ContentSecurityPolicy.h" #include "core/frame/DOMTimer.h" #include "core/frame/DOMWindow.h" #include "core/frame/DOMWindowTimers.h" #include "core/frame/Frame.h" #include "core/frame/FrameView.h" #include "core/frame/Settings.h" #include "core/storage/Storage.h" #include "platform/PlatformScreen.h" #include "platform/graphics/media/MediaPlayer.h" #include "wtf/ArrayBuffer.h" #include "wtf/Assertions.h" #include "wtf/OwnPtr.h" namespace WebCore { // FIXME: There is a lot of duplication with SetTimeoutOrInterval() in V8WorkerGlobalScopeCustom.cpp. // We should refactor this. void WindowSetTimeoutImpl(const v8::FunctionCallbackInfo& info, bool singleShot, ExceptionState& exceptionState) { int argumentCount = info.Length(); if (argumentCount < 1) return; DOMWindow* imp = V8Window::toNative(info.Holder()); if (!imp->document()) { exceptionState.throwDOMException(InvalidAccessError, "No script context is available in which to execute the script."); return; } v8::Handle function = info[0]; String functionString; if (!function->IsFunction()) { if (function->IsString()) { functionString = toCoreString(function.As()); } else { v8::Handle v8String = function->ToString(); // Bail out if string conversion failed. if (v8String.IsEmpty()) return; functionString = toCoreString(v8String); } // Don't allow setting timeouts to run empty functions! // (Bug 1009597) if (!functionString.length()) return; } if (!BindingSecurity::shouldAllowAccessToFrame(imp->frame(), exceptionState)) return; OwnPtr action; if (function->IsFunction()) { int paramCount = argumentCount >= 2 ? argumentCount - 2 : 0; OwnPtr[]> params; if (paramCount > 0) { params = adoptArrayPtr(new v8::Local[paramCount]); for (int i = 0; i < paramCount; i++) { // parameters must be globalized params[i] = info[i+2]; } } // params is passed to action, and released in action's destructor ASSERT(imp->frame()); action = adoptPtr(new ScheduledAction(imp->frame()->script().currentWorldContext(), v8::Handle::Cast(function), paramCount, params.get(), info.GetIsolate())); } else { if (imp->document() && !imp->document()->contentSecurityPolicy()->allowEval()) { v8SetReturnValue(info, 0); return; } ASSERT(imp->frame()); action = adoptPtr(new ScheduledAction(imp->frame()->script().currentWorldContext(), functionString, KURL(), info.GetIsolate())); } int32_t timeout = argumentCount >= 2 ? info[1]->Int32Value() : 0; int timerId; if (singleShot) timerId = DOMWindowTimers::setTimeout(imp, action.release(), timeout); else timerId = DOMWindowTimers::setInterval(imp, action.release(), timeout); // Try to do the idle notification before the timeout expires to get better // use of any idle time. Aim for the middle of the interval for simplicity. if (timeout >= 0) { double maximumFireInterval = static_cast(timeout) / 1000 / 2; V8GCForContextDispose::instanceTemplate().notifyIdleSooner(maximumFireInterval); } v8SetReturnValue(info, timerId); } void V8Window::eventAttributeGetterCustom(const v8::PropertyCallbackInfo& info) { v8::Handle holder = info.This()->FindInstanceInPrototypeChain(V8Window::domTemplate(info.GetIsolate(), worldTypeInMainThread(info.GetIsolate()))); if (holder.IsEmpty()) return; Frame* frame = V8Window::toNative(holder)->frame(); ExceptionState exceptionState(ExceptionState::GetterContext, "event", "Window", info.Holder(), info.GetIsolate()); if (!BindingSecurity::shouldAllowAccessToFrame(frame, exceptionState)) { exceptionState.throwIfNeeded(); return; } ASSERT(frame); v8::Local context = frame->script().currentWorldContext(); if (context.IsEmpty()) return; v8::Handle eventSymbol = V8HiddenPropertyName::event(info.GetIsolate()); v8::Handle jsEvent = context->Global()->GetHiddenValue(eventSymbol); if (jsEvent.IsEmpty()) return; v8SetReturnValue(info, jsEvent); } void V8Window::eventAttributeSetterCustom(v8::Local value, const v8::PropertyCallbackInfo& info) { v8::Handle holder = info.This()->FindInstanceInPrototypeChain(V8Window::domTemplate(info.GetIsolate(), worldTypeInMainThread(info.GetIsolate()))); if (holder.IsEmpty()) return; Frame* frame = V8Window::toNative(holder)->frame(); ExceptionState exceptionState(ExceptionState::SetterContext, "event", "Window", info.Holder(), info.GetIsolate()); if (!BindingSecurity::shouldAllowAccessToFrame(frame, exceptionState)) { exceptionState.throwIfNeeded(); return; } ASSERT(frame); v8::Local context = frame->script().currentWorldContext(); if (context.IsEmpty()) return; v8::Handle eventSymbol = V8HiddenPropertyName::event(info.GetIsolate()); context->Global()->SetHiddenValue(eventSymbol, value); } void V8Window::frameElementAttributeGetterCustom(const v8::PropertyCallbackInfo& info) { DOMWindow* imp = V8Window::toNative(info.Holder()); ExceptionState exceptionState(ExceptionState::GetterContext, "frame", "Window", info.Holder(), info.GetIsolate()); if (!BindingSecurity::shouldAllowAccessToNode(imp->frameElement(), exceptionState)) { v8SetReturnValueNull(info); exceptionState.throwIfNeeded(); return; } // The wrapper for an