Merge inbound to mozilla-central. a=merge

This commit is contained in:
Brindusan Cristian 2019-01-27 11:35:28 +02:00
Родитель e3d4bb863b 29330ddf5b
Коммит 4faab2f1b6
85 изменённых файлов: 830 добавлений и 396 удалений

Просмотреть файл

@ -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;
}