Bug 1435939: Process all the MediumFeatureChanges at the same time. r=xidorn

This avoids resetting the computed values all the time, and paves the way to
avoid using a StyleSet on XBL bindings / Shadow DOM, which we should really
really do because it's super overkill.

There are some XBL bits that are kind of hacky, in particular the mStylistDirty,
but they'll go away soon, since I want to redo how we store styles in XBL.

The alternative, which was returning an array of indices or something was even
more hacky I think.

MozReview-Commit-ID: 6tEl5gebXVF
This commit is contained in:
Emilio Cobos Álvarez 2018-02-06 16:52:22 +01:00
parent 75abcdb1ca
commit c2f6e9ff37
6 changed files with 71 additions and 115 deletions

View File

@ -767,47 +767,24 @@ bool
nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext,
mozilla::MediaFeatureChangeReason aReason)
{
MOZ_ASSERT(!mDocument->IsStyledByServo());
#ifdef MOZ_OLD_STYLE
bool rulesChanged = false;
RefPtr<nsPresContext> presContext = aPresContext;
bool isStyledByServo = mDocument->IsStyledByServo();
EnumerateBoundContentBindings([=, &rulesChanged](nsXBLBinding* aBinding) {
if (isStyledByServo) {
ServoStyleSet* styleSet = aBinding->PrototypeBinding()->GetServoStyleSet();
if (styleSet) {
bool styleSetChanged = false;
if (styleSet->IsPresContextChanged(presContext)) {
styleSetChanged = styleSet->SetPresContext(presContext);
} else {
// PresContext is not changed. This means aPresContext is still
// alive since the last time it initialized this XBL styleset.
// It's safe to check whether medium features changed.
bool viewportUnitsUsed = false;
styleSetChanged =
styleSet->MediumFeaturesChangedRules(&viewportUnitsUsed, aReason);
MOZ_ASSERT(!viewportUnitsUsed,
"Non-master stylesets shouldn't get flagged as using "
"viewport units!");
}
rulesChanged = rulesChanged || styleSetChanged;
}
} else {
#ifdef MOZ_OLD_STYLE
nsIStyleRuleProcessor* ruleProcessor =
aBinding->PrototypeBinding()->GetRuleProcessor();
if (ruleProcessor) {
bool thisChanged = ruleProcessor->MediumFeaturesChanged(presContext);
rulesChanged = rulesChanged || thisChanged;
}
#else
MOZ_CRASH("old style system disabled");
#endif
nsIStyleRuleProcessor* ruleProcessor =
aBinding->PrototypeBinding()->GetRuleProcessor();
if (ruleProcessor) {
bool thisChanged = ruleProcessor->MediumFeaturesChanged(presContext);
rulesChanged = rulesChanged || thisChanged;
}
return true;
});
return rulesChanged;
#else
MOZ_CRASH("old style system disabled");
return false;
#endif
}
void

View File

@ -86,14 +86,14 @@ SERVO_BINDING_FUNC(Servo_StyleSet_RebuildCachedData, void,
// We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
// work as return values with the Linux 32-bit ABI at the moment because
// they wrap the value in a struct.
SERVO_BINDING_FUNC(Servo_StyleSet_MediumFeaturesChanged, uint8_t,
RawServoStyleSetBorrowed set, bool* viewport_units_used,
SERVO_BINDING_FUNC(Servo_StyleSet_MediumFeaturesChanged,
MediumFeaturesChangedResult,
RawServoStyleSetBorrowed document_set,
const nsTArray<mozilla::ServoStyleSet*>* non_document_sets,
bool may_affect_default_style)
// We'd like to return `OriginFlags` here, but bindgen bitfield enums don't
// work as return values with the Linux 32-bit ABI at the moment because
// they wrap the value in a struct.
SERVO_BINDING_FUNC(Servo_StyleSet_SetDevice, uint8_t,
RawServoStyleSetBorrowed set, RawGeckoPresContextOwned pres_context)
SERVO_BINDING_FUNC(Servo_StyleSet_Drop, void, RawServoStyleSetOwned set)
SERVO_BINDING_FUNC(Servo_StyleSet_CompatModeChanged, void,
RawServoStyleSetBorrowed raw_data)

View File

@ -146,6 +146,12 @@ struct FontSizePrefs
nscoord mDefaultFantasySize;
};
struct MediumFeaturesChangedResult {
bool mAffectsDocumentRules;
bool mAffectsNonDocumentRules;
bool mUsesViewportUnits;
};
// DOM Traversal.
void Gecko_RecordTraversalStatistics(uint32_t total, uint32_t parallel,
uint32_t total_t, uint32_t parallel_t,

View File

@ -267,6 +267,7 @@ whitelist-types = [
"Image",
"ImageURL",
"Keyframe",
"MediumFeaturesChangedResult",
"nsAttrName",
"nsAttrValue",
"nscolor",
@ -468,6 +469,7 @@ structs-types = [
"mozilla::AnonymousCounterStyle",
"mozilla::AtomArray",
"mozilla::MallocSizeOf",
"mozilla::ServoStyleSet",
"mozilla::OriginFlags",
"mozilla::UniquePtr",
"ServoRawOffsetArc",
@ -475,6 +477,7 @@ structs-types = [
"nsIDocument",
"nsIDocument_DocumentTheme",
"nsSimpleContentList",
"MediumFeaturesChangedResult",
"RawGeckoAnimationPropertySegment",
"RawGeckoComputedTiming",
"RawGeckoCSSPropertyIDList",

View File

@ -133,6 +133,10 @@ ServoStyleSet::CreateXBLServoStyleSet(
set->ReplaceSheets(SheetType::Doc, aNewSheets);
// Update stylist immediately.
//
// NOTE(emilio): that this _needs_ to be the only call to UpdateStylist for
// XBL bindings, otherwise the Servo-side Device may have stale pres context
// pointers and such, which are not great.
set->UpdateStylist();
// XBL resources are shared for a given URL, even across documents, so we
@ -163,8 +167,6 @@ ServoStyleSet::Init(nsPresContext* aPresContext)
mDocument = aPresContext->Document();
MOZ_ASSERT(GetPresContext() == aPresContext);
mLastPresContextUsesXBLStyleSet = aPresContext;
mRawSet.reset(Servo_StyleSet_Init(aPresContext));
aPresContext->DeviceContext()->InitFontCache();
@ -209,24 +211,6 @@ ServoStyleSet::InvalidateStyleForCSSRuleChanges()
}
}
bool
ServoStyleSet::SetPresContext(nsPresContext* aPresContext)
{
MOZ_ASSERT(IsForXBL(), "Only XBL styleset can set PresContext!");
mLastPresContextUsesXBLStyleSet = aPresContext;
const OriginFlags rulesChanged = static_cast<OriginFlags>(
Servo_StyleSet_SetDevice(mRawSet.get(), aPresContext));
if (rulesChanged != OriginFlags(0)) {
MarkOriginsDirty(rulesChanged);
return true;
}
return false;
}
void
ServoStyleSet::InvalidateStyleForDocumentStateChanges(EventStates aStatesChanged)
{
@ -264,33 +248,6 @@ ServoStyleSet::InvalidateStyleForDocumentStateChanges(EventStates aStatesChanged
root, &styleSets, aStatesChanged.ServoValue());
}
nsRestyleHint
ServoStyleSet::MediumFeaturesChanged(MediaFeatureChangeReason aReason)
{
bool viewportUnitsUsed = false;
bool rulesChanged = MediumFeaturesChangedRules(&viewportUnitsUsed, aReason);
if (nsPresContext* pc = GetPresContext()) {
if (mDocument->BindingManager()->MediumFeaturesChanged(pc, aReason)) {
// TODO(emilio): We could technically just restyle the bound elements.
SetStylistXBLStyleSheetsDirty();
rulesChanged = true;
}
}
if (rulesChanged) {
return eRestyle_Subtree;
}
const bool viewportChanged =
bool(aReason & MediaFeatureChangeReason::ViewportChange);
if (viewportUnitsUsed && viewportChanged) {
return eRestyle_ForceDescendants;
}
return nsRestyleHint(0);
}
static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
// Zoom changes change the meaning of em units.
MediaFeatureChangeReason::ZoomChange |
@ -303,26 +260,51 @@ static const MediaFeatureChangeReason kMediaFeaturesAffectingDefaultStyle =
// the pres context (bug 1418159).
MediaFeatureChangeReason::ResolutionChange;
bool
ServoStyleSet::MediumFeaturesChangedRules(
bool* aViewportUnitsUsed,
MediaFeatureChangeReason aReason)
nsRestyleHint
ServoStyleSet::MediumFeaturesChanged(MediaFeatureChangeReason aReason)
{
MOZ_ASSERT(aViewportUnitsUsed);
AutoTArray<ServoStyleSet*, 20> nonDocumentStyleSets;
// FIXME(emilio): When bug 1425759 is fixed we need to enumerate ShadowRoots
// too.
//
// FIXME(emilio): This is broken for XBL. See bug 1406875.
mDocument->BindingManager()->EnumerateBoundContentBindings(
[&](nsXBLBinding* aBinding) {
if (ServoStyleSet* set = aBinding->PrototypeBinding()->GetServoStyleSet()) {
nonDocumentStyleSets.AppendElement(set);
}
return true;
});
bool mayAffectDefaultStyle =
bool(aReason & kMediaFeaturesAffectingDefaultStyle);
const OriginFlags rulesChanged = static_cast<OriginFlags>(
const MediumFeaturesChangedResult result =
Servo_StyleSet_MediumFeaturesChanged(
mRawSet.get(), aViewportUnitsUsed, mayAffectDefaultStyle));
mRawSet.get(), &nonDocumentStyleSets, mayAffectDefaultStyle);
if (rulesChanged != OriginFlags(0)) {
MarkOriginsDirty(rulesChanged);
return true;
const bool rulesChanged =
result.mAffectsDocumentRules || result.mAffectsNonDocumentRules;
if (result.mAffectsDocumentRules) {
SetStylistStyleSheetsDirty();
}
return false;
if (result.mAffectsNonDocumentRules) {
SetStylistXBLStyleSheetsDirty();
}
if (rulesChanged) {
return eRestyle_Subtree;
}
const bool viewportChanged =
bool(aReason & MediaFeatureChangeReason::ViewportChange);
if (result.mUsesViewportUnits && viewportChanged) {
return eRestyle_ForceDescendants;
}
return nsRestyleHint(0);
}
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
@ -1125,6 +1107,10 @@ ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins)
void
ServoStyleSet::SetStylistStyleSheetsDirty()
{
// Note that there's another hidden mutator of mStylistState for XBL style
// sets in MediumFeaturesChanged...
//
// We really need to stop using a full-blown StyleSet there...
mStylistState |= StylistState::StyleSheetsDirty;
// We need to invalidate cached style in getComputedStyle for undisplayed
@ -1468,6 +1454,9 @@ ServoStyleSet::UpdateStylist()
if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) {
MOZ_ASSERT(IsMaster(), "Only master styleset can mark XBL stylesets dirty!");
MOZ_ASSERT(GetPresContext(), "How did they get dirty?");
// NOTE(emilio): This right now rebuilds the stylist in the prototype
// binding. That is fine, and if we wanted to be more incremental, which we
// probably should, we need to move away from using a StyleSet for XBL.
mDocument->BindingManager()->UpdateBoundContentBindingsForServo(GetPresContext());
}

View File

@ -160,9 +160,6 @@ public:
return Servo_SourceSizeList_Evaluate(mRawSet.get(), aSourceSizeList);
}
// aViewportChanged outputs whether any viewport units is used.
bool MediumFeaturesChangedRules(bool* aViewportUnitsUsed, MediaFeatureChangeReason);
void InvalidateStyleForCSSRuleChanges();
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
@ -448,15 +445,6 @@ public:
// Returns the style rule map.
ServoStyleRuleMap* StyleRuleMap();
// Return whether this is the last PresContext which uses this XBL styleset.
bool IsPresContextChanged(nsPresContext* aPresContext) const {
return aPresContext != mLastPresContextUsesXBLStyleSet;
}
// Set PresContext (i.e. Device) for mRawSet. This should be called only
// by XBL stylesets. Returns true if there is any rule changing.
bool SetPresContext(nsPresContext* aPresContext);
/**
* Returns true if a modification to an an attribute with the specified
* local name might require us to restyle the element.
@ -608,13 +596,6 @@ private:
*/
nsPresContext* GetPresContext();
// Because XBL style set could be used by multiple PresContext, we need to
// store the last PresContext pointer which uses this XBL styleset for
// computing medium rule changes.
//
// FIXME(emilio): This is a hack, and is broken. See bug 1406875.
void* MOZ_NON_OWNING_REF mLastPresContextUsesXBLStyleSet = nullptr;
UniquePtr<RawServoStyleSet> mRawSet;
EnumeratedArray<SheetType, SheetType::Count,
nsTArray<RefPtr<ServoStyleSheet>>> mSheets;