зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to mozilla-central. a=merge
This commit is contained in:
Коммит
4faab2f1b6
|
@ -1333,24 +1333,16 @@
|
|||
byMouse: event.mozInputSource == MouseEvent.MOZ_SOURCE_MOUSE,
|
||||
});
|
||||
} else if (event.originalTarget.localName == "scrollbox") {
|
||||
// The user middleclicked an open space on the tabstrip. This could
|
||||
// be because they intend to open a new tab, but it could also be
|
||||
// because they just removed a tab and they now middleclicked on the
|
||||
// resulting space while that tab is closing. In that case, we don't
|
||||
// want to open a tab. So if we're removing one or more tabs, and
|
||||
// the tab click is before the end of the last visible tab, we do
|
||||
// nothing.
|
||||
if (gBrowser._removingTabs.length) {
|
||||
// The user middleclicked on the tabstrip. Check whether the click
|
||||
// was dispatched on the open space of it.
|
||||
let visibleTabs = this._getVisibleTabs();
|
||||
let lastTab = visibleTabs[visibleTabs.length - 1];
|
||||
let endOfTab = lastTab.getBoundingClientRect()[RTL_UI ? "left" : "right"];
|
||||
let winUtils = window.windowUtils;
|
||||
let endOfTab = winUtils.getBoundsWithoutFlushing(lastTab)[RTL_UI ? "left" : "right"];
|
||||
if ((!RTL_UI && event.clientX > endOfTab) ||
|
||||
(RTL_UI && event.clientX < endOfTab)) {
|
||||
BrowserOpenTab();
|
||||
}
|
||||
} else {
|
||||
BrowserOpenTab();
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -370,10 +370,11 @@ NS_IMPL_ISUPPORTS_INHERITED(IdleDispatchRunnable, IdleRunnable,
|
|||
auto runnable = MakeRefPtr<IdleDispatchRunnable>(global, aCallback);
|
||||
|
||||
if (aOptions.mTimeout.WasPassed()) {
|
||||
aRv = NS_IdleDispatchToCurrentThread(runnable.forget(),
|
||||
aOptions.mTimeout.Value());
|
||||
aRv = NS_DispatchToCurrentThreadQueue(
|
||||
runnable.forget(), aOptions.mTimeout.Value(), EventQueuePriority::Idle);
|
||||
} else {
|
||||
aRv = NS_IdleDispatchToCurrentThread(runnable.forget());
|
||||
aRv = NS_DispatchToCurrentThreadQueue(runnable.forget(),
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1295,6 +1295,7 @@ Document::Document(const char* aContentType)
|
|||
mAsyncOnloadBlockCount(0),
|
||||
mCompatMode(eCompatibility_FullStandards),
|
||||
mReadyState(ReadyState::READYSTATE_UNINITIALIZED),
|
||||
mAncestorIsLoading(false),
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
mVisibilityState(dom::VisibilityState::Hidden),
|
||||
#else
|
||||
|
@ -8116,14 +8117,52 @@ nsresult Document::CloneDocHelper(Document* clone) const {
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool SetLoadingInSubDocument(Document* aDocument, void* aData) {
|
||||
aDocument->SetAncestorLoading(*(static_cast<bool*>(aData)));
|
||||
return true;
|
||||
}
|
||||
|
||||
void Document::SetAncestorLoading(bool aAncestorIsLoading) {
|
||||
NotifyLoading(mAncestorIsLoading, aAncestorIsLoading, mReadyState,
|
||||
mReadyState);
|
||||
mAncestorIsLoading = aAncestorIsLoading;
|
||||
}
|
||||
|
||||
void Document::NotifyLoading(const bool& aCurrentParentIsLoading,
|
||||
bool aNewParentIsLoading,
|
||||
const ReadyState& aCurrentState,
|
||||
ReadyState aNewState) {
|
||||
// Mirror the top-level loading state down to all subdocuments
|
||||
bool was_loading = aCurrentParentIsLoading ||
|
||||
aCurrentState == READYSTATE_LOADING ||
|
||||
aCurrentState == READYSTATE_INTERACTIVE;
|
||||
bool is_loading = aNewParentIsLoading || aNewState == READYSTATE_LOADING ||
|
||||
aNewState == READYSTATE_INTERACTIVE; // new value for state
|
||||
bool set_load_state = was_loading != is_loading;
|
||||
|
||||
if (set_load_state && StaticPrefs::dom_timeout_defer_during_load()) {
|
||||
nsPIDOMWindowInner* inner = GetInnerWindow();
|
||||
if (inner) {
|
||||
inner->SetActiveLoadingState(is_loading);
|
||||
}
|
||||
EnumerateSubDocuments(SetLoadingInSubDocument, &is_loading);
|
||||
}
|
||||
}
|
||||
|
||||
void Document::SetReadyStateInternal(ReadyState rs) {
|
||||
mReadyState = rs;
|
||||
if (rs == READYSTATE_UNINITIALIZED) {
|
||||
// Transition back to uninitialized happens only to keep assertions happy
|
||||
// right before readyState transitions to something else. Make this
|
||||
// transition undetectable by Web content.
|
||||
mReadyState = rs;
|
||||
return;
|
||||
}
|
||||
|
||||
if (READYSTATE_LOADING == rs) {
|
||||
mLoadingTimeStamp = mozilla::TimeStamp::Now();
|
||||
}
|
||||
NotifyLoading(mAncestorIsLoading, mAncestorIsLoading, mReadyState, rs);
|
||||
mReadyState = rs;
|
||||
if (mTiming) {
|
||||
switch (rs) {
|
||||
case READYSTATE_LOADING:
|
||||
|
@ -8141,9 +8180,6 @@ void Document::SetReadyStateInternal(ReadyState rs) {
|
|||
}
|
||||
}
|
||||
// At the time of loading start, we don't have timing object, record time.
|
||||
if (READYSTATE_LOADING == rs) {
|
||||
mLoadingTimeStamp = mozilla::TimeStamp::Now();
|
||||
}
|
||||
|
||||
if (READYSTATE_INTERACTIVE == rs) {
|
||||
if (nsContentUtils::IsSystemPrincipal(NodePrincipal())) {
|
||||
|
@ -8788,7 +8824,8 @@ void Document::RegisterPendingLinkUpdate(Link* aLink) {
|
|||
NewRunnableMethod("Document::FlushPendingLinkUpdatesFromRunnable", this,
|
||||
&Document::FlushPendingLinkUpdatesFromRunnable);
|
||||
// Do this work in a second in the worst case.
|
||||
nsresult rv = NS_IdleDispatchToCurrentThread(event.forget(), 1000);
|
||||
nsresult rv = NS_DispatchToCurrentThreadQueue(event.forget(), 1000,
|
||||
EventQueuePriority::Idle);
|
||||
if (NS_FAILED(rv)) {
|
||||
// If during shutdown posting a runnable doesn't succeed, we probably
|
||||
// don't need to update link states.
|
||||
|
@ -11976,7 +12013,8 @@ void Document::MaybeStoreUserInteractionAsPermission() {
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> task = new UserIntractionTimer(this);
|
||||
nsresult rv = NS_IdleDispatchToCurrentThread(task.forget(), 2500);
|
||||
nsresult rv = NS_DispatchToCurrentThreadQueue(task.forget(), 2500,
|
||||
EventQueuePriority::Idle);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1903,6 +1903,11 @@ class Document : public nsINode,
|
|||
void SetReadyStateInternal(ReadyState rs);
|
||||
ReadyState GetReadyStateEnum() { return mReadyState; }
|
||||
|
||||
void SetAncestorLoading(bool aAncestorIsLoading);
|
||||
void NotifyLoading(const bool& aCurrentParentIsLoading,
|
||||
bool aNewParentIsLoading, const ReadyState& aCurrentState,
|
||||
ReadyState aNewState);
|
||||
|
||||
// notify that a content node changed state. This must happen under
|
||||
// a scriptblocker but NOT within a begin/end update.
|
||||
void ContentStateChanged(nsIContent* aContent,
|
||||
|
@ -4116,6 +4121,9 @@ class Document : public nsINode,
|
|||
// Our readyState
|
||||
ReadyState mReadyState;
|
||||
|
||||
// Ancestor's loading state
|
||||
bool mAncestorIsLoading;
|
||||
|
||||
#ifdef MOZILLA_INTERNAL_API
|
||||
// Our visibility state
|
||||
mozilla::dom::VisibilityState mVisibilityState;
|
||||
|
|
|
@ -1259,7 +1259,8 @@ class ContentUnbinder : public Runnable {
|
|||
sContentUnbinder = next;
|
||||
next->mLast = mLast;
|
||||
mLast = nullptr;
|
||||
NS_IdleDispatchToCurrentThread(next.forget());
|
||||
NS_DispatchToCurrentThreadQueue(next.forget(),
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
|
@ -1278,7 +1279,7 @@ class ContentUnbinder : public Runnable {
|
|||
if (!sContentUnbinder) {
|
||||
sContentUnbinder = new ContentUnbinder();
|
||||
nsCOMPtr<nsIRunnable> e = sContentUnbinder;
|
||||
NS_IdleDispatchToCurrentThread(e.forget());
|
||||
NS_DispatchToCurrentThreadQueue(e.forget(), EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
if (sContentUnbinder->mLast->mSubtreeRoots.Length() >=
|
||||
|
|
|
@ -43,6 +43,7 @@ NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(Timeout, Release)
|
|||
void Timeout::SetWhenOrTimeRemaining(const TimeStamp& aBaseTime,
|
||||
const TimeDuration& aDelay) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mWindow);
|
||||
mSubmitTime = aBaseTime;
|
||||
|
||||
// If we are frozen simply set mTimeRemaining to be the "time remaining" in
|
||||
// the timeout (i.e., the interval itself). This will be used to create a
|
||||
|
@ -68,6 +69,8 @@ const TimeStamp& Timeout::When() const {
|
|||
return mWhen;
|
||||
}
|
||||
|
||||
const TimeStamp& Timeout::SubmitTime() const { return mSubmitTime; }
|
||||
|
||||
const TimeDuration& Timeout::TimeRemaining() const {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mWhen.IsNull());
|
||||
// Note, mWindow->IsFrozen() can be false here. The Thaw() method calls
|
||||
|
|
|
@ -45,6 +45,8 @@ class Timeout final : public LinkedListElement<RefPtr<Timeout>> {
|
|||
// Can only be called when not frozen.
|
||||
const TimeStamp& When() const;
|
||||
|
||||
const TimeStamp& SubmitTime() const;
|
||||
|
||||
// Can only be called when frozen.
|
||||
const TimeDuration& TimeRemaining() const;
|
||||
|
||||
|
@ -58,6 +60,11 @@ class Timeout final : public LinkedListElement<RefPtr<Timeout>> {
|
|||
// Remaining time to wait. Used only when timeouts are frozen.
|
||||
TimeDuration mTimeRemaining;
|
||||
|
||||
// Time that the timeout started, restarted, or was frozen. Useful for
|
||||
// logging time from (virtual) start of a timer until the time it fires
|
||||
// (or is cancelled, etc)
|
||||
TimeStamp mSubmitTime;
|
||||
|
||||
~Timeout() = default;
|
||||
|
||||
public:
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
#include "nsIEventTarget.h"
|
||||
#include "nsString.h"
|
||||
|
||||
extern mozilla::LazyLogModule gTimeoutLog;
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
|
@ -30,8 +32,15 @@ nsresult TimeoutExecutor::ScheduleImmediate(const TimeStamp& aDeadline,
|
|||
MOZ_DIAGNOSTIC_ASSERT(mMode == Mode::None);
|
||||
MOZ_DIAGNOSTIC_ASSERT(aDeadline <= (aNow + mAllowedEarlyFiringTime));
|
||||
|
||||
nsresult rv =
|
||||
mOwner->EventTarget()->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
nsresult rv;
|
||||
if (mIsIdleQueue) {
|
||||
RefPtr<TimeoutExecutor> runnable(this);
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Starting IdleDispatch runnable"));
|
||||
rv = NS_DispatchToCurrentThreadQueue(runnable.forget(), mMaxIdleDeferMS,
|
||||
EventQueuePriority::DeferredTimers);
|
||||
} else {
|
||||
rv = mOwner->EventTarget()->Dispatch(this, nsIEventTarget::DISPATCH_NORMAL);
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mMode = Mode::Immediate;
|
||||
|
@ -50,6 +59,13 @@ nsresult TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
|||
|
||||
nsresult rv = NS_OK;
|
||||
|
||||
if (mIsIdleQueue) {
|
||||
// Nothing goes into the idletimeouts list if it wasn't going to
|
||||
// fire at that time, so we can always schedule idle-execution of
|
||||
// these immediately
|
||||
return ScheduleImmediate(aNow, aNow);
|
||||
}
|
||||
|
||||
if (!mTimer) {
|
||||
mTimer = NS_NewTimer(mOwner->EventTarget());
|
||||
NS_ENSURE_TRUE(mTimer, NS_ERROR_OUT_OF_MEMORY);
|
||||
|
@ -58,6 +74,10 @@ nsresult TimeoutExecutor::ScheduleDelayed(const TimeStamp& aDeadline,
|
|||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mTimer->GetAllowedEarlyFiringMicroseconds(&earlyMicros));
|
||||
mAllowedEarlyFiringTime = TimeDuration::FromMicroseconds(earlyMicros);
|
||||
// Re-evaluate if we should have scheduled this immediately
|
||||
if (aDeadline <= (aNow + mAllowedEarlyFiringTime)) {
|
||||
return ScheduleImmediate(aDeadline, aNow);
|
||||
}
|
||||
} else {
|
||||
// Always call Cancel() in case we are re-using a timer.
|
||||
rv = mTimer->Cancel();
|
||||
|
@ -154,11 +174,15 @@ void TimeoutExecutor::MaybeExecute() {
|
|||
|
||||
Cancel();
|
||||
|
||||
mOwner->RunTimeout(now, deadline);
|
||||
mOwner->RunTimeout(now, deadline, mIsIdleQueue);
|
||||
}
|
||||
|
||||
TimeoutExecutor::TimeoutExecutor(TimeoutManager* aOwner)
|
||||
: mOwner(aOwner), mMode(Mode::None) {
|
||||
TimeoutExecutor::TimeoutExecutor(TimeoutManager* aOwner, bool aIsIdleQueue,
|
||||
uint32_t aMaxIdleDeferMS)
|
||||
: mOwner(aOwner),
|
||||
mIsIdleQueue(aIsIdleQueue),
|
||||
mMaxIdleDeferMS(aMaxIdleDeferMS),
|
||||
mMode(Mode::None) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(mOwner);
|
||||
}
|
||||
|
||||
|
@ -201,6 +225,8 @@ NS_IMETHODIMP
|
|||
TimeoutExecutor::Run() {
|
||||
// If the executor is canceled and then rescheduled its possible to get
|
||||
// spurious executions here. Ignore these unless our current mode matches.
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Running Immediate %stimers", mIsIdleQueue ? "Idle" : ""));
|
||||
if (mMode == Mode::Immediate) {
|
||||
MaybeExecute();
|
||||
}
|
||||
|
|
|
@ -22,8 +22,10 @@ class TimeoutExecutor final : public nsIRunnable,
|
|||
public nsITimerCallback,
|
||||
public nsINamed {
|
||||
TimeoutManager* mOwner;
|
||||
bool mIsIdleQueue;
|
||||
nsCOMPtr<nsITimer> mTimer;
|
||||
TimeStamp mDeadline;
|
||||
uint32_t mMaxIdleDeferMS;
|
||||
|
||||
// Limits how far we allow timers to fire into the future from their
|
||||
// deadline. Starts off at zero, but is then adjusted when we start
|
||||
|
@ -67,7 +69,8 @@ class TimeoutExecutor final : public nsIRunnable,
|
|||
void MaybeExecute();
|
||||
|
||||
public:
|
||||
explicit TimeoutExecutor(TimeoutManager* aOwner);
|
||||
TimeoutExecutor(TimeoutManager* aOwner, bool aIsIdleQueue,
|
||||
uint32_t aMaxIdleDeferMS);
|
||||
|
||||
void Shutdown();
|
||||
|
||||
|
|
|
@ -22,11 +22,14 @@
|
|||
#include "TimeoutBudgetManager.h"
|
||||
#include "mozilla/net/WebSocketEventService.h"
|
||||
#include "mozilla/MediaManager.h"
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
# include "ProfilerMarkerPayload.h"
|
||||
#endif
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
||||
static LazyLogModule gLog("Timeout");
|
||||
LazyLogModule gTimeoutLog("Timeout");
|
||||
|
||||
static int32_t gRunningTimeoutDepth = 0;
|
||||
|
||||
|
@ -126,6 +129,65 @@ bool TimeoutManager::IsActive() const {
|
|||
return false;
|
||||
}
|
||||
|
||||
void TimeoutManager::SetLoading(bool value) {
|
||||
// When moving from loading to non-loading, we may need to
|
||||
// reschedule any existing timeouts from the idle timeout queue
|
||||
// to the normal queue.
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("%p: SetLoading(%d)", this, value));
|
||||
if (mIsLoading && !value) {
|
||||
MoveIdleToActive();
|
||||
}
|
||||
// We don't immediately move existing timeouts to the idle queue if we
|
||||
// move to loading. When they would have fired, we'll see we're loading
|
||||
// and move them then.
|
||||
mIsLoading = value;
|
||||
}
|
||||
|
||||
void TimeoutManager::MoveIdleToActive() {
|
||||
uint32_t num = 0;
|
||||
TimeStamp when;
|
||||
TimeStamp now;
|
||||
// Ensure we maintain the ordering of timeouts, so timeouts
|
||||
// never fire before a timeout set for an earlier time, or
|
||||
// before a timeout for the same time already submitted.
|
||||
// See https://html.spec.whatwg.org/#dom-settimeout #16 and #17
|
||||
while (RefPtr<Timeout> timeout = mIdleTimeouts.GetLast()) {
|
||||
if (num == 0) {
|
||||
when = timeout->When();
|
||||
}
|
||||
timeout->remove();
|
||||
mTimeouts.InsertFront(timeout);
|
||||
#if MOZ_GECKO_PROFILER
|
||||
if (profiler_is_active()) {
|
||||
if (num == 0) {
|
||||
now = TimeStamp::Now();
|
||||
}
|
||||
TimeDuration elapsed = now - timeout->SubmitTime();
|
||||
TimeDuration target = timeout->When() - timeout->SubmitTime();
|
||||
TimeDuration delta = now - timeout->When();
|
||||
nsPrintfCString marker(
|
||||
"Releasing deferred setTimeout() for %dms (original target time was "
|
||||
"%dms (%dms delta))",
|
||||
int(elapsed.ToMilliseconds()), int(target.ToMilliseconds()),
|
||||
int(delta.ToMilliseconds()));
|
||||
// don't have end before start...
|
||||
profiler_add_marker(
|
||||
"setTimeout release", js::ProfilingStackFrame::Category::DOM,
|
||||
MakeUnique<TextMarkerPayload>(
|
||||
marker, delta.ToMilliseconds() >= 0 ? timeout->When() : now,
|
||||
now));
|
||||
}
|
||||
#endif
|
||||
num++;
|
||||
}
|
||||
if (num > 0) {
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(when));
|
||||
mIdleExecutor->Cancel();
|
||||
}
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("%p: Moved %d timeouts from Idle to active", this, num));
|
||||
}
|
||||
|
||||
uint32_t TimeoutManager::CreateFiringId() {
|
||||
uint32_t id = mNextFiringId;
|
||||
mNextFiringId += 1;
|
||||
|
@ -382,20 +444,24 @@ int32_t gDisableOpenClickDelay;
|
|||
|
||||
} // anonymous namespace
|
||||
|
||||
TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow)
|
||||
TimeoutManager::TimeoutManager(nsGlobalWindowInner& aWindow,
|
||||
uint32_t aMaxIdleDeferMS)
|
||||
: mWindow(aWindow),
|
||||
mExecutor(new TimeoutExecutor(this)),
|
||||
mExecutor(new TimeoutExecutor(this, false, 0)),
|
||||
mIdleExecutor(new TimeoutExecutor(this, true, aMaxIdleDeferMS)),
|
||||
mTimeouts(*this),
|
||||
mTimeoutIdCounter(1),
|
||||
mNextFiringId(InvalidFiringId + 1),
|
||||
mRunningTimeout(nullptr),
|
||||
mIdleTimeouts(*this),
|
||||
mIdleCallbackTimeoutCounter(1),
|
||||
mLastBudgetUpdate(TimeStamp::Now()),
|
||||
mExecutionBudget(GetMaxBudget(mWindow.IsBackgroundInternal())),
|
||||
mThrottleTimeouts(false),
|
||||
mThrottleTrackingTimeouts(false),
|
||||
mBudgetThrottleTimeouts(false) {
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
mBudgetThrottleTimeouts(false),
|
||||
mIsLoading(false) {
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("TimeoutManager %p created, tracking bucketing %s\n", this,
|
||||
StaticPrefs::privacy_trackingprotection_annotate_channels()
|
||||
? "enabled"
|
||||
|
@ -407,8 +473,10 @@ TimeoutManager::~TimeoutManager() {
|
|||
MOZ_DIAGNOSTIC_ASSERT(!mThrottleTimeoutsTimer);
|
||||
|
||||
mExecutor->Shutdown();
|
||||
mIdleExecutor->Shutdown();
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Debug, ("TimeoutManager %p destroyed\n", this));
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("TimeoutManager %p destroyed\n", this));
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
@ -538,7 +606,7 @@ nsresult TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
|||
*aReturn = timeout->mTimeoutId;
|
||||
|
||||
MOZ_LOG(
|
||||
gLog, LogLevel::Debug,
|
||||
gTimeoutLog, LogLevel::Debug,
|
||||
("Set%s(TimeoutManager=%p, timeout=%p, delay=%i, "
|
||||
"minimum=%f, throttling=%s, state=%s(%s), realInterval=%f) "
|
||||
"returned timeout ID %u, budget=%d\n",
|
||||
|
@ -553,14 +621,27 @@ nsresult TimeoutManager::SetTimeout(nsITimeoutHandler* aHandler,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// Make sure we clear it no matter which list it's in
|
||||
void TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason) {
|
||||
uint32_t timerId = (uint32_t)aTimerId;
|
||||
if (ClearTimeoutInternal(aTimerId, aReason, false) ||
|
||||
mIdleTimeouts.IsEmpty()) {
|
||||
return; // no need to check the other list if we cleared the timeout
|
||||
}
|
||||
ClearTimeoutInternal(aTimerId, aReason, true);
|
||||
}
|
||||
|
||||
bool TimeoutManager::ClearTimeoutInternal(int32_t aTimerId,
|
||||
Timeout::Reason aReason,
|
||||
bool aIsIdle) {
|
||||
uint32_t timerId = (uint32_t)aTimerId;
|
||||
Timeouts& timeouts = aIsIdle ? mIdleTimeouts : mTimeouts;
|
||||
RefPtr<TimeoutExecutor>& executor = aIsIdle ? mIdleExecutor : mExecutor;
|
||||
bool firstTimeout = true;
|
||||
bool deferredDeletion = false;
|
||||
bool cleared = false;
|
||||
|
||||
mTimeouts.ForEachAbortable([&](Timeout* aTimeout) {
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
timeouts.ForEachAbortable([&](Timeout* aTimeout) {
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Clear%s(TimeoutManager=%p, timeout=%p, aTimerId=%u, ID=%u)\n",
|
||||
aTimeout->mIsInterval ? "Interval" : "Timeout", this, aTimeout,
|
||||
timerId, aTimeout->mTimeoutId));
|
||||
|
@ -576,6 +657,7 @@ void TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason) {
|
|||
/* Delete the aTimeout from the pending aTimeout list */
|
||||
aTimeout->remove();
|
||||
}
|
||||
cleared = true;
|
||||
return true; // abort!
|
||||
}
|
||||
|
||||
|
@ -593,20 +675,27 @@ void TimeoutManager::ClearTimeout(int32_t aTimerId, Timeout::Reason aReason) {
|
|||
// * If the window has become suspended then we should not start executing
|
||||
// Timeouts.
|
||||
if (!firstTimeout || deferredDeletion || mWindow.IsSuspended()) {
|
||||
return;
|
||||
return cleared;
|
||||
}
|
||||
|
||||
// Stop the executor and restart it at the next soonest deadline.
|
||||
mExecutor->Cancel();
|
||||
executor->Cancel();
|
||||
|
||||
Timeout* nextTimeout = mTimeouts.GetFirst();
|
||||
Timeout* nextTimeout = timeouts.GetFirst();
|
||||
if (nextTimeout) {
|
||||
if (aIsIdle) {
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
executor->MaybeSchedule(nextTimeout->When(), TimeDuration(0)));
|
||||
} else {
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
|
||||
}
|
||||
}
|
||||
return cleared;
|
||||
}
|
||||
|
||||
void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
||||
const TimeStamp& aTargetDeadline) {
|
||||
const TimeStamp& aTargetDeadline,
|
||||
bool aProcessIdle) {
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aNow.IsNull());
|
||||
MOZ_DIAGNOSTIC_ASSERT(!aTargetDeadline.IsNull());
|
||||
|
||||
|
@ -615,6 +704,8 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
return;
|
||||
}
|
||||
|
||||
Timeouts& timeouts(aProcessIdle ? mIdleTimeouts : mTimeouts);
|
||||
|
||||
// Limit the overall time spent in RunTimeout() to reduce jank.
|
||||
uint32_t totalTimeLimitMS =
|
||||
std::max(1u, gMaxConsecutiveCallbacksMilliseconds);
|
||||
|
@ -671,7 +762,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
// if the timer fired early. So we can stop walking if we get to timeouts
|
||||
// whose When() is greater than deadline, since once that happens we know
|
||||
// nothing past that point is expired.
|
||||
for (Timeout* timeout = mTimeouts.GetFirst(); timeout != nullptr;
|
||||
for (Timeout* timeout = timeouts.GetFirst(); timeout != nullptr;
|
||||
timeout = timeout->getNext()) {
|
||||
if (totalTimeLimit.IsZero() || timeout->When() > deadline) {
|
||||
nextDeadline = timeout->When();
|
||||
|
@ -696,6 +787,12 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
}
|
||||
}
|
||||
}
|
||||
if (aProcessIdle) {
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Running %u deferred timeouts on idle (TimeoutManager=%p), "
|
||||
"nextDeadline = %gms from now",
|
||||
numTimersToRun, this, (nextDeadline - now).ToMilliseconds()));
|
||||
}
|
||||
|
||||
now = TimeStamp::Now();
|
||||
|
||||
|
@ -709,8 +806,16 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
// method and the window should not have been suspended while
|
||||
// executing the loop above since it doesn't call out to js.
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mWindow.IsSuspended());
|
||||
if (aProcessIdle) {
|
||||
// We don't want to update timing budget for idle queue firings, and
|
||||
// all timeouts in the IdleTimeouts list have hit their deadlines,
|
||||
// and so should run as soon as possible.
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mIdleExecutor->MaybeSchedule(nextDeadline, TimeDuration()));
|
||||
} else {
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextDeadline, now));
|
||||
}
|
||||
}
|
||||
|
||||
// Maybe the timeout that the event was fired for has been deleted
|
||||
// and there are no others timeouts with deadlines that make them
|
||||
|
@ -736,16 +841,21 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
// timeout.
|
||||
RefPtr<Timeout> next;
|
||||
|
||||
for (RefPtr<Timeout> timeout = mTimeouts.GetFirst(); timeout != nullptr;
|
||||
for (RefPtr<Timeout> timeout = timeouts.GetFirst(); timeout != nullptr;
|
||||
timeout = next) {
|
||||
next = timeout->getNext();
|
||||
// We should only execute callbacks for the set of expired Timeout
|
||||
// objects we computed above.
|
||||
if (timeout->mFiringId != firingId) {
|
||||
// If the FiringId does not match, but is still valid, then this is
|
||||
// a TImeout for another RunTimeout() on the call stack. Just
|
||||
// a Timeout for another RunTimeout() on the call stack. Just
|
||||
// skip it.
|
||||
if (IsValidFiringId(timeout->mFiringId)) {
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Skipping Run%s(TimeoutManager=%p, timeout=%p) since "
|
||||
"firingId %d is valid (processing firingId %d)",
|
||||
timeout->mIsInterval ? "Interval" : "Timeout", this,
|
||||
timeout.get(), timeout->mFiringId, firingId));
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -767,6 +877,28 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
// The timeout is on the list to run at this depth, go ahead and
|
||||
// process it.
|
||||
|
||||
if (mIsLoading && !aProcessIdle) {
|
||||
// Any timeouts that would fire during a load will be deferred
|
||||
// until the load event occurs, but if there's an idle time,
|
||||
// they'll be run before the load event.
|
||||
timeout->remove();
|
||||
// MOZ_RELEASE_ASSERT(timeout->When() <= (TimeStamp::Now()));
|
||||
mIdleTimeouts.InsertBack(timeout);
|
||||
if (MOZ_LOG_TEST(gTimeoutLog, LogLevel::Debug)) {
|
||||
uint32_t num = 0;
|
||||
for (Timeout* t = mIdleTimeouts.GetFirst(); t != nullptr;
|
||||
t = t->getNext()) {
|
||||
num++;
|
||||
}
|
||||
MOZ_LOG(
|
||||
gTimeoutLog, LogLevel::Debug,
|
||||
("Deferring Run%s(TimeoutManager=%p, timeout=%p (%gms in the "
|
||||
"past)) (%u deferred)",
|
||||
timeout->mIsInterval ? "Interval" : "Timeout", this,
|
||||
timeout.get(), (now - timeout->When()).ToMilliseconds(), num));
|
||||
}
|
||||
MOZ_ALWAYS_SUCCEEDS(mIdleExecutor->MaybeSchedule(now, TimeDuration()));
|
||||
} else {
|
||||
// Get the script context (a strong ref to prevent it going away)
|
||||
// for this timeout and ensure the script language is enabled.
|
||||
nsCOMPtr<nsIScriptContext> scx = mWindow.GetContextInternal();
|
||||
|
@ -780,9 +912,29 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
}
|
||||
|
||||
// This timeout is good to run
|
||||
#if MOZ_GECKO_PROFILER
|
||||
if (profiler_is_active()) {
|
||||
if (aProcessIdle) {
|
||||
TimeDuration elapsed = now - timeout->SubmitTime();
|
||||
TimeDuration target = timeout->When() - timeout->SubmitTime();
|
||||
TimeDuration delta = now - timeout->When();
|
||||
nsPrintfCString marker(
|
||||
"%ssetTimeout() for %dms (original target time was %dms (%dms "
|
||||
"delta))",
|
||||
aProcessIdle ? "Deferred " : "", int(elapsed.ToMilliseconds()),
|
||||
int(target.ToMilliseconds()), int(delta.ToMilliseconds()));
|
||||
// don't have end before start...
|
||||
profiler_add_marker(
|
||||
"setTimeout", js::ProfilingStackFrame::Category::DOM,
|
||||
MakeUnique<TextMarkerPayload>(
|
||||
marker, delta.ToMilliseconds() >= 0 ? timeout->When() : now,
|
||||
now));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
bool timeout_was_cleared = mWindow.RunTimeoutHandler(timeout, scx);
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("Run%s(TimeoutManager=%p, timeout=%p) returned %d\n",
|
||||
timeout->mIsInterval ? "Interval" : "Timeout", this,
|
||||
timeout.get(), !!timeout_was_cleared));
|
||||
|
@ -806,7 +958,8 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
|
||||
// If we have a regular interval timer, we re-schedule the
|
||||
// timeout, accounting for clock drift.
|
||||
bool needsReinsertion = RescheduleTimeout(timeout, lastCallbackTime, now);
|
||||
bool needsReinsertion =
|
||||
RescheduleTimeout(timeout, lastCallbackTime, now);
|
||||
|
||||
// Running a timeout can cause another timeout to be deleted, so
|
||||
// we need to reset the pointer to the following timeout.
|
||||
|
@ -817,11 +970,12 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
if (needsReinsertion) {
|
||||
// Insert interval timeout onto the corresponding list sorted in
|
||||
// deadline order. AddRefs timeout.
|
||||
// Always re-insert into the normal time queue!
|
||||
mTimeouts.Insert(timeout, mWindow.IsFrozen()
|
||||
? Timeouts::SortBy::TimeRemaining
|
||||
: Timeouts::SortBy::TimeWhen);
|
||||
}
|
||||
|
||||
}
|
||||
// Check to see if we have run out of time to execute timeout handlers.
|
||||
// If we've exceeded our time budget then terminate the loop immediately.
|
||||
TimeDuration elapsed = now - start;
|
||||
|
@ -832,6 +986,15 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
// that happened then we must skip this step.
|
||||
if (!mWindow.IsSuspended()) {
|
||||
if (next) {
|
||||
if (aProcessIdle) {
|
||||
// We don't want to update timing budget for idle queue firings,
|
||||
// and all timeouts in the IdleTimeouts list have hit their
|
||||
// deadlines, and so should run as soon as possible.
|
||||
|
||||
// Shouldn't need cancelling since it never waits
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mIdleExecutor->MaybeSchedule(next->When(), TimeDuration()));
|
||||
} else {
|
||||
// If we ran out of execution budget we need to force a
|
||||
// reschedule. By cancelling the executor we will not run
|
||||
// immediately, but instead reschedule to the minimum
|
||||
|
@ -843,6 +1006,7 @@ void TimeoutManager::RunTimeout(const TimeStamp& aNow,
|
|||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(next->When(), now));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -893,7 +1057,7 @@ bool TimeoutManager::RescheduleTimeout(Timeout* aTimeout,
|
|||
void TimeoutManager::ClearAllTimeouts() {
|
||||
bool seenRunningTimeout = false;
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("ClearAllTimeouts(TimeoutManager=%p)\n", this));
|
||||
|
||||
if (mThrottleTimeoutsTimer) {
|
||||
|
@ -902,6 +1066,7 @@ void TimeoutManager::ClearAllTimeouts() {
|
|||
}
|
||||
|
||||
mExecutor->Cancel();
|
||||
mIdleExecutor->Cancel();
|
||||
|
||||
ForEachUnorderedTimeout([&](Timeout* aTimeout) {
|
||||
/* If RunTimeout() is higher up on the stack for this
|
||||
|
@ -918,8 +1083,9 @@ void TimeoutManager::ClearAllTimeouts() {
|
|||
aTimeout->mCleared = true;
|
||||
});
|
||||
|
||||
// Clear out our list
|
||||
// Clear out our lists
|
||||
mTimeouts.Clear();
|
||||
mIdleTimeouts.Clear();
|
||||
}
|
||||
|
||||
void TimeoutManager::Timeouts::Insert(Timeout* aTimeout, SortBy aSortBy) {
|
||||
|
@ -976,7 +1142,7 @@ void TimeoutManager::UnmarkGrayTimers() {
|
|||
}
|
||||
|
||||
void TimeoutManager::Suspend() {
|
||||
MOZ_LOG(gLog, LogLevel::Debug, ("Suspend(TimeoutManager=%p)\n", this));
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Suspend(TimeoutManager=%p)\n", this));
|
||||
|
||||
if (mThrottleTimeoutsTimer) {
|
||||
mThrottleTimeoutsTimer->Cancel();
|
||||
|
@ -984,10 +1150,11 @@ void TimeoutManager::Suspend() {
|
|||
}
|
||||
|
||||
mExecutor->Cancel();
|
||||
mIdleExecutor->Cancel();
|
||||
}
|
||||
|
||||
void TimeoutManager::Resume() {
|
||||
MOZ_LOG(gLog, LogLevel::Debug, ("Resume(TimeoutManager=%p)\n", this));
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Resume(TimeoutManager=%p)\n", this));
|
||||
|
||||
// When Suspend() has been called after IsDocumentLoaded(), but the
|
||||
// throttle tracking timer never managed to fire, start the timer
|
||||
|
@ -1000,10 +1167,15 @@ void TimeoutManager::Resume() {
|
|||
if (nextTimeout) {
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
|
||||
}
|
||||
nextTimeout = mIdleTimeouts.GetFirst();
|
||||
if (nextTimeout) {
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mIdleExecutor->MaybeSchedule(nextTimeout->When(), TimeDuration()));
|
||||
}
|
||||
}
|
||||
|
||||
void TimeoutManager::Freeze() {
|
||||
MOZ_LOG(gLog, LogLevel::Debug, ("Freeze(TimeoutManager=%p)\n", this));
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Freeze(TimeoutManager=%p)\n", this));
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
ForEachUnorderedTimeout([&](Timeout* aTimeout) {
|
||||
|
@ -1021,7 +1193,7 @@ void TimeoutManager::Freeze() {
|
|||
}
|
||||
|
||||
void TimeoutManager::Thaw() {
|
||||
MOZ_LOG(gLog, LogLevel::Debug, ("Thaw(TimeoutManager=%p)\n", this));
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug, ("Thaw(TimeoutManager=%p)\n", this));
|
||||
|
||||
TimeStamp now = TimeStamp::Now();
|
||||
|
||||
|
@ -1045,6 +1217,17 @@ void TimeoutManager::UpdateBackgroundState() {
|
|||
mExecutor->Cancel();
|
||||
MOZ_ALWAYS_SUCCEEDS(MaybeSchedule(nextTimeout->When()));
|
||||
}
|
||||
// the Idle queue should all be past their firing time, so there we just
|
||||
// need to restart the queue
|
||||
|
||||
// XXX May not be needed if we don't stop the idle queue, as
|
||||
// MinSchedulingDelay isn't relevant here
|
||||
nextTimeout = mIdleTimeouts.GetFirst();
|
||||
if (nextTimeout) {
|
||||
mIdleExecutor->Cancel();
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
mIdleExecutor->MaybeSchedule(nextTimeout->When(), TimeDuration()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1307,7 @@ void TimeoutManager::StartThrottlingTimeouts() {
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_DIAGNOSTIC_ASSERT(mThrottleTimeoutsTimer);
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("TimeoutManager %p started to throttle tracking timeouts\n", this));
|
||||
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mThrottleTimeouts);
|
||||
|
@ -1151,7 +1334,7 @@ void TimeoutManager::MaybeStartThrottleTimeout() {
|
|||
|
||||
MOZ_DIAGNOSTIC_ASSERT(!mThrottleTimeouts);
|
||||
|
||||
MOZ_LOG(gLog, LogLevel::Debug,
|
||||
MOZ_LOG(gTimeoutLog, LogLevel::Debug,
|
||||
("TimeoutManager %p delaying tracking timeout throttling by %dms\n",
|
||||
this, gTimeoutThrottlingDelay));
|
||||
|
||||
|
|
|
@ -25,8 +25,11 @@ class TimeoutExecutor;
|
|||
|
||||
// This class manages the timeouts in a Window's setTimeout/setInterval pool.
|
||||
class TimeoutManager final {
|
||||
private:
|
||||
struct Timeouts;
|
||||
|
||||
public:
|
||||
explicit TimeoutManager(nsGlobalWindowInner& aWindow);
|
||||
TimeoutManager(nsGlobalWindowInner& aWindow, uint32_t aMaxIdleDeferMS);
|
||||
~TimeoutManager();
|
||||
TimeoutManager(const TimeoutManager& rhs) = delete;
|
||||
void operator=(const TimeoutManager& rhs) = delete;
|
||||
|
@ -36,15 +39,21 @@ class TimeoutManager final {
|
|||
static uint32_t GetNestingLevel() { return sNestingLevel; }
|
||||
static void SetNestingLevel(uint32_t aLevel) { sNestingLevel = aLevel; }
|
||||
|
||||
bool HasTimeouts() const { return !mTimeouts.IsEmpty(); }
|
||||
bool HasTimeouts() const {
|
||||
return !mTimeouts.IsEmpty() || !mIdleTimeouts.IsEmpty();
|
||||
}
|
||||
|
||||
nsresult SetTimeout(nsITimeoutHandler* aHandler, int32_t interval,
|
||||
bool aIsInterval, mozilla::dom::Timeout::Reason aReason,
|
||||
int32_t* aReturn);
|
||||
void ClearTimeout(int32_t aTimerId, mozilla::dom::Timeout::Reason aReason);
|
||||
bool ClearTimeoutInternal(int32_t aTimerId,
|
||||
mozilla::dom::Timeout::Reason aReason,
|
||||
bool aIsIdle);
|
||||
|
||||
// The timeout implementation functions.
|
||||
void RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline);
|
||||
void RunTimeout(const TimeStamp& aNow, const TimeStamp& aTargetDeadline,
|
||||
bool aProcessIdle);
|
||||
|
||||
void ClearAllTimeouts();
|
||||
uint32_t GetTimeoutId(mozilla::dom::Timeout::Reason aReason);
|
||||
|
@ -81,6 +90,7 @@ class TimeoutManager final {
|
|||
// doesn't guarantee that Timeouts are iterated in any particular order.
|
||||
template <class Callable>
|
||||
void ForEachUnorderedTimeout(Callable c) {
|
||||
mIdleTimeouts.ForEach(c);
|
||||
mTimeouts.ForEach(c);
|
||||
}
|
||||
|
||||
|
@ -93,6 +103,8 @@ class TimeoutManager final {
|
|||
|
||||
static const uint32_t InvalidFiringId;
|
||||
|
||||
void SetLoading(bool value);
|
||||
|
||||
private:
|
||||
void MaybeStartThrottleTimeout();
|
||||
|
||||
|
@ -101,6 +113,8 @@ class TimeoutManager final {
|
|||
const TimeStamp& aLastCallbackTime,
|
||||
const TimeStamp& aCurrentNow);
|
||||
|
||||
void MoveIdleToActive();
|
||||
|
||||
bool IsBackground() const;
|
||||
|
||||
bool IsActive() const;
|
||||
|
@ -141,6 +155,7 @@ class TimeoutManager final {
|
|||
Timeout* GetLast() { return mTimeoutList.getLast(); }
|
||||
bool IsEmpty() const { return mTimeoutList.isEmpty(); }
|
||||
void InsertFront(Timeout* aTimeout) { mTimeoutList.insertFront(aTimeout); }
|
||||
void InsertBack(Timeout* aTimeout) { mTimeoutList.insertBack(aTimeout); }
|
||||
void Clear() { mTimeoutList.clear(); }
|
||||
|
||||
template <class Callable>
|
||||
|
@ -182,6 +197,8 @@ class TimeoutManager final {
|
|||
// can live past the destruction of the window if its scheduled. Therefore
|
||||
// it must be a separate ref-counted object.
|
||||
RefPtr<TimeoutExecutor> mExecutor;
|
||||
// For timeouts run off the idle queue
|
||||
RefPtr<TimeoutExecutor> mIdleExecutor;
|
||||
// The list of timeouts coming from non-tracking scripts.
|
||||
Timeouts mTimeouts;
|
||||
uint32_t mTimeoutIdCounter;
|
||||
|
@ -189,6 +206,10 @@ class TimeoutManager final {
|
|||
AutoTArray<uint32_t, 2> mFiringIdStack;
|
||||
mozilla::dom::Timeout* mRunningTimeout;
|
||||
|
||||
// Timeouts that would have fired but are being deferred until MainThread
|
||||
// is idle (because we're loading)
|
||||
Timeouts mIdleTimeouts;
|
||||
|
||||
// The current idle request callback timeout handle
|
||||
uint32_t mIdleCallbackTimeoutCounter;
|
||||
|
||||
|
@ -200,6 +221,8 @@ class TimeoutManager final {
|
|||
bool mThrottleTrackingTimeouts;
|
||||
bool mBudgetThrottleTimeouts;
|
||||
|
||||
bool mIsLoading;
|
||||
|
||||
static uint32_t sNestingLevel;
|
||||
};
|
||||
|
||||
|
|
|
@ -88,7 +88,8 @@ WindowDestroyedEvent::Run() {
|
|||
mPhase = Phase::Nuking;
|
||||
|
||||
nsCOMPtr<nsIRunnable> copy(this);
|
||||
NS_IdleDispatchToCurrentThread(copy.forget(), 1000);
|
||||
NS_DispatchToCurrentThreadQueue(copy.forget(), 1000,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
} break;
|
||||
|
||||
|
|
|
@ -3674,13 +3674,16 @@ void nsContentUtils::AsyncPrecreateStringBundles() {
|
|||
|
||||
for (uint32_t bundleIndex = 0; bundleIndex < PropertiesFile_COUNT;
|
||||
++bundleIndex) {
|
||||
nsresult rv = NS_IdleDispatchToCurrentThread(
|
||||
NS_NewRunnableFunction("AsyncPrecreateStringBundles", [bundleIndex]() {
|
||||
PropertiesFile file = static_cast<PropertiesFile>(bundleIndex);
|
||||
nsresult rv = NS_DispatchToCurrentThreadQueue(
|
||||
NS_NewRunnableFunction("AsyncPrecreateStringBundles",
|
||||
[bundleIndex]() {
|
||||
PropertiesFile file =
|
||||
static_cast<PropertiesFile>(bundleIndex);
|
||||
EnsureStringBundle(file);
|
||||
nsIStringBundle* bundle = sStringBundles[file];
|
||||
bundle->AsyncPreload();
|
||||
}));
|
||||
}),
|
||||
EventQueuePriority::Idle);
|
||||
Unused << NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -617,7 +617,7 @@ void IdleRequestExecutor::ScheduleDispatch() {
|
|||
MOZ_ASSERT(mWindow);
|
||||
mDelayedExecutorHandle = Nothing();
|
||||
RefPtr<IdleRequestExecutor> request = this;
|
||||
NS_IdleDispatchToCurrentThread(request.forget());
|
||||
NS_DispatchToCurrentThreadQueue(request.forget(), EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
void IdleRequestExecutor::DelayedDispatch(uint32_t aDelay) {
|
||||
|
@ -886,7 +886,8 @@ nsGlobalWindowInner::nsGlobalWindowInner(nsGlobalWindowOuter* aOuterWindow)
|
|||
// add this inner window to the outer window list of inners.
|
||||
PR_INSERT_AFTER(this, aOuterWindow);
|
||||
|
||||
mTimeoutManager = MakeUnique<dom::TimeoutManager>(*this);
|
||||
mTimeoutManager = MakeUnique<dom::TimeoutManager>(
|
||||
*this, StaticPrefs::dom_timeout_max_idle_defer_ms());
|
||||
|
||||
mObserver = new nsGlobalWindowObserver(this);
|
||||
nsCOMPtr<nsIObserverService> os = mozilla::services::GetObserverService();
|
||||
|
@ -2541,6 +2542,12 @@ void nsPIDOMWindowInner::SetAudioCapture(bool aCapture) {
|
|||
}
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::SetActiveLoadingState(bool aIsLoading) /* const? */ {
|
||||
if (!nsGlobalWindowInner::Cast(this)->IsChromeWindow()) {
|
||||
mTimeoutManager->SetLoading(aIsLoading);
|
||||
}
|
||||
}
|
||||
|
||||
// nsISpeechSynthesisGetter
|
||||
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
|
|
|
@ -2056,6 +2056,12 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|||
newInnerGlobal = newInnerWindow->GetWrapperPreserveColor();
|
||||
} else {
|
||||
newInnerWindow = nsGlobalWindowInner::Create(this, thisChrome);
|
||||
if (StaticPrefs::dom_timeout_defer_during_load()) {
|
||||
// ensure the initial loading state is known
|
||||
newInnerWindow->SetActiveLoadingState(
|
||||
aDocument->GetReadyStateEnum() ==
|
||||
Document::ReadyState::READYSTATE_LOADING);
|
||||
}
|
||||
|
||||
// The outer window is automatically treated as frozen when we
|
||||
// null out the inner window. As a result, initializing classes
|
||||
|
|
|
@ -169,10 +169,14 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
// Returns true if this window is the same as mTopInnerWindow
|
||||
inline bool IsTopInnerWindow() const;
|
||||
|
||||
// Check whether a document is currently loading
|
||||
// Check whether a document is currently loading (really checks if the
|
||||
// load event has completed). May not be reset to false on errors.
|
||||
inline bool IsLoading() const;
|
||||
inline bool IsHandlingResizeEvent() const;
|
||||
|
||||
// Note: not related to IsLoading. Set to false if there's an error, etc.
|
||||
void SetActiveLoadingState(bool aIsActiveLoading);
|
||||
|
||||
bool AddAudioContext(mozilla::dom::AudioContext* aAudioContext);
|
||||
void RemoveAudioContext(mozilla::dom::AudioContext* aAudioContext);
|
||||
void MuteAudioContexts();
|
||||
|
|
|
@ -1718,7 +1718,8 @@ mozilla::ipc::IPCResult ContentChild::RecvPBrowserConstructor(
|
|||
RefPtr<CancelableRunnable> firstIdleTask =
|
||||
NewCancelableRunnableFunction("FirstIdleRunnable", FirstIdle);
|
||||
gFirstIdleTask = firstIdleTask;
|
||||
if (NS_FAILED(NS_IdleDispatchToCurrentThread(firstIdleTask.forget()))) {
|
||||
if (NS_FAILED(NS_DispatchToCurrentThreadQueue(firstIdleTask.forget(),
|
||||
EventQueuePriority::Idle))) {
|
||||
gFirstIdleTask = nullptr;
|
||||
hasRunOnce = false;
|
||||
}
|
||||
|
|
|
@ -245,9 +245,10 @@ void PreallocatedProcessManagerImpl::AllocateOnIdle() {
|
|||
return;
|
||||
}
|
||||
|
||||
NS_IdleDispatchToCurrentThread(
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewRunnableMethod("PreallocatedProcessManagerImpl::AllocateNow", this,
|
||||
&PreallocatedProcessManagerImpl::AllocateNow));
|
||||
&PreallocatedProcessManagerImpl::AllocateNow),
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
void PreallocatedProcessManagerImpl::AllocateNow() {
|
||||
|
|
|
@ -415,8 +415,10 @@ nsresult WritableSharedMap::KeyChanged(const nsACString& aName) {
|
|||
mEntryArray.reset();
|
||||
|
||||
if (!mPendingFlush) {
|
||||
MOZ_TRY(NS_IdleDispatchToCurrentThread(NewRunnableMethod(
|
||||
"WritableSharedMap::IdleFlush", this, &WritableSharedMap::IdleFlush)));
|
||||
MOZ_TRY(NS_DispatchToCurrentThreadQueue(
|
||||
NewRunnableMethod("WritableSharedMap::IdleFlush", this,
|
||||
&WritableSharedMap::IdleFlush),
|
||||
EventQueuePriority::Idle));
|
||||
mPendingFlush = true;
|
||||
}
|
||||
return NS_OK;
|
||||
|
|
|
@ -2755,7 +2755,8 @@ void ScriptLoader::MaybeTriggerBytecodeEncoding() {
|
|||
// give-up on encoding the bytecode.
|
||||
nsCOMPtr<nsIRunnable> encoder = NewRunnableMethod(
|
||||
"ScriptLoader::EncodeBytecode", this, &ScriptLoader::EncodeBytecode);
|
||||
if (NS_FAILED(NS_IdleDispatchToCurrentThread(encoder.forget()))) {
|
||||
if (NS_FAILED(NS_DispatchToCurrentThreadQueue(encoder.forget(),
|
||||
EventQueuePriority::Idle))) {
|
||||
GiveUpBytecodeEncoding();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "DOMSVGAngle.h"
|
||||
#include "SVGAngle.h"
|
||||
#include "mozilla/dom/SVGAngleBinding.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
|
@ -16,7 +17,7 @@ NS_SVG_VAL_IMPL_CYCLE_COLLECTION_WRAPPERCACHED(DOMSVGAngle, mSVGElement)
|
|||
NS_IMPL_CYCLE_COLLECTION_ROOT_NATIVE(DOMSVGAngle, AddRef)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNROOT_NATIVE(DOMSVGAngle, Release)
|
||||
|
||||
DOMSVGAngle::DOMSVGAngle(SVGElement* aSVGElement)
|
||||
DOMSVGAngle::DOMSVGAngle(SVGSVGElement* aSVGElement)
|
||||
: mSVGElement(aSVGElement), mType(DOMSVGAngle::CreatedValue) {
|
||||
mVal = new SVGAngle();
|
||||
mVal->Init();
|
||||
|
|
|
@ -15,6 +15,7 @@ class SVGAngle;
|
|||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
class SVGSVGElement;
|
||||
|
||||
class DOMSVGAngle final : public nsWrapperCache {
|
||||
public:
|
||||
|
@ -33,7 +34,7 @@ class DOMSVGAngle final : public nsWrapperCache {
|
|||
* Ctor for creating the objects returned by SVGSVGElement.createSVGAngle(),
|
||||
* which do not initially belong to an attribute.
|
||||
*/
|
||||
explicit DOMSVGAngle(SVGElement* aSVGElement);
|
||||
explicit DOMSVGAngle(SVGSVGElement* aSVGElement);
|
||||
|
||||
// WebIDL
|
||||
SVGElement* GetParentObject() { return mSVGElement; }
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "nsError.h"
|
||||
#include "nsContentUtils.h" // for NS_ENSURE_FINITE
|
||||
#include "mozilla/dom/SVGNumberBinding.h"
|
||||
#include "mozilla/dom/SVGSVGElement.h"
|
||||
|
||||
// See the architecture comment in DOMSVGAnimatedNumberList.h.
|
||||
|
||||
|
@ -105,6 +106,14 @@ DOMSVGNumber::DOMSVGNumber(nsISupports* aParent)
|
|||
mIsAnimValItem(false),
|
||||
mValue(0.0f) {}
|
||||
|
||||
DOMSVGNumber::DOMSVGNumber(SVGSVGElement* aParent)
|
||||
: mList(nullptr),
|
||||
mParent(ToSupports(aParent)),
|
||||
mListIndex(0),
|
||||
mAttrEnum(0),
|
||||
mIsAnimValItem(false),
|
||||
mValue(0.0f) {}
|
||||
|
||||
float DOMSVGNumber::Value() {
|
||||
if (mIsAnimValItem && HasOwner()) {
|
||||
Element()->FlushAnimations(); // May make HasOwner() == false
|
||||
|
|
|
@ -22,6 +22,7 @@ namespace mozilla {
|
|||
|
||||
namespace dom {
|
||||
class SVGElement;
|
||||
class SVGSVGElement;
|
||||
|
||||
/**
|
||||
* Class DOMSVGNumber
|
||||
|
@ -62,8 +63,12 @@ class DOMSVGNumber final : public nsISupports, public nsWrapperCache {
|
|||
* Ctor for creating the objects returned by SVGSVGElement.createSVGNumber(),
|
||||
* which do not initially belong to an attribute.
|
||||
*/
|
||||
explicit DOMSVGNumber(SVGSVGElement* aParent);
|
||||
|
||||
private:
|
||||
explicit DOMSVGNumber(nsISupports* aParent);
|
||||
|
||||
public:
|
||||
/**
|
||||
* Create an unowned copy. The caller is responsible for the first AddRef().
|
||||
*/
|
||||
|
|
|
@ -83,7 +83,7 @@ bool SVGGeometryElement::GeometryDependsOnCoordCtx() {
|
|||
|
||||
bool SVGGeometryElement::IsMarkable() { return false; }
|
||||
|
||||
void SVGGeometryElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {}
|
||||
void SVGGeometryElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {}
|
||||
|
||||
already_AddRefed<Path> SVGGeometryElement::GetOrBuildPath(
|
||||
const DrawTarget* aDrawTarget, FillRule aFillRule) {
|
||||
|
|
|
@ -12,7 +12,9 @@
|
|||
#include "nsISVGPoint.h"
|
||||
#include "nsSVGNumber2.h"
|
||||
|
||||
struct nsSVGMark {
|
||||
namespace mozilla {
|
||||
|
||||
struct SVGMark {
|
||||
enum Type {
|
||||
eStart,
|
||||
eMid,
|
||||
|
@ -23,11 +25,10 @@ struct nsSVGMark {
|
|||
|
||||
float x, y, angle;
|
||||
Type type;
|
||||
nsSVGMark(float aX, float aY, float aAngle, Type aType)
|
||||
SVGMark(float aX, float aY, float aAngle, Type aType)
|
||||
: x(aX), y(aY), angle(aAngle), type(aType) {}
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SVGAnimatedNumber;
|
||||
|
@ -78,7 +79,7 @@ class SVGGeometryElement : public SVGGeometryElementBase {
|
|||
bool GeometryDependsOnCoordCtx();
|
||||
|
||||
virtual bool IsMarkable();
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark>* aMarks);
|
||||
virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks);
|
||||
|
||||
/**
|
||||
* A method that can be faster than using a Moz2D Path and calling GetBounds/
|
||||
|
|
|
@ -99,15 +99,15 @@ SVGElement::LengthAttributesInfo SVGLineElement::GetLengthInfo() {
|
|||
//----------------------------------------------------------------------
|
||||
// SVGGeometryElement methods
|
||||
|
||||
void SVGLineElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {
|
||||
void SVGLineElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
||||
float x1, y1, x2, y2;
|
||||
|
||||
GetAnimatedLengthValues(&x1, &y1, &x2, &y2, nullptr);
|
||||
|
||||
float angle = atan2(y2 - y1, x2 - x1);
|
||||
|
||||
aMarks->AppendElement(nsSVGMark(x1, y1, angle, nsSVGMark::eStart));
|
||||
aMarks->AppendElement(nsSVGMark(x2, y2, angle, nsSVGMark::eEnd));
|
||||
aMarks->AppendElement(SVGMark(x1, y1, angle, SVGMark::eStart));
|
||||
aMarks->AppendElement(SVGMark(x2, y2, angle, SVGMark::eEnd));
|
||||
}
|
||||
|
||||
void SVGLineElement::GetAsSimplePath(SimplePath* aSimplePath) {
|
||||
|
|
|
@ -37,7 +37,7 @@ class SVGLineElement final : public SVGLineElementBase {
|
|||
|
||||
// SVGGeometryElement methods:
|
||||
virtual bool IsMarkable() override { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark>* aMarks) override;
|
||||
virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks) override;
|
||||
virtual void GetAsSimplePath(SimplePath* aSimplePath) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
virtual bool GetGeometryBounds(
|
||||
|
|
|
@ -250,7 +250,7 @@ SVGAnimatedPreserveAspectRatio* SVGMarkerElement::GetPreserveAspectRatio() {
|
|||
// public helpers
|
||||
|
||||
gfx::Matrix SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
|
||||
const nsSVGMark& aMark) {
|
||||
const SVGMark& aMark) {
|
||||
float scale =
|
||||
mEnumAttributes[MARKERUNITS].GetAnimValue() == SVG_MARKERUNITS_STROKEWIDTH
|
||||
? aStrokeWidth
|
||||
|
@ -262,7 +262,7 @@ gfx::Matrix SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
|
|||
angle = aMark.angle;
|
||||
break;
|
||||
case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
|
||||
angle = aMark.angle + (aMark.type == nsSVGMark::eStart ? M_PI : 0.0f);
|
||||
angle = aMark.angle + (aMark.type == SVGMark::eStart ? M_PI : 0.0f);
|
||||
break;
|
||||
default: // SVG_MARKER_ORIENT_ANGLE
|
||||
angle = mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0f;
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
#include "mozilla/dom/SVGMarkerElementBinding.h"
|
||||
|
||||
class nsSVGMarkerFrame;
|
||||
struct nsSVGMark;
|
||||
|
||||
nsresult NS_NewSVGMarkerElement(
|
||||
nsIContent** aResult, already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo);
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct SVGMark;
|
||||
|
||||
namespace dom {
|
||||
|
||||
// Non-Exposed Marker Orientation Types
|
||||
|
@ -108,7 +110,7 @@ class SVGMarkerElement : public SVGMarkerElementBase {
|
|||
virtual bool HasValidDimensions() const override;
|
||||
|
||||
// public helpers
|
||||
gfx::Matrix GetMarkerTransform(float aStrokeWidth, const nsSVGMark& aMark);
|
||||
gfx::Matrix GetMarkerTransform(float aStrokeWidth, const SVGMark& aMark);
|
||||
SVGViewBoxRect GetViewBoxRect();
|
||||
gfx::Matrix GetViewBoxTransform();
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
#include <stdarg.h>
|
||||
#include "nsStyleConsts.h"
|
||||
#include "SVGContentUtils.h"
|
||||
#include "SVGGeometryElement.h" // for nsSVGMark
|
||||
#include "SVGGeometryElement.h"
|
||||
#include "SVGPathSegUtils.h"
|
||||
#include <algorithm>
|
||||
|
||||
|
@ -748,7 +748,7 @@ static float AngleOfVector(const Point& cp1, const Point& cp2) {
|
|||
return static_cast<float>(AngleOfVector(cp1 - cp2));
|
||||
}
|
||||
|
||||
void SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark>* aMarks) const {
|
||||
void SVGPathData::GetMarkerPositioningData(nsTArray<SVGMark>* aMarks) const {
|
||||
// This code should assume that ANY type of segment can appear at ANY index.
|
||||
// It should also assume that segments such as M and Z can appear in weird
|
||||
// places, and repeat multiple times consecutively.
|
||||
|
@ -1018,7 +1018,7 @@ void SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark>* aMarks) const {
|
|||
|
||||
// Set the angle of the mark at the start of this segment:
|
||||
if (aMarks->Length()) {
|
||||
nsSVGMark& mark = aMarks->LastElement();
|
||||
SVGMark& mark = aMarks->LastElement();
|
||||
if (!IsMoveto(segType) && IsMoveto(prevSegType)) {
|
||||
// start of new subpath
|
||||
pathStartAngle = mark.angle = segStartAngle;
|
||||
|
@ -1033,9 +1033,9 @@ void SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark>* aMarks) const {
|
|||
}
|
||||
|
||||
// Add the mark at the end of this segment, and set its position:
|
||||
if (!aMarks->AppendElement(nsSVGMark(static_cast<float>(segEnd.x),
|
||||
if (!aMarks->AppendElement(SVGMark(static_cast<float>(segEnd.x),
|
||||
static_cast<float>(segEnd.y), 0.0f,
|
||||
nsSVGMark::eMid))) {
|
||||
SVGMark::eMid))) {
|
||||
aMarks->Clear(); // OOM, so try to free some
|
||||
return;
|
||||
}
|
||||
|
@ -1057,8 +1057,8 @@ void SVGPathData::GetMarkerPositioningData(nsTArray<nsSVGMark>* aMarks) const {
|
|||
if (prevSegType != PATHSEG_CLOSEPATH) {
|
||||
aMarks->LastElement().angle = prevSegEndAngle;
|
||||
}
|
||||
aMarks->LastElement().type = nsSVGMark::eEnd;
|
||||
aMarks->ElementAt(0).type = nsSVGMark::eStart;
|
||||
aMarks->LastElement().type = SVGMark::eEnd;
|
||||
aMarks->ElementAt(0).type = SVGMark::eStart;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,10 +21,10 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
struct nsSVGMark;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct SVGMark;
|
||||
|
||||
class SVGPathDataParser; // IWYU pragma: keep
|
||||
|
||||
/**
|
||||
|
@ -137,7 +137,7 @@ class SVGPathData {
|
|||
|
||||
uint32_t GetPathSegAtLength(float aLength) const;
|
||||
|
||||
void GetMarkerPositioningData(nsTArray<nsSVGMark>* aMarks) const;
|
||||
void GetMarkerPositioningData(nsTArray<SVGMark>* aMarks) const;
|
||||
|
||||
/**
|
||||
* Returns true, except on OOM, in which case returns false.
|
||||
|
|
|
@ -244,7 +244,7 @@ bool SVGPathElement::AttributeDefinesGeometry(const nsAtom* aName) {
|
|||
|
||||
bool SVGPathElement::IsMarkable() { return true; }
|
||||
|
||||
void SVGPathElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {
|
||||
void SVGPathElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
||||
mD.GetAnimValue().GetMarkerPositioningData(aMarks);
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ class SVGPathElement final : public SVGPathElementBase {
|
|||
// SVGGeometryElement methods:
|
||||
virtual bool AttributeDefinesGeometry(const nsAtom* aName) override;
|
||||
virtual bool IsMarkable() override;
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark>* aMarks) override;
|
||||
virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
|
||||
/**
|
||||
|
|
|
@ -64,14 +64,14 @@ bool SVGPolyElement::AttributeDefinesGeometry(const nsAtom* aName) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void SVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {
|
||||
void SVGPolyElement::GetMarkPoints(nsTArray<SVGMark>* aMarks) {
|
||||
const SVGPointList& points = mPoints.GetAnimValue();
|
||||
|
||||
if (!points.Length()) return;
|
||||
|
||||
float px = points[0].mX, py = points[0].mY, prevAngle = 0.0;
|
||||
|
||||
aMarks->AppendElement(nsSVGMark(px, py, 0, nsSVGMark::eStart));
|
||||
aMarks->AppendElement(SVGMark(px, py, 0, SVGMark::eStart));
|
||||
|
||||
for (uint32_t i = 1; i < points.Length(); ++i) {
|
||||
float x = points[i].mX;
|
||||
|
@ -86,7 +86,7 @@ void SVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {
|
|||
SVGContentUtils::AngleBisect(prevAngle, angle);
|
||||
}
|
||||
|
||||
aMarks->AppendElement(nsSVGMark(x, y, 0, nsSVGMark::eMid));
|
||||
aMarks->AppendElement(SVGMark(x, y, 0, SVGMark::eMid));
|
||||
|
||||
prevAngle = angle;
|
||||
px = x;
|
||||
|
@ -94,7 +94,7 @@ void SVGPolyElement::GetMarkPoints(nsTArray<nsSVGMark>* aMarks) {
|
|||
}
|
||||
|
||||
aMarks->LastElement().angle = prevAngle;
|
||||
aMarks->LastElement().type = nsSVGMark::eEnd;
|
||||
aMarks->LastElement().type = SVGMark::eEnd;
|
||||
}
|
||||
|
||||
bool SVGPolyElement::GetGeometryBounds(Rect* aBounds,
|
||||
|
|
|
@ -45,7 +45,7 @@ class SVGPolyElement : public SVGPolyElementBase {
|
|||
// SVGGeometryElement methods:
|
||||
virtual bool AttributeDefinesGeometry(const nsAtom* aName) override;
|
||||
virtual bool IsMarkable() override { return true; }
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark>* aMarks) override;
|
||||
virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks) override;
|
||||
virtual bool GetGeometryBounds(
|
||||
Rect* aBounds, const StrokeOptions& aStrokeOptions,
|
||||
const Matrix& aToBoundsSpace,
|
||||
|
|
|
@ -37,25 +37,25 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(SVGPolygonElement)
|
|||
//----------------------------------------------------------------------
|
||||
// SVGGeometryElement methods
|
||||
|
||||
void SVGPolygonElement::GetMarkPoints(nsTArray<nsSVGMark> *aMarks) {
|
||||
void SVGPolygonElement::GetMarkPoints(nsTArray<SVGMark> *aMarks) {
|
||||
SVGPolyElement::GetMarkPoints(aMarks);
|
||||
|
||||
if (aMarks->IsEmpty() || aMarks->LastElement().type != nsSVGMark::eEnd) {
|
||||
if (aMarks->IsEmpty() || aMarks->LastElement().type != SVGMark::eEnd) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsSVGMark *endMark = &aMarks->LastElement();
|
||||
nsSVGMark *startMark = &aMarks->ElementAt(0);
|
||||
SVGMark *endMark = &aMarks->LastElement();
|
||||
SVGMark *startMark = &aMarks->ElementAt(0);
|
||||
float angle = atan2(startMark->y - endMark->y, startMark->x - endMark->x);
|
||||
|
||||
endMark->type = nsSVGMark::eMid;
|
||||
endMark->type = SVGMark::eMid;
|
||||
endMark->angle = SVGContentUtils::AngleBisect(angle, endMark->angle);
|
||||
startMark->angle = SVGContentUtils::AngleBisect(angle, startMark->angle);
|
||||
// for a polygon (as opposed to a polyline) there's an implicit extra point
|
||||
// co-located with the start point that SVGPolyElement::GetMarkPoints
|
||||
// doesn't return
|
||||
aMarks->AppendElement(
|
||||
nsSVGMark(startMark->x, startMark->y, startMark->angle, nsSVGMark::eEnd));
|
||||
SVGMark(startMark->x, startMark->y, startMark->angle, SVGMark::eEnd));
|
||||
}
|
||||
|
||||
already_AddRefed<Path> SVGPolygonElement::BuildPath(PathBuilder *aBuilder) {
|
||||
|
|
|
@ -30,7 +30,7 @@ class SVGPolygonElement final : public SVGPolygonElementBase {
|
|||
|
||||
public:
|
||||
// SVGGeometryElement methods:
|
||||
virtual void GetMarkPoints(nsTArray<nsSVGMark>* aMarks) override;
|
||||
virtual void GetMarkPoints(nsTArray<SVGMark>* aMarks) override;
|
||||
virtual already_AddRefed<Path> BuildPath(PathBuilder* aBuilder) override;
|
||||
|
||||
virtual nsresult Clone(dom::NodeInfo*, nsINode** aResult) const override;
|
||||
|
|
|
@ -252,13 +252,11 @@ void SVGSVGElement::DeselectAll() {
|
|||
}
|
||||
|
||||
already_AddRefed<DOMSVGNumber> SVGSVGElement::CreateSVGNumber() {
|
||||
RefPtr<DOMSVGNumber> number = new DOMSVGNumber(ToSupports(this));
|
||||
return number.forget();
|
||||
return do_AddRef(new DOMSVGNumber(this));
|
||||
}
|
||||
|
||||
already_AddRefed<DOMSVGLength> SVGSVGElement::CreateSVGLength() {
|
||||
nsCOMPtr<DOMSVGLength> length = new DOMSVGLength();
|
||||
return length.forget();
|
||||
return do_AddRef(new DOMSVGLength());
|
||||
}
|
||||
|
||||
already_AddRefed<DOMSVGAngle> SVGSVGElement::CreateSVGAngle() {
|
||||
|
@ -266,13 +264,11 @@ already_AddRefed<DOMSVGAngle> SVGSVGElement::CreateSVGAngle() {
|
|||
}
|
||||
|
||||
already_AddRefed<nsISVGPoint> SVGSVGElement::CreateSVGPoint() {
|
||||
nsCOMPtr<nsISVGPoint> point = new DOMSVGPoint(0, 0);
|
||||
return point.forget();
|
||||
return do_AddRef(new DOMSVGPoint(0, 0));
|
||||
}
|
||||
|
||||
already_AddRefed<SVGMatrix> SVGSVGElement::CreateSVGMatrix() {
|
||||
RefPtr<SVGMatrix> matrix = new SVGMatrix();
|
||||
return matrix.forget();
|
||||
return do_AddRef(new SVGMatrix());
|
||||
}
|
||||
|
||||
already_AddRefed<SVGIRect> SVGSVGElement::CreateSVGRect() {
|
||||
|
@ -280,14 +276,12 @@ already_AddRefed<SVGIRect> SVGSVGElement::CreateSVGRect() {
|
|||
}
|
||||
|
||||
already_AddRefed<DOMSVGTransform> SVGSVGElement::CreateSVGTransform() {
|
||||
RefPtr<DOMSVGTransform> transform = new DOMSVGTransform();
|
||||
return transform.forget();
|
||||
return do_AddRef(new DOMSVGTransform());
|
||||
}
|
||||
|
||||
already_AddRefed<DOMSVGTransform> SVGSVGElement::CreateSVGTransformFromMatrix(
|
||||
SVGMatrix& matrix) {
|
||||
RefPtr<DOMSVGTransform> transform = new DOMSVGTransform(matrix.GetMatrix());
|
||||
return transform.forget();
|
||||
return do_AddRef(new DOMSVGTransform(matrix.GetMatrix()));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------
|
||||
|
|
|
@ -188,7 +188,8 @@ DictionaryFetcher::Fetch(nsIEditor* aEditor) {
|
|||
|
||||
nsCOMPtr<nsIRunnable> runnable =
|
||||
new ContentPrefInitializerRunnable(aEditor, this);
|
||||
NS_IdleDispatchToCurrentThread(runnable.forget(), 1000);
|
||||
NS_DispatchToCurrentThreadQueue(runnable.forget(), 1000,
|
||||
EventQueuePriority::Idle);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -455,7 +455,8 @@ class mozInlineSpellResume : public Runnable {
|
|||
|
||||
nsresult Post() {
|
||||
nsCOMPtr<nsIRunnable> runnable(this);
|
||||
return NS_IdleDispatchToCurrentThread(runnable.forget(), 1000);
|
||||
return NS_DispatchToCurrentThreadQueue(runnable.forget(), 1000,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override {
|
||||
|
|
|
@ -3061,6 +3061,9 @@ bool gfxFont::SplitAndInitTextRun(
|
|||
flags | gfx::ShapedTextFlags::TEXT_IS_8BIT, rounding, tp);
|
||||
if (sw) {
|
||||
aTextRun->CopyGlyphDataFrom(sw, aRunStart + i);
|
||||
if (boundary == ' ') {
|
||||
aTextRun->GetCharacterGlyphs()[aRunStart + i].SetIsSpace();
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -401,7 +401,7 @@ void gfxPlatformFontList::InitOtherFamilyNames(
|
|||
RefPtr<mozilla::CancelableRunnable> task =
|
||||
new InitOtherFamilyNamesRunnable();
|
||||
mPendingOtherFamilyNameTask = task;
|
||||
NS_IdleDispatchToMainThread(task.forget());
|
||||
NS_DispatchToMainThreadQueue(task.forget(), EventQueuePriority::Idle);
|
||||
}
|
||||
} else {
|
||||
InitOtherFamilyNamesInternal(false);
|
||||
|
|
|
@ -1536,6 +1536,7 @@ void gfxTextRun::SetSpaceGlyph(gfxFont* aFont, DrawTarget* aDrawTarget,
|
|||
AddGlyphRun(aFont, gfxTextRange::MatchType::kFontGroup, aCharIndex, false,
|
||||
aOrientation);
|
||||
CopyGlyphDataFrom(sw, aCharIndex);
|
||||
GetCharacterGlyphs()[aCharIndex].SetIsSpace();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -317,9 +317,10 @@ nsStringBundle::~nsStringBundle() {}
|
|||
|
||||
NS_IMETHODIMP
|
||||
nsStringBundleBase::AsyncPreload() {
|
||||
return NS_IdleDispatchToCurrentThread(
|
||||
return NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod("nsStringBundleBase::LoadProperties", this,
|
||||
&nsStringBundleBase::LoadProperties));
|
||||
&nsStringBundleBase::LoadProperties),
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
size_t nsStringBundle::SizeOfIncludingThis(
|
||||
|
|
|
@ -156,7 +156,8 @@ class AsyncFreeSnowWhite : public Runnable {
|
|||
|
||||
nsresult Dispatch() {
|
||||
nsCOMPtr<nsIRunnable> self(this);
|
||||
return NS_IdleDispatchToCurrentThread(self.forget(), 500);
|
||||
return NS_DispatchToCurrentThreadQueue(self.forget(), 500,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
void Start(bool aContinuation = false, bool aPurge = false) {
|
||||
|
|
|
@ -2006,8 +2006,9 @@ void nsRefreshDriver::Tick(VsyncId aId, TimeStamp aNowTime) {
|
|||
AutoTArray<RunnableWithDelay, 8>* runnables = sPendingIdleRunnables;
|
||||
sPendingIdleRunnables = nullptr;
|
||||
for (RunnableWithDelay& runnableWithDelay : *runnables) {
|
||||
NS_IdleDispatchToCurrentThread(runnableWithDelay.mRunnable.forget(),
|
||||
runnableWithDelay.mDelay);
|
||||
NS_DispatchToCurrentThreadQueue(runnableWithDelay.mRunnable.forget(),
|
||||
runnableWithDelay.mDelay,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
delete runnables;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<div style="font:300px monospace;width:3ch;text-align:right">ab<br>cd</div>
|
|
@ -0,0 +1,2 @@
|
|||
<!DOCTYPE html>
|
||||
<div style="font:300px monospace;width:3ch;text-align:right">ab cd</div>
|
|
@ -188,6 +188,7 @@ fails-if(/^Windows\x20NT\x206\.1/.test(http.oscpu)) == 1320665-cmap-format-13.ht
|
|||
skip-if(!cocoaWidget) != 1349308-1.html 1349308-notref.html # macOS-specific test for -apple-system glyph metrics
|
||||
fails-if(winWidget||gtkWidget||Android) == 1463020-letter-spacing-text-transform-1.html 1463020-letter-spacing-text-transform-1-ref.html # Linux, Win7: bug 1463161; Android, Win10: regional indicators not supported by system emoji font
|
||||
fails-if(Android) == 1463020-letter-spacing-text-transform-2.html 1463020-letter-spacing-text-transform-2-ref.html # missing font coverage on Android
|
||||
fuzzy-if(!webrender,12-66,288-1660) == 1522857-1.html 1522857-1-ref.html # antialiasing fuzz in non-webrender cases
|
||||
|
||||
# ensure emoji chars don't render blank (bug 715798, bug 779042);
|
||||
# should at least render hexboxes if there's no font support
|
||||
|
|
|
@ -600,14 +600,14 @@ SVGBBox SVGGeometryFrame::GetBBoxContribution(const Matrix& aToBBoxUserspace,
|
|||
// Account for markers:
|
||||
if ((aFlags & nsSVGUtils::eBBoxIncludeMarkers) != 0 &&
|
||||
element->IsMarkable()) {
|
||||
nsSVGMarkerFrame* markerFrames[nsSVGMark::eTypeCount];
|
||||
nsSVGMarkerFrame* markerFrames[SVGMark::eTypeCount];
|
||||
if (SVGObserverUtils::GetAndObserveMarkers(this, &markerFrames)) {
|
||||
nsTArray<nsSVGMark> marks;
|
||||
nsTArray<SVGMark> marks;
|
||||
element->GetMarkPoints(&marks);
|
||||
if (uint32_t num = marks.Length()) {
|
||||
float strokeWidth = nsSVGUtils::GetStrokeWidth(this);
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
const nsSVGMark& mark = marks[i];
|
||||
const SVGMark& mark = marks[i];
|
||||
nsSVGMarkerFrame* frame = markerFrames[mark.type];
|
||||
if (frame) {
|
||||
SVGBBox mbbox = frame->GetMarkBBoxContribution(
|
||||
|
@ -758,16 +758,16 @@ void SVGGeometryFrame::PaintMarkers(gfxContext& aContext,
|
|||
auto element = static_cast<SVGGeometryElement*>(GetContent());
|
||||
|
||||
if (element->IsMarkable()) {
|
||||
nsSVGMarkerFrame* markerFrames[nsSVGMark::eTypeCount];
|
||||
nsSVGMarkerFrame* markerFrames[SVGMark::eTypeCount];
|
||||
if (SVGObserverUtils::GetAndObserveMarkers(this, &markerFrames)) {
|
||||
nsTArray<nsSVGMark> marks;
|
||||
nsTArray<SVGMark> marks;
|
||||
element->GetMarkPoints(&marks);
|
||||
if (uint32_t num = marks.Length()) {
|
||||
SVGContextPaint* contextPaint =
|
||||
SVGContextPaint::GetContextPaint(GetContent());
|
||||
float strokeWidth = nsSVGUtils::GetStrokeWidth(this, contextPaint);
|
||||
for (uint32_t i = 0; i < num; i++) {
|
||||
const nsSVGMark& mark = marks[i];
|
||||
const SVGMark& mark = marks[i];
|
||||
nsSVGMarkerFrame* frame = markerFrames[mark.type];
|
||||
if (frame) {
|
||||
frame->PaintMark(aContext, aTransform, this, mark, strokeWidth,
|
||||
|
|
|
@ -1044,7 +1044,7 @@ bool SVGObserverUtils::GetAndObserveMarkers(nsIFrame* aMarkedFrame,
|
|||
LayoutFrameType::SVGMarker, nullptr) \
|
||||
: nullptr; \
|
||||
foundMarker = foundMarker || bool(marker); \
|
||||
(*aFrames)[nsSVGMark::e##type] = static_cast<nsSVGMarkerFrame*>(marker);
|
||||
(*aFrames)[SVGMark::e##type] = static_cast<nsSVGMarkerFrame*>(marker);
|
||||
|
||||
GET_MARKER(Start)
|
||||
GET_MARKER(Mid)
|
||||
|
|
|
@ -88,7 +88,7 @@ static nsIFrame* GetAnonymousChildFrame(nsIFrame* aFrame) {
|
|||
void nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
|
||||
const gfxMatrix& aToMarkedFrameUserSpace,
|
||||
SVGGeometryFrame* aMarkedFrame,
|
||||
const nsSVGMark& aMark, float aStrokeWidth,
|
||||
const SVGMark& aMark, float aStrokeWidth,
|
||||
imgDrawingParams& aImgParams) {
|
||||
// If the flag is set when we get here, it means this marker frame
|
||||
// has already been used painting the current mark, and the document
|
||||
|
@ -136,8 +136,7 @@ void nsSVGMarkerFrame::PaintMark(gfxContext& aContext,
|
|||
|
||||
SVGBBox nsSVGMarkerFrame::GetMarkBBoxContribution(
|
||||
const Matrix& aToBBoxUserspace, uint32_t aFlags,
|
||||
SVGGeometryFrame* aMarkedFrame, const nsSVGMark& aMark,
|
||||
float aStrokeWidth) {
|
||||
SVGGeometryFrame* aMarkedFrame, const SVGMark& aMark, float aStrokeWidth) {
|
||||
SVGBBox bbox;
|
||||
|
||||
// If the flag is set when we get here, it means this marker frame
|
||||
|
|
|
@ -19,15 +19,18 @@
|
|||
class gfxContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class SVGGeometryFrame;
|
||||
|
||||
struct SVGMark;
|
||||
|
||||
namespace dom {
|
||||
class SVGViewportElement;
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
struct nsSVGMark;
|
||||
|
||||
class nsSVGMarkerFrame final : public nsSVGContainerFrame {
|
||||
typedef mozilla::SVGMark SVGMark;
|
||||
typedef mozilla::image::imgDrawingParams imgDrawingParams;
|
||||
|
||||
friend class nsSVGMarkerAnonChildFrame;
|
||||
|
@ -75,14 +78,13 @@ class nsSVGMarkerFrame final : public nsSVGContainerFrame {
|
|||
|
||||
// nsSVGMarkerFrame methods:
|
||||
void PaintMark(gfxContext& aContext, const gfxMatrix& aToMarkedFrameUserSpace,
|
||||
mozilla::SVGGeometryFrame* aMarkedFrame,
|
||||
const nsSVGMark& aMark, float aStrokeWidth,
|
||||
imgDrawingParams& aImgParams);
|
||||
mozilla::SVGGeometryFrame* aMarkedFrame, const SVGMark& aMark,
|
||||
float aStrokeWidth, imgDrawingParams& aImgParams);
|
||||
|
||||
SVGBBox GetMarkBBoxContribution(const Matrix& aToBBoxUserspace,
|
||||
uint32_t aFlags,
|
||||
mozilla::SVGGeometryFrame* aMarkedFrame,
|
||||
const nsSVGMark& aMark, float aStrokeWidth);
|
||||
const SVGMark& aMark, float aStrokeWidth);
|
||||
|
||||
// Return our anonymous box child.
|
||||
void AppendDirectlyOwnedAnonBoxes(nsTArray<OwnedAnonBox>& aResult) override;
|
||||
|
|
|
@ -244,6 +244,21 @@ VARCACHE_PREF(
|
|||
RelaxedAtomicBool, true
|
||||
)
|
||||
|
||||
// Should we defer timeouts and intervals while loading a page. Released
|
||||
// on Idle or when the page is loaded.
|
||||
VARCACHE_PREF(
|
||||
"dom.timeout.defer_during_load",
|
||||
dom_timeout_defer_during_load,
|
||||
bool, true
|
||||
)
|
||||
|
||||
// Maximum deferral time for setTimeout/Interval in milliseconds
|
||||
VARCACHE_PREF(
|
||||
"dom.timeout.max_idle_defer_ms",
|
||||
dom_timeout_max_idle_defer_ms,
|
||||
uint32_t, 10*1000
|
||||
)
|
||||
|
||||
VARCACHE_PREF(
|
||||
"dom.performance.children_results_ipc_timeout",
|
||||
dom_performance_children_results_ipc_timeout,
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
|
||||
function _contentHeroHandler() {
|
||||
function _contentHeroHandler(isload) {
|
||||
var obs = null;
|
||||
var el = content.window.document.querySelector("[elementtiming]");
|
||||
if (el) {
|
||||
|
@ -23,6 +23,9 @@ function _contentHeroHandler() {
|
|||
} catch (err) {
|
||||
sendAsyncMessage("PageLoader:Error", {"msg": err.message});
|
||||
}
|
||||
} else if (isload) {
|
||||
// If the hero element is added from a settimeout handler, it might not run before 'load'
|
||||
setTimeout(function() { _contentHeroHandler(false); }, 5000);
|
||||
} else {
|
||||
var err = "Could not find a tag with an elmenttiming attr on the page";
|
||||
sendAsyncMessage("PageLoader:Error", {"msg": err});
|
||||
|
@ -30,5 +33,8 @@ function _contentHeroHandler() {
|
|||
return obs;
|
||||
}
|
||||
|
||||
function _contentHeroLoadHandler() {
|
||||
_contentHeroHandler(true);
|
||||
}
|
||||
|
||||
addEventListener("load", contentLoadHandlerCallback(_contentHeroHandler), true); // eslint-disable-line no-undef
|
||||
addEventListener("load", contentLoadHandlerCallback(_contentHeroLoadHandler), true); // eslint-disable-line no-undef
|
||||
|
|
|
@ -287,7 +287,7 @@ void ReportBlockingToConsole(nsPIDOMWindowOuter* aWindow, nsIURI* aURI,
|
|||
|
||||
nsCOMPtr<nsIURI> uri(aURI);
|
||||
|
||||
nsresult rv = NS_IdleDispatchToCurrentThread(
|
||||
nsresult rv = NS_DispatchToCurrentThreadQueue(
|
||||
NS_NewRunnableFunction(
|
||||
"ReportBlockingToConsoleDelayed",
|
||||
[doc, sourceLine, lineNumber, columnNumber, uri, aRejectedReason]() {
|
||||
|
@ -338,7 +338,7 @@ void ReportBlockingToConsole(nsPIDOMWindowOuter* aWindow, nsIURI* aURI,
|
|||
ArrayLength(params), nullptr, sourceLine, lineNumber,
|
||||
columnNumber);
|
||||
}),
|
||||
kMaxConsoleOutputDelayMs);
|
||||
kMaxConsoleOutputDelayMs, EventQueuePriority::Idle);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
@ -374,7 +374,7 @@ void ReportUnblockingToConsole(
|
|||
nsJSUtils::GetCallingLocation(cx, sourceLine, &lineNumber, &columnNumber);
|
||||
}
|
||||
|
||||
nsresult rv = NS_IdleDispatchToCurrentThread(
|
||||
nsresult rv = NS_DispatchToCurrentThreadQueue(
|
||||
NS_NewRunnableFunction(
|
||||
"ReportUnblockingToConsoleDelayed",
|
||||
[doc, principal, trackingOrigin, grantedOrigin, sourceLine,
|
||||
|
@ -422,7 +422,7 @@ void ReportUnblockingToConsole(
|
|||
params, 3, nullptr, sourceLine, lineNumber, columnNumber);
|
||||
}
|
||||
}),
|
||||
kMaxConsoleOutputDelayMs);
|
||||
kMaxConsoleOutputDelayMs, EventQueuePriority::Idle);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ prefs =
|
|||
browser.chrome.guess_favicon=true
|
||||
|
||||
[test_ext_async_clipboard.html]
|
||||
skip-if = (toolkit == 'android') # near-permafail after landing bug 1270059: Bug 1523131
|
||||
[test_ext_background_canvas.html]
|
||||
[test_ext_background_page.html]
|
||||
skip-if = (toolkit == 'android') # android doesn't have devtools
|
||||
|
|
|
@ -2080,11 +2080,11 @@ void nsBaseWidget::UnregisterPluginWindowForRemoteUpdates() {
|
|||
|
||||
nsresult nsBaseWidget::AsyncEnableDragDrop(bool aEnable) {
|
||||
RefPtr<nsBaseWidget> kungFuDeathGrip = this;
|
||||
return NS_IdleDispatchToCurrentThread(
|
||||
return NS_DispatchToCurrentThreadQueue(
|
||||
NS_NewRunnableFunction(
|
||||
"AsyncEnableDragDropFn",
|
||||
[this, aEnable, kungFuDeathGrip]() { EnableDragDrop(aEnable); }),
|
||||
kAsyncDragDropTimeout);
|
||||
kAsyncDragDropTimeout, EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
// static
|
||||
|
|
|
@ -427,7 +427,7 @@ void CycleCollectedJSContext::IsIdleGCTaskNeeded() const {
|
|||
|
||||
if (Runtime()->IsIdleGCTaskNeeded()) {
|
||||
nsCOMPtr<nsIRunnable> gc_task = new IdleTimeGCTaskRunnable();
|
||||
NS_IdleDispatchToCurrentThread(gc_task.forget());
|
||||
NS_DispatchToCurrentThreadQueue(gc_task.forget(), EventQueuePriority::Idle);
|
||||
Runtime()->SetPendingIdleGCTask();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1326,7 +1326,8 @@ void CycleCollectedJSRuntime::FinalizeDeferredThings(
|
|||
MOZ_ASSERT(mDeferredFinalizerTable.Count() == 0);
|
||||
|
||||
if (aType == CycleCollectedJSContext::FinalizeIncrementally) {
|
||||
NS_IdleDispatchToCurrentThread(do_AddRef(mFinalizeRunnable), 2500);
|
||||
NS_DispatchToCurrentThreadQueue(do_AddRef(mFinalizeRunnable), 2500,
|
||||
EventQueuePriority::Idle);
|
||||
} else {
|
||||
mFinalizeRunnable->ReleaseNow(false);
|
||||
MOZ_ASSERT(!mFinalizeRunnable);
|
||||
|
|
|
@ -525,9 +525,11 @@ nsresult MemoryTelemetry::Observe(nsISupports* aSubject, const char* aTopic,
|
|||
|
||||
mLastPoll = now;
|
||||
|
||||
NS_IdleDispatchToCurrentThread(NewRunnableMethod<std::function<void()>>(
|
||||
"MemoryTelemetry::GatherReports", this, &MemoryTelemetry::GatherReports,
|
||||
nullptr));
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewRunnableMethod<std::function<void()>>(
|
||||
"MemoryTelemetry::GatherReports", this,
|
||||
&MemoryTelemetry::GatherReports, nullptr),
|
||||
EventQueuePriority::Idle);
|
||||
} else if (strcmp(aTopic, "content-child-shutdown") == 0) {
|
||||
if (nsCOMPtr<nsITelemetry> telemetry =
|
||||
do_GetService("@mozilla.org/base/telemetry;1")) {
|
||||
|
|
|
@ -55,9 +55,9 @@ TEST(EventPriorities, IdleAfterNormal) {
|
|||
RefPtr<TestEvent> evIdle =
|
||||
new TestEvent(&idleRan, [&] { ASSERT_EQ(normalRan, 3); });
|
||||
|
||||
NS_IdleDispatchToCurrentThread(do_AddRef(evIdle));
|
||||
NS_IdleDispatchToCurrentThread(do_AddRef(evIdle));
|
||||
NS_IdleDispatchToCurrentThread(do_AddRef(evIdle));
|
||||
NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(do_AddRef(evIdle), EventQueuePriority::Idle);
|
||||
NS_DispatchToMainThread(evNormal);
|
||||
NS_DispatchToMainThread(evNormal);
|
||||
NS_DispatchToMainThread(evNormal);
|
||||
|
|
|
@ -607,13 +607,13 @@ class IdleObject final {
|
|||
|
||||
NS_NewTimerWithFuncCallback(getter_AddRefs(mTimer), Method4, this, 10,
|
||||
nsITimer::TYPE_ONE_SHOT, "IdleObject::Method3");
|
||||
NS_IdleDispatchToCurrentThread(
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethodWithTimer("IdleObject::Method5", this,
|
||||
&IdleObject::Method5),
|
||||
50);
|
||||
NS_IdleDispatchToCurrentThread(
|
||||
50, EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewRunnableMethod("IdleObject::Method6", this, &IdleObject::Method6),
|
||||
100);
|
||||
100, EventQueuePriority::Idle);
|
||||
|
||||
PR_Sleep(PR_MillisecondsToInterval(200));
|
||||
mRunnableExecuted[3] = true;
|
||||
|
@ -664,23 +664,33 @@ TEST(ThreadUtils, IdleRunnableMethod) {
|
|||
|
||||
NS_DispatchToCurrentThread(
|
||||
NewRunnableMethod("IdleObject::Method0", idle, &IdleObject::Method0));
|
||||
NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod(
|
||||
"IdleObject::Method1", idle, &IdleObject::Method1));
|
||||
NS_IdleDispatchToCurrentThread(
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod("IdleObject::Method1", idle,
|
||||
&IdleObject::Method1),
|
||||
EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethodWithTimer("IdleObject::Method2", idle,
|
||||
&IdleObject::Method2),
|
||||
60000);
|
||||
NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod(
|
||||
"IdleObject::Method7", idle, &IdleObject::Method7));
|
||||
NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod<const char*, uint32_t>(
|
||||
60000, EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod("IdleObject::Method7", idle,
|
||||
&IdleObject::Method7),
|
||||
EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod<const char*, uint32_t>(
|
||||
"IdleObject::CheckExecutedMethods", idle,
|
||||
&IdleObject::CheckExecutedMethods, "final", 8));
|
||||
NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod(
|
||||
"IdleObjectWithoutSetDeadline::Method", idleNoSetDeadline,
|
||||
&IdleObjectWithoutSetDeadline::Method));
|
||||
NS_IdleDispatchToCurrentThread(NewIdleRunnableMethod(
|
||||
"IdleObjectInheritedSetDeadline::Method", idleInheritedSetDeadline,
|
||||
&IdleObjectInheritedSetDeadline::Method));
|
||||
&IdleObject::CheckExecutedMethods, "final", 8),
|
||||
EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod("IdleObjectWithoutSetDeadline::Method",
|
||||
idleNoSetDeadline,
|
||||
&IdleObjectWithoutSetDeadline::Method),
|
||||
EventQueuePriority::Idle);
|
||||
NS_DispatchToCurrentThreadQueue(
|
||||
NewIdleRunnableMethod("IdleObjectInheritedSetDeadline::Method",
|
||||
idleInheritedSetDeadline,
|
||||
&IdleObjectInheritedSetDeadline::Method),
|
||||
EventQueuePriority::Idle);
|
||||
|
||||
NS_ProcessPendingEvents(nullptr);
|
||||
|
||||
|
|
|
@ -15,10 +15,11 @@ class nsIRunnable;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
enum class EventPriority {
|
||||
enum class EventQueuePriority {
|
||||
High,
|
||||
Input,
|
||||
Normal,
|
||||
DeferredTimers,
|
||||
Idle,
|
||||
|
||||
Count
|
||||
|
@ -46,7 +47,7 @@ class AbstractEventQueue {
|
|||
// and the implementing class supports prioritization, aPriority represents
|
||||
// the result of calling nsIRunnablePriority::GetPriority().
|
||||
virtual void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority,
|
||||
EventQueuePriority aPriority,
|
||||
const MutexAutoLock& aProofOfLock) = 0;
|
||||
|
||||
// Get an event from the front of the queue. aPriority is an out param. If the
|
||||
|
@ -54,7 +55,7 @@ class AbstractEventQueue {
|
|||
// that the event was pushed with. aPriority may be null. This should return
|
||||
// null if the queue is non-empty but the event in front is not ready to run.
|
||||
virtual already_AddRefed<nsIRunnable> GetEvent(
|
||||
EventPriority* aPriority, const MutexAutoLock& aProofOfLock) = 0;
|
||||
EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) = 0;
|
||||
|
||||
// Returns true if the queue is empty. Implies !HasReadyEvent().
|
||||
virtual bool IsEmpty(const MutexAutoLock& aProofOfLock) = 0;
|
||||
|
|
|
@ -9,23 +9,23 @@
|
|||
|
||||
using namespace mozilla;
|
||||
|
||||
EventQueue::EventQueue(EventPriority aPriority) {}
|
||||
EventQueue::EventQueue(EventQueuePriority aPriority) {}
|
||||
|
||||
void EventQueue::PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority,
|
||||
EventQueuePriority aPriority,
|
||||
const MutexAutoLock& aProofOfLock) {
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
mQueue.Push(std::move(event));
|
||||
}
|
||||
|
||||
already_AddRefed<nsIRunnable> EventQueue::GetEvent(
|
||||
EventPriority* aPriority, const MutexAutoLock& aProofOfLock) {
|
||||
EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) {
|
||||
if (mQueue.IsEmpty()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (aPriority) {
|
||||
*aPriority = EventPriority::Normal;
|
||||
*aPriority = EventQueuePriority::Normal;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> result = mQueue.Pop();
|
||||
|
|
|
@ -20,12 +20,13 @@ class EventQueue final : public AbstractEventQueue {
|
|||
static const bool SupportsPrioritization = false;
|
||||
|
||||
EventQueue() {}
|
||||
explicit EventQueue(EventPriority aPriority);
|
||||
explicit EventQueue(EventQueuePriority aPriority);
|
||||
|
||||
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
|
||||
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventQueuePriority aPriority,
|
||||
const MutexAutoLock& aProofOfLock) final;
|
||||
already_AddRefed<nsIRunnable> GetEvent(
|
||||
EventPriority* aPriority, const MutexAutoLock& aProofOfLock) final;
|
||||
EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) final;
|
||||
|
||||
bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
|
||||
bool HasReadyEvent(const MutexAutoLock& aProofOfLock) final;
|
||||
|
|
|
@ -85,7 +85,7 @@ void IdleTaskRunner::SetDeadline(mozilla::TimeStamp aDeadline) {
|
|||
void IdleTaskRunner::SetTimer(uint32_t aDelay, nsIEventTarget* aTarget) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
// aTarget is always the main thread event target provided from
|
||||
// NS_IdleDispatchToCurrentThread(). We ignore aTarget here to ensure that
|
||||
// NS_DispatchToCurrentThreadQueue(). We ignore aTarget here to ensure that
|
||||
// CollectorRunner always run specifically on SystemGroup::EventTargetFor(
|
||||
// TaskCategory::GarbageCollection) of the main thread.
|
||||
SetTimerInternal(aDelay);
|
||||
|
@ -127,7 +127,8 @@ void IdleTaskRunner::Schedule(bool aAllowIdleDispatch) {
|
|||
if (aAllowIdleDispatch) {
|
||||
nsCOMPtr<nsIRunnable> runnable = this;
|
||||
SetTimerInternal(mDelay);
|
||||
NS_IdleDispatchToCurrentThread(runnable.forget());
|
||||
NS_DispatchToCurrentThreadQueue(runnable.forget(),
|
||||
EventQueuePriority::Idle);
|
||||
} else {
|
||||
if (!mScheduleTimer) {
|
||||
nsIEventTarget* target = nullptr;
|
||||
|
|
|
@ -486,7 +486,8 @@ LazyIdleThread::HasPendingHighPriorityEvents(bool* aHasPendingEvents) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
LazyIdleThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) {
|
||||
LazyIdleThread::DispatchToQueue(already_AddRefed<nsIRunnable> aEvent,
|
||||
EventQueuePriority aQueue) {
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,10 +23,12 @@ inline already_AddRefed<nsThread> CreateMainThread(
|
|||
using MainThreadQueueT = PrioritizedEventQueue<InnerQueueT>;
|
||||
|
||||
auto queue = MakeUnique<MainThreadQueueT>(
|
||||
MakeUnique<InnerQueueT>(EventPriority::High),
|
||||
MakeUnique<InnerQueueT>(EventPriority::Input),
|
||||
MakeUnique<InnerQueueT>(EventPriority::Normal),
|
||||
MakeUnique<InnerQueueT>(EventPriority::Idle), do_AddRef(aIdlePeriod));
|
||||
MakeUnique<InnerQueueT>(EventQueuePriority::High),
|
||||
MakeUnique<InnerQueueT>(EventQueuePriority::Input),
|
||||
MakeUnique<InnerQueueT>(EventQueuePriority::Normal),
|
||||
MakeUnique<InnerQueueT>(EventQueuePriority::DeferredTimers),
|
||||
MakeUnique<InnerQueueT>(EventQueuePriority::Idle),
|
||||
do_AddRef(aIdlePeriod));
|
||||
|
||||
MainThreadQueueT* prioritized = queue.get();
|
||||
|
||||
|
|
|
@ -16,11 +16,14 @@ using namespace mozilla;
|
|||
template <class InnerQueueT>
|
||||
PrioritizedEventQueue<InnerQueueT>::PrioritizedEventQueue(
|
||||
UniquePtr<InnerQueueT> aHighQueue, UniquePtr<InnerQueueT> aInputQueue,
|
||||
UniquePtr<InnerQueueT> aNormalQueue, UniquePtr<InnerQueueT> aIdleQueue,
|
||||
UniquePtr<InnerQueueT> aNormalQueue,
|
||||
UniquePtr<InnerQueueT> aDeferredTimersQueue,
|
||||
UniquePtr<InnerQueueT> aIdleQueue,
|
||||
already_AddRefed<nsIIdlePeriod> aIdlePeriod)
|
||||
: mHighQueue(std::move(aHighQueue)),
|
||||
mInputQueue(std::move(aInputQueue)),
|
||||
mNormalQueue(std::move(aNormalQueue)),
|
||||
mDeferredTimersQueue(std::move(aDeferredTimersQueue)),
|
||||
mIdleQueue(std::move(aIdleQueue)),
|
||||
mIdlePeriod(aIdlePeriod) {
|
||||
static_assert(IsBaseOf<AbstractEventQueue, InnerQueueT>::value,
|
||||
|
@ -29,31 +32,35 @@ PrioritizedEventQueue<InnerQueueT>::PrioritizedEventQueue(
|
|||
|
||||
template <class InnerQueueT>
|
||||
void PrioritizedEventQueue<InnerQueueT>::PutEvent(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority,
|
||||
const MutexAutoLock& aProofOfLock) {
|
||||
// Double check the priority with a QI.
|
||||
RefPtr<nsIRunnable> event(aEvent);
|
||||
EventPriority priority = aPriority;
|
||||
EventQueuePriority priority = aPriority;
|
||||
|
||||
if (priority == EventPriority::Input && mInputQueueState == STATE_DISABLED) {
|
||||
priority = EventPriority::Normal;
|
||||
if (priority == EventQueuePriority::Input &&
|
||||
mInputQueueState == STATE_DISABLED) {
|
||||
priority = EventQueuePriority::Normal;
|
||||
}
|
||||
|
||||
switch (priority) {
|
||||
case EventPriority::High:
|
||||
case EventQueuePriority::High:
|
||||
mHighQueue->PutEvent(event.forget(), priority, aProofOfLock);
|
||||
break;
|
||||
case EventPriority::Input:
|
||||
case EventQueuePriority::Input:
|
||||
mInputQueue->PutEvent(event.forget(), priority, aProofOfLock);
|
||||
break;
|
||||
case EventPriority::Normal:
|
||||
case EventQueuePriority::Normal:
|
||||
mNormalQueue->PutEvent(event.forget(), priority, aProofOfLock);
|
||||
break;
|
||||
case EventPriority::Idle:
|
||||
case EventQueuePriority::DeferredTimers:
|
||||
mDeferredTimersQueue->PutEvent(event.forget(), priority, aProofOfLock);
|
||||
break;
|
||||
case EventQueuePriority::Idle:
|
||||
mIdleQueue->PutEvent(event.forget(), priority, aProofOfLock);
|
||||
break;
|
||||
case EventPriority::Count:
|
||||
MOZ_CRASH("EventPriority::Count isn't a valid priority");
|
||||
case EventQueuePriority::Count:
|
||||
MOZ_CRASH("EventQueuePriority::Count isn't a valid priority");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -105,10 +112,8 @@ TimeStamp PrioritizedEventQueue<InnerQueueT>::GetIdleDeadline() {
|
|||
}
|
||||
|
||||
template <class InnerQueueT>
|
||||
EventPriority PrioritizedEventQueue<InnerQueueT>::SelectQueue(
|
||||
EventQueuePriority PrioritizedEventQueue<InnerQueueT>::SelectQueue(
|
||||
bool aUpdateState, const MutexAutoLock& aProofOfLock) {
|
||||
bool highPending = !mHighQueue->IsEmpty(aProofOfLock);
|
||||
bool normalPending = !mNormalQueue->IsEmpty(aProofOfLock);
|
||||
size_t inputCount = mInputQueue->Count(aProofOfLock);
|
||||
|
||||
if (aUpdateState && mInputQueueState == STATE_ENABLED &&
|
||||
|
@ -130,39 +135,44 @@ EventPriority PrioritizedEventQueue<InnerQueueT>::SelectQueue(
|
|||
//
|
||||
// HIGH
|
||||
// INPUT
|
||||
// DEFERREDTIMERS: if GetIdleDeadline()
|
||||
// IDLE: if GetIdleDeadline()
|
||||
//
|
||||
// If we don't get an event in this pass, then we return null since no events
|
||||
// are ready.
|
||||
|
||||
// This variable determines which queue we will take an event from.
|
||||
EventPriority queue;
|
||||
EventQueuePriority queue;
|
||||
bool highPending = !mHighQueue->IsEmpty(aProofOfLock);
|
||||
|
||||
if (mProcessHighPriorityQueue) {
|
||||
queue = EventPriority::High;
|
||||
queue = EventQueuePriority::High;
|
||||
} else if (inputCount > 0 && (mInputQueueState == STATE_FLUSHING ||
|
||||
(mInputQueueState == STATE_ENABLED &&
|
||||
!mInputHandlingStartTime.IsNull() &&
|
||||
TimeStamp::Now() > mInputHandlingStartTime))) {
|
||||
queue = EventPriority::Input;
|
||||
} else if (normalPending) {
|
||||
queue = EventQueuePriority::Input;
|
||||
} else if (!mNormalQueue->IsEmpty(aProofOfLock)) {
|
||||
MOZ_ASSERT(mInputQueueState != STATE_FLUSHING,
|
||||
"Shouldn't consume normal event when flusing input events");
|
||||
queue = EventPriority::Normal;
|
||||
"Shouldn't consume normal event when flushing input events");
|
||||
queue = EventQueuePriority::Normal;
|
||||
} else if (highPending) {
|
||||
queue = EventPriority::High;
|
||||
queue = EventQueuePriority::High;
|
||||
} else if (inputCount > 0 && mInputQueueState != STATE_SUSPEND) {
|
||||
MOZ_ASSERT(
|
||||
mInputQueueState != STATE_DISABLED,
|
||||
"Shouldn't consume input events when the input queue is disabled");
|
||||
queue = EventPriority::Input;
|
||||
queue = EventQueuePriority::Input;
|
||||
} else if (!mDeferredTimersQueue->IsEmpty(aProofOfLock)) {
|
||||
// We may not actually return an idle event in this case.
|
||||
queue = EventQueuePriority::DeferredTimers;
|
||||
} else {
|
||||
// We may not actually return an idle event in this case.
|
||||
queue = EventPriority::Idle;
|
||||
queue = EventQueuePriority::Idle;
|
||||
}
|
||||
|
||||
MOZ_ASSERT_IF(
|
||||
queue == EventPriority::Input,
|
||||
queue == EventQueuePriority::Input,
|
||||
mInputQueueState != STATE_DISABLED && mInputQueueState != STATE_SUSPEND);
|
||||
|
||||
if (aUpdateState) {
|
||||
|
@ -174,7 +184,7 @@ EventPriority PrioritizedEventQueue<InnerQueueT>::SelectQueue(
|
|||
|
||||
template <class InnerQueueT>
|
||||
already_AddRefed<nsIRunnable> PrioritizedEventQueue<InnerQueueT>::GetEvent(
|
||||
EventPriority* aPriority, const MutexAutoLock& aProofOfLock) {
|
||||
EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) {
|
||||
auto guard =
|
||||
MakeScopeExit([&] { mHasPendingEventsPromisedIdleEvent = false; });
|
||||
|
||||
|
@ -184,13 +194,13 @@ already_AddRefed<nsIRunnable> PrioritizedEventQueue<InnerQueueT>::GetEvent(
|
|||
*mNextIdleDeadline = TimeStamp();
|
||||
#endif
|
||||
|
||||
EventPriority queue = SelectQueue(true, aProofOfLock);
|
||||
EventQueuePriority queue = SelectQueue(true, aProofOfLock);
|
||||
|
||||
if (aPriority) {
|
||||
*aPriority = queue;
|
||||
}
|
||||
|
||||
if (queue == EventPriority::High) {
|
||||
if (queue == EventQueuePriority::High) {
|
||||
nsCOMPtr<nsIRunnable> event = mHighQueue->GetEvent(aPriority, aProofOfLock);
|
||||
MOZ_ASSERT(event);
|
||||
mInputHandlingStartTime = TimeStamp();
|
||||
|
@ -198,23 +208,25 @@ already_AddRefed<nsIRunnable> PrioritizedEventQueue<InnerQueueT>::GetEvent(
|
|||
return event.forget();
|
||||
}
|
||||
|
||||
if (queue == EventPriority::Input) {
|
||||
if (queue == EventQueuePriority::Input) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
mInputQueue->GetEvent(aPriority, aProofOfLock);
|
||||
MOZ_ASSERT(event);
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
if (queue == EventPriority::Normal) {
|
||||
if (queue == EventQueuePriority::Normal) {
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
mNormalQueue->GetEvent(aPriority, aProofOfLock);
|
||||
return event.forget();
|
||||
}
|
||||
|
||||
// If we get here, then all queues except idle are empty.
|
||||
MOZ_ASSERT(queue == EventPriority::Idle);
|
||||
// If we get here, then all queues except deferredtimers and idle are empty.
|
||||
MOZ_ASSERT(queue == EventQueuePriority::Idle ||
|
||||
queue == EventQueuePriority::DeferredTimers);
|
||||
|
||||
if (mIdleQueue->IsEmpty(aProofOfLock)) {
|
||||
if (mIdleQueue->IsEmpty(aProofOfLock) &&
|
||||
mDeferredTimersQueue->IsEmpty(aProofOfLock)) {
|
||||
MOZ_ASSERT(!mHasPendingEventsPromisedIdleEvent);
|
||||
return nullptr;
|
||||
}
|
||||
|
@ -224,7 +236,11 @@ already_AddRefed<nsIRunnable> PrioritizedEventQueue<InnerQueueT>::GetEvent(
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> event = mIdleQueue->GetEvent(aPriority, aProofOfLock);
|
||||
nsCOMPtr<nsIRunnable> event =
|
||||
mDeferredTimersQueue->GetEvent(aPriority, aProofOfLock);
|
||||
if (!event) {
|
||||
event = mIdleQueue->GetEvent(aPriority, aProofOfLock);
|
||||
}
|
||||
if (event) {
|
||||
nsCOMPtr<nsIIdleRunnable> idleEvent = do_QueryInterface(event);
|
||||
if (idleEvent) {
|
||||
|
@ -249,6 +265,7 @@ bool PrioritizedEventQueue<InnerQueueT>::IsEmpty(
|
|||
return mHighQueue->IsEmpty(aProofOfLock) &&
|
||||
mInputQueue->IsEmpty(aProofOfLock) &&
|
||||
mNormalQueue->IsEmpty(aProofOfLock) &&
|
||||
mDeferredTimersQueue->IsEmpty(aProofOfLock) &&
|
||||
mIdleQueue->IsEmpty(aProofOfLock);
|
||||
}
|
||||
|
||||
|
@ -257,26 +274,29 @@ bool PrioritizedEventQueue<InnerQueueT>::HasReadyEvent(
|
|||
const MutexAutoLock& aProofOfLock) {
|
||||
mHasPendingEventsPromisedIdleEvent = false;
|
||||
|
||||
EventPriority queue = SelectQueue(false, aProofOfLock);
|
||||
EventQueuePriority queue = SelectQueue(false, aProofOfLock);
|
||||
|
||||
if (queue == EventPriority::High) {
|
||||
if (queue == EventQueuePriority::High) {
|
||||
return mHighQueue->HasReadyEvent(aProofOfLock);
|
||||
} else if (queue == EventPriority::Input) {
|
||||
} else if (queue == EventQueuePriority::Input) {
|
||||
return mInputQueue->HasReadyEvent(aProofOfLock);
|
||||
} else if (queue == EventPriority::Normal) {
|
||||
} else if (queue == EventQueuePriority::Normal) {
|
||||
return mNormalQueue->HasReadyEvent(aProofOfLock);
|
||||
}
|
||||
|
||||
MOZ_ASSERT(queue == EventPriority::Idle);
|
||||
MOZ_ASSERT(queue == EventQueuePriority::Idle ||
|
||||
queue == EventQueuePriority::DeferredTimers);
|
||||
|
||||
// If we get here, then both the high and normal queues are empty.
|
||||
|
||||
if (mIdleQueue->IsEmpty(aProofOfLock)) {
|
||||
if (mDeferredTimersQueue->IsEmpty(aProofOfLock) &&
|
||||
mIdleQueue->IsEmpty(aProofOfLock)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
TimeStamp idleDeadline = GetIdleDeadline();
|
||||
if (idleDeadline && mIdleQueue->HasReadyEvent(aProofOfLock)) {
|
||||
if (idleDeadline && (mDeferredTimersQueue->HasReadyEvent(aProofOfLock) ||
|
||||
mIdleQueue->HasReadyEvent(aProofOfLock))) {
|
||||
mHasPendingEventsPromisedIdleEvent = true;
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,9 @@ class nsIRunnable;
|
|||
|
||||
namespace mozilla {
|
||||
|
||||
// This AbstractEventQueue implementation has one queue for each EventPriority.
|
||||
// The type of queue used for each priority is determined by the template
|
||||
// parameter.
|
||||
// This AbstractEventQueue implementation has one queue for each
|
||||
// EventQueuePriority. The type of queue used for each priority is determined by
|
||||
// the template parameter.
|
||||
//
|
||||
// When an event is pushed, its priority is determined by QIing the runnable to
|
||||
// nsIRunnablePriority, or by falling back to the aPriority parameter if the QI
|
||||
|
@ -43,13 +43,15 @@ class PrioritizedEventQueue final : public AbstractEventQueue {
|
|||
PrioritizedEventQueue(UniquePtr<InnerQueueT> aHighQueue,
|
||||
UniquePtr<InnerQueueT> aInputQueue,
|
||||
UniquePtr<InnerQueueT> aNormalQueue,
|
||||
UniquePtr<InnerQueueT> aDeferredTimersQueue,
|
||||
UniquePtr<InnerQueueT> aIdleQueue,
|
||||
already_AddRefed<nsIIdlePeriod> aIdlePeriod);
|
||||
|
||||
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
|
||||
void PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventQueuePriority aPriority,
|
||||
const MutexAutoLock& aProofOfLock) final;
|
||||
already_AddRefed<nsIRunnable> GetEvent(
|
||||
EventPriority* aPriority, const MutexAutoLock& aProofOfLock) final;
|
||||
EventQueuePriority* aPriority, const MutexAutoLock& aProofOfLock) final;
|
||||
|
||||
bool IsEmpty(const MutexAutoLock& aProofOfLock) final;
|
||||
size_t Count(const MutexAutoLock& aProofOfLock) const final;
|
||||
|
@ -83,6 +85,7 @@ class PrioritizedEventQueue final : public AbstractEventQueue {
|
|||
n += mHighQueue->SizeOfIncludingThis(aMallocSizeOf);
|
||||
n += mInputQueue->SizeOfIncludingThis(aMallocSizeOf);
|
||||
n += mNormalQueue->SizeOfIncludingThis(aMallocSizeOf);
|
||||
n += mDeferredTimersQueue->SizeOfIncludingThis(aMallocSizeOf);
|
||||
n += mIdleQueue->SizeOfIncludingThis(aMallocSizeOf);
|
||||
|
||||
if (mIdlePeriod) {
|
||||
|
@ -93,7 +96,7 @@ class PrioritizedEventQueue final : public AbstractEventQueue {
|
|||
}
|
||||
|
||||
private:
|
||||
EventPriority SelectQueue(bool aUpdateState,
|
||||
EventQueuePriority SelectQueue(bool aUpdateState,
|
||||
const MutexAutoLock& aProofOfLock);
|
||||
|
||||
// Returns a null TimeStamp if we're not in the idle period.
|
||||
|
@ -102,6 +105,7 @@ class PrioritizedEventQueue final : public AbstractEventQueue {
|
|||
UniquePtr<InnerQueueT> mHighQueue;
|
||||
UniquePtr<InnerQueueT> mInputQueue;
|
||||
UniquePtr<InnerQueueT> mNormalQueue;
|
||||
UniquePtr<InnerQueueT> mDeferredTimersQueue;
|
||||
UniquePtr<InnerQueueT> mIdleQueue;
|
||||
|
||||
// We need to drop the queue mutex when checking the idle deadline, so we keep
|
||||
|
|
|
@ -173,7 +173,7 @@ class SchedulerGroup : public LinkedListElement<SchedulerGroup> {
|
|||
|
||||
using RunnableEpochQueue = Queue<EpochQueueEntry, 32>;
|
||||
|
||||
RunnableEpochQueue& GetQueue(mozilla::EventPriority aPriority) {
|
||||
RunnableEpochQueue& GetQueue(mozilla::EventQueuePriority aPriority) {
|
||||
return mEventQueues[size_t(aPriority)];
|
||||
}
|
||||
|
||||
|
@ -218,7 +218,7 @@ class SchedulerGroup : public LinkedListElement<SchedulerGroup> {
|
|||
|
||||
nsCOMPtr<nsISerialEventTarget> mEventTargets[size_t(TaskCategory::Count)];
|
||||
RefPtr<AbstractThread> mAbstractThreads[size_t(TaskCategory::Count)];
|
||||
RunnableEpochQueue mEventQueues[size_t(mozilla::EventPriority::Count)];
|
||||
RunnableEpochQueue mEventQueues[size_t(mozilla::EventQueuePriority::Count)];
|
||||
};
|
||||
|
||||
NS_DEFINE_STATIC_IID_ACCESSOR(SchedulerGroup::Runnable,
|
||||
|
|
|
@ -36,7 +36,7 @@ class ThreadTargetSink {
|
|||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadTargetSink)
|
||||
|
||||
virtual bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority) = 0;
|
||||
EventQueuePriority aPriority) = 0;
|
||||
|
||||
// After this method is called, no more events can be posted.
|
||||
virtual void Disconnect(const MutexAutoLock& aProofOfLock) = 0;
|
||||
|
@ -54,8 +54,8 @@ class ThreadTargetSink {
|
|||
|
||||
class SynchronizedEventQueue : public ThreadTargetSink {
|
||||
public:
|
||||
virtual already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
|
||||
EventPriority* aPriority) = 0;
|
||||
virtual already_AddRefed<nsIRunnable> GetEvent(
|
||||
bool aMayWait, EventQueuePriority* aPriority) = 0;
|
||||
virtual bool HasPendingEvent() = 0;
|
||||
|
||||
virtual bool HasPendingHighPriorityEvents() = 0;
|
||||
|
|
|
@ -23,7 +23,7 @@ class ThreadEventQueue<InnerQueueT>::NestedSink : public ThreadTargetSink {
|
|||
: mQueue(aQueue), mOwner(aOwner) {}
|
||||
|
||||
bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority) final {
|
||||
EventQueuePriority aPriority) final {
|
||||
return mOwner->PutEventInternal(std::move(aEvent), aPriority, this);
|
||||
}
|
||||
|
||||
|
@ -61,13 +61,13 @@ ThreadEventQueue<InnerQueueT>::~ThreadEventQueue() {
|
|||
|
||||
template <class InnerQueueT>
|
||||
bool ThreadEventQueue<InnerQueueT>::PutEvent(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority) {
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority) {
|
||||
return PutEventInternal(std::move(aEvent), aPriority, nullptr);
|
||||
}
|
||||
|
||||
template <class InnerQueueT>
|
||||
bool ThreadEventQueue<InnerQueueT>::PutEventInternal(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventPriority aPriority,
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aPriority,
|
||||
NestedSink* aSink) {
|
||||
// We want to leak the reference when we fail to dispatch it, so that
|
||||
// we won't release the event in a wrong thread.
|
||||
|
@ -84,9 +84,9 @@ bool ThreadEventQueue<InnerQueueT>::PutEventInternal(
|
|||
uint32_t prio = nsIRunnablePriority::PRIORITY_NORMAL;
|
||||
runnablePrio->GetPriority(&prio);
|
||||
if (prio == nsIRunnablePriority::PRIORITY_HIGH) {
|
||||
aPriority = EventPriority::High;
|
||||
aPriority = EventQueuePriority::High;
|
||||
} else if (prio == nsIRunnablePriority::PRIORITY_INPUT) {
|
||||
aPriority = EventPriority::Input;
|
||||
aPriority = EventQueuePriority::Input;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,7 +125,7 @@ bool ThreadEventQueue<InnerQueueT>::PutEventInternal(
|
|||
|
||||
template <class InnerQueueT>
|
||||
already_AddRefed<nsIRunnable> ThreadEventQueue<InnerQueueT>::GetEvent(
|
||||
bool aMayWait, EventPriority* aPriority) {
|
||||
bool aMayWait, EventQueuePriority* aPriority) {
|
||||
MutexAutoLock lock(mLock);
|
||||
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
|
@ -244,7 +244,7 @@ void ThreadEventQueue<InnerQueueT>::PopEventQueue(nsIEventTarget* aTarget) {
|
|||
|
||||
// Move events from the old queue to the new one.
|
||||
nsCOMPtr<nsIRunnable> event;
|
||||
EventPriority prio;
|
||||
EventQueuePriority prio;
|
||||
while ((event = item.mQueue->GetEvent(&prio, lock))) {
|
||||
prevQueue->PutEvent(event.forget(), prio, lock);
|
||||
}
|
||||
|
|
|
@ -37,10 +37,10 @@ class ThreadEventQueue final : public SynchronizedEventQueue {
|
|||
explicit ThreadEventQueue(UniquePtr<InnerQueueT> aQueue);
|
||||
|
||||
bool PutEvent(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority) final;
|
||||
EventQueuePriority aPriority) final;
|
||||
|
||||
already_AddRefed<nsIRunnable> GetEvent(bool aMayWait,
|
||||
EventPriority* aPriority) final;
|
||||
EventQueuePriority* aPriority) final;
|
||||
bool HasPendingEvent() final;
|
||||
bool HasPendingHighPriorityEvents() final;
|
||||
|
||||
|
@ -90,7 +90,7 @@ class ThreadEventQueue final : public SynchronizedEventQueue {
|
|||
virtual ~ThreadEventQueue();
|
||||
|
||||
bool PutEventInternal(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventPriority aPriority, NestedSink* aQueue);
|
||||
EventQueuePriority aPriority, NestedSink* aQueue);
|
||||
|
||||
UniquePtr<InnerQueueT> mBaseQueue;
|
||||
|
||||
|
|
|
@ -138,7 +138,7 @@ ThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
|
|||
RefPtr<nsThreadSyncDispatch> wrapper =
|
||||
new nsThreadSyncDispatch(current.forget(), event.take());
|
||||
bool success = mSink->PutEvent(do_AddRef(wrapper),
|
||||
EventPriority::Normal); // hold a ref
|
||||
EventQueuePriority::Normal); // hold a ref
|
||||
if (!success) {
|
||||
// PutEvent leaked the wrapper runnable object on failure, so we
|
||||
// explicitly release this object once for that. Note that this
|
||||
|
@ -156,7 +156,7 @@ ThreadEventTarget::Dispatch(already_AddRefed<nsIRunnable> aEvent,
|
|||
|
||||
NS_ASSERTION(aFlags == NS_DISPATCH_NORMAL || aFlags == NS_DISPATCH_AT_END,
|
||||
"unexpected dispatch flags");
|
||||
if (!mSink->PutEvent(event.take(), EventPriority::Normal)) {
|
||||
if (!mSink->PutEvent(event.take(), EventQueuePriority::Normal)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
// Delay to encourage the receiving task to run before we do work.
|
||||
|
|
|
@ -314,7 +314,7 @@ class ThrottledEventQueue::Inner final : public nsISupports {
|
|||
|
||||
// Only add the event to the underlying queue if are able to
|
||||
// dispatch to our base target.
|
||||
mEventQueue.PutEvent(std::move(aEvent), EventPriority::Normal, lock);
|
||||
mEventQueue.PutEvent(std::move(aEvent), EventQueuePriority::Normal, lock);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,10 +10,12 @@
|
|||
#include "mozilla/AlreadyAddRefed.h"
|
||||
namespace mozilla {
|
||||
class TimeStamp;
|
||||
enum class EventQueuePriority;
|
||||
}
|
||||
%}
|
||||
|
||||
[ptr] native PRThread(PRThread);
|
||||
native EventQueuePriority(mozilla::EventQueuePriority);
|
||||
|
||||
native nsIEventTargetPtr(nsIEventTarget*);
|
||||
native nsISerialEventTargetPtr(nsISerialEventTarget*);
|
||||
|
@ -130,12 +132,16 @@ interface nsIThread : nsISerialEventTarget
|
|||
void asyncShutdown();
|
||||
|
||||
/**
|
||||
* Dispatch an event to the thread's idle queue. This function may be called
|
||||
* from any thread, and it may be called re-entrantly.
|
||||
* Dispatch an event to a specified queue for the thread. This function
|
||||
* may be called from any thread, and it may be called re-entrantly.
|
||||
* Most users should use the NS_Dispatch*() functions in nsThreadUtils instead
|
||||
* of calling this directly.
|
||||
*
|
||||
* @param event
|
||||
* The alreadyAddRefed<> event to dispatch.
|
||||
* NOTE that the event will be leaked if it fails to dispatch.
|
||||
* @param queue
|
||||
* Which event priority queue this should be added to
|
||||
*
|
||||
* @throws NS_ERROR_INVALID_ARG
|
||||
* Indicates that event is null.
|
||||
|
@ -143,7 +149,8 @@ interface nsIThread : nsISerialEventTarget
|
|||
* Indicates that the thread is shutting down and has finished processing
|
||||
* events, so this event would never run and has not been dispatched.
|
||||
*/
|
||||
[noscript] void idleDispatch(in alreadyAddRefed_nsIRunnable event);
|
||||
[noscript] void dispatchToQueue(in alreadyAddRefed_nsIRunnable event,
|
||||
in EventQueuePriority queue);
|
||||
|
||||
/**
|
||||
* Use this attribute to dispatch runnables to the thread. Eventually, the
|
||||
|
|
|
@ -664,7 +664,7 @@ nsresult nsThread::Init(const nsACString& aName) {
|
|||
// that mThread is set properly.
|
||||
{
|
||||
mEvents->PutEvent(do_AddRef(startup),
|
||||
EventPriority::Normal); // retain a reference
|
||||
EventQueuePriority::Normal); // retain a reference
|
||||
}
|
||||
|
||||
// Wait for thread to call ThreadManager::SetupCurrentThread, which completes
|
||||
|
@ -808,7 +808,7 @@ nsThreadShutdownContext* nsThread::ShutdownInternal(bool aSync) {
|
|||
nsCOMPtr<nsIRunnable> event =
|
||||
new nsThreadShutdownEvent(WrapNotNull(this), WrapNotNull(context.get()));
|
||||
// XXXroc What if posting the event fails due to OOM?
|
||||
mEvents->PutEvent(event.forget(), EventPriority::Normal);
|
||||
mEvents->PutEvent(event.forget(), EventQueuePriority::Normal);
|
||||
|
||||
// We could still end up with other events being added after the shutdown
|
||||
// task, but that's okay because we process pending events in ThreadFunc
|
||||
|
@ -900,14 +900,15 @@ nsThread::HasPendingHighPriorityEvents(bool* aResult) {
|
|||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsThread::IdleDispatch(already_AddRefed<nsIRunnable> aEvent) {
|
||||
nsThread::DispatchToQueue(already_AddRefed<nsIRunnable> aEvent,
|
||||
EventQueuePriority aQueue) {
|
||||
nsCOMPtr<nsIRunnable> event = aEvent;
|
||||
|
||||
if (NS_WARN_IF(!event)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (!mEvents->PutEvent(event.forget(), EventPriority::Idle)) {
|
||||
if (!mEvents->PutEvent(event.forget(), aQueue)) {
|
||||
NS_WARNING(
|
||||
"An idle event was posted to a thread that will never run it "
|
||||
"(rejected)");
|
||||
|
@ -966,7 +967,7 @@ void canary_alarm_handler(int signum) {
|
|||
|
||||
#ifdef MOZ_COLLECTING_RUNNABLE_TELEMETRY
|
||||
static bool GetLabeledRunnableName(nsIRunnable* aEvent, nsACString& aName,
|
||||
EventPriority aPriority) {
|
||||
EventQueuePriority aPriority) {
|
||||
bool labeled = false;
|
||||
if (RefPtr<SchedulerGroup::Runnable> groupRunnable = do_QueryObject(aEvent)) {
|
||||
labeled = true;
|
||||
|
@ -980,7 +981,7 @@ static bool GetLabeledRunnableName(nsIRunnable* aEvent, nsACString& aName,
|
|||
aName.AssignLiteral("anonymous runnable");
|
||||
}
|
||||
|
||||
if (!labeled && aPriority > EventPriority::Input) {
|
||||
if (!labeled && aPriority > EventQueuePriority::Input) {
|
||||
aName.AppendLiteral("(unlabeled)");
|
||||
}
|
||||
|
||||
|
@ -1084,7 +1085,7 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) {
|
|||
// Scope for |event| to make sure that its destructor fires while
|
||||
// mNestedEventLoopDepth has been incremented, since that destructor can
|
||||
// also do work.
|
||||
EventPriority priority;
|
||||
EventQueuePriority priority;
|
||||
nsCOMPtr<nsIRunnable> event = mEvents->GetEvent(reallyWait, &priority);
|
||||
|
||||
*aResult = (event.get() != nullptr);
|
||||
|
@ -1139,7 +1140,7 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) {
|
|||
}
|
||||
#endif
|
||||
Maybe<AutoTimeDurationHelper> timeDurationHelper;
|
||||
if (priority == EventPriority::Input) {
|
||||
if (priority == EventQueuePriority::Input) {
|
||||
timeDurationHelper.emplace();
|
||||
}
|
||||
|
||||
|
@ -1166,14 +1167,15 @@ nsThread::ProcessNextEvent(bool aMayWait, bool* aResult) {
|
|||
duration = now - mCurrentEventStart;
|
||||
if (duration.ToMilliseconds() > LONGTASK_BUSY_WINDOW_MS) {
|
||||
// Idle events (gc...) don't *really* count here
|
||||
if (priority != EventPriority::Idle) {
|
||||
if (priority != EventQueuePriority::Idle) {
|
||||
mLastLongNonIdleTaskEnd = now;
|
||||
}
|
||||
mLastLongTaskEnd = now;
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
if (profiler_thread_is_being_profiled()) {
|
||||
profiler_add_marker(
|
||||
(priority != EventPriority::Idle) ? "LongTask" : "LongIdleTask",
|
||||
(priority != EventQueuePriority::Idle) ? "LongTask"
|
||||
: "LongIdleTask",
|
||||
js::ProfilingStackFrame::Category::OTHER,
|
||||
MakeUnique<LongTaskMarkerPayload>(mCurrentEventStart, now));
|
||||
}
|
||||
|
|
|
@ -580,16 +580,18 @@ bool nsThreadManager::MainThreadHasPendingHighPriorityEvents() {
|
|||
NS_IMETHODIMP
|
||||
nsThreadManager::IdleDispatchToMainThread(nsIRunnable* aEvent,
|
||||
uint32_t aTimeout) {
|
||||
// Note: C++ callers should instead use NS_IdleDispatchToThread or
|
||||
// NS_IdleDispatchToCurrentThread.
|
||||
// Note: C++ callers should instead use NS_DispatchToThreadQueue or
|
||||
// NS_DispatchToCurrentThreadQueue.
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
if (aTimeout) {
|
||||
return NS_IdleDispatchToThread(event.forget(), aTimeout, mMainThread);
|
||||
return NS_DispatchToThreadQueue(event.forget(), aTimeout, mMainThread,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
return NS_IdleDispatchToThread(event.forget(), mMainThread);
|
||||
return NS_DispatchToThreadQueue(event.forget(), mMainThread,
|
||||
EventQueuePriority::Idle);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -91,7 +91,7 @@ nsresult nsThreadPool::PutEvent(already_AddRefed<nsIRunnable> aEvent,
|
|||
spawnThread = true;
|
||||
}
|
||||
|
||||
mEvents.PutEvent(std::move(aEvent), EventPriority::Normal, lock);
|
||||
mEvents.PutEvent(std::move(aEvent), EventQueuePriority::Normal, lock);
|
||||
mEventsAvailable.Notify();
|
||||
stackSize = mStackSize;
|
||||
}
|
||||
|
|
|
@ -266,8 +266,9 @@ nsresult NS_DelayedDispatchToCurrentThread(
|
|||
return thread->DelayedDispatch(event.forget(), aDelayMs);
|
||||
}
|
||||
|
||||
nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
nsIThread* aThread) {
|
||||
nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
nsIThread* aThread,
|
||||
EventQueuePriority aQueue) {
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIRunnable> event(aEvent);
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_INVALID_ARG);
|
||||
|
@ -277,7 +278,7 @@ nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
|||
// To keep us from leaking the runnable if dispatch method fails,
|
||||
// we grab the reference on failures and release it.
|
||||
nsIRunnable* temp = event.get();
|
||||
rv = aThread->IdleDispatch(event.forget());
|
||||
rv = aThread->DispatchToQueue(event.forget(), aQueue);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
// Dispatch() leaked the reference to the event, but due to caller's
|
||||
// assumptions, we shouldn't leak here. And given we are on the same
|
||||
|
@ -288,17 +289,18 @@ nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
|||
return rv;
|
||||
}
|
||||
|
||||
nsresult NS_IdleDispatchToCurrentThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent) {
|
||||
return NS_IdleDispatchToThread(std::move(aEvent), NS_GetCurrentThread());
|
||||
nsresult NS_DispatchToCurrentThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
EventQueuePriority aQueue) {
|
||||
return NS_DispatchToThreadQueue(std::move(aEvent), NS_GetCurrentThread(),
|
||||
aQueue);
|
||||
}
|
||||
|
||||
extern nsresult NS_IdleDispatchToMainThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent) {
|
||||
extern nsresult NS_DispatchToMainThreadQueue(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, EventQueuePriority aQueue) {
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
nsresult rv = NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
return NS_IdleDispatchToThread(std::move(aEvent), mainThread);
|
||||
return NS_DispatchToThreadQueue(std::move(aEvent), mainThread, aQueue);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
@ -359,10 +361,13 @@ class IdleRunnableWrapper final : public IdleRunnable {
|
|||
nsCOMPtr<nsIRunnable> mRunnable;
|
||||
};
|
||||
|
||||
extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
uint32_t aTimeout, nsIThread* aThread) {
|
||||
extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
uint32_t aTimeout, nsIThread* aThread,
|
||||
EventQueuePriority aQueue) {
|
||||
nsCOMPtr<nsIRunnable> event(std::move(aEvent));
|
||||
NS_ENSURE_TRUE(event, NS_ERROR_INVALID_ARG);
|
||||
MOZ_ASSERT(aQueue == EventQueuePriority::Idle ||
|
||||
aQueue == EventQueuePriority::DeferredTimers);
|
||||
|
||||
// XXX Using current thread for now as the nsIEventTarget.
|
||||
nsIEventTarget* target = mozilla::GetCurrentThreadEventTarget();
|
||||
|
@ -379,13 +384,14 @@ extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
|||
}
|
||||
idleEvent->SetTimer(aTimeout, target);
|
||||
|
||||
return NS_IdleDispatchToThread(event.forget(), aThread);
|
||||
return NS_DispatchToThreadQueue(event.forget(), aThread, aQueue);
|
||||
}
|
||||
|
||||
extern nsresult NS_IdleDispatchToCurrentThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout) {
|
||||
return NS_IdleDispatchToThread(std::move(aEvent), aTimeout,
|
||||
NS_GetCurrentThread());
|
||||
extern nsresult NS_DispatchToCurrentThreadQueue(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout,
|
||||
EventQueuePriority aQueue) {
|
||||
return NS_DispatchToThreadQueue(std::move(aEvent), aTimeout,
|
||||
NS_GetCurrentThread(), aQueue);
|
||||
}
|
||||
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "xpcpublic.h"
|
||||
#include "mozilla/AbstractEventQueue.h"
|
||||
#include "mozilla/Atomics.h"
|
||||
#include "mozilla/Likely.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
|
@ -113,34 +114,35 @@ extern nsresult NS_DelayedDispatchToCurrentThread(
|
|||
already_AddRefed<nsIRunnable>&& aEvent, uint32_t aDelayMs);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to the idle queue of the current thread.
|
||||
*
|
||||
* @param aEvent
|
||||
* The event to dispatch.
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_IdleDispatchToCurrentThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to the idle queue of the main thread.
|
||||
* Dispatch the given event to the specified queue of the current thread.
|
||||
*
|
||||
* @param aEvent The event to dispatch.
|
||||
* @param aQueue The event queue for the thread to use
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_IdleDispatchToMainThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent);
|
||||
extern nsresult NS_DispatchToCurrentThreadQueue(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to the idle queue of the current thread.
|
||||
* Dispatch the given event to the specified queue of the main thread.
|
||||
*
|
||||
* @param aEvent The event to dispatch.
|
||||
* @param aQueue The event queue for the thread to use
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_DispatchToMainThreadQueue(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, mozilla::EventQueuePriority aQueue);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to an idle queue of the current thread.
|
||||
*
|
||||
* @param aEvent The event to dispatch. If the event implements
|
||||
* nsIIdleRunnable, it will receive a call on
|
||||
|
@ -148,36 +150,42 @@ extern nsresult NS_IdleDispatchToMainThread(
|
|||
* aTimeout.
|
||||
*
|
||||
* @param aTimeout The time in milliseconds until the event should be
|
||||
* moved from the idle queue to the regular queue, if it hasn't been
|
||||
* moved from an idle queue to the regular queue, if it hasn't been
|
||||
* executed. If aEvent is also an nsIIdleRunnable, it is expected
|
||||
* that it should handle the timeout itself, after a call to
|
||||
* nsIIdleRunnable::SetTimer.
|
||||
*
|
||||
* @param aQueue
|
||||
* The event queue for the thread to use. Must be an idle queue
|
||||
* (Idle or DeferredTimers)
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_IdleDispatchToCurrentThread(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout);
|
||||
extern nsresult NS_DispatchToCurrentThreadQueue(
|
||||
already_AddRefed<nsIRunnable>&& aEvent, uint32_t aTimeout,
|
||||
mozilla::EventQueuePriority aQueue);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to the idle queue of a thread.
|
||||
* Dispatch the given event to a queue of a thread.
|
||||
*
|
||||
* @param aEvent The event to dispatch.
|
||||
*
|
||||
* @param aThread The target thread for the dispatch.
|
||||
* @param aQueue The event queue for the thread to use.
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
nsIThread* aThread);
|
||||
extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
nsIThread* aThread,
|
||||
mozilla::EventQueuePriority aQueue);
|
||||
|
||||
/**
|
||||
* Dispatch the given event to the idle queue of a thread.
|
||||
* Dispatch the given event to an idle queue of a thread.
|
||||
*
|
||||
* @param aEvent The event to dispatch. If the event implements
|
||||
* nsIIdleRunnable, it will receive a call on
|
||||
|
@ -185,20 +193,25 @@ extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
|||
* aTimeout.
|
||||
*
|
||||
* @param aTimeout The time in milliseconds until the event should be
|
||||
* moved from the idle queue to the regular queue, if it hasn't been
|
||||
* moved from an idle queue to the regular queue, if it hasn't been
|
||||
* executed. If aEvent is also an nsIIdleRunnable, it is expected
|
||||
* that it should handle the timeout itself, after a call to
|
||||
* nsIIdleRunnable::SetTimer.
|
||||
*
|
||||
* @param aThread The target thread for the dispatch.
|
||||
*
|
||||
* @param aQueue
|
||||
* The event queue for the thread to use. Must be an idle queue
|
||||
* (Idle or DeferredTimers)
|
||||
*
|
||||
* @returns NS_ERROR_INVALID_ARG
|
||||
* If event is null.
|
||||
* @returns NS_ERROR_UNEXPECTED
|
||||
* If the thread is shutting down.
|
||||
*/
|
||||
extern nsresult NS_IdleDispatchToThread(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
uint32_t aTimeout, nsIThread* aThread);
|
||||
extern nsresult NS_DispatchToThreadQueue(already_AddRefed<nsIRunnable>&& aEvent,
|
||||
uint32_t aTimeout, nsIThread* aThread,
|
||||
mozilla::EventQueuePriority aQueue);
|
||||
|
||||
#ifndef XPCOM_GLUE_AVOID_NSPR
|
||||
/**
|
||||
|
|
|
@ -296,7 +296,7 @@ nsresult nsTimerImpl::InitCommon(const TimeDuration& aDelay, uint32_t aType,
|
|||
Callback&& newCallback) {
|
||||
mMutex.AssertCurrentThreadOwns();
|
||||
|
||||
if (NS_WARN_IF(!gThread)) {
|
||||
if (!gThread) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче