bool ScriptController::anyPageIsProcessingUserGesture() const { Page* page = m_frame->page(); if (!page) return false; const HashSet<Page*>& pages = page->group().pages(); HashSet<Page*>::const_iterator end = pages.end(); for (HashSet<Page*>::const_iterator it = pages.begin(); it != end; ++it) { for (Frame* frame = page->mainFrame(); frame; frame = frame->tree()->traverseNext()) { if (frame->script()->processingUserGesture()) return true; } } return false; }
void ScheduledAction::execute(ScriptExecutionContext* context) { if (context->isDocument()) { Frame* frame = static_cast<Document*>(context)->frame(); ScriptController* scriptController = frame->script(); if (!scriptController->canExecuteScripts(NotAboutToExecuteScript)) return; V8Proxy* proxy = V8Proxy::retrieve(frame); execute(proxy); } #if ENABLE(WORKERS) else { ASSERT(context->isWorkerContext()); execute(static_cast<WorkerContext*>(context)); } #endif }
void CachedFrameBase::restore() { ASSERT(m_document->view() == m_view); if (m_isMainFrame) m_view->setParentVisible(true); Frame* frame = m_view->frame(); m_cachedFrameScriptData->restore(frame); #if ENABLE(SVG) if (m_document->svgExtensions()) m_document->accessSVGExtensions()->unpauseAnimations(); #endif frame->animation()->resumeAnimationsForDocument(m_document.get()); frame->eventHandler()->setMousePressNode(m_mousePressNode.get()); m_document->resumeActiveDOMObjects(); m_document->resumeScriptedAnimationControllerCallbacks(); // It is necessary to update any platform script objects after restoring the // cached page. frame->script()->updatePlatformScriptObjects(); frame->loader()->client()->didRestoreFromPageCache(); // Reconstruct the FrameTree for (unsigned i = 0; i < m_childFrames.size(); ++i) frame->tree()->appendChild(m_childFrames[i]->view()->frame()); // Open the child CachedFrames in their respective FrameLoaders. for (unsigned i = 0; i < m_childFrames.size(); ++i) m_childFrames[i]->open(); m_document->enqueuePageshowEvent(PageshowEventPersisted); HistoryItem* historyItem = frame->loader()->history()->currentItem(); m_document->enqueuePopstateEvent(historyItem && historyItem->stateObject() ? historyItem->stateObject() : SerializedScriptValue::nullValue()); #if ENABLE(TOUCH_EVENTS) if (m_document->hasListenerType(Document::TOUCH_LISTENER)) m_document->page()->chrome()->client()->needTouchEvents(true); #endif m_document->documentDidBecomeActive(); }
void JSDocument::setLocation(ExecState* exec, JSValuePtr value) { Frame* frame = static_cast<Document*>(impl())->frame(); if (!frame) return; String str = value->toString(exec); // IE and Mozilla both resolve the URL relative to the source frame, // not the target frame. Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); if (activeFrame) str = activeFrame->document()->completeURL(str).string(); bool userGesture = activeFrame->script()->processingUserGesture(); frame->loader()->scheduleLocationChange(str, activeFrame->loader()->outgoingReferrer(), false, userGesture); }
PassScriptInstance HTMLPlugInElement::getInstance() const { Frame* frame = document()->frame(); if (!frame) return 0; // If the host dynamically turns off JavaScript (or Java) we will still return // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. if (m_instance) return m_instance; RenderWidget* renderWidget = renderWidgetForJSBindings(); if (renderWidget && renderWidget->widget()) m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); return m_instance; }
bool ScriptController::processingUserGesture() const { Frame* activeFrame = V8Proxy::retrieveFrameForEnteredContext(); // No script is running, so it must be run by users. if (!activeFrame) return true; V8Proxy* activeProxy = activeFrame->script()->proxy(); v8::HandleScope handleScope; v8::Handle<v8::Context> context = V8Proxy::GetContext(activeFrame); // FIXME: find all cases context can be empty: // 1) JS is disabled; // 2) page is NULL; if (context.IsEmpty()) return true; v8::Context::Scope scope(context); v8::Handle<v8::Object> global = context->Global(); v8::Handle<v8::Value> jsEvent = global->Get(v8::String::NewSymbol("event")); Event* event = V8Proxy::ToNativeEvent(jsEvent); // Based on code from kjs_bindings.cpp. // Note: This is more liberal than Firefox's implementation. if (event) { const AtomicString& type = event->type(); bool eventOk = // 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; if (eventOk) return true; } else if (activeProxy->inlineCode() && !activeProxy->timerCallback()) { // This is the <a href="javascript:window.open('...')> case -> we let it through. return true; } // This is the <script>window.open(...)</script> case or a timer callback -> block it. return false; }
HTMLParserOptions::HTMLParserOptions(Document* document) { Frame* frame = document ? document->frame() : 0; scriptEnabled = frame && frame->script().canExecuteScripts(NotAboutToExecuteScript); pluginsEnabled = frame && frame->loader().subframeLoader()->allowPlugins(NotAboutToInstantiatePlugin); Settings* settings = document ? document->settings() : 0; usePreHTML5ParserQuirks = settings && settings->usePreHTML5ParserQuirks(); #if ENABLE(THREADED_HTML_PARSER) // We force the main-thread parser for about:blank, javascript: and data: urls for compatibility // with historical synchronous loading/parsing behavior of those schemes. useThreading = settings && settings->threadedHTMLParser() && !document->url().isBlankURL() && (settings->useThreadedHTMLParserForDataURLs() || !document->url().protocolIsData()); #else useThreading = false; #endif maximumDOMTreeDepth = settings ? settings->maximumHTMLParserDOMTreeDepth() : Settings::defaultMaximumHTMLParserDOMTreeDepth; }
void JSDocument::setLocation(ExecState* exec, JSValue value) { Frame* frame = static_cast<Document*>(impl())->frame(); if (!frame) return; String str = ustringToString(value.toString(exec)); Frame* lexicalFrame = asJSDOMWindow(exec->lexicalGlobalObject())->impl()->frame(); // IE and Mozilla both resolve the URL relative to the source frame, // not the target frame. Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); str = activeFrame->document()->completeURL(str).string(); frame->navigationScheduler()->scheduleLocationChange(lexicalFrame->document()->securityOrigin(), str, activeFrame->loader()->outgoingReferrer(), !activeFrame->script()->anyPageIsProcessingUserGesture(), false); }
v8::Local<v8::Value> V8EventListener::callListenerFunction(ScriptExecutionContext* context, v8::Handle<v8::Value> jsEvent, Event* event) { v8::Local<v8::Function> handlerFunction = getListenerFunction(context); v8::Local<v8::Object> receiver = getReceiverObject(event); if (handlerFunction.IsEmpty() || receiver.IsEmpty()) return v8::Local<v8::Value>(); v8::Handle<v8::Value> parameters[1] = { jsEvent }; if (V8Proxy* proxy = V8Proxy::retrieve(context)) { Frame* frame = static_cast<Document*>(context)->frame(); if (frame->script()->canExecuteScripts(AboutToExecuteScript)) return proxy->callFunction(handlerFunction, receiver, 1, parameters); } return v8::Local<v8::Value>(); }
void ScriptCachedPageData::restore(Page* page) { Frame* mainFrame = page->mainFrame(); JSLock lock(false); ScriptController* scriptController = mainFrame->script(); if (scriptController->haveWindowShell()) { JSDOMWindowShell* windowShell = scriptController->windowShell(); if (m_window) { windowShell->setWindow(m_window.get()); } else { windowShell->setWindow(mainFrame->domWindow()); scriptController->attachDebugger(page->debugger()); windowShell->window()->setProfileGroup(page->group().identifier()); } } }
void V8Window::eventAttrSetterCustom(v8::Local<v8::String> name, v8::Local<v8::Value> value, const v8::PropertyCallbackInfo<void>& info) { v8::Handle<v8::Object> holder = info.This()->FindInstanceInPrototypeChain(V8Window::GetTemplate(info.GetIsolate(), worldTypeInMainThread(info.GetIsolate()))); if (holder.IsEmpty()) return; Frame* frame = V8Window::toNative(holder)->frame(); if (!BindingSecurity::shouldAllowAccessToFrame(frame)) return; ASSERT(frame); v8::Local<v8::Context> context = frame->script()->currentWorldContext(); if (context.IsEmpty()) return; v8::Handle<v8::String> eventSymbol = V8HiddenPropertyName::event(); context->Global()->SetHiddenValue(eventSymbol, value); }
bool InspectorClient::doDispatchMessageOnFrontendPage(Page* frontendPage, const String& message) { if (!frontendPage) return false; Frame* frame = frontendPage->mainFrame(); if (!frame) return false; ScriptController* scriptController = frame->script(); if (!scriptController) return false; String dispatchToFrontend = "InspectorFrontendAPI.dispatchMessageAsync(" + message + ");"; // FIXME: This should execute the script in the appropriate world. scriptController->evaluate(ScriptSourceCode(dispatchToFrontend)); return true; }
bool InspectorClient::sendMessageToFrontend(const String& message) { if (!m_frontendPage) return false; Frame* frame = m_frontendPage->mainFrame(); if (!frame) return false; ScriptController* scriptController = frame->script(); if (!scriptController) return false; String dispatchToFrontend("WebInspector.dispatchMessageFromBackend("); dispatchToFrontend += message; dispatchToFrontend += ");"; scriptController->executeScript(dispatchToFrontend); return true; }
bool _NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npObject, NPString* npScript, NPVariant* result) { VOID_TO_NPVARIANT(*result); if (!npObject) return false; if (npObject->_class != npScriptObjectClass) { // Check if the object passed in is wrapped. If yes, then we need to invoke on the underlying object. NPObject* actualObject = NPObjectWrapper::getUnderlyingNPObject(npObject); if (!actualObject) return false; npObject = actualObject; } v8::HandleScope handleScope; v8::Handle<v8::Context> context = toV8Context(npp, npObject); if (context.IsEmpty()) return false; v8::Context::Scope scope(context); ExceptionCatcher exceptionCatcher; // FIXME: Is this branch still needed after switching to using UserGestureIndicator? String filename; if (!popupsAllowed) filename = "npscript"; V8NPObject* v8NpObject = reinterpret_cast<V8NPObject*>(npObject); Frame* frame = v8NpObject->rootObject->frame(); ASSERT(frame); String script = String::fromUTF8(npScript->UTF8Characters, npScript->UTF8Length); UserGestureIndicator gestureIndicator(popupsAllowed ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture); v8::Local<v8::Value> v8result = frame->script()->compileAndRunScript(ScriptSourceCode(script, KURL(ParsedURLString, filename))); if (v8result.IsEmpty()) return false; if (_NPN_IsAlive(npObject)) convertV8ObjectToNPVariant(v8result, npObject, result); return true; }
WebString WebPluginContainerImpl::executeScriptURL(const WebURL& url, bool popupsAllowed) { Frame* frame = m_element->document()->frame(); if (!frame) return WebString(); const KURL& kurl = url; ASSERT(kurl.protocolIs("javascript")); String script = decodeURLEscapeSequences( kurl.string().substring(strlen("javascript:"))); ScriptValue result = frame->script()->executeScript(script, popupsAllowed); // Failure is reported as a null string. String resultStr; result.getString(resultStr); return resultStr; }
void WebMediaPlayerProxy::invokeMethod(const String& methodName) { Frame* frame = element()->document()->frame(); RootObject *root = frame->script()->bindingRootObject(); if (!root) return; ExecState *exec = root->globalObject()->globalExec(); Instance* instance = pluginInstance().get(); if (!instance) return; instance->begin(); Class *aClass = instance->getClass(); Identifier iden(exec, methodName); MethodList methodList = aClass->methodsNamed(iden, instance); ArgList args; instance->invokeMethod(exec, methodList , args); instance->end(); }
bool handleOutOfMemory() { v8::Local<v8::Context> context = v8::Isolate::GetCurrent()->GetCurrentContext(); if (!context->HasOutOfMemoryException()) return false; // Warning, error, disable JS for this frame? Frame* frame = toFrameIfNotDetached(context); if (!frame) return true; frame->script().clearForOutOfMemory(); frame->loader().client()->didExhaustMemoryAvailableForScript(); if (Settings* settings = frame->settings()) settings->setScriptEnabled(false); return true; }
bool SubframeLoader::requestFrame(HTMLFrameOwnerElement& ownerElement, const String& urlString, const AtomicString& frameName, bool lockHistory, bool lockBackForwardList) { // Support for <frame src="javascript:string"> URL scriptURL; URL url; if (protocolIsJavaScript(urlString)) { scriptURL = completeURL(urlString); // completeURL() encodes the URL. url = blankURL(); } else url = completeURL(urlString); Frame* frame = loadOrRedirectSubframe(ownerElement, url, frameName, lockHistory, lockBackForwardList); if (!frame) return false; if (!scriptURL.isEmpty()) frame->script().executeIfJavaScriptURL(scriptURL); return true; }
void CachedFrame::restore() { ASSERT(m_document->view() == m_view); Frame* frame = m_view->frame(); m_cachedFrameScriptData->restore(frame); #if ENABLE(SVG) if (m_document->svgExtensions()) m_document->accessSVGExtensions()->unpauseAnimations(); #endif frame->animation()->resumeAnimations(m_document.get()); frame->eventHandler()->setMousePressNode(mousePressNode()); m_document->resumeActiveDOMObjects(); // It is necessary to update any platform script objects after restoring the // cached page. frame->script()->updatePlatformScriptObjects(); }
bool _NPN_EvaluateHelper(NPP npp, bool popupsAllowed, NPObject* npObject, NPString* npScript, NPVariant* result) { VOID_TO_NPVARIANT(*result); if (!npObject) return false; V8NPObject* v8NpObject = npObjectToV8NPObject(npObject); if (!v8NpObject) return false; v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope handleScope(isolate); v8::Handle<v8::Context> context = toV8Context(npp, npObject); if (context.IsEmpty()) return false; v8::Context::Scope scope(context); ExceptionCatcher exceptionCatcher; // FIXME: Is this branch still needed after switching to using UserGestureIndicator? String filename; if (!popupsAllowed) filename = "npscript"; Frame* frame = v8NpObject->rootObject->frame(); ASSERT(frame); String script = String::fromUTF8(npScript->UTF8Characters, npScript->UTF8Length); UserGestureIndicator gestureIndicator(popupsAllowed ? DefinitelyProcessingNewUserGesture : PossiblyProcessingUserGesture); v8::Local<v8::Value> v8result = frame->script().executeScriptAndReturnValue(context, ScriptSourceCode(script, KURL(ParsedURLString, filename))); if (v8result.IsEmpty()) return false; if (_NPN_IsAlive(npObject)) convertV8ObjectToNPVariant(v8result, npObject, result, isolate); return true; }
void CachedPage::restore(Page* page) { ASSERT(m_document->view() == m_view); Frame* mainFrame = page->mainFrame(); JSLock lock(false); ScriptController* proxy = mainFrame->script(); if (proxy->haveWindowShell()) { JSDOMWindowShell* windowShell = proxy->windowShell(); if (m_window) { windowShell->setWindow(m_window.get()); windowShell->window()->resumeTimeouts(m_pausedTimeouts); } else { windowShell->setWindow(mainFrame->domWindow()); proxy->attachDebugger(page->debugger()); windowShell->window()->setProfileGroup(page->group().identifier()); } } #if ENABLE(SVG) if (m_document && m_document->svgExtensions()) m_document->accessSVGExtensions()->unpauseAnimations(); #endif mainFrame->animation()->resumeAnimations(m_document.get()); mainFrame->eventHandler()->setMousePressNode(mousePressNode()); // Restore the focus appearance for the focused element. // FIXME: Right now we don't support pages w/ frames in the b/f cache. This may need to be tweaked when we add support for that. Document* focusedDocument = page->focusController()->focusedOrMainFrame()->document(); if (Node* node = focusedDocument->focusedNode()) { if (node->isElementNode()) static_cast<Element*>(node)->updateFocusAppearance(true); } }
void ReplayController::unloadSegment(bool suppressNotifications) { ASSERT(m_sessionState != SessionState::Inactive); ASSERT(m_segmentState == SegmentState::Loaded || m_segmentState == SegmentState::Appending); setSegmentState(SegmentState::Unloaded); LOG(WebReplay, "%-20s Clearing input cursors for page: %p\n", "ReplayController", &m_page); m_activeCursor = nullptr; RefPtr<ReplaySessionSegment> unloadedSegment = m_loadedSegment.release(); for (Frame* frame = &m_page.mainFrame(); frame; frame = frame->tree().traverseNext()) { frame->script().globalObject(mainThreadNormalWorld())->setInputCursor(m_emptyCursor.copyRef()); frame->document()->setInputCursor(m_emptyCursor.copyRef()); } // When we stop capturing, don't send out segment unloaded events since we // didn't send out the corresponding segmentLoaded event at the start of capture. if (!suppressNotifications) { LOG(WebReplay, "%-20sUnloading segment: %p.\n", "ReplayController", unloadedSegment.get()); InspectorInstrumentation::segmentUnloaded(m_page); } }
PassScriptInstance HTMLPlugInElement::getInstance() const { Frame* frame = document()->frame(); if (!frame) return 0; // If the host dynamically turns off JavaScript (or Java) we will still return // the cached allocated Bindings::Instance. Not supporting this edge-case is OK. if (m_instance) return m_instance; if (m_inBeforeLoadEventHandler) { // The plug-in hasn't loaded yet, and it makes no sense to try to load if beforeload handler happened to touch the plug-in element. // That would recursively call beforeload for the same element. return 0; } RenderWidget* renderWidget = renderWidgetForJSBindings(); if (renderWidget && renderWidget->widget()) m_instance = frame->script()->createScriptInstanceForWidget(renderWidget->widget()); return m_instance; }
void V8Window::eventAttributeGetterCustom(const v8::PropertyCallbackInfo<v8::Value>& info) { v8::Handle<v8::Object> 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<v8::Context> context = frame->script().currentWorldContext(); if (context.IsEmpty()) return; v8::Handle<v8::String> eventSymbol = V8HiddenPropertyName::event(info.GetIsolate()); v8::Handle<v8::Value> jsEvent = context->Global()->GetHiddenValue(eventSymbol); if (jsEvent.IsEmpty()) return; v8SetReturnValue(info, jsEvent); }
void V8Custom::WindowSetLocation(DOMWindow* window, const String& v) { if (!window->frame()) return; Frame* activeFrame = V8Proxy::retrieveFrameForEnteredContext(); if (!activeFrame) return; if (!activeFrame->loader()->shouldAllowNavigation(window->frame())) return; if (!parseURL(v).startsWith("javascript:", false) || ScriptController::isSafeScript(window->frame())) { String completedUrl = activeFrame->loader()->completeURL(v).string(); // FIXME: The JSC bindings pass !anyPageIsProcessingUserGesture() for // the lockHistory parameter. We should probably do something similar. window->frame()->loader()->scheduleLocationChange(completedUrl, activeFrame->loader()->outgoingReferrer(), false, false, activeFrame->script()->processingUserGesture()); } }
void JSAbstractEventListener::handleEvent(Event* event, bool isWindowEvent) { JSObject* listener = listenerObj(); if (!listener) return; JSDOMWindow* window = this->window(); // Null check as clearWindow() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 if (!window) return; Frame* frame = window->impl()->frame(); if (!frame) return; ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; JSLock lock(false); ExecState* exec = window->globalExec(); JSValue* handleEventFunction = listener->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction->getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = 0; callType = listener->getCallData(callData); } if (callType != CallTypeNone) { ref(); ArgList args; args.append(toJS(exec, event)); Event* savedEvent = window->currentEvent(); window->setCurrentEvent(event); JSValue* retval; if (handleEventFunction) { window->startTimeoutCheck(); retval = call(exec, handleEventFunction, callType, callData, listener, args); } else { JSValue* thisValue; if (isWindowEvent) thisValue = window->shell(); else thisValue = toJS(exec, event->currentTarget()); window->startTimeoutCheck(); retval = call(exec, listener, callType, callData, thisValue, args); } window->stopTimeoutCheck(); window->setCurrentEvent(savedEvent); if (exec->hadException()) frame->domWindow()->console()->reportCurrentException(exec); else { if (!retval->isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval->toString(exec)); if (m_isHTML) { bool retvalbool; if (retval->getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } Document::updateDocumentsRendering(); deref(); } }
bool _NPN_Invoke(NPP npp, NPObject* npObject, NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result) { if (!npObject) return false; v8::Isolate* isolate = v8::Isolate::GetCurrent(); V8NPObject* v8NpObject = npObjectToV8NPObject(npObject); if (!v8NpObject) { if (npObject->_class->invoke) return npObject->_class->invoke(npObject, methodName, arguments, argumentCount, result); VOID_TO_NPVARIANT(*result); return true; } PrivateIdentifier* identifier = static_cast<PrivateIdentifier*>(methodName); if (!identifier->isString) return false; if (!strcmp(identifier->value.string, "eval")) { if (argumentCount != 1) return false; if (arguments[0].type != NPVariantType_String) return false; return _NPN_Evaluate(npp, npObject, const_cast<NPString*>(&arguments[0].value.stringValue), result); } v8::HandleScope handleScope(isolate); // FIXME: should use the plugin's owner frame as the security context. v8::Handle<v8::Context> context = toV8Context(npp, npObject); if (context.IsEmpty()) return false; v8::Context::Scope scope(context); ExceptionCatcher exceptionCatcher; v8::Handle<v8::Object> v8Object = v8::Local<v8::Object>::New(isolate, v8NpObject->v8Object); v8::Handle<v8::Value> functionObject = v8Object->Get(v8::String::NewSymbol(identifier->value.string)); if (functionObject.IsEmpty() || functionObject->IsNull()) { NULL_TO_NPVARIANT(*result); return false; } if (functionObject->IsUndefined()) { VOID_TO_NPVARIANT(*result); return false; } Frame* frame = v8NpObject->rootObject->frame(); ASSERT(frame); // Call the function object. v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(functionObject); OwnPtr<v8::Handle<v8::Value>[]> argv = createValueListFromVariantArgs(arguments, argumentCount, npObject, isolate); v8::Local<v8::Value> resultObject = frame->script().callFunction(function, v8Object, argumentCount, argv.get()); // If we had an error, return false. The spec is a little unclear here, but says "Returns true if the method was // successfully invoked". If we get an error return value, was that successfully invoked? if (resultObject.IsEmpty()) return false; convertV8ObjectToNPVariant(resultObject, npObject, result, isolate); return true; }
void V8LazyEventListener::prepareListenerObject(ScriptExecutionContext* context) { if (hasExistingListenerObject()) return; if (context->isDocument() && !static_cast<Document*>(context)->contentSecurityPolicy()->allowInlineEventHandlers(m_sourceURL, m_position.m_line)) return; v8::HandleScope handleScope; ASSERT(context->isDocument()); Frame* frame = static_cast<Document*>(context)->frame(); ASSERT(frame); if (!frame->script()->canExecuteScripts(NotAboutToExecuteScript)) return; // Use the outer scope to hold context. v8::Local<v8::Context> v8Context = toV8Context(context, worldContext()); // Bail out if we cannot get the context. if (v8Context.IsEmpty()) return; v8::Context::Scope scope(v8Context); // Nodes other than the document object, when executing inline event // handlers push document, form, and the target node on the scope chain. // We do this by using 'with' statement. // See chrome/fast/forms/form-action.html // chrome/fast/forms/selected-index-value.html // base/fast/overflow/onscroll-layer-self-destruct.html // // Don't use new lines so that lines in the modified handler // have the same numbers as in the original code. // FIXME: V8 does not allow us to programmatically create object environments so // we have to do this hack! What if m_code escapes to run arbitrary script? // // Call with 4 arguments instead of 3, pass additional null as the last parameter. // By calling the function with 4 arguments, we create a setter on arguments object // which would shadow property "3" on the prototype. String code = "(function() {" "with (this[2]) {" "with (this[1]) {" "with (this[0]) {" "return function(" + m_eventParameterName + ") {" + m_code + "\n" // Insert '\n' otherwise //-style comments could break the handler. "};" "}}}})"; v8::Handle<v8::String> codeExternalString = v8ExternalString(code); v8::Handle<v8::Script> script = ScriptSourceCode::compileScript(codeExternalString, m_sourceURL, m_position); if (script.IsEmpty()) return; // FIXME: Remove this code when we stop doing the 'with' hack above. v8::Local<v8::Value> value; { V8RecursionScope::MicrotaskSuppression scope; value = script->Run(); } if (value.IsEmpty()) return; // Call the outer function to get the inner function. ASSERT(value->IsFunction()); v8::Local<v8::Function> intermediateFunction = value.As<v8::Function>(); HTMLFormElement* formElement = 0; if (m_node && m_node->isHTMLElement()) formElement = static_cast<HTMLElement*>(m_node)->form(); v8::Handle<v8::Object> nodeWrapper = toObjectWrapper<Node>(m_node); v8::Handle<v8::Object> formWrapper = toObjectWrapper<HTMLFormElement>(formElement); v8::Handle<v8::Object> documentWrapper = toObjectWrapper<Document>(m_node ? m_node->ownerDocument() : 0); v8::Local<v8::Object> thisObject = v8::Object::New(); if (thisObject.IsEmpty()) return; if (!thisObject->ForceSet(v8UnsignedInteger(0), nodeWrapper)) return; if (!thisObject->ForceSet(v8UnsignedInteger(1), formWrapper)) return; if (!thisObject->ForceSet(v8UnsignedInteger(2), documentWrapper)) return; // FIXME: Remove this code when we stop doing the 'with' hack above. v8::Local<v8::Value> innerValue; { V8RecursionScope::MicrotaskSuppression scope; innerValue = intermediateFunction->Call(thisObject, 0, 0); } if (innerValue.IsEmpty() || !innerValue->IsFunction()) return; v8::Local<v8::Function> wrappedFunction = innerValue.As<v8::Function>(); // Change the toString function on the wrapper function to avoid it // returning the source for the actual wrapper function. Instead it // returns source for a clean wrapper function with the event // argument wrapping the event source code. The reason for this is // that some web sites use toString on event functions and eval the // source returned (sometimes a RegExp is applied as well) for some // other use. That fails miserably if the actual wrapper source is // returned. v8::Persistent<v8::FunctionTemplate>& toStringTemplate = V8PerIsolateData::current()->lazyEventListenerToStringTemplate(); if (toStringTemplate.IsEmpty()) toStringTemplate = v8::Persistent<v8::FunctionTemplate>::New(v8::FunctionTemplate::New(V8LazyEventListenerToString)); v8::Local<v8::Function> toStringFunction; if (!toStringTemplate.IsEmpty()) toStringFunction = toStringTemplate->GetFunction(); if (!toStringFunction.IsEmpty()) { String toStringString = "function " + m_functionName + "(" + m_eventParameterName + ") {\n " + m_code + "\n}"; wrappedFunction->SetHiddenValue(V8HiddenPropertyName::toStringString(), v8ExternalString(toStringString)); wrappedFunction->Set(v8::String::NewSymbol("toString"), toStringFunction); } wrappedFunction->SetName(v8String(m_functionName)); // FIXME: Remove the following comment-outs. // See https://bugs.webkit.org/show_bug.cgi?id=85152 for more details. // // For the time being, we comment out the following code since the // second parsing can happen. // // Since we only parse once, there's no need to keep data used for parsing around anymore. // m_functionName = String(); // m_code = String(); // m_eventParameterName = String(); // m_sourceURL = String(); setListenerObject(wrappedFunction); }
JSValuePtr windowProtoFuncOpen(ExecState* exec, JSObject*, JSValuePtr thisValue, const ArgList& args) { JSDOMWindow* window = toJSDOMWindow(thisValue); if (!window) return throwError(exec, TypeError); if (!window->allowsAccessFrom(exec)) return jsUndefined(); Frame* frame = window->impl()->frame(); if (!frame) return jsUndefined(); Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); if (!activeFrame) return jsUndefined(); Page* page = frame->page(); String urlString = valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 0)); AtomicString frameName = args.at(exec, 1)->isUndefinedOrNull() ? "_blank" : AtomicString(args.at(exec, 1)->toString(exec)); // Because FrameTree::find() returns true for empty strings, we must check for empty framenames. // Otherwise, illegitimate window.open() calls with no name will pass right through the popup blocker. if (!allowPopUp(exec) && (frameName.isEmpty() || !frame->tree()->find(frameName))) return jsUndefined(); // Get the target frame for the special cases of _top and _parent. In those // cases, we can schedule a location change right now and return early. bool topOrParent = false; if (frameName == "_top") { frame = frame->tree()->top(); topOrParent = true; } else if (frameName == "_parent") { if (Frame* parent = frame->tree()->parent()) frame = parent; topOrParent = true; } if (topOrParent) { if (!activeFrame->loader()->shouldAllowNavigation(frame)) return jsUndefined(); String completedURL; if (!urlString.isEmpty()) completedURL = activeFrame->document()->completeURL(urlString).string(); const JSDOMWindow* targetedWindow = toJSDOMWindow(frame); if (!completedURL.isEmpty() && (!protocolIs(completedURL, "javascript") || (targetedWindow && targetedWindow->allowsAccessFrom(exec)))) { bool userGesture = activeFrame->script()->processingUserGesture(); frame->loader()->scheduleLocationChange(completedURL, activeFrame->loader()->outgoingReferrer(), false, userGesture); } return toJS(exec, frame->domWindow()); } // In the case of a named frame or a new window, we'll use the createWindow() helper WindowFeatures windowFeatures(valueToStringWithUndefinedOrNullCheck(exec, args.at(exec, 2))); FloatRect windowRect(windowFeatures.xSet ? windowFeatures.x : 0, windowFeatures.ySet ? windowFeatures.y : 0, windowFeatures.widthSet ? windowFeatures.width : 0, windowFeatures.heightSet ? windowFeatures.height : 0); DOMWindow::adjustWindowRect(screenAvailableRect(page ? page->mainFrame()->view() : 0), windowRect, windowRect); windowFeatures.x = windowRect.x(); windowFeatures.y = windowRect.y(); windowFeatures.height = windowRect.height(); windowFeatures.width = windowRect.width(); frame = createWindow(exec, frame, urlString, frameName, windowFeatures, noValue()); if (!frame) return jsUndefined(); return toJS(exec, frame->domWindow()); // global object }
JSValue JSLocation::assign(ExecState* exec, const ArgList& args) { Frame* frame = impl()->frame(); if (!frame) return jsUndefined(); Frame* activeFrame = asJSDOMWindow(exec->dynamicGlobalObject())->impl()->frame(); if (!activeFrame) return jsUndefined(); if (!activeFrame->loader()->shouldAllowNavigation(frame)) return jsUndefined(); // We want a new history item if this JS was called via a user gesture navigateIfAllowed(exec, frame, activeFrame->loader()->completeURL(args.at(0).toString(exec)), !frame->script()->anyPageIsProcessingUserGesture(), false); return jsUndefined(); }