/* * Copyright (C) 2008 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ #include "config.h" #include "ActiveDOMObject.h" // #include "Document.h" #include "Event.h" #include "EventTarget.h" #include "EventLoop.h" #include "ScriptExecutionContext.h" namespace WebCore { static inline ScriptExecutionContext* suitableScriptExecutionContext(ScriptExecutionContext* scriptExecutionContext) { // For detached documents, make sure we observe their context document instead. // return is(scriptExecutionContext) ? &downcast(*scriptExecutionContext).contextDocument() : scriptExecutionContext; return scriptExecutionContext; } inline ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* context, CheckedScriptExecutionContextType) : ContextDestructionObserver(context) { // ASSERT(!is(context) || &downcast(context)->contextDocument() == downcast(context)); if (!context) return; ASSERT(context->isContextThread()); context->didCreateActiveDOMObject(*this); } ActiveDOMObject::ActiveDOMObject(ScriptExecutionContext* scriptExecutionContext) : ActiveDOMObject(suitableScriptExecutionContext(scriptExecutionContext), CheckedScriptExecutionContext) { } // ActiveDOMObject::ActiveDOMObject(Document* document) // : ActiveDOMObject(document ? &document->contextDocument() : nullptr, CheckedScriptExecutionContext) // { // } // ActiveDOMObject::ActiveDOMObject(Document& document) // : ActiveDOMObject(&document.contextDocument(), CheckedScriptExecutionContext) // { // } ActiveDOMObject::~ActiveDOMObject() { ASSERT(canCurrentThreadAccessThreadLocalData(m_creationThread)); // ActiveDOMObject may be inherited by a sub-class whose life-cycle // exceeds that of the associated ScriptExecutionContext. In those cases, // m_scriptExecutionContext would/should have been nullified by // ContextDestructionObserver::contextDestroyed() (which we implement / // inherit). Hence, we should ensure that this is not 0 before use it // here. auto* context = scriptExecutionContext(); if (!context) return; ASSERT(m_suspendIfNeededWasCalled); ASSERT(context->isContextThread()); context->willDestroyActiveDOMObject(*this); } void ActiveDOMObject::suspendIfNeeded() { #if ASSERT_ENABLED ASSERT(!m_suspendIfNeededWasCalled); m_suspendIfNeededWasCalled = true; #endif if (auto* context = scriptExecutionContext()) context->suspendActiveDOMObjectIfNeeded(*this); } #if ASSERT_ENABLED void ActiveDOMObject::assertSuspendIfNeededWasCalled() const { if (!m_suspendIfNeededWasCalled) WTFLogAlways("Failed to call suspendIfNeeded() for %s", activeDOMObjectName()); ASSERT(m_suspendIfNeededWasCalled); } #endif // ASSERT_ENABLED void ActiveDOMObject::suspend(ReasonForSuspension) { } void ActiveDOMObject::resume() { } void ActiveDOMObject::stop() { } bool ActiveDOMObject::isContextStopped() const { return !scriptExecutionContext() || scriptExecutionContext()->activeDOMObjectsAreStopped(); } bool ActiveDOMObject::isAllowedToRunScript() const { return scriptExecutionContext() && !scriptExecutionContext()->activeDOMObjectsAreStopped() && !scriptExecutionContext()->activeDOMObjectsAreSuspended(); } void ActiveDOMObject::queueTaskInEventLoop(TaskSource source, Function&& function) { auto* context = scriptExecutionContext(); if (!context) return; context->eventLoop().queueTask(source, WTFMove(function)); } class ActiveDOMObjectEventDispatchTask : public EventLoopTask { public: ActiveDOMObjectEventDispatchTask(TaskSource source, EventLoopTaskGroup& group, ActiveDOMObject& object, Function&& dispatchEvent) : EventLoopTask(source, group) , m_object(object) , m_dispatchEvent(WTFMove(dispatchEvent)) { ++m_object.m_pendingActivityInstanceCount; } ~ActiveDOMObjectEventDispatchTask() { ASSERT(m_object.m_pendingActivityInstanceCount); --m_object.m_pendingActivityInstanceCount; } void execute() final { // If this task executes after the script execution context has been stopped, don't // actually dispatch the event. if (m_object.isAllowedToRunScript()) m_dispatchEvent(); } private: ActiveDOMObject& m_object; Function m_dispatchEvent; }; void ActiveDOMObject::queueTaskToDispatchEventInternal(EventTarget& target, TaskSource source, Ref&& event) { ASSERT(!event->target() || &target == event->target()); auto* context = scriptExecutionContext(); if (!context) return; auto& eventLoopTaskGroup = context->eventLoop(); auto task = makeUnique(source, eventLoopTaskGroup, *this, [target = Ref { target }, event = WTFMove(event)] { target->dispatchEvent(event); }); eventLoopTaskGroup.queueTask(WTFMove(task)); } void ActiveDOMObject::queueCancellableTaskToDispatchEventInternal(EventTarget& target, TaskSource source, TaskCancellationGroup& cancellationGroup, Ref&& event) { ASSERT(!event->target() || &target == event->target()); auto* context = scriptExecutionContext(); if (!context) return; auto& eventLoopTaskGroup = context->eventLoop(); auto task = makeUnique(source, eventLoopTaskGroup, *this, CancellableTask(cancellationGroup, [target = Ref { target }, event = WTFMove(event)] { target->dispatchEvent(event); })); eventLoopTaskGroup.queueTask(WTFMove(task)); } } // namespace WebCore