Bug 1523181 - Don't implicitly flush the user font set.

Summary:
Flushing it at a bad time can cancel loads whose timer / completion
handler is in progress, which makes no sense.

Reviewers: jfkthame, jwatt, heycam

Tags: #secure-revision

Bug #: 1523181

Differential Revision: https://phabricator.services.mozilla.com/D17856
This commit is contained in:
Emilio Cobos Álvarez 2019-01-27 16:30:38 +01:00
parent 38a8cb51e1
commit 0ebf739646
11 changed files with 30 additions and 72 deletions

View File

@ -1246,7 +1246,6 @@ Document::Document(const char* aContentType)
mDidDocumentOpen(false),
mHasDisplayDocument(false),
mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false),
@ -11601,33 +11600,7 @@ nsAutoSyncOperation::~nsAutoSyncOperation() {
}
}
gfxUserFontSet* Document::GetUserFontSet(bool aFlushUserFontSet) {
// We want to initialize the user font set lazily the first time the
// user asks for it, rather than building it too early and forcing
// rule cascade creation. Thus we try to enforce the invariant that
// we *never* build the user font set until the first call to
// GetUserFontSet. However, once it's been requested, we can't wait
// for somebody to call GetUserFontSet in order to rebuild it (see
// comments below in MarkUserFontSetDirty for why).
#ifdef DEBUG
bool userFontSetGottenBefore = mGetUserFontSetCalled;
#endif
// Set mGetUserFontSetCalled up front, so that FlushUserFontSet will actually
// flush.
mGetUserFontSetCalled = true;
if (mFontFaceSetDirty && aFlushUserFontSet) {
// If this assertion fails, and there have actually been changes to
// @font-face rules, then we will call StyleChangeReflow in
// FlushUserFontSet. If we're in the middle of reflow,
// that's a bad thing to do, and the caller was responsible for
// flushing first. If we're not (e.g., in frame construction), it's
// ok.
NS_ASSERTION(!userFontSetGottenBefore || !GetShell() ||
!GetShell()->IsReflowLocked(),
"FlushUserFontSet should have been called first");
FlushUserFontSet();
}
gfxUserFontSet* Document::GetUserFontSet() {
if (!mFontFaceSet) {
return nullptr;
}
@ -11636,12 +11609,6 @@ gfxUserFontSet* Document::GetUserFontSet(bool aFlushUserFontSet) {
}
void Document::FlushUserFontSet() {
if (!mGetUserFontSetCalled) {
return; // No one cares about this font set yet, but we want to be careful
// to not unset our mFontFaceSetDirty bit, so when someone really
// does we'll create it.
}
if (!mFontFaceSetDirty) {
return;
}
@ -11678,22 +11645,20 @@ void Document::FlushUserFontSet() {
}
void Document::MarkUserFontSetDirty() {
if (!mGetUserFontSetCalled) {
// We want to lazily build the user font set the first time it's
// requested (so we don't force creation of rule cascades too
// early), so don't do anything now.
if (mFontFaceSetDirty) {
return;
}
mFontFaceSetDirty = true;
if (nsIPresShell* shell = GetShell()) {
shell->EnsureStyleFlush();
}
}
FontFaceSet* Document::Fonts() {
if (!mFontFaceSet) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this);
GetUserFontSet(); // this will cause the user font set to be
// created/updated
FlushUserFontSet();
}
return mFontFaceSet;
}

View File

@ -3339,7 +3339,7 @@ class Document : public nsINode,
}
}
gfxUserFontSet* GetUserFontSet(bool aFlushUserFontSet = true);
gfxUserFontSet* GetUserFontSet();
void FlushUserFontSet();
void MarkUserFontSetDirty();
mozilla::dom::FontFaceSet* GetFonts() { return mFontFaceSet; }
@ -4065,9 +4065,6 @@ class Document : public nsINode,
// Is the current mFontFaceSet valid?
bool mFontFaceSetDirty : 1;
// Has GetUserFontSet() been called?
bool mGetUserFontSetCalled : 1;
// True if we have fired the DOMContentLoaded event, or don't plan to fire one
// (e.g. we're not being parsed at all).
bool mDidFireDOMContentLoaded : 1;

View File

@ -3486,6 +3486,8 @@ bool CanvasRenderingContext2D::SetFontInternal(const nsAString& aFont,
resizedFont.size =
(fontStyle->mSize * c->AppUnitsPerDevPixel()) / AppUnitsPerCSSPixel();
c->Document()->FlushUserFontSet();
nsFontMetrics::Params params;
params.language = fontStyle->mLanguage;
params.explicitLanguage = fontStyle->mExplicitLanguage;
@ -4026,6 +4028,7 @@ nsresult CanvasRenderingContext2D::DrawOrMeasureText(
nsPresContext* presContext = presShell->GetPresContext();
// ensure user font set is up to date
presContext->Document()->FlushUserFontSet();
currentFontStyle->SetUserFontSet(presContext->GetUserFontSet());
if (currentFontStyle->GetStyle()->size == 0.0F) {

View File

@ -1157,9 +1157,7 @@ void PresShell::Destroy() {
}
}
if (mPresContext) {
const bool mayFlushUserFontSet = false;
gfxUserFontSet* fs = mPresContext->GetUserFontSet(mayFlushUserFontSet);
if (fs) {
if (gfxUserFontSet* fs = mPresContext->GetUserFontSet()) {
uint32_t fontCount;
uint64_t fontSize;
fs->GetLoadStatistics(fontCount, fontSize);

View File

@ -9583,8 +9583,7 @@ static nsRect ComputeHTMLReferenceRect(nsIFrame* aFrame,
/* static */
already_AddRefed<nsFontMetrics> nsLayoutUtils::GetMetricsFor(
nsPresContext* aPresContext, bool aIsVertical,
const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet,
FlushUserFontSet aFlushUserFontSet) {
const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet) {
nsFont font = aStyleFont->mFont;
font.size = aFontSize;
gfxFont::Orientation orientation =
@ -9593,10 +9592,8 @@ already_AddRefed<nsFontMetrics> nsLayoutUtils::GetMetricsFor(
params.language = aStyleFont->mLanguage;
params.explicitLanguage = aStyleFont->mExplicitLanguage;
params.orientation = orientation;
params.userFontSet = aUseUserFontSet
? aPresContext->GetUserFontSet(aFlushUserFontSet ==
FlushUserFontSet::Yes)
: nullptr;
params.userFontSet =
aUseUserFontSet ? aPresContext->GetUserFontSet() : nullptr;
params.textPerf = aPresContext->GetTextPerfMetrics();
return aPresContext->DeviceContext()->GetMetricsFor(font, params);
}

View File

@ -2945,15 +2945,11 @@ class nsLayoutUtils {
// from preferences.
static uint8_t ControlCharVisibilityDefault();
enum class FlushUserFontSet {
Yes,
No,
};
// Callers are responsible to ensure the user-font-set is up-to-date if
// aUseUserFontSet is true.
static already_AddRefed<nsFontMetrics> GetMetricsFor(
nsPresContext* aPresContext, bool aIsVertical,
const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet,
FlushUserFontSet aFlushUserFontSet);
const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet);
/**
* Appropriately add the correct font if we are using DocumentFonts or

View File

@ -1864,8 +1864,8 @@ bool nsPresContext::HasAuthorSpecifiedRules(const nsIFrame* aFrame,
aRuleTypeMask, UseDocumentColors());
}
gfxUserFontSet* nsPresContext::GetUserFontSet(bool aFlushUserFontSet) {
return mDocument->GetUserFontSet(aFlushUserFontSet);
gfxUserFontSet* nsPresContext::GetUserFontSet() {
return mDocument->GetUserFontSet();
}
void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {

View File

@ -901,7 +901,7 @@ class nsPresContext : public nsISupports,
bool SuppressingResizeReflow() const { return mSuppressResizeReflow; }
gfxUserFontSet* GetUserFontSet(bool aFlushUserFontSet = true);
gfxUserFontSet* GetUserFontSet();
// Should be called whenever the set of fonts available in the user
// font set changes (e.g., because a new font loads, or because the

View File

@ -2048,8 +2048,7 @@ GeckoFontMetrics Gecko_GetFontMetrics(RawGeckoPresContextBorrowed aPresContext,
nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
presContext->SetUsesExChUnits(true);
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet,
nsLayoutUtils::FlushUserFontSet::No);
presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
ret.mXSize = fm->XHeight();
gfxFloat zeroWidth = fm->GetThebesFontGroup()

View File

@ -351,9 +351,7 @@ void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) {
already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleFor(
Element* aElement, LazyComputeBehavior aMayCompute) {
if (aMayCompute == LazyComputeBehavior::Allow) {
PreTraverseSync();
return ResolveStyleLazilyInternal(aElement,
CSSPseudoElementType::NotPseudo);
return ResolveStyleLazily(aElement, CSSPseudoElementType::NotPseudo);
}
return ResolveServoStyle(*aElement);
@ -378,6 +376,12 @@ void ServoStyleSet::PreTraverseSync() {
// is necessary to avoid a data race when updating the cache.
mozilla::Unused << mDocument->GetRootElement();
// FIXME(emilio): This shouldn't be needed in theory, the call to the same
// function in PresShell should do the work, but as it turns out we
// ProcessPendingRestyles() twice, and runnables from frames just constructed
// can end up doing editing stuff, which adds stylesheets etc...
mDocument->FlushUserFontSet();
ResolveMappedAttrDeclarationBlocks();
nsMediaFeatures::InitSystemMetrics();
@ -536,7 +540,6 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily(
Element* aElement, CSSPseudoElementType aPseudoType,
StyleRuleInclusion aRuleInclusion) {
PreTraverseSync();
return ResolveStyleLazilyInternal(aElement, aPseudoType, aRuleInclusion);
}

View File

@ -640,8 +640,8 @@ void nsDocLoader::DocLoaderIsEmpty(bool aFlushLayout) {
// since the reflow is what starts font loads.
mozilla::FlushType flushType = mozilla::FlushType::Style;
// Be safe in case this presshell is in teardown now
nsPresContext* presContext = doc->GetPresContext();
if (presContext && presContext->GetUserFontSet()) {
doc->FlushUserFontSet();
if (doc->GetUserFontSet()) {
flushType = mozilla::FlushType::Layout;
}
mDontFlushLayout = mIsFlushingLayout = true;