зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1665196 - Use the main-thread idle queue rather than a repeating timer to finalize font loading. r=lsalzman
Differential Revision: https://phabricator.services.mozilla.com/D92302
This commit is contained in:
Родитель
0b7d12d042
Коммит
1101dcaf73
|
@ -128,9 +128,7 @@ gfxFontInfoLoader::ShutdownObserver::Observe(nsISupports* aSubject,
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval) {
|
void gfxFontInfoLoader::StartLoader(uint32_t aDelay) {
|
||||||
mInterval = aInterval;
|
|
||||||
|
|
||||||
NS_ASSERTION(!mFontInfo, "fontinfo should be null when starting font loader");
|
NS_ASSERTION(!mFontInfo, "fontinfo should be null when starting font loader");
|
||||||
|
|
||||||
// sanity check
|
// sanity check
|
||||||
|
@ -183,6 +181,12 @@ void gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval) {
|
||||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PRThread* prThread;
|
||||||
|
if (NS_SUCCEEDED(mFontLoaderThread->GetPRThread(&prThread))) {
|
||||||
|
PR_SetThreadPriority(prThread, PR_PRIORITY_LOW);
|
||||||
|
}
|
||||||
|
|
||||||
mState = stateAsyncLoad;
|
mState = stateAsyncLoad;
|
||||||
|
|
||||||
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
|
nsCOMPtr<nsIRunnable> loadEvent = new AsyncFontInfoLoader(mFontInfo);
|
||||||
|
@ -195,6 +199,32 @@ void gfxFontInfoLoader::StartLoader(uint32_t aDelay, uint32_t aInterval) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FinalizeLoaderRunnable : public Runnable {
|
||||||
|
virtual ~FinalizeLoaderRunnable() = default;
|
||||||
|
|
||||||
|
public:
|
||||||
|
NS_INLINE_DECL_REFCOUNTING_INHERITED(FinalizeLoaderRunnable, Runnable)
|
||||||
|
|
||||||
|
explicit FinalizeLoaderRunnable(gfxFontInfoLoader* aLoader)
|
||||||
|
: mozilla::Runnable("FinalizeLoaderRunnable"), mLoader(aLoader) {}
|
||||||
|
|
||||||
|
NS_IMETHOD Run() override {
|
||||||
|
nsresult rv;
|
||||||
|
if (mLoader->LoadFontInfo()) {
|
||||||
|
mLoader->CancelLoader();
|
||||||
|
rv = NS_OK;
|
||||||
|
} else {
|
||||||
|
nsCOMPtr<nsIRunnable> runnable = this;
|
||||||
|
rv = NS_DispatchToCurrentThreadQueue(
|
||||||
|
runnable.forget(), PR_INTERVAL_NO_TIMEOUT, EventQueuePriority::Idle);
|
||||||
|
}
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
gfxFontInfoLoader* mLoader;
|
||||||
|
};
|
||||||
|
|
||||||
void gfxFontInfoLoader::FinalizeLoader(FontInfoData* aFontInfo) {
|
void gfxFontInfoLoader::FinalizeLoader(FontInfoData* aFontInfo) {
|
||||||
// Avoid loading data if loader has already been canceled.
|
// Avoid loading data if loader has already been canceled.
|
||||||
// This should mean that CancelLoader() ran and the Load
|
// This should mean that CancelLoader() ran and the Load
|
||||||
|
@ -207,24 +237,13 @@ void gfxFontInfoLoader::FinalizeLoader(FontInfoData* aFontInfo) {
|
||||||
|
|
||||||
mLoadTime = mFontInfo->mLoadTime;
|
mLoadTime = mFontInfo->mLoadTime;
|
||||||
|
|
||||||
// try to load all font data immediately
|
MOZ_ASSERT(NS_IsMainThread());
|
||||||
if (LoadFontInfo()) {
|
nsCOMPtr<nsIRunnable> runnable = new FinalizeLoaderRunnable(this);
|
||||||
CancelLoader();
|
if (NS_FAILED(NS_DispatchToCurrentThreadQueue(runnable.forget(),
|
||||||
return;
|
PR_INTERVAL_NO_TIMEOUT,
|
||||||
|
EventQueuePriority::Idle))) {
|
||||||
|
NS_WARNING("Failed to finalize async font info");
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_ASSERTION(!sFontLoaderShutdownObserved,
|
|
||||||
"Bug 1508626 - Finalize with interval timer for font loader "
|
|
||||||
"after shutdown observed");
|
|
||||||
NS_ASSERTION(!gXPCOMThreadsShutDown,
|
|
||||||
"Bug 1508626 - Finalize with interval timer for font loader "
|
|
||||||
"after shutdown but before observer");
|
|
||||||
|
|
||||||
// not all work completed ==> run load on interval
|
|
||||||
mState = stateTimerOnInterval;
|
|
||||||
mTimer->InitWithNamedFuncCallback(LoadFontInfoCallback, this, mInterval,
|
|
||||||
nsITimer::TYPE_REPEATING_SLACK,
|
|
||||||
"gfxFontInfoLoader::FinalizeLoader");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxFontInfoLoader::CancelLoader() {
|
void gfxFontInfoLoader::CancelLoader() {
|
||||||
|
@ -246,25 +265,6 @@ void gfxFontInfoLoader::CancelLoader() {
|
||||||
CleanupLoader();
|
CleanupLoader();
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxFontInfoLoader::LoadFontInfoTimerFire() {
|
|
||||||
if (mState == stateTimerOnDelay) {
|
|
||||||
NS_ASSERTION(!sFontLoaderShutdownObserved,
|
|
||||||
"Bug 1508626 - Setting interval timer for font loader after "
|
|
||||||
"shutdown observed");
|
|
||||||
NS_ASSERTION(!gXPCOMThreadsShutDown,
|
|
||||||
"Bug 1508626 - Setting interval timer for font loader after "
|
|
||||||
"shutdown but before observer");
|
|
||||||
|
|
||||||
mState = stateTimerOnInterval;
|
|
||||||
mTimer->SetDelay(mInterval);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool done = LoadFontInfo();
|
|
||||||
if (done) {
|
|
||||||
CancelLoader();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
gfxFontInfoLoader::~gfxFontInfoLoader() {
|
gfxFontInfoLoader::~gfxFontInfoLoader() {
|
||||||
RemoveShutdownObserver();
|
RemoveShutdownObserver();
|
||||||
MOZ_COUNT_DTOR(gfxFontInfoLoader);
|
MOZ_COUNT_DTOR(gfxFontInfoLoader);
|
||||||
|
|
|
@ -125,46 +125,43 @@ class FontInfoData {
|
||||||
// (e.g. localized names, face names, cmaps) are loaded async.
|
// (e.g. localized names, face names, cmaps) are loaded async.
|
||||||
|
|
||||||
// helper class for loading in font info on a separate async thread
|
// helper class for loading in font info on a separate async thread
|
||||||
// once async thread completes, completion process is run on regular
|
// once async thread completes, completion process is run on the main
|
||||||
// intervals to prevent tying up the main thread
|
// thread's idle queue in short slices
|
||||||
|
|
||||||
class gfxFontInfoLoader {
|
class gfxFontInfoLoader {
|
||||||
public:
|
public:
|
||||||
// state transitions:
|
// state transitions:
|
||||||
// initial ---StartLoader with delay---> timer on delay
|
// initial ---StartLoader with delay---> timer on delay
|
||||||
// initial ---StartLoader without delay---> timer on interval
|
// initial ---StartLoader without delay---> timer off
|
||||||
// timer on delay ---LoaderTimerFire---> timer on interval
|
// timer on delay ---LoaderTimerFire---> timer off
|
||||||
// timer on delay ---CancelLoader---> timer off
|
// timer on delay ---CancelLoader---> timer off
|
||||||
// timer on interval ---CancelLoader---> timer off
|
|
||||||
// timer off ---StartLoader with delay---> timer on delay
|
// timer off ---StartLoader with delay---> timer on delay
|
||||||
// timer off ---StartLoader without delay---> timer on interval
|
// timer off ---StartLoader without delay---> timer off
|
||||||
typedef enum {
|
typedef enum {
|
||||||
stateInitial,
|
stateInitial,
|
||||||
stateTimerOnDelay,
|
stateTimerOnDelay,
|
||||||
stateAsyncLoad,
|
stateAsyncLoad,
|
||||||
stateTimerOnInterval,
|
|
||||||
stateTimerOff
|
stateTimerOff
|
||||||
} TimerState;
|
} TimerState;
|
||||||
|
|
||||||
gfxFontInfoLoader() : mInterval(0), mState(stateInitial) {
|
gfxFontInfoLoader() : mState(stateInitial) {
|
||||||
MOZ_COUNT_CTOR(gfxFontInfoLoader);
|
MOZ_COUNT_CTOR(gfxFontInfoLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ~gfxFontInfoLoader();
|
virtual ~gfxFontInfoLoader();
|
||||||
|
|
||||||
// start timer with an initial delay, then call Run method at regular
|
// start timer with an initial delay
|
||||||
// intervals
|
void StartLoader(uint32_t aDelay);
|
||||||
void StartLoader(uint32_t aDelay, uint32_t aInterval);
|
|
||||||
|
|
||||||
// Finalize - async load complete, transfer data (on intervals if necessary)
|
// Finalize - async load complete, transfer data (on idle)
|
||||||
virtual void FinalizeLoader(FontInfoData* aFontInfo);
|
virtual void FinalizeLoader(FontInfoData* aFontInfo);
|
||||||
|
|
||||||
// cancel the timer and cleanup
|
// cancel the timer and cleanup
|
||||||
void CancelLoader();
|
void CancelLoader();
|
||||||
|
|
||||||
uint32_t GetInterval() { return mInterval; }
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
friend class FinalizeLoaderRunnable;
|
||||||
|
|
||||||
class ShutdownObserver : public nsIObserver {
|
class ShutdownObserver : public nsIObserver {
|
||||||
public:
|
public:
|
||||||
NS_DECL_ISUPPORTS
|
NS_DECL_ISUPPORTS
|
||||||
|
@ -194,15 +191,9 @@ class gfxFontInfoLoader {
|
||||||
// Cleanup - finish and cleanup after done, including possible reflows
|
// Cleanup - finish and cleanup after done, including possible reflows
|
||||||
virtual void CleanupLoader() { mFontInfo = nullptr; }
|
virtual void CleanupLoader() { mFontInfo = nullptr; }
|
||||||
|
|
||||||
// Timer interval callbacks
|
|
||||||
static void LoadFontInfoCallback(nsITimer* aTimer, void* aThis) {
|
|
||||||
gfxFontInfoLoader* loader = static_cast<gfxFontInfoLoader*>(aThis);
|
|
||||||
loader->LoadFontInfoTimerFire();
|
|
||||||
}
|
|
||||||
|
|
||||||
static void DelayedStartCallback(nsITimer* aTimer, void* aThis) {
|
static void DelayedStartCallback(nsITimer* aTimer, void* aThis) {
|
||||||
gfxFontInfoLoader* loader = static_cast<gfxFontInfoLoader*>(aThis);
|
gfxFontInfoLoader* loader = static_cast<gfxFontInfoLoader*>(aThis);
|
||||||
loader->StartLoader(0, loader->GetInterval());
|
loader->StartLoader(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LoadFontInfoTimerFire();
|
void LoadFontInfoTimerFire();
|
||||||
|
@ -213,7 +204,6 @@ class gfxFontInfoLoader {
|
||||||
nsCOMPtr<nsITimer> mTimer;
|
nsCOMPtr<nsITimer> mTimer;
|
||||||
nsCOMPtr<nsIObserver> mObserver;
|
nsCOMPtr<nsIObserver> mObserver;
|
||||||
nsCOMPtr<nsIThread> mFontLoaderThread;
|
nsCOMPtr<nsIThread> mFontLoaderThread;
|
||||||
uint32_t mInterval;
|
|
||||||
TimerState mState;
|
TimerState mState;
|
||||||
|
|
||||||
// after async font loader completes, data is stored here
|
// after async font loader completes, data is stored here
|
||||||
|
|
|
@ -127,10 +127,6 @@ const gfxFontEntry::ScriptRange gfxPlatformFontList::sComplexScriptRanges[] = {
|
||||||
{0, 0, 0, {0, 0, 0}} // terminator
|
{0, 0, 0, {0, 0, 0}} // terminator
|
||||||
};
|
};
|
||||||
|
|
||||||
// prefs for the font info loader
|
|
||||||
#define FONT_LOADER_DELAY_PREF "gfx.font_loader.delay"
|
|
||||||
#define FONT_LOADER_INTERVAL_PREF "gfx.font_loader.interval"
|
|
||||||
|
|
||||||
static const char* kObservedPrefs[] = {"font.",
|
static const char* kObservedPrefs[] = {"font.",
|
||||||
"font.name-list.",
|
"font.name-list.",
|
||||||
"intl.accept_languages", // hmmmm...
|
"intl.accept_languages", // hmmmm...
|
||||||
|
@ -638,7 +634,7 @@ void gfxPlatformFontList::InitOtherFamilyNames(
|
||||||
// (This is used so we can reliably run reftests that depend on localized
|
// (This is used so we can reliably run reftests that depend on localized
|
||||||
// font-family names being available.)
|
// font-family names being available.)
|
||||||
if (aDeferOtherFamilyNamesLoading &&
|
if (aDeferOtherFamilyNamesLoading &&
|
||||||
Preferences::GetUint(FONT_LOADER_DELAY_PREF) > 0) {
|
StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) {
|
||||||
if (!mPendingOtherFamilyNameTask) {
|
if (!mPendingOtherFamilyNameTask) {
|
||||||
RefPtr<mozilla::CancelableRunnable> task =
|
RefPtr<mozilla::CancelableRunnable> task =
|
||||||
new InitOtherFamilyNamesRunnable();
|
new InitOtherFamilyNamesRunnable();
|
||||||
|
@ -2104,7 +2100,7 @@ void gfxPlatformFontList::InitLoader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
#define FONT_LOADER_MAX_TIMESLICE \
|
#define FONT_LOADER_MAX_TIMESLICE \
|
||||||
100 // max time for one pass through RunLoader = 100ms
|
20 // max time for one pass through RunLoader = 20ms
|
||||||
|
|
||||||
bool gfxPlatformFontList::LoadFontInfo() {
|
bool gfxPlatformFontList::LoadFontInfo() {
|
||||||
TimeStamp start = TimeStamp::Now();
|
TimeStamp start = TimeStamp::Now();
|
||||||
|
@ -2142,12 +2138,16 @@ bool gfxPlatformFontList::LoadFontInfo() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// limit the time spent reading fonts in one pass
|
// Limit the time spent reading fonts in one pass, unless the font-loader
|
||||||
TimeDuration elapsed = TimeStamp::Now() - start;
|
// delay was set to zero, in which case we run to completion even if it
|
||||||
if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
|
// causes some jank.
|
||||||
i + 1 != endIndex) {
|
if (StaticPrefs::gfx_font_loader_delay_AtStartup() > 0) {
|
||||||
endIndex = i + 1;
|
TimeDuration elapsed = TimeStamp::Now() - start;
|
||||||
break;
|
if (elapsed.ToMilliseconds() > FONT_LOADER_MAX_TIMESLICE &&
|
||||||
|
i + 1 != endIndex) {
|
||||||
|
endIndex = i + 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2216,11 +2216,8 @@ void gfxPlatformFontList::CleanupLoader() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxPlatformFontList::GetPrefsAndStartLoader() {
|
void gfxPlatformFontList::GetPrefsAndStartLoader() {
|
||||||
uint32_t delay = std::max(1u, Preferences::GetUint(FONT_LOADER_DELAY_PREF));
|
uint32_t delay = std::max(1u, StaticPrefs::gfx_font_loader_delay_AtStartup());
|
||||||
uint32_t interval =
|
StartLoader(delay);
|
||||||
std::max(1u, Preferences::GetUint(FONT_LOADER_INTERVAL_PREF));
|
|
||||||
|
|
||||||
StartLoader(delay, interval);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfxPlatformFontList::ForceGlobalReflow() {
|
void gfxPlatformFontList::ForceGlobalReflow() {
|
||||||
|
|
|
@ -4199,6 +4199,15 @@
|
||||||
value: @IS_NIGHTLY_BUILD@
|
value: @IS_NIGHTLY_BUILD@
|
||||||
mirror: once
|
mirror: once
|
||||||
|
|
||||||
|
- name: gfx.font_loader.delay
|
||||||
|
type: uint32_t
|
||||||
|
#if defined(XP_WIN)
|
||||||
|
value: 60000
|
||||||
|
#else
|
||||||
|
value: 8000
|
||||||
|
#endif
|
||||||
|
mirror: once
|
||||||
|
|
||||||
# Disable antialiasing of Ahem, for use in tests.
|
# Disable antialiasing of Ahem, for use in tests.
|
||||||
- name: gfx.font_rendering.ahem_antialias_none
|
- name: gfx.font_rendering.ahem_antialias_none
|
||||||
type: RelaxedAtomicBool
|
type: RelaxedAtomicBool
|
||||||
|
|
|
@ -612,15 +612,6 @@ pref("gfx.downloadable_fonts.disable_cache", false);
|
||||||
// whether to try and do something about it (e.g. download additional fonts)?
|
// whether to try and do something about it (e.g. download additional fonts)?
|
||||||
pref("gfx.missing_fonts.notify", false);
|
pref("gfx.missing_fonts.notify", false);
|
||||||
|
|
||||||
// prefs controlling the font (name/cmap) loader that runs shortly after startup
|
|
||||||
#ifdef XP_WIN
|
|
||||||
pref("gfx.font_loader.delay", 120000); // 2 minutes after startup
|
|
||||||
pref("gfx.font_loader.interval", 1000); // every 1 second until complete
|
|
||||||
#else
|
|
||||||
pref("gfx.font_loader.delay", 8000); // 8 secs after startup
|
|
||||||
pref("gfx.font_loader.interval", 50); // run every 50 ms
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// whether to always search all font cmaps during system font fallback
|
// whether to always search all font cmaps during system font fallback
|
||||||
pref("gfx.font_rendering.fallback.always_use_cmaps", false);
|
pref("gfx.font_rendering.fallback.always_use_cmaps", false);
|
||||||
|
|
||||||
|
|
Загрузка…
Ссылка в новой задаче