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), mDidDocumentOpen(false),
mHasDisplayDocument(false), mHasDisplayDocument(false),
mFontFaceSetDirty(true), mFontFaceSetDirty(true),
mGetUserFontSetCalled(false),
mDidFireDOMContentLoaded(true), mDidFireDOMContentLoaded(true),
mHasScrollLinkedEffect(false), mHasScrollLinkedEffect(false),
mFrameRequestCallbacksScheduled(false), mFrameRequestCallbacksScheduled(false),
@ -11601,33 +11600,7 @@ nsAutoSyncOperation::~nsAutoSyncOperation() {
} }
} }
gfxUserFontSet* Document::GetUserFontSet(bool aFlushUserFontSet) { gfxUserFontSet* Document::GetUserFontSet() {
// 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();
}
if (!mFontFaceSet) { if (!mFontFaceSet) {
return nullptr; return nullptr;
} }
@ -11636,12 +11609,6 @@ gfxUserFontSet* Document::GetUserFontSet(bool aFlushUserFontSet) {
} }
void Document::FlushUserFontSet() { 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) { if (!mFontFaceSetDirty) {
return; return;
} }
@ -11678,22 +11645,20 @@ void Document::FlushUserFontSet() {
} }
void Document::MarkUserFontSetDirty() { void Document::MarkUserFontSetDirty() {
if (!mGetUserFontSetCalled) { if (mFontFaceSetDirty) {
// 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.
return; return;
} }
mFontFaceSetDirty = true; mFontFaceSetDirty = true;
if (nsIPresShell* shell = GetShell()) {
shell->EnsureStyleFlush();
}
} }
FontFaceSet* Document::Fonts() { FontFaceSet* Document::Fonts() {
if (!mFontFaceSet) { if (!mFontFaceSet) {
nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject()); nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(GetScopeObject());
mFontFaceSet = new FontFaceSet(window, this); mFontFaceSet = new FontFaceSet(window, this);
GetUserFontSet(); // this will cause the user font set to be FlushUserFontSet();
// created/updated
} }
return mFontFaceSet; return mFontFaceSet;
} }

View File

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

View File

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

View File

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

View File

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

View File

@ -2945,15 +2945,11 @@ class nsLayoutUtils {
// from preferences. // from preferences.
static uint8_t ControlCharVisibilityDefault(); static uint8_t ControlCharVisibilityDefault();
enum class FlushUserFontSet { // Callers are responsible to ensure the user-font-set is up-to-date if
Yes, // aUseUserFontSet is true.
No,
};
static already_AddRefed<nsFontMetrics> GetMetricsFor( static already_AddRefed<nsFontMetrics> GetMetricsFor(
nsPresContext* aPresContext, bool aIsVertical, nsPresContext* aPresContext, bool aIsVertical,
const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet, const nsStyleFont* aStyleFont, nscoord aFontSize, bool aUseUserFontSet);
FlushUserFontSet aFlushUserFontSet);
/** /**
* Appropriately add the correct font if we are using DocumentFonts or * 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()); aRuleTypeMask, UseDocumentColors());
} }
gfxUserFontSet* nsPresContext::GetUserFontSet(bool aFlushUserFontSet) { gfxUserFontSet* nsPresContext::GetUserFontSet() {
return mDocument->GetUserFontSet(aFlushUserFontSet); return mDocument->GetUserFontSet();
} }
void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) { void nsPresContext::UserFontSetUpdated(gfxUserFontEntry* aUpdatedFont) {

View File

@ -901,7 +901,7 @@ class nsPresContext : public nsISupports,
bool SuppressingResizeReflow() const { return mSuppressResizeReflow; } bool SuppressingResizeReflow() const { return mSuppressResizeReflow; }
gfxUserFontSet* GetUserFontSet(bool aFlushUserFontSet = true); gfxUserFontSet* GetUserFontSet();
// Should be called whenever the set of fonts available in the user // 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 // 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); nsPresContext* presContext = const_cast<nsPresContext*>(aPresContext);
presContext->SetUsesExChUnits(true); presContext->SetUsesExChUnits(true);
RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor( RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetMetricsFor(
presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet, presContext, aIsVertical, aFont, aFontSize, aUseUserFontSet);
nsLayoutUtils::FlushUserFontSet::No);
ret.mXSize = fm->XHeight(); ret.mXSize = fm->XHeight();
gfxFloat zeroWidth = fm->GetThebesFontGroup() gfxFloat zeroWidth = fm->GetThebesFontGroup()

View File

@ -351,9 +351,7 @@ void ServoStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled) {
already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleFor( already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleFor(
Element* aElement, LazyComputeBehavior aMayCompute) { Element* aElement, LazyComputeBehavior aMayCompute) {
if (aMayCompute == LazyComputeBehavior::Allow) { if (aMayCompute == LazyComputeBehavior::Allow) {
PreTraverseSync(); return ResolveStyleLazily(aElement, CSSPseudoElementType::NotPseudo);
return ResolveStyleLazilyInternal(aElement,
CSSPseudoElementType::NotPseudo);
} }
return ResolveServoStyle(*aElement); return ResolveServoStyle(*aElement);
@ -378,6 +376,12 @@ void ServoStyleSet::PreTraverseSync() {
// is necessary to avoid a data race when updating the cache. // is necessary to avoid a data race when updating the cache.
mozilla::Unused << mDocument->GetRootElement(); 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(); ResolveMappedAttrDeclarationBlocks();
nsMediaFeatures::InitSystemMetrics(); nsMediaFeatures::InitSystemMetrics();
@ -536,7 +540,6 @@ already_AddRefed<ComputedStyle> ServoStyleSet::ResolveStyleLazily(
Element* aElement, CSSPseudoElementType aPseudoType, Element* aElement, CSSPseudoElementType aPseudoType,
StyleRuleInclusion aRuleInclusion) { StyleRuleInclusion aRuleInclusion) {
PreTraverseSync(); PreTraverseSync();
return ResolveStyleLazilyInternal(aElement, aPseudoType, aRuleInclusion); return ResolveStyleLazilyInternal(aElement, aPseudoType, aRuleInclusion);
} }

View File

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