Bug 1722487 - Avoid some work for font list updates. r=jfkthame

Differential Revision: https://phabricator.services.mozilla.com/D123363
This commit is contained in:
Emilio Cobos Álvarez 2021-08-26 23:17:54 +00:00
Родитель 3e1dc3d1eb
Коммит cfca657d9c
16 изменённых файлов: 100 добавлений и 107 удалений

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

@ -2392,6 +2392,14 @@ mozilla::ipc::IPCResult ContentChild::RecvFontListChanged() {
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvForceGlobalReflow(
bool aNeedsReframe) {
gfxPlatform::ForceGlobalReflow(aNeedsReframe ? gfxPlatform::NeedsReframe::Yes
: gfxPlatform::NeedsReframe::No);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentChild::RecvGeolocationUpdate(
nsIDOMGeoPosition* aPosition) {
RefPtr<nsGeolocationService> gs =

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

@ -339,6 +339,7 @@ class ContentChild final : public PContentChild,
nsTArray<IPCBlob>&& aBlobs, nsTArray<nsCString>&& aChangedKeys);
mozilla::ipc::IPCResult RecvFontListChanged();
mozilla::ipc::IPCResult RecvForceGlobalReflow(bool aNeedsReframe);
mozilla::ipc::IPCResult RecvGeolocationUpdate(nsIDOMGeoPosition* aPosition);

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

@ -645,7 +645,7 @@ child:
* This message has raised priority so that it will take precedence over
* vsync messages to the child.
*/
[Priority=mediumhigh] async RebuildFontList(bool aFulLRebuild);
[Priority=mediumhigh] async RebuildFontList(bool aFullRebuild);
/**
* The shared font list has been modified, potentially adding matches
@ -654,6 +654,12 @@ child:
*/
async FontListChanged();
/**
* The font list or prefs have been updated in such a way that we might need
* to do a reflow and maybe reframe.
*/
async ForceGlobalReflow(bool aNeedsReframe);
/**
* A new shmem block has been added to the font list; the child process
* should map the new block and add to its index.

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

@ -132,7 +132,7 @@ void gfxDWriteFont::SystemTextQualityChanged() {
// flush cached stuff that depended on the old setting, and force
// reflow everywhere to ensure we are using correct glyph metrics.
gfxPlatform::FlushFontAndWordCaches();
gfxPlatform::ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No);
}
mozilla::Atomic<bool> gfxDWriteFont::sForceGDIClassicEnabled{true};

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

@ -2429,8 +2429,8 @@ void gfxFcPlatformFontList::CheckFontUpdates(nsITimer* aTimer, void* aThis) {
FcConfig* current = FcConfigGetCurrent();
if (current != pfl->GetLastConfig()) {
pfl->UpdateFontList();
pfl->ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
mozilla::dom::ContentParent::NotifyUpdatedFonts(true);
}
}

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

@ -1313,9 +1313,7 @@ void gfxMacPlatformFontList::RegisteredFontsChangedNotificationCallback(
// xxx - should be carefully pruning the list of fonts, not rebuilding it from scratch
fl->UpdateFontList();
// modify a preference that will trigger reflow everywhere
fl->ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
dom::ContentParent::NotifyUpdatedFonts(true);
}

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

@ -141,6 +141,7 @@ static const uint32_t kDefaultGlyphCacheSize = -1;
#include "SoftwareVsyncSource.h"
#include "nscore.h" // for NS_FREE_PERMANENT_DATA
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/TouchEvent.h"
#include "gfxVR.h"
#include "VRManager.h"
@ -2260,20 +2261,20 @@ void gfxPlatform::FlushFontAndWordCaches() {
}
/* static */
void gfxPlatform::ForceGlobalReflow() {
void gfxPlatform::ForceGlobalReflow(NeedsReframe aNeedsReframe) {
MOZ_ASSERT(NS_IsMainThread());
const bool reframe = aNeedsReframe == NeedsReframe::Yes;
// Send a notification that will be observed by PresShells in this process
// only.
if (nsCOMPtr<nsIObserverService> obs = services::GetObserverService()) {
char16_t needsReframe[] = {char16_t(reframe), 0};
obs->NotifyObservers(nullptr, "font-info-updated", needsReframe);
}
if (XRE_IsParentProcess()) {
// Modify a preference that will trigger reflow everywhere (in all
// content processes, as well as the parent).
static const char kPrefName[] = "font.internaluseonly.changed";
bool fontInternalChange = Preferences::GetBool(kPrefName, false);
Preferences::SetBool(kPrefName, !fontInternalChange);
} else {
// Send a notification that will be observed by PresShells in this
// process only.
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
if (obs) {
obs->NotifyObservers(nullptr, "font-info-updated", nullptr);
// Propagate the change to child processes.
for (auto* process :
dom::ContentParent::AllProcesses(dom::ContentParent::eLive)) {
Unused << process->SendForceGlobalReflow(reframe);
}
}
}

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

@ -626,7 +626,8 @@ class gfxPlatform : public mozilla::layers::MemoryPressureListener {
* something about platform settings changes that might have an effect
* on layout, such as font rendering settings that influence metrics.
*/
static void ForceGlobalReflow();
enum class NeedsReframe : bool { No, Yes };
static void ForceGlobalReflow(NeedsReframe);
static void FlushFontAndWordCaches();

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

@ -170,7 +170,7 @@ static void FontListPrefChanged(const char* aPref, void* aData = nullptr) {
!strcmp(aPref, "privacy.resistFingerprinting"))) {
gfxPlatformFontList::PlatformFontList()->SetVisibilityLevel();
if (XRE_IsParentProcess()) {
gfxPlatform::ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No);
}
}
}
@ -188,7 +188,7 @@ gfxFontListPrefObserver::Observe(nsISupports* aSubject, const char* aTopic,
FontListPrefChanged(nullptr);
if (XRE_IsParentProcess()) {
gfxPlatform::ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No);
}
return NS_OK;
}
@ -336,9 +336,6 @@ void gfxPlatformFontList::FontWhitelistPrefChanged(const char* aPref,
dom::ContentParent::NotifyUpdatedFonts(true);
}
// number of CSS generic font families
const uint32_t kNumGenerics = 5;
void gfxPlatformFontList::ApplyWhitelist() {
uint32_t numFonts = mEnabledFontsList.Length();
mFontFamilyWhitelistActive = (numFonts > 0);
@ -637,7 +634,7 @@ void gfxPlatformFontList::FontListChanged() {
// safe to use: ensure they all get flushed.
RebuildLocalFonts(/*aForgetLocalFaces*/ true);
}
ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
}
void gfxPlatformFontList::GenerateFontListKey(const nsACString& aKeyName,
@ -857,7 +854,7 @@ void gfxPlatformFontList::UpdateFontList(bool aFullRebuild) {
if (mStartedLoadingCmapsFrom != 0xffffffffu) {
InitializeCodepointsWithNoFonts();
mStartedLoadingCmapsFrom = 0xffffffffu;
gfxPlatform::ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No);
}
}
}
@ -2491,7 +2488,7 @@ void gfxPlatformFontList::CleanupLoader() {
FindFamiliesFlags::eNoAddToNamesMissedWhenSearching));
});
if (forceReflow) {
ForceGlobalReflow();
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::No);
}
mOtherNamesMissed = nullptr;
@ -2523,10 +2520,6 @@ void gfxPlatformFontList::GetPrefsAndStartLoader() {
}
}
void gfxPlatformFontList::ForceGlobalReflow() {
gfxPlatform::ForceGlobalReflow();
}
void gfxPlatformFontList::RebuildLocalFonts(bool aForgetLocalFaces) {
for (auto* fontset : mUserFontSetList) {
if (aForgetLocalFaces) {

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

@ -760,9 +760,6 @@ class gfxPlatformFontList : public gfxFontInfoLoader {
// read the loader initialization prefs, and start it
void GetPrefsAndStartLoader();
// for font list changes that affect all documents
void ForceGlobalReflow();
// If aForgetLocalFaces is true, all gfxFontEntries for src:local fonts must
// be discarded (not potentially reused to satisfy the rebuilt rules),
// because they may no longer be valid.

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

@ -9932,7 +9932,9 @@ PresShell::Observe(nsISupports* aSubject, const char* aTopic,
}
if (!nsCRT::strcmp(aTopic, "font-info-updated")) {
mPresContext->ForceReflowForFontInfoUpdate();
// See how gfxPlatform::ForceGlobalReflow encodes this.
bool needsReframe = aData && !!aData[0];
mPresContext->ForceReflowForFontInfoUpdate(needsReframe);
return NS_OK;
}

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

@ -138,11 +138,42 @@ bool nsPresContext::IsDOMPaintEventPending() {
return false;
}
void nsPresContext::ForceReflowForFontInfoUpdate() {
// We can trigger reflow by pretending a font.* preference has changed;
// this is the same mechanism as gfxPlatform::ForceGlobalReflow() uses
// if new fonts are installed during the session, for example.
PreferenceChanged("font.internaluseonly.changed");
void nsPresContext::ForceReflowForFontInfoUpdate(bool aNeedsReframe) {
// In the case of a static-clone document used for printing or print-preview,
// this is undesirable because the nsPrintJob is holding weak refs to frames
// that will get blown away unexpectedly by this reconstruction. So the
// prescontext for a print/preview doc ignores the font-list update.
//
// This means the print document may still be using cached fonts that are no
// longer present in the font list, but that should be safe given that all the
// required font instances have already been created, so it won't be depending
// on access to the font-list entries.
//
// XXX Actually, I think it's probably a bad idea to do *any* restyling of
// print documents in response to pref changes. We could be in the middle
// of printing the document, and reflowing all the frames might cause some
// kind of unwanted mid-document discontinuity.
if (IsPrintingOrPrintPreview()) {
return;
}
// If there's a user font set, discard any src:local() faces it may have
// loaded because their font entries may no longer be valid.
if (auto* fonts = Document()->GetFonts()) {
fonts->GetUserFontSet()->ForgetLocalFaces();
}
FlushFontCache();
nsChangeHint changeHint =
aNeedsReframe ? nsChangeHint_ReconstructFrame : NS_STYLE_HINT_REFLOW;
// We also need to trigger restyling for ex/ch units changes to take effect,
// if needed.
auto restyleHint =
UsesExChUnits() ? RestyleHint::RecascadeSubtree() : RestyleHint{0};
RebuildAllStyleData(changeHint, restyleHint);
}
static bool IsVisualCharset(NotNull<const Encoding*> aCharset) {
@ -567,46 +598,16 @@ void nsPresContext::PreferenceChanged(const char* aPrefName) {
mMissingFonts = nullptr;
}
}
if (prefName.EqualsLiteral("font.internaluseonly.changed") &&
!IsPrintingOrPrintPreview()) {
// If there's a user font set, discard any src:local() faces it may have
// loaded because their font entries may no longer be valid.
if (auto* fonts = Document()->GetFonts()) {
fonts->GetUserFontSet()->ForgetLocalFaces();
}
// If there's a change to the font list, we generally need to reconstruct
// frames, as the existing frames may be referring to fonts that are no
// longer available. But in the case of a static-clone document used for
// printing or print-preview, this is undesirable because the nsPrintJob
// is holding weak refs to frames that will get blown away unexpectedly by
// this reconstruction. So the prescontext for a print/preview doc ignores
// the font-list update.
//
// This means the print document may still be using cached fonts that are
// no longer present in the font list, but that should be safe given that
// all the required font instances have already been created, so it won't
// be depending on access to the font-list entries.
//
// XXX Actually, I think it's probably a bad idea to do *any* restyling of
// print documents in response to pref changes. We could be in the middle
// of printing the document, and reflowing all the frames might cause some
// kind of unwanted mid-document discontinuity.
changeHint |= nsChangeHint_ReconstructFrame;
// We also need to trigger restyling for ex/ch units changes to take effect,
// if needed.
if (UsesExChUnits()) {
restyleHint |= RestyleHint::RecascadeSubtree();
}
} else if (StringBeginsWith(prefName, "font."_ns) ||
// Changes to font family preferences don't change anything in the
// computed style data, so the style system won't generate a reflow
// hint for us. We need to do that manually.
prefName.EqualsLiteral("intl.accept_languages") ||
// Changes to bidi prefs need to trigger a reflow (see bug 443629)
StringBeginsWith(prefName, "bidi."_ns) ||
// Changes to font_rendering prefs need to trigger a reflow
StringBeginsWith(prefName, "gfx.font_rendering."_ns)) {
if (StringBeginsWith(prefName, "font."_ns) ||
// Changes to font family preferences don't change anything in the
// computed style data, so the style system won't generate a reflow hint
// for us. We need to do that manually.
prefName.EqualsLiteral("intl.accept_languages") ||
// Changes to bidi prefs need to trigger a reflow (see bug 443629)
StringBeginsWith(prefName, "bidi."_ns) ||
// Changes to font_rendering prefs need to trigger a reflow
StringBeginsWith(prefName, "gfx.font_rendering."_ns)) {
changeHint |= NS_STYLE_HINT_REFLOW;
if (UsesExChUnits()) {
restyleHint |= RestyleHint::RecascadeSubtree();

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

@ -1114,7 +1114,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
public:
// Used by the PresShell to force a reflow when some aspect of font info
// has been updated, potentially affecting font selection and layout.
void ForceReflowForFontInfoUpdate();
void ForceReflowForFontInfoUpdate(bool aNeedsReframe);
/**
* Checks for MozAfterPaint listeners on the document

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

@ -50,7 +50,7 @@ void PostTraversalTask::Run() {
nsPresContext* pc =
static_cast<ServoStyleSet*>(mTarget)->GetPresContext();
if (pc) {
pc->ForceReflowForFontInfoUpdate();
pc->ForceReflowForFontInfoUpdate(/* aNeedsReframe = */ false);
}
break;
}

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

@ -97,22 +97,16 @@ add_task(async function() {
}
}
// Pref "font.internaluseonly.changed" is updated when system
// fonts change. We use it to wait for changes to be detected
// in the browser.
let prefBranch = Services.prefs.getBranch("font.internaluseonly.");
// Returns a promise that resolves when the pref is changed
// Returns a promise that resolves when font info is changed.
let getFontNotificationPromise = () =>
new Promise(resolve => {
let prefObserver = {
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
observe() {
prefBranch.removeObserver("changed", prefObserver);
resolve();
},
};
prefBranch.addObserver("changed", prefObserver);
const kTopic = "font-info-updated";
function observe() {
Services.obs.removeObserver(observe, kTopic);
resolve();
}
Services.obs.addObserver(observe, kTopic);
});
let homeDir = Services.dirsvc.get("Home", Ci.nsIFile);

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

@ -5048,17 +5048,6 @@ const char16_t* GetQuitType() {
return nullptr;
}
static void ForceFontUpdate() {
// update device context font cache
// Dirty but easiest way:
// Changing nsIPrefBranch entry which triggers callbacks
// and flows into calling mDeviceContext->FlushFontCache()
// to update the font cache in all the instance of Browsers
static const char kPrefName[] = "font.internaluseonly.changed";
bool fontInternalChange = Preferences::GetBool(kPrefName, false);
Preferences::SetBool(kPrefName, !fontInternalChange);
}
bool nsWindow::ExternalHandlerProcessMessage(UINT aMessage, WPARAM& aWParam,
LPARAM& aLParam,
MSGResult& aResult) {
@ -5231,7 +5220,9 @@ bool nsWindow::ProcessMessage(UINT msg, WPARAM& wParam, LPARAM& lParam,
do_GetService("@mozilla.org/gfx/fontenumerator;1", &rv);
if (NS_SUCCEEDED(rv)) {
fontEnum->UpdateFontList(&didChange);
ForceFontUpdate();
if (didChange) {
gfxPlatform::ForceGlobalReflow(gfxPlatform::NeedsReframe::Yes);
}
} // if (NS_SUCCEEDED(rv))
} break;