new file mode 100644
--- /dev/null
+++ b/dom/base/Timeout.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "Timeout.h"
+
+#include "nsGlobalWindow.h"
+#include "nsIScriptTimeoutHandler.h"
+#include "nsITimer.h"
+#include "nsPIDOMWindow.h"
+
+namespace mozilla {
+namespace dom {
+
+Timeout::Timeout()
+ : mCleared(false),
+ mRunning(false),
+ mIsInterval(false),
+ mPublicId(0),
+ mInterval(0),
+ mFiringDepth(0),
+ mNestingLevel(0),
+ mPopupState(openAllowed)
+{
+ MOZ_COUNT_CTOR(Timeout);
+}
+
+Timeout::~Timeout()
+{
+ if (mTimer) {
+ mTimer->Cancel();
+ mTimer = nullptr;
+ }
+
+ MOZ_COUNT_DTOR(Timeout);
+}
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(Timeout)
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(Timeout)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mWindow)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mPrincipal)
+ NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptHandler)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(Timeout)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPrincipal)
+ NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(Timeout, AddRef)
+NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Timeout, Release)
+
+nsresult
+Timeout::InitTimer(uint32_t aDelay)
+{
+ return mTimer->InitWithNameableFuncCallback(
+ nsGlobalWindow::TimerCallback, this, aDelay,
+ nsITimer::TYPE_ONE_SHOT, Timeout::TimerNameCallback);
+}
+
+// static
+void
+Timeout::TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
+ size_t aLen)
+{
+ RefPtr<Timeout> timeout = (Timeout*)aClosure;
+
+ const char* filename;
+ uint32_t lineNum, column;
+ timeout->mScriptHandler->GetLocation(&filename, &lineNum, &column);
+ snprintf(aBuf, aLen, "[content] %s:%u:%u", filename, lineNum, column);
+}
+
+
+// Return true if this timeout has a refcount of 1. This is used to check
+// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
+#ifdef DEBUG
+bool
+Timeout::HasRefCntOne() const
+{
+ return mRefCnt.get() == 1;
+}
+#endif // DEBUG
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/base/Timeout.h
@@ -0,0 +1,97 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_timeout_h
+#define mozilla_dom_timeout_h
+
+#include "mozilla/LinkedList.h"
+#include "mozilla/TimeStamp.h"
+#include "nsCOMPtr.h"
+#include "nsCycleCollectionParticipant.h"
+
+class nsGlobalWindow;
+class nsIPrincipal;
+class nsIScriptTimeoutHandler;
+class nsITimer;
+
+namespace mozilla {
+namespace dom {
+
+/*
+ * Timeout struct that holds information about each script
+ * timeout. Holds a strong reference to an nsIScriptTimeoutHandler, which
+ * abstracts the language specific cruft.
+ */
+class Timeout final
+ : public LinkedListElement<Timeout>
+{
+public:
+ Timeout();
+
+ NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(Timeout)
+ NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(Timeout)
+
+ nsresult InitTimer(uint32_t aDelay);
+
+ static void TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
+ size_t aLen);
+
+#ifdef DEBUG
+ bool HasRefCntOne() const;
+#endif // DEBUG
+
+ // Window for which this timeout fires
+ RefPtr<nsGlobalWindow> mWindow;
+
+ // The actual timer object
+ nsCOMPtr<nsITimer> mTimer;
+
+ // True if the timeout was cleared
+ bool mCleared;
+
+ // True if this is one of the timeouts that are currently running
+ bool mRunning;
+
+ // True if this is a repeating/interval timer
+ bool mIsInterval;
+
+ // Returned as value of setTimeout()
+ uint32_t mPublicId;
+
+ // Interval in milliseconds
+ uint32_t mInterval;
+
+ // mWhen and mTimeRemaining can't be in a union, sadly, because they
+ // have constructors.
+ // Nominal time to run this timeout. Use only when timeouts are not
+ // suspended.
+ TimeStamp mWhen;
+ // Remaining time to wait. Used only when timeouts are suspended.
+ TimeDuration mTimeRemaining;
+
+ // Principal with which to execute
+ nsCOMPtr<nsIPrincipal> mPrincipal;
+
+ // stack depth at which timeout is firing
+ uint32_t mFiringDepth;
+
+ uint32_t mNestingLevel;
+
+ // The popup state at timeout creation time if not created from
+ // another timeout
+ PopupControlState mPopupState;
+
+ // The language-specific information about the callback.
+ nsCOMPtr<nsIScriptTimeoutHandler> mScriptHandler;
+
+private:
+ ~Timeout();
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_timeout_h
--- a/dom/base/moz.build
+++ b/dom/base/moz.build
@@ -203,16 +203,17 @@ EXPORTS.mozilla.dom += [
'ScreenOrientation.h',
'ScriptSettings.h',
'ShadowRoot.h',
'StructuredCloneHolder.h',
'StructuredCloneTags.h',
'StyleSheetList.h',
'SubtleCrypto.h',
'Text.h',
+ 'Timeout.h',
'TreeWalker.h',
'WebKitCSSMatrix.h',
'WebSocket.h',
'WindowOrientationObserver.h',
]
UNIFIED_SOURCES += [
'AnonymousContent.cpp',
@@ -345,16 +346,17 @@ UNIFIED_SOURCES += [
'ScriptSettings.cpp',
'ShadowRoot.cpp',
'StructuredCloneHolder.cpp',
'StyleSheetList.cpp',
'SubtleCrypto.cpp',
'Text.cpp',
'TextInputProcessor.cpp',
'ThirdPartyUtil.cpp',
+ 'Timeout.cpp',
'TreeWalker.cpp',
'WebKitCSSMatrix.cpp',
'WebSocket.cpp',
'WindowNamedPropertiesHandler.cpp',
'WindowOrientationObserver.cpp',
]
if CONFIG['MOZ_WEBRTC']:
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -16,16 +16,17 @@
#include "nsScreen.h"
#include "nsHistory.h"
#include "nsDOMNavigationTiming.h"
#include "nsIDOMStorageManager.h"
#include "mozilla/dom/DOMStorage.h"
#include "mozilla/dom/Performance.h"
#include "mozilla/dom/StorageEvent.h"
#include "mozilla/dom/StorageEventBinding.h"
+#include "mozilla/dom/Timeout.h"
#include "mozilla/IntegerPrintfMacros.h"
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
#include "mozilla/dom/WindowOrientationObserver.h"
#endif
#include "nsDOMOfflineResourceList.h"
#include "nsError.h"
#include "nsIIdleService.h"
#include "nsISizeOfEventTarget.h"
@@ -498,81 +499,16 @@ private:
// This reference is non-owning and safe because it's cleared by
// nsGlobalWindow::CleanUp().
nsGlobalWindow* MOZ_NON_OWNING_REF mWindow;
};
NS_IMPL_ISUPPORTS(nsGlobalWindowObserver, nsIObserver, nsIInterfaceRequestor)
-nsTimeout::nsTimeout()
- : mCleared(false),
- mRunning(false),
- mIsInterval(false),
- mPublicId(0),
- mInterval(0),
- mFiringDepth(0),
- mNestingLevel(0),
- mPopupState(openAllowed)
-{
-#ifdef DEBUG_jst
- {
- extern int gTimeoutCnt;
-
- ++gTimeoutCnt;
- }
-#endif
-
- MOZ_COUNT_CTOR(nsTimeout);
-}
-
-nsTimeout::~nsTimeout()
-{
-#ifdef DEBUG_jst
- {
- extern int gTimeoutCnt;
-
- --gTimeoutCnt;
- }
-#endif
-
- if (mTimer) {
- mTimer->Cancel();
- mTimer = nullptr;
- }
-
- MOZ_COUNT_DTOR(nsTimeout);
-}
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(nsTimeout)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_0(nsTimeout)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsTimeout)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mWindow)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptHandler)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(nsTimeout, AddRef)
-NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(nsTimeout, Release)
-
-nsresult
-nsTimeout::InitTimer(uint32_t aDelay)
-{
- return mTimer->InitWithNameableFuncCallback(
- nsGlobalWindow::TimerCallback, this, aDelay,
- nsITimer::TYPE_ONE_SHOT, nsGlobalWindow::TimerNameCallback);
-}
-
-// Return true if this timeout has a refcount of 1. This is used to check
-// that dummy_timeout doesn't leak from nsGlobalWindow::RunTimeout.
-bool
-nsTimeout::HasRefCntOne()
-{
- return mRefCnt.get() == 1;
-}
-
static already_AddRefed<nsIVariant>
CreateVoidVariant()
{
RefPtr<nsVariantCC> writable = new nsVariantCC();
writable->SetAsVoid();
return writable.forget();
}
@@ -1891,20 +1827,20 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_
#ifdef MOZ_WEBSPEECH
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSpeechSynthesis)
#endif
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mOuterWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mListenerManager)
- for (nsTimeout* timeout = tmp->mTimeouts.getFirst();
+ for (Timeout* timeout = tmp->mTimeouts.getFirst();
timeout;
timeout = timeout->getNext()) {
- cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(nsTimeout));
+ cb.NoteNativeChild(timeout, NS_CYCLE_COLLECTION_PARTICIPANT(Timeout));
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocation)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mHistory)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mCustomElements)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLocalStorage)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mSessionStorage)
@@ -2054,17 +1990,17 @@ nsGlobalWindow::IsBlackForCC(bool aTraci
IsBlack()) &&
(!aTracingNeeded ||
HasNothingToTrace(static_cast<nsIDOMEventTarget*>(this)));
}
void
nsGlobalWindow::UnmarkGrayTimers()
{
- for (nsTimeout* timeout = mTimeouts.getFirst();
+ for (Timeout* timeout = mTimeouts.getFirst();
timeout;
timeout = timeout->getNext()) {
if (timeout->mScriptHandler) {
Function* f = timeout->mScriptHandler->GetCallback();
if (f) {
f->MarkForCC();
}
}
@@ -11700,17 +11636,17 @@ nsGlobalWindow::Suspend()
for (uint32_t i = 0; i < mEnabledSensors.Length(); i++)
ac->RemoveWindowListener(mEnabledSensors[i], this);
}
DisableGamepadUpdates();
DisableVRUpdates();
mozilla::dom::workers::SuspendWorkersForWindow(AsInner());
- for (nsTimeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
+ for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
// Leave the timers with the current time remaining. This will
// cause the timers to potentially fire when the window is
// Resume()'d. Time effectively passes while suspended.
// Drop the XPCOM timer; we'll reschedule when restoring the state.
if (t->mTimer) {
t->mTimer->Cancel();
t->mTimer = nullptr;
@@ -11759,17 +11695,17 @@ nsGlobalWindow::Resume()
for (uint32_t i = 0; i < mAudioContexts.Length(); ++i) {
ErrorResult dummy;
RefPtr<Promise> d = mAudioContexts[i]->Resume(dummy);
}
TimeStamp now = TimeStamp::Now();
DebugOnly<bool> _seenDummyTimeout = false;
- for (nsTimeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
+ for (Timeout* t = mTimeouts.getFirst(); t; t = t->getNext()) {
// There's a chance we're being called with RunTimeout on the stack in which
// case we have a dummy timeout in the list that *must not* be resumed. It
// can be identified by a null mWindow.
if (!t->mWindow) {
NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
_seenDummyTimeout = true;
continue;
}
@@ -11846,17 +11782,17 @@ nsGlobalWindow::FreezeInternal()
MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
if (mFreezeDepth != 1) {
return;
}
mozilla::dom::workers::FreezeWorkersForWindow(AsInner());
TimeStamp now = TimeStamp::Now();
- for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
+ for (Timeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
// Save the current remaining time for this timeout. We will
// re-apply it when the window is Thaw()'d. This effectively
// shifts timers to the right as if time does not pass while
// the window is frozen.
if (t->mWhen > now) {
t->mTimeRemaining = t->mWhen - now;
} else {
t->mTimeRemaining = TimeDuration(0);
@@ -11892,17 +11828,17 @@ nsGlobalWindow::ThawInternal()
MOZ_ASSERT(mSuspendDepth >= mFreezeDepth);
if (mFreezeDepth != 0) {
return;
}
TimeStamp now = TimeStamp::Now();
DebugOnly<bool> _seenDummyTimeout = false;
- for (nsTimeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
+ for (Timeout *t = mTimeouts.getFirst(); t; t = t->getNext()) {
// There's a chance we're being called with RunTimeout on the stack in which
// case we have a dummy timeout in the list that *must not* be resumed. It
// can be identified by a null mWindow.
if (!t->mWindow) {
NS_ASSERTION(!_seenDummyTimeout, "More than one dummy timeout?!");
_seenDummyTimeout = true;
continue;
}
@@ -12430,19 +12366,19 @@ nsGlobalWindow::SetInterval(JSContext* a
ErrorResult& aError)
{
int32_t timeout;
bool isInterval = IsInterval(aTimeout, timeout);
return SetTimeoutOrInterval(aCx, aHandler, timeout, isInterval, aError);
}
nsresult
-nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
- int32_t interval,
- bool aIsInterval, int32_t *aReturn)
+nsGlobalWindow::SetTimeoutOrInterval(nsIScriptTimeoutHandler* aHandler,
+ int32_t interval, bool aIsInterval,
+ int32_t* aReturn)
{
MOZ_ASSERT(IsInnerWindow());
// If we don't have a document (we could have been unloaded since
// the call to setTimeout was made), do nothing.
if (!mDoc) {
return NS_OK;
}
@@ -12454,17 +12390,17 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
// Make sure we don't proceed with an interval larger than our timer
// code can handle. (Note: we already forced |interval| to be non-negative,
// so the uint32_t cast (to avoid compiler warnings) is ok.)
uint32_t maxTimeoutMs = PR_IntervalToMilliseconds(DOM_MAX_TIMEOUT_VALUE);
if (static_cast<uint32_t>(interval) > maxTimeoutMs) {
interval = maxTimeoutMs;
}
- RefPtr<nsTimeout> timeout = new nsTimeout();
+ RefPtr<Timeout> timeout = new Timeout();
timeout->mIsInterval = aIsInterval;
timeout->mInterval = interval;
timeout->mScriptHandler = aHandler;
// Now clamp the actual interval we will use for the timer based on
uint32_t nestingLevel = sNestingLevel + 1;
uint32_t realInterval = interval;
if (aIsInterval || nestingLevel >= DOM_CLAMP_TIMEOUT_NESTING_LEVEL) {
@@ -12493,17 +12429,17 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
MOZ_ASSERT(!timeout->mWhen.IsNull());
nsresult rv;
timeout->mTimer = do_CreateInstance("@mozilla.org/timer;1", &rv);
if (NS_FAILED(rv)) {
return rv;
}
- RefPtr<nsTimeout> copy = timeout;
+ RefPtr<Timeout> copy = timeout;
rv = timeout->InitTimer(realInterval);
if (NS_FAILED(rv)) {
return rv;
}
// The timeout is now also held in the timer's closure.
Unused << copy.forget();
@@ -12536,17 +12472,16 @@ nsGlobalWindow::SetTimeoutOrInterval(nsI
}
InsertTimeoutIntoList(timeout);
timeout->mPublicId = ++mTimeoutPublicIdCounter;
*aReturn = timeout->mPublicId;
return NS_OK;
-
}
int32_t
nsGlobalWindow::SetTimeoutOrInterval(JSContext *aCx, Function& aFunction,
int32_t aTimeout,
const Sequence<JS::Value>& aArguments,
bool aIsInterval, ErrorResult& aError)
{
@@ -12593,23 +12528,23 @@ nsGlobalWindow::SetTimeoutOrInterval(JSC
}
int32_t result;
aError = SetTimeoutOrInterval(handler, aTimeout, aIsInterval, &result);
return result;
}
bool
-nsGlobalWindow::RunTimeoutHandler(nsTimeout* aTimeout,
+nsGlobalWindow::RunTimeoutHandler(Timeout* aTimeout,
nsIScriptContext* aScx)
{
// Hold on to the timeout in case mExpr or mFunObj releases its
// doc.
- RefPtr<nsTimeout> timeout = aTimeout;
- nsTimeout* last_running_timeout = mRunningTimeout;
+ RefPtr<Timeout> timeout = aTimeout;
+ Timeout* last_running_timeout = mRunningTimeout;
mRunningTimeout = timeout;
timeout->mRunning = true;
// Push this timeout's popup control state, which should only be
// eabled the first time a timeout fires that was created while
// popups were enabled and with a delay less than
// "dom.disable_open_click_delay".
nsAutoPopupStatePusher popupStatePusher(timeout->mPopupState);
@@ -12633,16 +12568,17 @@ nsGlobalWindow::RunTimeoutHandler(nsTime
reason = "setInterval handler";
} else {
reason = "setTimeout handler";
}
bool abortIntervalHandler = false;
nsCOMPtr<nsIScriptTimeoutHandler> handler(timeout->mScriptHandler);
RefPtr<Function> callback = handler->GetCallback();
+
if (!callback) {
// Evaluate the timeout expression.
const nsAString& script = handler->GetHandlerText();
const char* filename = nullptr;
uint32_t lineNo = 0, dummyColumn = 0;
handler->GetLocation(&filename, &lineNo, &dummyColumn);
@@ -12705,17 +12641,17 @@ nsGlobalWindow::RunTimeoutHandler(nsTime
mRunningTimeout = last_running_timeout;
timeout->mRunning = false;
return timeout->mCleared;
}
bool
-nsGlobalWindow::RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
+nsGlobalWindow::RescheduleTimeout(Timeout* aTimeout, const TimeStamp& now,
bool aRunningPendingTimeouts)
{
if (!aTimeout->mIsInterval) {
if (aTimeout->mTimer) {
// The timeout still has an OS timer, and it's not an interval,
// that means that the OS timer could still fire; cancel the OS
// timer and release its reference to the timeout.
aTimeout->mTimer->Cancel();
@@ -12784,27 +12720,28 @@ nsGlobalWindow::RescheduleTimeout(nsTime
return false;
}
return true;
}
void
-nsGlobalWindow::RunTimeout(nsTimeout *aTimeout)
+nsGlobalWindow::RunTimeout(Timeout* aTimeout)
{
if (IsSuspended()) {
return;
}
NS_ASSERTION(IsInnerWindow(), "Timeout running on outer window!");
NS_ASSERTION(!IsFrozen(), "Timeout running on a window in the bfcache!");
- nsTimeout *nextTimeout;
- nsTimeout *last_expired_timeout, *last_insertion_point;
+ Timeout* nextTimeout;
+ Timeout* last_expired_timeout;
+ Timeout* last_insertion_point;
uint32_t firingDepth = mTimeoutFiringDepth + 1;
// Make sure that the window and the script context don't go away as
// a result of running timeouts
nsCOMPtr<nsIScriptGlobalObject> windowKungFuDeathGrip(this);
// A native timer has gone off. See which of our timeouts need
// servicing
@@ -12825,17 +12762,17 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
// The timeout list is kept in deadline order. Discover the latest timeout
// whose deadline has expired. On some platforms, native timeout events fire
// "early", but we handled that above by setting deadline to aTimeout->mWhen
// if the timer fired early. So we can stop walking if we get to timeouts
// whose mWhen is greater than deadline, since once that happens we know
// nothing past that point is expired.
last_expired_timeout = nullptr;
- for (nsTimeout *timeout = mTimeouts.getFirst();
+ for (Timeout* timeout = mTimeouts.getFirst();
timeout && timeout->mWhen <= deadline;
timeout = timeout->getNext()) {
if (timeout->mFiringDepth == 0) {
// Mark any timeouts that are on the list to be fired with the
// firing depth so that we can reentrantly run timeouts
timeout->mFiringDepth = firingDepth;
last_expired_timeout = timeout;
}
@@ -12855,28 +12792,28 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
gLastRecordedRecentTimeouts = now;
}
// Insert a dummy timeout into the list of timeouts between the
// portion of the list that we are about to process now and those
// timeouts that will be processed in a future call to
// win_run_timeout(). This dummy timeout serves as the head of the
// list for any timeouts inserted as a result of running a timeout.
- RefPtr<nsTimeout> dummy_timeout = new nsTimeout();
+ RefPtr<Timeout> dummy_timeout = new Timeout();
dummy_timeout->mFiringDepth = firingDepth;
dummy_timeout->mWhen = now;
last_expired_timeout->setNext(dummy_timeout);
- RefPtr<nsTimeout> timeoutExtraRef(dummy_timeout);
+ RefPtr<Timeout> timeoutExtraRef(dummy_timeout);
last_insertion_point = mTimeoutInsertionPoint;
// If we ever start setting mTimeoutInsertionPoint to a non-dummy timeout,
// the logic in ResetTimersForNonBackgroundWindow will need to change.
mTimeoutInsertionPoint = dummy_timeout;
- for (nsTimeout *timeout = mTimeouts.getFirst();
+ for (Timeout* timeout = mTimeouts.getFirst();
timeout != dummy_timeout && !IsFrozen();
timeout = nextTimeout) {
nextTimeout = timeout->getNext();
if (timeout->mFiringDepth != firingDepth) {
// We skip the timeout since it's on the list to run at another
// depth.
@@ -12943,25 +12880,25 @@ nsGlobalWindow::RunTimeout(nsTimeout *aT
dummy_timeout->remove();
timeoutExtraRef = nullptr;
MOZ_ASSERT(dummy_timeout->HasRefCntOne(), "dummy_timeout may leak");
mTimeoutInsertionPoint = last_insertion_point;
}
void
-nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerID)
+nsGlobalWindow::ClearTimeoutOrInterval(int32_t aTimerId)
{
MOZ_RELEASE_ASSERT(IsInnerWindow());
- uint32_t public_id = (uint32_t)aTimerID;
- nsTimeout *timeout;
+ uint32_t timerId = (uint32_t)aTimerId;
+ Timeout* timeout;
for (timeout = mTimeouts.getFirst(); timeout; timeout = timeout->getNext()) {
- if (timeout->mPublicId == public_id) {
+ if (timeout->mPublicId == timerId) {
if (timeout->mRunning) {
/* We're running from inside the timeout. Mark this
timeout for deferred deletion by the code in
RunTimeout() */
timeout->mIsInterval = false;
}
else {
/* Delete the timeout from the pending timeout list */
@@ -12992,17 +12929,17 @@ nsresult nsGlobalWindow::ResetTimersForN
// If mTimeoutInsertionPoint is non-null, we're in the middle of firing
// timers and the timers we're planning to fire all come before
// mTimeoutInsertionPoint; mTimeoutInsertionPoint itself is a dummy timeout
// with an mWhen that may be semi-bogus. In that case, we don't need to do
// anything with mTimeoutInsertionPoint or anything before it, so should
// start at the timer after mTimeoutInsertionPoint, if there is one.
// Otherwise, start at the beginning of the list.
- for (nsTimeout *timeout = mTimeoutInsertionPoint ?
+ for (Timeout* timeout = mTimeoutInsertionPoint ?
mTimeoutInsertionPoint->getNext() : mTimeouts.getFirst();
timeout; ) {
// It's important that this check be <= so that we guarantee that
// taking std::max with |now| won't make a quantity equal to
// timeout->mWhen below.
if (timeout->mWhen <= now) {
timeout = timeout->getNext();
continue;
@@ -13036,17 +12973,17 @@ nsresult nsGlobalWindow::ResetTimersForN
TimeDuration delay = firingTime - now;
timeout->mWhen = firingTime;
// Since we reset mWhen we need to move |timeout| to the right
// place in the list so that it remains sorted by mWhen.
// Get the pointer to the next timeout now, before we move the
// current timeout in the list.
- nsTimeout* nextTimeout = timeout->getNext();
+ Timeout* nextTimeout = timeout->getNext();
// It is safe to remove and re-insert because mWhen is now
// strictly smaller than it used to be, so we know we'll insert
// |timeout| before nextTimeout.
NS_ASSERTION(!nextTimeout ||
timeout->mWhen < nextTimeout->mWhen, "How did that happen?");
timeout->remove();
// InsertTimeoutIntoList will addref |timeout| and reset
@@ -13070,17 +13007,18 @@ nsresult nsGlobalWindow::ResetTimersForN
}
return NS_OK;
}
void
nsGlobalWindow::ClearAllTimeouts()
{
- nsTimeout *timeout, *nextTimeout;
+ Timeout* timeout;
+ Timeout* nextTimeout;
for (timeout = mTimeouts.getFirst(); timeout; timeout = nextTimeout) {
/* If RunTimeout() is higher up on the stack for this
window, e.g. as a result of document.write from a timeout,
then we need to reset the list insertion point for
newly-created timeouts in case the user adds a timeout,
before we pop the stack back to RunTimeout. */
if (mRunningTimeout == timeout)
@@ -13105,25 +13043,25 @@ nsGlobalWindow::ClearAllTimeouts()
timeout->Release();
}
// Clear out our list
mTimeouts.clear();
}
void
-nsGlobalWindow::InsertTimeoutIntoList(nsTimeout *aTimeout)
+nsGlobalWindow::InsertTimeoutIntoList(Timeout* aTimeout)
{
NS_ASSERTION(IsInnerWindow(),
"InsertTimeoutIntoList() called on outer window!");
// Start at mLastTimeout and go backwards. Don't go further than
// mTimeoutInsertionPoint, though. This optimizes for the common case of
// insertion at the end.
- nsTimeout* prevSibling;
+ Timeout* prevSibling;
for (prevSibling = mTimeouts.getLast();
prevSibling && prevSibling != mTimeoutInsertionPoint &&
// This condition needs to match the one in SetTimeoutOrInterval that
// determines whether to set mWhen or mTimeRemaining.
(IsFrozen() ?
prevSibling->mTimeRemaining > aTimeout->mTimeRemaining :
prevSibling->mWhen > aTimeout->mWhen);
prevSibling = prevSibling->getPrevious()) {
@@ -13143,34 +13081,21 @@ nsGlobalWindow::InsertTimeoutIntoList(ns
// by the list
aTimeout->AddRef();
}
// static
void
nsGlobalWindow::TimerCallback(nsITimer *aTimer, void *aClosure)
{
- RefPtr<nsTimeout> timeout = (nsTimeout *)aClosure;
+ RefPtr<Timeout> timeout = (Timeout*)aClosure;
timeout->mWindow->RunTimeout(timeout);
}
-// static
-void
-nsGlobalWindow::TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
- size_t aLen)
-{
- RefPtr<nsTimeout> timeout = (nsTimeout*)aClosure;
-
- const char* filename;
- uint32_t lineNum, column;
- timeout->mScriptHandler->GetLocation(&filename, &lineNum, &column);
- snprintf(aBuf, aLen, "[content] %s:%u:%u", filename, lineNum, column);
-}
-
//*****************************************************************************
// nsGlobalWindow: Helper Functions
//*****************************************************************************
already_AddRefed<nsIDocShellTreeOwner>
nsGlobalWindow::GetTreeOwner()
{
FORWARD_TO_OUTER(GetTreeOwner, (), nullptr);
--- a/dom/base/nsGlobalWindow.h
+++ b/dom/base/nsGlobalWindow.h
@@ -51,16 +51,17 @@
#include "nsIDocument.h"
#include "mozilla/dom/EventTarget.h"
#include "mozilla/dom/WindowBinding.h"
#include "Units.h"
#include "nsComponentManagerUtils.h"
#include "nsSize.h"
#include "nsCheapSets.h"
#include "mozilla/dom/ImageBitmapSource.h"
+#include "mozilla/dom/Timeout.h"
#define DEFAULT_HOME_PAGE "www.mozilla.org"
#define PREF_BROWSER_STARTUP_HOMEPAGE "browser.startup.homepage"
// Amount of time allowed between alert/prompt/confirm before enabling
// the stop dialog checkbox.
#define DEFAULT_SUCCESSIVE_DIALOG_TIME_LIMIT 3 // 3 sec
@@ -119,16 +120,17 @@ class Navigator;
class OwningExternalOrWindowProxy;
class Promise;
class PostMessageEvent;
struct RequestInit;
class RequestOrUSVString;
class Selection;
class SpeechSynthesis;
class TabGroup;
+class Timeout;
class U2F;
class VRDisplay;
class VREventObserver;
class WakeLock;
#if defined(MOZ_WIDGET_ANDROID) || defined(MOZ_WIDGET_GONK)
class WindowOrientationObserver;
#endif
namespace cache {
@@ -146,79 +148,16 @@ NS_CreateJSTimeoutHandler(JSContext* aCx
extern already_AddRefed<nsIScriptTimeoutHandler>
NS_CreateJSTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
const nsAString& aExpression,
mozilla::ErrorResult& aError);
extern const js::Class OuterWindowProxyClass;
-/*
- * Timeout struct that holds information about each script
- * timeout. Holds a strong reference to an nsIScriptTimeoutHandler, which
- * abstracts the language specific cruft.
- */
-struct nsTimeout final
- : mozilla::LinkedListElement<nsTimeout>
-{
-private:
- ~nsTimeout();
-
-public:
- nsTimeout();
-
- NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsTimeout)
- NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(nsTimeout)
-
- nsresult InitTimer(uint32_t aDelay);
-
- bool HasRefCntOne();
-
- // Window for which this timeout fires
- RefPtr<nsGlobalWindow> mWindow;
-
- // The actual timer object
- nsCOMPtr<nsITimer> mTimer;
-
- // True if the timeout was cleared
- bool mCleared;
-
- // True if this is one of the timeouts that are currently running
- bool mRunning;
-
- // True if this is a repeating/interval timer
- bool mIsInterval;
-
- // Returned as value of setTimeout()
- uint32_t mPublicId;
-
- // Interval in milliseconds
- uint32_t mInterval;
-
- // mWhen and mTimeRemaining can't be in a union, sadly, because they
- // have constructors.
- // Nominal time to run this timeout. Use only when timeouts are not
- // suspended.
- mozilla::TimeStamp mWhen;
- // Remaining time to wait. Used only when timeouts are suspended.
- mozilla::TimeDuration mTimeRemaining;
-
- // stack depth at which timeout is firing
- uint32_t mFiringDepth;
-
- uint32_t mNestingLevel;
-
- // The popup state at timeout creation time if not created from
- // another timeout
- PopupControlState mPopupState;
-
- // The language-specific information about the callback.
- nsCOMPtr<nsIScriptTimeoutHandler> mScriptHandler;
-};
-
struct IdleObserverHolder
{
nsCOMPtr<nsIIdleObserver> mIdleObserver;
uint32_t mTimeInS;
bool mPrevNotificationIdle;
IdleObserverHolder()
: mTimeInS(0), mPrevNotificationIdle(false)
@@ -1504,48 +1443,46 @@ private:
void FreezeInternal();
void ThawInternal();
public:
// Timeout Functions
// Language agnostic timeout function (all args passed).
// |interval| is in milliseconds.
- nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler *aHandler,
- int32_t interval,
- bool aIsInterval, int32_t* aReturn);
+ nsresult SetTimeoutOrInterval(nsIScriptTimeoutHandler* aHandler,
+ int32_t interval, bool aIsInterval,
+ int32_t* aReturn);
int32_t SetTimeoutOrInterval(JSContext* aCx,
mozilla::dom::Function& aFunction,
int32_t aTimeout,
const mozilla::dom::Sequence<JS::Value>& aArguments,
bool aIsInterval, mozilla::ErrorResult& aError);
int32_t SetTimeoutOrInterval(JSContext* aCx, const nsAString& aHandler,
int32_t aTimeout, bool aIsInterval,
mozilla::ErrorResult& aError);
- void ClearTimeoutOrInterval(int32_t aTimerID);
+ void ClearTimeoutOrInterval(int32_t aTimerId);
// JS specific timeout functions (JS args grabbed from context).
nsresult ResetTimersForNonBackgroundWindow();
// The timeout implementation functions.
- void RunTimeout(nsTimeout *aTimeout);
+ void RunTimeout(mozilla::dom::Timeout* aTimeout);
void RunTimeout() { RunTimeout(nullptr); }
// Return true if |aTimeout| was cleared while its handler ran.
- bool RunTimeoutHandler(nsTimeout* aTimeout, nsIScriptContext* aScx);
+ bool RunTimeoutHandler(mozilla::dom::Timeout* aTimeout, nsIScriptContext* aScx);
// Return true if |aTimeout| needs to be reinserted into the timeout list.
- bool RescheduleTimeout(nsTimeout* aTimeout, const TimeStamp& now,
+ bool RescheduleTimeout(mozilla::dom::Timeout* aTimeout, const TimeStamp& now,
bool aRunningPendingTimeouts);
void ClearAllTimeouts();
// Insert aTimeout into the list, before all timeouts that would
// fire after it, but no earlier than mTimeoutInsertionPoint, if any.
- void InsertTimeoutIntoList(nsTimeout *aTimeout);
+ void InsertTimeoutIntoList(mozilla::dom::Timeout* aTimeout);
static void TimerCallback(nsITimer *aTimer, void *aClosure);
- static void TimerNameCallback(nsITimer* aTimer, void* aClosure, char* aBuf,
- size_t aLen);
// Helper Functions
already_AddRefed<nsIDocShellTreeOwner> GetTreeOwner();
already_AddRefed<nsIBaseWindow> GetTreeOwnerWindow();
already_AddRefed<nsIWebBrowserChrome> GetWebBrowserChrome();
nsresult SecurityCheckURL(const char *aURL);
bool IsPrivateBrowsing();
@@ -1844,17 +1781,17 @@ protected:
RefPtr<nsDOMWindowList> mFrames;
// All BarProps are inner window only.
RefPtr<mozilla::dom::BarProp> mMenubar;
RefPtr<mozilla::dom::BarProp> mToolbar;
RefPtr<mozilla::dom::BarProp> mLocationbar;
RefPtr<mozilla::dom::BarProp> mPersonalbar;
RefPtr<mozilla::dom::BarProp> mStatusbar;
RefPtr<mozilla::dom::BarProp> mScrollbars;
- RefPtr<nsDOMWindowUtils> mWindowUtils;
+ RefPtr<nsDOMWindowUtils> mWindowUtils;
nsString mStatus;
nsString mDefaultStatus;
RefPtr<nsGlobalWindowObserver> mObserver; // Inner windows only.
RefPtr<mozilla::dom::Crypto> mCrypto;
RefPtr<mozilla::dom::U2F> mU2F;
RefPtr<mozilla::dom::cache::CacheStorage> mCacheStorage;
RefPtr<mozilla::dom::Console> mConsole;
// We need to store an nsISupports pointer to this object because the
@@ -1869,23 +1806,23 @@ protected:
RefPtr<mozilla::dom::DOMStorage> mSessionStorage;
// These member variable are used only on inner windows.
RefPtr<mozilla::EventListenerManager> mListenerManager;
// mTimeouts is generally sorted by mWhen, unless mTimeoutInsertionPoint is
// non-null. In that case, the dummy timeout pointed to by
// mTimeoutInsertionPoint may have a later mWhen than some of the timeouts
// that come after it.
- mozilla::LinkedList<nsTimeout> mTimeouts;
+ mozilla::LinkedList<mozilla::dom::Timeout> mTimeouts;
// If mTimeoutInsertionPoint is non-null, insertions should happen after it.
// This is a dummy timeout at the moment; if that ever changes, the logic in
// ResetTimersForNonBackgroundWindow needs to change.
- nsTimeout* mTimeoutInsertionPoint;
- uint32_t mTimeoutPublicIdCounter;
- uint32_t mTimeoutFiringDepth;
+ mozilla::dom::Timeout* mTimeoutInsertionPoint;
+ uint32_t mTimeoutPublicIdCounter;
+ uint32_t mTimeoutFiringDepth;
RefPtr<mozilla::dom::Location> mLocation;
RefPtr<nsHistory> mHistory;
RefPtr<mozilla::dom::CustomElementRegistry> mCustomElements;
// These member variables are used on both inner and the outer windows.
nsCOMPtr<nsIPrincipal> mDocumentPrincipal;
typedef nsTArray<RefPtr<mozilla::dom::StorageEvent>> nsDOMStorageEventArray;
--- a/dom/base/nsIScriptTimeoutHandler.h
+++ b/dom/base/nsIScriptTimeoutHandler.h
@@ -3,16 +3,18 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsIScriptTimeoutHandler_h___
#define nsIScriptTimeoutHandler_h___
#include "nsTArray.h"
#include "js/TypeDecls.h"
+#include "mozilla/Function.h"
+#include "mozilla/Maybe.h"
namespace mozilla {
namespace dom {
class Function;
} // namespace dom
} // namespace mozilla
#define NS_ISCRIPTTIMEOUTHANDLER_IID \
@@ -26,17 +28,17 @@ class Function;
class nsIScriptTimeoutHandler : public nsISupports
{
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTTIMEOUTHANDLER_IID)
// Get the Function to call. If this returns nullptr, GetHandlerText() will
// be called to get the string.
- virtual mozilla::dom::Function *GetCallback() = 0;
+ virtual mozilla::dom::Function* GetCallback() = 0;
// Get the handler text of not a compiled object.
virtual const nsAString& GetHandlerText() = 0;
// Get the location of the script.
// Note: The memory pointed to by aFileName is owned by the
// nsIScriptTimeoutHandler and should not be freed by the caller.
virtual void GetLocation(const char **aFileName, uint32_t *aLineNo,
--- a/dom/base/nsJSTimeoutHandler.cpp
+++ b/dom/base/nsJSTimeoutHandler.cpp
@@ -1,29 +1,32 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include <algorithm>
+
+#include "mozilla/Attributes.h"
+#include "mozilla/Function.h"
+#include "mozilla/Likely.h"
+#include "mozilla/Maybe.h"
+#include "mozilla/dom/FunctionBinding.h"
+#include "nsAXPCNativeCallContext.h"
#include "nsCOMPtr.h"
+#include "nsContentUtils.h"
+#include "nsError.h"
+#include "nsGlobalWindow.h"
+#include "nsIContentSecurityPolicy.h"
#include "nsIDocument.h"
#include "nsIScriptTimeoutHandler.h"
#include "nsIXPConnect.h"
#include "nsJSUtils.h"
-#include "nsContentUtils.h"
-#include "nsError.h"
-#include "nsGlobalWindow.h"
-#include "nsIContentSecurityPolicy.h"
-#include "mozilla/Attributes.h"
-#include "mozilla/Likely.h"
-#include <algorithm>
-#include "mozilla/dom/FunctionBinding.h"
#include "WorkerPrivate.h"
-#include "nsAXPCNativeCallContext.h"
static const char kSetIntervalStr[] = "setInterval";
static const char kSetTimeoutStr[] = "setTimeout";
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
@@ -32,34 +35,36 @@ class nsJSScriptTimeoutHandler final : p
{
public:
// nsISupports
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(nsJSScriptTimeoutHandler)
nsJSScriptTimeoutHandler();
// This will call SwapElements on aArguments with an empty array.
- nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
+ nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow* aWindow,
Function& aFunction,
nsTArray<JS::Heap<JS::Value>>&& aArguments,
ErrorResult& aError);
- nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow *aWindow,
+ nsJSScriptTimeoutHandler(JSContext* aCx, nsGlobalWindow* aWindow,
const nsAString& aExpression, bool* aAllowEval,
ErrorResult& aError);
nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
Function& aFunction,
nsTArray<JS::Heap<JS::Value>>&& aArguments);
nsJSScriptTimeoutHandler(JSContext* aCx, WorkerPrivate* aWorkerPrivate,
const nsAString& aExpression);
virtual const nsAString& GetHandlerText() override;
+
virtual Function* GetCallback() override
{
return mFunction;
}
+
virtual void GetLocation(const char** aFileName, uint32_t* aLineNo,
uint32_t* aColumn) override
{
*aFileName = mFileName.get();
*aLineNo = mLineNo;
*aColumn = mColumn;
}
--- a/dom/base/nsPIDOMWindow.h
+++ b/dom/base/nsPIDOMWindow.h
@@ -31,26 +31,26 @@ class nsIDocument;
class nsIIdleObserver;
class nsIPrincipal;
class nsIScriptTimeoutHandler;
class nsIURI;
class nsPIDOMWindowInner;
class nsPIDOMWindowOuter;
class nsPIWindowRoot;
class nsXBLPrototypeHandler;
-struct nsTimeout;
typedef uint32_t SuspendTypes;
namespace mozilla {
namespace dom {
class AudioContext;
class Element;
class Performance;
class ServiceWorkerRegistration;
+class Timeout;
class CustomElementRegistry;
} // namespace dom
} // namespace mozilla
// Popup control state enum. The values in this enum must go from most
// permissive to least permissive so that it's safe to push state in
// all situations. Pushing popup state onto the stack never makes the
// current popup state less permissive (see
@@ -616,17 +616,17 @@ protected:
typedef nsRefPtrHashtable<nsStringHashKey,
mozilla::dom::ServiceWorkerRegistration>
ServiceWorkerRegistrationTable;
ServiceWorkerRegistrationTable mServiceWorkerRegistrationTable;
uint32_t mModalStateDepth;
// These variables are only used on inner windows.
- nsTimeout *mRunningTimeout;
+ mozilla::dom::Timeout *mRunningTimeout;
uint32_t mMutationBits;
bool mIsDocumentLoaded;
bool mIsHandlingResizeEvent;
bool mIsInnerWindow;
bool mMayHavePaintEventListener;
bool mMayHaveTouchEventListener;