From d537ea001cb6b55e72a11ddde5edf7238e1d3b4c Mon Sep 17 00:00:00 2001 From: Ting-Yu Lin Date: Sat, 2 Sep 2017 15:25:45 +0800 Subject: [PATCH] Bug 1382078 Part 3 - Support media changes for XBL stylesheets. r=emilio MozReview-Commit-ID: EJp8EMyanBT --HG-- extra : rebase_source : 524aaa95070c7708b3c24a0c9ee8a24344be2645 --- dom/xbl/nsBindingManager.cpp | 51 ++++++++++++++++++++++++++++--- dom/xbl/nsBindingManager.h | 14 ++++++--- dom/xbl/nsXBLPrototypeBinding.cpp | 8 +++++ dom/xbl/nsXBLPrototypeBinding.h | 1 + layout/style/ServoStyleSet.cpp | 50 ++++++++++++++++++++++++------ layout/style/ServoStyleSet.h | 43 ++++++++++++++++++++------ layout/style/test/mochitest.ini | 1 - 7 files changed, 138 insertions(+), 30 deletions(-) diff --git a/dom/xbl/nsBindingManager.cpp b/dom/xbl/nsBindingManager.cpp index 39d631d78560..e1bc1e066fb8 100644 --- a/dom/xbl/nsBindingManager.cpp +++ b/dom/xbl/nsBindingManager.cpp @@ -50,6 +50,7 @@ #include "nsThreadUtils.h" #include "mozilla/dom/NodeListBinding.h" #include "mozilla/dom/ScriptSettings.h" +#include "mozilla/ServoStyleSet.h" #include "mozilla/Unused.h" using namespace mozilla; @@ -745,19 +746,59 @@ nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext) { bool rulesChanged = false; RefPtr presContext = aPresContext; + bool isStyledByServo = mDocument->IsStyledByServo(); EnumerateBoundContentBindings([=, &rulesChanged](nsXBLBinding* aBinding) { - nsIStyleRuleProcessor* ruleProcessor = - aBinding->PrototypeBinding()->GetRuleProcessor(); - if (ruleProcessor) { - bool thisChanged = ruleProcessor->MediumFeaturesChanged(presContext); - rulesChanged = rulesChanged || thisChanged; + if (isStyledByServo) { + ServoStyleSet* styleSet = aBinding->PrototypeBinding()->GetServoStyleSet(); + if (styleSet) { + bool styleSetChanged = false; + + if (styleSet->IsPresContextChanged(presContext)) { + styleSetChanged = true; + } 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); + MOZ_ASSERT(!viewportUnitsUsed, + "Non-master stylesets shouldn't get flagged as using " + "viewport units!"); + } + rulesChanged = rulesChanged || styleSetChanged; + } + } else { + nsIStyleRuleProcessor* ruleProcessor = + aBinding->PrototypeBinding()->GetRuleProcessor(); + if (ruleProcessor) { + bool thisChanged = ruleProcessor->MediumFeaturesChanged(presContext); + rulesChanged = rulesChanged || thisChanged; + } } }); return rulesChanged; } +void +nsBindingManager::UpdateBoundContentBindingsForServo(nsPresContext* aPresContext) +{ + MOZ_ASSERT(mDocument->IsStyledByServo(), + "This should be called only by servo-backend!"); + + RefPtr presContext = aPresContext; + + EnumerateBoundContentBindings([=](nsXBLBinding* aBinding) { + nsXBLPrototypeBinding* protoBinding = aBinding->PrototypeBinding(); + ServoStyleSet* styleSet = protoBinding->GetServoStyleSet(); + if (styleSet && styleSet->StyleSheetsHaveChanged()) { + protoBinding->ComputeServoStyleSet(presContext); + } + }); +} + void nsBindingManager::AppendAllSheets(nsTArray& aArray) { diff --git a/dom/xbl/nsBindingManager.h b/dom/xbl/nsBindingManager.h index cde7889e4454..d18cc212e81d 100644 --- a/dom/xbl/nsBindingManager.h +++ b/dom/xbl/nsBindingManager.h @@ -130,13 +130,17 @@ public: void WalkAllRules(nsIStyleRuleProcessor::EnumFunc aFunc, ElementDependentRuleProcessorData* aData); - /** - * Do any processing that needs to happen as a result of a change in - * the characteristics of the medium, and return whether this rule - * processor's rules have changed (e.g., because of media queries). - */ + + // Do any processing that needs to happen as a result of a change in the + // characteristics of the medium, and return whether this rule processor's + // rules or the servo style set have changed (e.g., because of media + // queries). bool MediumFeaturesChanged(nsPresContext* aPresContext); + // Update the content bindings in mBoundContentSet due to medium features + // changed. + void UpdateBoundContentBindingsForServo(nsPresContext* aPresContext); + void AppendAllSheets(nsTArray& aArray); void Traverse(nsIContent *aContent, diff --git a/dom/xbl/nsXBLPrototypeBinding.cpp b/dom/xbl/nsXBLPrototypeBinding.cpp index e007cefb57b8..11a37aa6d324 100644 --- a/dom/xbl/nsXBLPrototypeBinding.cpp +++ b/dom/xbl/nsXBLPrototypeBinding.cpp @@ -569,6 +569,14 @@ nsXBLPrototypeBinding::GetRuleProcessor() return nullptr; } +void +nsXBLPrototypeBinding::ComputeServoStyleSet(nsPresContext* aPresContext) +{ + if (mResources) { + mResources->ComputeServoStyleSet(aPresContext); + } +} + ServoStyleSet* nsXBLPrototypeBinding::GetServoStyleSet() const { diff --git a/dom/xbl/nsXBLPrototypeBinding.h b/dom/xbl/nsXBLPrototypeBinding.h index 81765f539239..b2dce738188d 100644 --- a/dom/xbl/nsXBLPrototypeBinding.h +++ b/dom/xbl/nsXBLPrototypeBinding.h @@ -131,6 +131,7 @@ public: void AppendStyleSheetsTo(nsTArray& aResult) const; nsIStyleRuleProcessor* GetRuleProcessor(); + void ComputeServoStyleSet(nsPresContext* aPresContext); mozilla::ServoStyleSet* GetServoStyleSet() const; nsresult FlushSkinSheets(); diff --git a/layout/style/ServoStyleSet.cpp b/layout/style/ServoStyleSet.cpp index d28016cfdd6c..860ee3a66b4d 100644 --- a/layout/style/ServoStyleSet.cpp +++ b/layout/style/ServoStyleSet.cpp @@ -109,6 +109,8 @@ void ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager) { mPresContext = aPresContext; + mPresContextInitXBLStyleSet = aPresContext; + mRawSet.reset(Servo_StyleSet_Init(aPresContext)); mBindingManager = aBindingManager; @@ -168,11 +170,15 @@ nsRestyleHint ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged) { bool viewportUnitsUsed = false; - const OriginFlags rulesChanged = static_cast( - Servo_StyleSet_MediumFeaturesChanged(mRawSet.get(), &viewportUnitsUsed)); + bool rulesChanged = MediumFeaturesChangedRules(&viewportUnitsUsed); - if (rulesChanged != OriginFlags(0)) { - MarkOriginsDirty(rulesChanged); + if (mBindingManager && + mBindingManager->MediumFeaturesChanged(mPresContext)) { + SetStylistXBLStyleSheetsDirty(); + rulesChanged = true; + } + + if (rulesChanged) { return eRestyle_Subtree; } @@ -183,6 +189,22 @@ ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged) return nsRestyleHint(0); } +bool +ServoStyleSet::MediumFeaturesChangedRules(bool* aViewportUnitsUsed) +{ + MOZ_ASSERT(aViewportUnitsUsed); + + const OriginFlags rulesChanged = static_cast( + Servo_StyleSet_MediumFeaturesChanged(mRawSet.get(), aViewportUnitsUsed)); + + if (rulesChanged != OriginFlags(0)) { + MarkOriginsDirty(rulesChanged); + return true; + } + + return false; +} + MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf) void @@ -1372,13 +1394,21 @@ ServoStyleSet::UpdateStylist() { MOZ_ASSERT(StylistNeedsUpdate()); - // There's no need to compute invalidations and such for an XBL styleset, - // since they are loaded and unloaded synchronously, and they don't have to - // deal with dynamic content changes. - Element* root = - IsMaster() ? mPresContext->Document()->GetDocumentElement() : nullptr; + if (mStylistState & StylistState::StyleSheetsDirty) { + // There's no need to compute invalidations and such for an XBL styleset, + // since they are loaded and unloaded synchronously, and they don't have to + // deal with dynamic content changes. + Element* root = + IsMaster() ? mPresContext->Document()->GetDocumentElement() : nullptr; + + Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root); + } + + if (MOZ_UNLIKELY(mStylistState & StylistState::XBLStyleSheetsDirty)) { + MOZ_ASSERT(IsMaster(), "Only master styleset can mark XBL stylesets dirty!"); + mBindingManager->UpdateBoundContentBindingsForServo(mPresContext); + } - Servo_StyleSet_FlushStyleSheets(mRawSet.get(), root); mStylistState = StylistState::NotDirty; } diff --git a/layout/style/ServoStyleSet.h b/layout/style/ServoStyleSet.h index c48c7ea7eaf8..27611b211d20 100644 --- a/layout/style/ServoStyleSet.h +++ b/layout/style/ServoStyleSet.h @@ -46,18 +46,22 @@ struct TreeMatchContext; namespace mozilla { -/** - * A few flags used to track which kind of stylist state we may need to - * update. - */ +// A few flags used to track which kind of stylist state we may need to +// update. enum class StylistState : uint8_t { - /** The stylist is not dirty, we should do nothing */ + // The stylist is not dirty, we should do nothing. NotDirty = 0, - /** The style sheets have changed, so we need to update the style data. */ - StyleSheetsDirty, + // The style sheets have changed, so we need to update the style data. + StyleSheetsDirty = 1 << 0, + + // Some of the style sheets of the bound elements in binding manager have + // changed, so we need to tell the binding manager to update style data. + XBLStyleSheetsDirty = 1 << 1, }; +MOZ_MAKE_ENUM_CLASS_BITWISE_OPERATORS(StylistState) + // Bitfield type to represent Servo stylesheet origins. enum class OriginFlags : uint8_t { UserAgent = 0x01, @@ -133,6 +137,9 @@ public: nsRestyleHint MediumFeaturesChanged(bool aViewportChanged); + // aViewportChanged outputs whether any viewport units is used. + bool MediumFeaturesChangedRules(bool* aViewportUnitsUsed); + void InvalidateStyleForCSSRuleChanges(); void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const; @@ -433,6 +440,11 @@ public: mPresContext = nullptr; } + // Return whether this is the PresContext that initialized us. + bool IsPresContextChanged(nsPresContext* aPresContext) const { + return aPresContext != mPresContextInitXBLStyleSet; + } + /** * Returns true if a modification to an an attribute with the specified * local name might require us to restyle the element. @@ -525,7 +537,12 @@ private: */ void SetStylistStyleSheetsDirty() { - mStylistState = StylistState::StyleSheetsDirty; + mStylistState |= StylistState::StyleSheetsDirty; + } + + void SetStylistXBLStyleSheetsDirty() + { + mStylistState |= StylistState::XBLStyleSheetsDirty; } bool StylistNeedsUpdate() const @@ -565,7 +582,15 @@ private: ServoStyleSheet* aSheet); const Kind mKind; - nsPresContext* mPresContext; + + // Nullptr if this is an XBL style set. + nsPresContext* MOZ_NON_OWNING_REF mPresContext = nullptr; + + // Because XBL style set could be used by multiple PresContext, we need to + // store the PresContext pointer which initializes this style set for + // computing medium rule changes. + void* MOZ_NON_OWNING_REF mPresContextInitXBLStyleSet = nullptr; + UniquePtr mRawSet; EnumeratedArray>> mSheets; diff --git a/layout/style/test/mochitest.ini b/layout/style/test/mochitest.ini index 021494e6c99a..fb7453603b3e 100644 --- a/layout/style/test/mochitest.ini +++ b/layout/style/test/mochitest.ini @@ -242,7 +242,6 @@ skip-if = !stylo skip-if = android_version == '18' #debug-only failure; timed out #Android 4.3 aws only; bug 1030419 [test_media_queries_dynamic.html] [test_media_queries_dynamic_xbl.html] -fail-if = stylo # bug 1382078 [test_media_query_list.html] [test_media_query_serialization.html] [test_moz_device_pixel_ratio.html]