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;
    }
}
Esempio n. 2
0
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();
}
Esempio n. 3
0
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();
}
Esempio n. 4
0
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);
}
Esempio n. 5
0
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();
}
Esempio n. 6
0
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);
}
Esempio n. 7
0
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);
}
Esempio n. 9
0
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))));
}
Esempio n. 10
0
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();
}
Esempio n. 13
0
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);
}
Esempio n. 14
0
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();
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
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);
}
Esempio n. 17
0
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();
        }
    }
}
Esempio n. 18
0
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);
}
Esempio n. 20
0
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();
}
Esempio n. 21
0
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;
}
Esempio n. 22
0
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());
    }
Esempio n. 24
0
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);
}
Esempio n. 28
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()));
}