Bug 1727399 - When style updates font information, make sure to invalidate style asynchronously. r=jfkthame

Some style system APIs (like StyleNewSubtree) don't deal with nested
restyles really well (it'd be weird if StyleNewSubtree would end up
styling not only that subtree but the whole document).

To prevent breaking style system invariants, make sure to invalidate the
style asynchronously using an early runner. This should ensure at most
one frame of wrong metrics, but usually zero.

Differential Revision: https://phabricator.services.mozilla.com/D126076
This commit is contained in:
Emilio Cobos Álvarez 2021-09-20 09:47:45 +00:00
Родитель 889ce29976
Коммит 9b0fa46c68
3 изменённых файлов: 52 добавлений и 22 удалений

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

@ -136,6 +136,52 @@ bool nsPresContext::IsDOMPaintEventPending() {
return false;
}
struct WeakRunnableMethod : Runnable {
using Method = void (nsPresContext::*)();
WeakRunnableMethod(const char* aName, nsPresContext* aPc, Method aMethod)
: Runnable(aName), mPresContext(aPc), mMethod(aMethod) {}
NS_IMETHOD Run() override {
if (nsPresContext* pc = mPresContext.get()) {
(pc->*mMethod)();
}
return NS_OK;
}
private:
WeakPtr<nsPresContext> mPresContext;
Method mMethod;
};
// When forcing a font-info-update reflow from style, we don't need to reframe,
// but we'll need to restyle to pick up updated font metrics. In order to avoid
// synchronously having to deal with multiple restyles, we use an early refresh
// driver runner, which should prevent flashing for users.
//
// We might do a bit of extra work if the page flushes layout between the
// restyle and when this happens, which is a bit unfortunate, but not worse than
// what we used to do...
//
// A better solution would be to be able to synchronously initialize font
// information from style worker threads, perhaps...
void nsPresContext::ForceReflowForFontInfoUpdateFromStyle() {
if (mPendingFontInfoUpdateReflowFromStyle) {
return;
}
mPendingFontInfoUpdateReflowFromStyle = true;
nsCOMPtr<nsIRunnable> ev = new WeakRunnableMethod(
"nsPresContext::DoForceReflowForFontInfoUpdateFromStyle", this,
&nsPresContext::DoForceReflowForFontInfoUpdateFromStyle);
RefreshDriver()->AddEarlyRunner(ev);
}
void nsPresContext::DoForceReflowForFontInfoUpdateFromStyle() {
mPendingFontInfoUpdateReflowFromStyle = false;
ForceReflowForFontInfoUpdate(false);
}
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
@ -223,6 +269,7 @@ nsPresContext::nsPresContext(dom::Document* aDocument, nsPresContextType aType)
mPendingThemeChanged(false),
mPendingThemeChangeKind(0),
mPendingUIResolutionChanged(false),
mPendingFontInfoUpdateReflowFromStyle(false),
mIsGlyph(false),
mUsesExChUnits(false),
mCounterStylesDirty(true),
@ -654,24 +701,6 @@ void nsPresContext::PreferenceChanged(const char* aPrefName) {
InvalidatePaintedLayers();
}
struct WeakRunnableMethod : Runnable {
using Method = void (nsPresContext::*)();
WeakRunnableMethod(const char* aName, nsPresContext* aPc, Method aMethod)
: Runnable(aName), mPresContext(aPc), mMethod(aMethod) {}
NS_IMETHOD Run() override {
if (nsPresContext* pc = mPresContext.get()) {
(pc->*mMethod)();
}
return NS_OK;
}
private:
WeakPtr<nsPresContext> mPresContext;
Method mMethod;
};
nsresult nsPresContext::Init(nsDeviceContext* aDeviceContext) {
NS_ASSERTION(!mInitialized, "attempt to reinit pres context");
NS_ENSURE_ARG(aDeviceContext);

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

@ -1103,10 +1103,12 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
void UpdateCharSet(NotNull<const Encoding*> aCharSet);
void DoForceReflowForFontInfoUpdateFromStyle();
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(bool aNeedsReframe);
void ForceReflowForFontInfoUpdateFromStyle();
/**
* Checks for MozAfterPaint listeners on the document
@ -1311,6 +1313,7 @@ class nsPresContext : public nsISupports, public mozilla::SupportsWeakPtr {
// widget::ThemeChangeKind
unsigned mPendingThemeChangeKind : kThemeChangeKindBits;
unsigned mPendingUIResolutionChanged : 1;
unsigned mPendingFontInfoUpdateReflowFromStyle : 1;
// Are we currently drawing an SVG glyph?
unsigned mIsGlyph : 1;

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

@ -47,10 +47,8 @@ void PostTraversalTask::Run() {
break;
case Type::FontInfoUpdate:
nsPresContext* pc =
static_cast<ServoStyleSet*>(mTarget)->GetPresContext();
if (pc) {
pc->ForceReflowForFontInfoUpdate(/* aNeedsReframe = */ false);
if (auto* pc = static_cast<ServoStyleSet*>(mTarget)->GetPresContext()) {
pc->ForceReflowForFontInfoUpdateFromStyle();
}
break;
}