void WorkerThreadableWebSocketChannel::Bridge::mainThreadInitialize(ScriptExecutionContext& context, WorkerLoaderProxy* loaderProxy, PassRefPtr<ThreadableWebSocketChannelClientWrapper> prpClientWrapper, const String& taskMode) { ASSERT(isMainThread()); ASSERT_UNUSED(context, context.isDocument()); RefPtr<ThreadableWebSocketChannelClientWrapper> clientWrapper = prpClientWrapper; Peer* peerPtr = Peer::create(clientWrapper, *loaderProxy, &context, taskMode); bool sent = loaderProxy->postTaskForModeToWorkerGlobalScope({ ScriptExecutionContext::Task::CleanupTask, [clientWrapper, loaderProxy, peerPtr] (ScriptExecutionContext& context) { ASSERT_UNUSED(context, context.isWorkerGlobalScope()); if (clientWrapper->failedWebSocketChannelCreation()) { // If Bridge::initialize() quitted earlier, we need to kick mainThreadDestroy() to delete the peer. loaderProxy->postTaskToLoader([peerPtr] (ScriptExecutionContext& context) { ASSERT(isMainThread()); ASSERT_UNUSED(context, context.isDocument()); delete peerPtr; }); } else clientWrapper->didCreateWebSocketChannel(peerPtr); } }, taskMode); if (!sent) { clientWrapper->clearPeer(); delete peerPtr; } }
PassRefPtr<EventSource> EventSource::create(ScriptExecutionContext& context, const String& url, const Dictionary& eventSourceInit, ExceptionCode& ec) { if (url.isEmpty()) { ec = SYNTAX_ERR; return 0; } URL fullURL = context.completeURL(url); if (!fullURL.isValid()) { ec = SYNTAX_ERR; return 0; } // FIXME: Convert this to check the isolated world's Content Security Policy once webkit.org/b/104520 is solved. bool shouldBypassMainWorldContentSecurityPolicy = false; if (context.isDocument()) { Document& document = toDocument(context); shouldBypassMainWorldContentSecurityPolicy = document.frame()->script().shouldBypassMainWorldContentSecurityPolicy(); } if (!shouldBypassMainWorldContentSecurityPolicy && !context.contentSecurityPolicy()->allowConnectToSource(fullURL)) { // FIXME: Should this be throwing an exception? ec = SECURITY_ERR; return 0; } RefPtr<EventSource> source = adoptRef(new EventSource(context, fullURL, eventSourceInit)); source->setPendingActivity(source.get()); source->scheduleInitialConnect(); source->suspendIfNeeded(); return source.release(); }
void reportException(ScriptState* scriptState, v8::TryCatch& exceptionCatcher) { String errorMessage; int lineNumber = 0; String sourceURL; // There can be a situation that an exception is thrown without setting a message. v8::Local<v8::Message> message = exceptionCatcher.Message(); if (message.IsEmpty()) { v8::Local<v8::String> exceptionString = exceptionCatcher.Exception()->ToString(); // Conversion of the exception object to string can fail if an // exception is thrown during conversion. if (!exceptionString.IsEmpty()) errorMessage = toWebCoreString(exceptionString); } else { errorMessage = toWebCoreString(message->Get()); lineNumber = message->GetLineNumber(); sourceURL = toWebCoreString(message->GetScriptResourceName()); } // Do not report the exception if the current execution context is Document because we do not want to lead to duplicate error messages in the console. // FIXME (31171): need better design to solve the duplicate error message reporting problem. ScriptExecutionContext* context = getScriptExecutionContext(scriptState); // During the frame teardown, there may not be a valid context. if (context && !context->isDocument()) context->reportException(errorMessage, lineNumber, sourceURL); exceptionCatcher.Reset(); }
RefPtr<Worker> Worker::create(ScriptExecutionContext& context, const String& url, ExceptionCode& ec) { ASSERT(isMainThread()); // We don't currently support nested workers, so workers can only be created from documents. ASSERT_WITH_SECURITY_IMPLICATION(context.isDocument()); Ref<Worker> worker = adoptRef(*new Worker(context)); worker->suspendIfNeeded(); bool shouldBypassMainWorldContentSecurityPolicy = context.shouldBypassMainWorldContentSecurityPolicy(); URL scriptURL = worker->resolveURL(url, shouldBypassMainWorldContentSecurityPolicy, ec); if (scriptURL.isEmpty()) return nullptr; worker->m_shouldBypassMainWorldContentSecurityPolicy = shouldBypassMainWorldContentSecurityPolicy; // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners. worker->setPendingActivity(worker.ptr()); worker->m_scriptLoader = WorkerScriptLoader::create(); auto contentSecurityPolicyEnforcement = shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceChildSrcDirective; worker->m_scriptLoader->loadAsynchronously(&context, scriptURL, DenyCrossOriginRequests, contentSecurityPolicyEnforcement, worker.ptr()); return WTFMove(worker); }
PassRefPtr<Worker> Worker::create(ScriptExecutionContext& context, const String& url, ExceptionCode& ec) { ASSERT(isMainThread()); // We don't currently support nested workers, so workers can only be created from documents. ASSERT_WITH_SECURITY_IMPLICATION(context.isDocument()); Document& document = static_cast<Document&>(context); FeatureObserver::observe(document.domWindow(), FeatureObserver::WorkerStart); RefPtr<Worker> worker = adoptRef(new Worker(context)); worker->suspendIfNeeded(); URL scriptURL = worker->resolveURL(url, ec); if (scriptURL.isEmpty()) return 0; // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners. worker->setPendingActivity(worker.get()); worker->m_scriptLoader = WorkerScriptLoader::create(); worker->m_scriptLoader->loadAsynchronously(&context, scriptURL, DenyCrossOriginRequests, worker.get()); return worker.release(); }
ExceptionOr<Ref<Worker>> Worker::create(ScriptExecutionContext& context, const String& url, JSC::RuntimeFlags runtimeFlags) { ASSERT(isMainThread()); // We don't currently support nested workers, so workers can only be created from documents. ASSERT_WITH_SECURITY_IMPLICATION(context.isDocument()); auto worker = adoptRef(*new Worker(context, runtimeFlags)); worker->suspendIfNeeded(); bool shouldBypassMainWorldContentSecurityPolicy = context.shouldBypassMainWorldContentSecurityPolicy(); auto scriptURL = worker->resolveURL(url, shouldBypassMainWorldContentSecurityPolicy); if (scriptURL.hasException()) return scriptURL.releaseException(); worker->m_shouldBypassMainWorldContentSecurityPolicy = shouldBypassMainWorldContentSecurityPolicy; // The worker context does not exist while loading, so we must ensure that the worker object is not collected, nor are its event listeners. worker->setPendingActivity(worker.ptr()); worker->m_scriptLoader = WorkerScriptLoader::create(); auto contentSecurityPolicyEnforcement = shouldBypassMainWorldContentSecurityPolicy ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceChildSrcDirective; worker->m_scriptLoader->loadAsynchronously(&context, scriptURL.releaseReturnValue(), FetchOptions::Mode::SameOrigin, contentSecurityPolicyEnforcement, worker->m_identifier, worker.ptr()); return WTFMove(worker); }
EncodedJSValue JSC_HOST_CALL JSAudioContextConstructor::constructJSAudioContext(ExecState* exec) { JSAudioContextConstructor* jsConstructor = jsCast<JSAudioContextConstructor*>(exec->callee()); if (!jsConstructor) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor callee is unavailable")); ScriptExecutionContext* scriptExecutionContext = jsConstructor->scriptExecutionContext(); if (!scriptExecutionContext) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor script execution context is unavailable")); if (!scriptExecutionContext->isDocument()) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor called in a script execution context which is not a document")); Document* document = static_cast<Document*>(scriptExecutionContext); RefPtr<AudioContext> audioContext; if (!exec->argumentCount()) { // Constructor for default AudioContext which talks to audio hardware. ExceptionCode ec = 0; audioContext = AudioContext::create(document, ec); if (ec) { setDOMException(exec, ec); return JSValue::encode(JSValue()); } if (!audioContext.get()) return throwVMError(exec, createSyntaxError(exec, "audio resources unavailable for AudioContext construction")); } else { // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); if (exec->argumentCount() < 3) return throwVMError(exec, createNotEnoughArgumentsError(exec)); int32_t numberOfChannels = exec->argument(0).toInt32(exec); int32_t numberOfFrames = exec->argument(1).toInt32(exec); float sampleRate = exec->argument(2).toFloat(exec); if (numberOfChannels <= 0 || numberOfChannels > 10) return throwVMError(exec, createSyntaxError(exec, "Invalid number of channels")); if (numberOfFrames <= 0) return throwVMError(exec, createSyntaxError(exec, "Invalid number of frames")); if (sampleRate <= 0) return throwVMError(exec, createSyntaxError(exec, "Invalid sample rate")); ExceptionCode ec = 0; audioContext = AudioContext::createOfflineContext(document, numberOfChannels, numberOfFrames, sampleRate, ec); if (ec) { setDOMException(exec, ec); return throwVMError(exec, createSyntaxError(exec, "Error creating OfflineAudioContext")); } } if (!audioContext.get()) return throwVMError(exec, createReferenceError(exec, "Error creating AudioContext")); return JSValue::encode(CREATE_DOM_WRAPPER(exec, jsConstructor->globalObject(), AudioContext, audioContext.get())); }
void InspectorTimelineAgent::breakpointActionProbe(JSC::ExecState* exec, const Inspector::ScriptBreakpointAction& action, int hitCount, const Deprecated::ScriptValue&) { ASSERT(exec); ScriptExecutionContext* context = scriptExecutionContextFromExecState(exec); Document* document = (context && context->isDocument()) ? toDocument(context) : nullptr; Frame* frame = document ? document->frame() : nullptr; appendRecord(TimelineRecordFactory::createProbeSampleData(action, hitCount), TimelineRecordType::ProbeSample, false, frame); }
void injectInternalsObject(v8::Local<v8::Context> context) { v8::Context::Scope contextScope(context); v8::HandleScope scope; ScriptExecutionContext* scriptContext = getScriptExecutionContext(); if (scriptContext->isDocument()) context->Global()->Set(v8::String::New(Internals::internalsId), toV8(Internals::create(static_cast<Document*>(scriptContext)))); }
void resetInternalsObject(JSContextRef context) { JSLock lock(SilenceAssertionsOnly); ExecState* exec = toJS(context); JSDOMGlobalObject* globalObject = static_cast<JSDOMGlobalObject*>(exec->lexicalGlobalObject()); Internals * internals = toInternals(globalObject->getDirect(exec->globalData(), Identifier(exec, Internals::internalsId))); if (internals) { ScriptExecutionContext* scriptContext = globalObject->scriptExecutionContext(); if (scriptContext->isDocument()) internals->reset(static_cast<Document*>(scriptContext)); } }
MessagePort* MessagePortChannel::locallyEntangledPort(const ScriptExecutionContext* context) { LockHolder lock(m_channel->m_mutex); // See if both contexts are run by the same thread (are the same context, or are both documents). if (m_channel->m_remotePort) { // The remote port's ScriptExecutionContext is guaranteed not to change here - MessagePort::contextDestroyed() // will close the port before the context goes away, and close() will block because we are holding the mutex. ScriptExecutionContext* remoteContext = m_channel->m_remotePort->scriptExecutionContext(); if (remoteContext == context || (remoteContext && remoteContext->isDocument() && context->isDocument())) return m_channel->m_remotePort; } return 0; }
void WorkerThreadableWebSocketChannel::Bridge::mainThreadInitialize(ScriptExecutionContext& context, WorkerLoaderProxy& loaderProxy, Ref<ThreadableWebSocketChannelClientWrapper>&& clientWrapper, const String& taskMode) { ASSERT(isMainThread()); ASSERT(context.isDocument()); bool sent = loaderProxy.postTaskForModeToWorkerGlobalScope({ ScriptExecutionContext::Task::CleanupTask, [clientWrapper = clientWrapper.copyRef(), &loaderProxy, peer = std::make_unique<Peer>(clientWrapper.copyRef(), loaderProxy, context, taskMode)](ScriptExecutionContext& context) mutable { ASSERT_UNUSED(context, context.isWorkerGlobalScope()); if (clientWrapper->failedWebSocketChannelCreation()) { // If Bridge::initialize() quitted earlier, we need to kick mainThreadDestroy() to delete the peer. loaderProxy.postTaskToLoader([peer = WTFMove(peer)](ScriptExecutionContext& context) { ASSERT(isMainThread()); ASSERT_UNUSED(context, context.isDocument()); }); } else clientWrapper->didCreateWebSocketChannel(peer.release()); } }, taskMode); if (!sent) clientWrapper->clearPeer(); }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { Ref<EventTarget> protect(*this); // Fire all listeners registered for this event. Don't fire listeners removed during event dispatch. // Also, don't fire event listeners added during event dispatch. Conveniently, all new event listeners will be added // after or at index |size|, so iterating up to (but not including) |size| naturally excludes new event listeners. bool userEventWasHandled = false; size_t i = 0; size_t size = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = std::make_unique<FiringEventIteratorVector>(); d->firingEventIterators->append(FiringEventIterator(event->type(), i, size)); ScriptExecutionContext* context = scriptExecutionContext(); Document* document = nullptr; InspectorInstrumentationCookie willDispatchEventCookie; if (context && context->isDocument()) { document = toDocument(context); willDispatchEventCookie = InspectorInstrumentation::willDispatchEvent(document, *event, size > 0); } for (; i < size; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); if (!userEventWasHandled && ScriptController::processingUserGesture()) userEventWasHandled = true; InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); if (userEventWasHandled && document) document->resetLastHandledUserGestureTimestamp(); if (document) InspectorInstrumentation::didDispatchEvent(willDispatchEventCookie); }
void resetInternalsObject(v8::Local<v8::Context> context) { // This can happen if JavaScript is disabled in the main frame. if (context.IsEmpty()) return; v8::Context::Scope contextScope(context); v8::HandleScope scope; ScriptExecutionContext* scriptContext = getScriptExecutionContext(); ASSERT(scriptContext->isDocument()); Page* page = static_cast<Document*>(scriptContext)->frame()->page(); Internals::resetToConsistentState(page); InternalSettings::from(page)->resetToConsistentState(); }
v8::Handle<v8::Value> V8XMLHttpRequest::constructorCustom(const v8::Arguments& args) { ScriptExecutionContext* context = getScriptExecutionContext(); RefPtr<SecurityOrigin> securityOrigin; if (context->isDocument()) { if (DOMWrapperWorld* world = isolatedWorldForEnteredContext()) securityOrigin = world->isolatedWorldSecurityOrigin(); } RefPtr<XMLHttpRequest> xmlHttpRequest = XMLHttpRequest::create(context, securityOrigin); v8::Handle<v8::Object> wrapper = args.Holder(); V8DOMWrapper::associateObjectWithWrapper(xmlHttpRequest.release(), &info, wrapper, args.GetIsolate(), WrapperConfiguration::Dependent); return wrapper; }
void EventTarget::setupLegacyTypeObserverIfNeeded(const AtomicString& legacyTypeName, bool hasLegacyTypeListeners, bool hasNewTypeListeners) { ASSERT(!legacyTypeName.isEmpty()); ASSERT(hasLegacyTypeListeners || hasNewTypeListeners); ScriptExecutionContext* context = scriptExecutionContext(); if (!context || !context->isDocument()) return; Document* document = toDocument(context); if (!document->domWindow()) return; FeatureObserver::Feature feature; if (shouldObserveLegacyType(legacyTypeName, hasLegacyTypeListeners, hasNewTypeListeners, feature)) FeatureObserver::observe(document->domWindow(), feature); }
void EventTarget::fireEventListeners(Event* event, EventTargetData* d, EventListenerVector& entry) { RefPtr<EventTarget> protect = this; // Fire all listeners registered for this event. Don't fire listeners removed // during event dispatch. Also, don't fire event listeners added during event // dispatch. Conveniently, all new event listeners will be added after 'end', // so iterating to 'end' naturally excludes new event listeners. bool userEventWasHandled = false; size_t i = 0; size_t end = entry.size(); if (!d->firingEventIterators) d->firingEventIterators = adoptPtr(new FiringEventIteratorVector); d->firingEventIterators->append(FiringEventIterator(event->type(), i, end)); for ( ; i < end; ++i) { RegisteredEventListener& registeredListener = entry[i]; if (event->eventPhase() == Event::CAPTURING_PHASE && !registeredListener.useCapture) continue; if (event->eventPhase() == Event::BUBBLING_PHASE && registeredListener.useCapture) continue; // If stopImmediatePropagation has been called, we just break out immediately, without // handling any more events on this target. if (event->immediatePropagationStopped()) break; ScriptExecutionContext* context = scriptExecutionContext(); InspectorInstrumentationCookie cookie = InspectorInstrumentation::willHandleEvent(context, event); // To match Mozilla, the AT_TARGET phase fires both capturing and bubbling // event listeners, even though that violates some versions of the DOM spec. registeredListener.listener->handleEvent(context, event); if (!userEventWasHandled && ScriptController::processingUserGesture()) userEventWasHandled = true; InspectorInstrumentation::didHandleEvent(cookie); } d->firingEventIterators->removeLast(); if (userEventWasHandled) { ScriptExecutionContext* context = scriptExecutionContext(); if (context && context->isDocument()) { Document* document = toDocument(context); document->resetLastHandledUserGestureTimestamp(); } } }
void JSMutationCallback::call(const Vector<RefPtr<MutationRecord> >& mutations, MutationObserver* observer) { if (!canInvokeCallback()) return; RefPtr<JSMutationCallback> protect(this); JSLockHolder lock(m_isolatedWorld->globalData()); if (!m_callback) return; JSValue callback = m_callback.get(); CallData callData; CallType callType = getCallData(callback, callData); if (callType == CallTypeNone) { ASSERT_NOT_REACHED(); return; } ScriptExecutionContext* context = scriptExecutionContext(); if (!context) return; ASSERT(context->isDocument()); JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, m_isolatedWorld.get()); ExecState* exec = globalObject->globalExec(); JSValue jsObserver = toJS(exec, globalObject, observer); MarkedArgumentBuffer args; args.append(jsArray(exec, globalObject, mutations)); args.append(jsObserver); globalObject->globalData().timeoutChecker.start(); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); JSMainThreadExecState::call(exec, callback, callType, callData, jsObserver, args); InspectorInstrumentation::didCallFunction(cookie); globalObject->globalData().timeoutChecker.stop(); if (exec->hadException()) reportCurrentException(exec); }
void JSMutationCallback::call(const Vector<RefPtr<MutationRecord>>& mutations, MutationObserver* observer) { if (!canInvokeCallback()) return; Ref<JSMutationCallback> protect(*this); JSLockHolder lock(m_isolatedWorld->vm()); if (!m_callback) return; JSValue callback = m_callback.get(); CallData callData; CallType callType = getCallData(callback, callData); if (callType == CallType::None) { ASSERT_NOT_REACHED(); return; } ScriptExecutionContext* context = scriptExecutionContext(); if (!context) return; ASSERT(context->isDocument()); JSDOMGlobalObject* globalObject = toJSDOMGlobalObject(context, *m_isolatedWorld); ExecState* exec = globalObject->globalExec(); JSValue jsObserver = toJS(exec, globalObject, observer); MarkedArgumentBuffer args; args.append(jsArray(exec, globalObject, mutations)); args.append(jsObserver); InspectorInstrumentationCookie cookie = JSMainThreadExecState::instrumentFunctionCall(context, callType, callData); NakedPtr<Exception> exception; JSMainThreadExecState::profiledCall(exec, JSC::ProfilingReason::Other, callback, callType, callData, jsObserver, args, exception); InspectorInstrumentation::didCallFunction(cookie, context); if (exception) reportException(exec, exception); }
PassRefPtr<OfflineAudioContext> OfflineAudioContext::create(ScriptExecutionContext& context, unsigned numberOfChannels, size_t numberOfFrames, float sampleRate, ExceptionCode& ec) { // FIXME: add support for workers. if (!context.isDocument()) { ec = NOT_SUPPORTED_ERR; return nullptr; } Document& document = toDocument(context); if (numberOfChannels > 10 || !isSampleRateRangeGood(sampleRate)) { ec = SYNTAX_ERR; return nullptr; } RefPtr<OfflineAudioContext> audioContext(adoptRef(new OfflineAudioContext(document, numberOfChannels, numberOfFrames, sampleRate))); audioContext->suspendIfNeeded(); return audioContext.release(); }
JSValue JSCallbackData::invokeCallback(MarkedArgumentBuffer& args, bool* raisedException) { ASSERT(callback()); ASSERT(globalObject()); ExecState* exec = globalObject()->globalExec(); JSValue function = callback()->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = getCallData(function, callData); if (callType == CallTypeNone) { callType = callback()->methodTable()->getCallData(callback(), callData); if (callType == CallTypeNone) return JSValue(); function = callback(); } globalObject()->globalData().timeoutChecker.start(); ScriptExecutionContext* context = globalObject()->scriptExecutionContext(); // We will fail to get the context if the frame has been detached. if (!context) return JSValue(); bool contextIsDocument = context->isDocument(); JSValue result = contextIsDocument ? JSMainThreadExecState::call(exec, function, callType, callData, callback(), args) : JSC::call(exec, function, callType, callData, callback(), args); globalObject()->globalData().timeoutChecker.stop(); if (contextIsDocument) Document::updateStyleForAllDocuments(); if (exec->hadException()) { reportCurrentException(exec); if (raisedException) *raisedException = true; return result; } return result; }
bool EventTarget::fireEventListeners(Event* event) { ASSERT(!NoEventDispatchAssertion::isEventDispatchForbidden()); ASSERT(event && !event->type().isEmpty()); EventTargetData* d = eventTargetData(); if (!d) return true; EventListenerVector* listenerPrefixedVector = 0; AtomicString prefixedTypeName = prefixedType(event); if (!prefixedTypeName.isEmpty()) listenerPrefixedVector = d->eventListenerMap.find(prefixedTypeName); EventListenerVector* listenerUnprefixedVector = d->eventListenerMap.find(event->type()); if (listenerUnprefixedVector) fireEventListeners(event, d, *listenerUnprefixedVector); else if (listenerPrefixedVector) fireEventListeners(createMatchingPrefixedEvent(event).get(), d, *listenerPrefixedVector); if (!prefixedTypeName.isEmpty()) { ScriptExecutionContext* context = scriptExecutionContext(); if (context && context->isDocument()) { Document* document = toDocument(context); if (document->domWindow()) { if (listenerPrefixedVector) if (listenerUnprefixedVector) UseCounter::count(document->domWindow(), UseCounter::PrefixedAndUnprefixedTransitionEndEvent); else UseCounter::count(document->domWindow(), UseCounter::PrefixedTransitionEndEvent); else if (listenerUnprefixedVector) UseCounter::count(document->domWindow(), UseCounter::UnprefixedTransitionEndEvent); } } } return !event->defaultPrevented(); }
void call() { if (!canInvokeCallback()) return; Ref<JSGlobalObjectCallback> protectedThis(*this); JSLockHolder lock(m_globalObject->vm()); ExecState* exec = m_globalObject->globalExec(); ScriptExecutionContext* context = m_globalObject->scriptExecutionContext(); // We will fail to get the context if the frame has been detached. if (!context) return; // When on the main thread (e.g. the document's thread), we need to make sure to // push the current ExecState on to the JSMainThreadExecState stack. if (context->isDocument()) JSMainThreadExecState::runTask(exec, m_task); else m_task->run(exec); ASSERT(!exec->hadException()); }
void DOMTimer::fired() { ScriptExecutionContext* context = scriptExecutionContext(); ASSERT(context); #if PLATFORM(IOS) Document* document = nullptr; if (!context->isDocument()) { document = toDocument(context); ASSERT(!document->frame()->timersPaused()); } #endif timerNestingLevel = m_nestingLevel; ASSERT(!isSuspended()); ASSERT(!context->activeDOMObjectsAreSuspended()); UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); // Only the first execution of a multi-shot timer should get an affirmative user gesture indicator. m_shouldForwardUserGesture = false; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId); // Simple case for non-one-shot timers. if (isActive()) { double minimumInterval = context->minimumTimerInterval(); if (repeatInterval() && repeatInterval() < minimumInterval) { m_nestingLevel++; if (m_nestingLevel >= maxTimerNestingLevel) augmentRepeatInterval(minimumInterval - repeatInterval()); } // No access to member variables after this point, it can delete the timer. m_action->execute(context); InspectorInstrumentation::didFireTimer(cookie); return; } // Delete timer before executing the action for one-shot timers. OwnPtr<ScheduledAction> action = m_action.release(); // No access to member variables after this point. delete this; #if PLATFORM(IOS) bool shouldReportLackOfChanges; bool shouldBeginObservingChanges; if (document) { shouldReportLackOfChanges = WebThreadCountOfObservedContentModifiers() == 1; shouldBeginObservingChanges = WebThreadContainsObservedContentModifier(this); } else { shouldReportLackOfChanges = false; shouldBeginObservingChanges = false; } if (shouldBeginObservingChanges) { WKBeginObservingContentChanges(false); WebThreadRemoveObservedContentModifier(this); } #endif action->execute(context); #if PLATFORM(IOS) if (shouldBeginObservingChanges) { WKStopObservingContentChanges(); if (WKObservedContentChange() == WKContentVisibilityChange || shouldReportLackOfChanges) if (document && document->page()) document->page()->chrome().client().observedContentChange(document->frame()); } #endif InspectorInstrumentation::didFireTimer(cookie); timerNestingLevel = 0; }
void JSEventListener::handleEvent(Event* event, bool isWindowEvent) { JSLock lock(SilenceAssertionsOnly); JSObject* jsFunction = this->jsFunction(); if (!jsFunction) return; JSDOMGlobalObject* globalObject = m_globalObject; // Null check as clearGlobalObject() can clear this and we still get called back by // xmlhttprequest objects. See http://bugs.webkit.org/show_bug.cgi?id=13275 // FIXME: Is this check still necessary? Requests are supposed to be stopped before clearGlobalObject() is called. ASSERT(globalObject); if (!globalObject) return; ScriptExecutionContext* scriptExecutionContext = globalObject->scriptExecutionContext(); if (!scriptExecutionContext) return; if (scriptExecutionContext->isDocument()) { JSDOMWindow* window = static_cast<JSDOMWindow*>(globalObject); Frame* frame = window->impl()->frame(); if (!frame) return; // The window must still be active in its frame. See <https://bugs.webkit.org/show_bug.cgi?id=21921>. // FIXME: A better fix for this may be to change DOMWindow::frame() to not return a frame the detached window used to be in. if (frame->domWindow() != window->impl()) return; // FIXME: Is this check needed for other contexts? ScriptController* script = frame->script(); if (!script->isEnabled() || script->isPaused()) return; } ExecState* exec = globalObject->globalExec(); JSValue handleEventFunction = jsFunction->get(exec, Identifier(exec, "handleEvent")); CallData callData; CallType callType = handleEventFunction.getCallData(callData); if (callType == CallTypeNone) { handleEventFunction = JSValue(); callType = jsFunction->getCallData(callData); } if (callType != CallTypeNone) { ref(); MarkedArgumentBuffer args; args.append(toJS(exec, globalObject, event)); Event* savedEvent = globalObject->currentEvent(); globalObject->setCurrentEvent(event); // If this event handler is the first JavaScript to execute, then the // dynamic global object should be set to the global object of the // window in which the event occurred. JSGlobalData* globalData = globalObject->globalData(); DynamicGlobalObjectScope globalObjectScope(exec, globalData->dynamicGlobalObject ? globalData->dynamicGlobalObject : globalObject); JSValue retval; if (handleEventFunction) { globalObject->globalData()->timeoutChecker.start(); retval = call(exec, handleEventFunction, callType, callData, jsFunction, args); } else { JSValue thisValue; if (isWindowEvent) thisValue = globalObject->toThisObject(exec); else thisValue = toJS(exec, globalObject, event->currentTarget()); globalObject->globalData()->timeoutChecker.start(); retval = call(exec, jsFunction, callType, callData, thisValue, args); } globalObject->globalData()->timeoutChecker.stop(); globalObject->setCurrentEvent(savedEvent); if (exec->hadException()) reportCurrentException(exec); else { if (!retval.isUndefinedOrNull() && event->storesResultAsString()) event->storeResult(retval.toString(exec)); if (m_isAttribute) { bool retvalbool; if (retval.getBoolean(retvalbool) && !retvalbool) event->preventDefault(); } } if (scriptExecutionContext->isDocument()) Document::updateStyleForAllDocuments(); deref(); } }
Document* NotificationCenter::document() const { ScriptExecutionContext* context = scriptExecutionContext(); return context->isDocument() ? static_cast<Document*>(context) : 0; }
void DOMTimer::fired() { // Retain this - if the timer is cancelled while this function is on the stack (implicitly and always // for one-shot timers, or if removeById is called on itself from within an interval timer fire) then // wait unit the end of this function to delete DOMTimer. RefPtr<DOMTimer> reference = this; ScriptExecutionContext* context = scriptExecutionContext(); ASSERT(context); DOMTimerFireState fireState(context); #if PLATFORM(IOS) Document* document = nullptr; if (context->isDocument()) { document = toDocument(context); ASSERT(!document->frame()->timersPaused()); } #endif context->setTimerNestingLevel(std::min(m_nestingLevel + 1, maxTimerNestingLevel)); ASSERT(!isSuspended()); ASSERT(!context->activeDOMObjectsAreSuspended()); UserGestureIndicator gestureIndicator(m_shouldForwardUserGesture ? DefinitelyProcessingUserGesture : PossiblyProcessingUserGesture); // Only the first execution of a multi-shot timer should get an affirmative user gesture indicator. m_shouldForwardUserGesture = false; InspectorInstrumentationCookie cookie = InspectorInstrumentation::willFireTimer(context, m_timeoutId); // Simple case for non-one-shot timers. if (isActive()) { if (m_nestingLevel < maxTimerNestingLevel) { m_nestingLevel++; updateTimerIntervalIfNecessary(); } m_action->execute(context); InspectorInstrumentation::didFireTimer(cookie); if (fireState.scriptDidInteractWithUserObservablePlugin && m_throttleState != ShouldNotThrottle) { m_throttleState = ShouldNotThrottle; updateTimerIntervalIfNecessary(); } else if (fireState.scriptDidInteractWithNonUserObservablePlugin && m_throttleState == Undetermined) { m_throttleState = ShouldThrottle; updateTimerIntervalIfNecessary(); } return; } context->removeTimeout(m_timeoutId); #if PLATFORM(IOS) bool shouldReportLackOfChanges; bool shouldBeginObservingChanges; if (document) { shouldReportLackOfChanges = WebThreadCountOfObservedContentModifiers() == 1; shouldBeginObservingChanges = WebThreadContainsObservedContentModifier(this); } else { shouldReportLackOfChanges = false; shouldBeginObservingChanges = false; } if (shouldBeginObservingChanges) { WKBeginObservingContentChanges(false); WebThreadRemoveObservedContentModifier(this); } #endif m_action->execute(context); #if PLATFORM(IOS) if (shouldBeginObservingChanges) { WKStopObservingContentChanges(); if (WKObservedContentChange() == WKContentVisibilityChange || shouldReportLackOfChanges) if (document && document->page()) document->page()->chrome().client().observedContentChange(document->frame()); } #endif InspectorInstrumentation::didFireTimer(cookie); context->setTimerNestingLevel(0); }
EncodedJSValue JSC_HOST_CALL constructJSAudioContext(ExecState* exec) { DOMConstructorObject* jsConstructor = jsCast<DOMConstructorObject*>(exec->callee()); if (!jsConstructor) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor callee is unavailable")); ScriptExecutionContext* scriptExecutionContext = jsConstructor->scriptExecutionContext(); if (!scriptExecutionContext) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor script execution context is unavailable")); if (!scriptExecutionContext->isDocument()) return throwVMError(exec, createReferenceError(exec, "AudioContext constructor called in a script execution context which is not a document")); Document& document = toDocument(*scriptExecutionContext); RefPtr<AudioContext> audioContext; if (!exec->argumentCount()) { // Constructor for default AudioContext which talks to audio hardware. ExceptionCode ec = 0; audioContext = AudioContext::create(document, ec); if (ec) { setDOMException(exec, ec); return JSValue::encode(JSValue()); } if (!audioContext.get()) return throwVMError(exec, createSyntaxError(exec, "audio resources unavailable for AudioContext construction")); } else { #if ENABLE(LEGACY_WEB_AUDIO) // Constructor for offline (render-target) AudioContext which renders into an AudioBuffer. // new AudioContext(in unsigned long numberOfChannels, in unsigned long numberOfFrames, in float sampleRate); document.addConsoleMessage(MessageSource::JS, MessageLevel::Warning, ASCIILiteral("Deprecated AudioContext constructor: use OfflineAudioContext instead")); if (exec->argumentCount() < 3) return throwVMError(exec, createNotEnoughArgumentsError(exec)); int32_t numberOfChannels = exec->argument(0).toInt32(exec); int32_t numberOfFrames = exec->argument(1).toInt32(exec); float sampleRate = exec->argument(2).toFloat(exec); if (numberOfChannels <= 0 || numberOfChannels > 10) return throwVMError(exec, createSyntaxError(exec, "Invalid number of channels")); if (numberOfFrames <= 0) return throwVMError(exec, createSyntaxError(exec, "Invalid number of frames")); if (sampleRate <= 0) return throwVMError(exec, createSyntaxError(exec, "Invalid sample rate")); ExceptionCode ec = 0; audioContext = OfflineAudioContext::create(document, numberOfChannels, numberOfFrames, sampleRate, ec); if (ec) { setDOMException(exec, ec); return throwVMError(exec, createSyntaxError(exec, "Error creating OfflineAudioContext")); } #else return throwVMError(exec, createSyntaxError(exec, "Illegal AudioContext constructor")); #endif } if (!audioContext.get()) return throwVMError(exec, createReferenceError(exec, "Error creating AudioContext")); return JSValue::encode(CREATE_DOM_WRAPPER(jsConstructor->globalObject(), AudioContext, audioContext.get())); }