Bug 1382078 Part 3 - Support media changes for XBL stylesheets.
MozReview-Commit-ID: EJp8EMyanBT
--- a/dom/xbl/nsBindingManager.cpp
+++ b/dom/xbl/nsBindingManager.cpp
@@ -45,16 +45,17 @@
#include "nsIScriptContext.h"
#include "xpcpublic.h"
#include "jswrapper.h"
#include "nsThreadUtils.h"
#include "mozilla/dom/NodeListBinding.h"
#include "mozilla/dom/ScriptSettings.h"
+#include "mozilla/ServoStyleSet.h"
#include "mozilla/Unused.h"
using namespace mozilla;
using namespace mozilla::dom;
// Implement our nsISupports methods
NS_IMPL_CYCLE_COLLECTION_CLASS(nsBindingManager)
@@ -740,30 +741,70 @@ nsBindingManager::WalkAllRules(nsIStyleR
});
}
bool
nsBindingManager::MediumFeaturesChanged(nsPresContext* aPresContext)
{
bool rulesChanged = false;
RefPtr<nsPresContext> 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<nsPresContext> presContext = aPresContext;
+
+ EnumerateBoundContentBindings([=](nsXBLBinding* aBinding) {
+ nsXBLPrototypeBinding* protoBinding = aBinding->PrototypeBinding();
+ ServoStyleSet* styleSet = protoBinding->GetServoStyleSet();
+ if (styleSet && styleSet->StyleSheetsHaveChanged()) {
+ protoBinding->ComputeServoStyleSet(presContext);
+ }
+ });
+}
+
+void
nsBindingManager::AppendAllSheets(nsTArray<StyleSheet*>& aArray)
{
EnumerateBoundContentBindings([&aArray](nsXBLBinding* aBinding) {
aBinding->PrototypeBinding()->AppendStyleSheetsTo(aArray);
});
}
static void
--- a/dom/xbl/nsBindingManager.h
+++ b/dom/xbl/nsBindingManager.h
@@ -125,23 +125,27 @@ public:
// Style rule methods
nsresult WalkRules(nsIStyleRuleProcessor::EnumFunc aFunc,
ElementDependentRuleProcessorData* aData,
bool* aCutOffInheritance);
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<mozilla::StyleSheet*>& aArray);
void Traverse(nsIContent *aContent,
nsCycleCollectionTraversalCallback &cb);
NS_DECL_CYCLE_COLLECTION_CLASS(nsBindingManager)
// Notify the binding manager when an outermost update begins and
--- a/dom/xbl/nsXBLPrototypeBinding.cpp
+++ b/dom/xbl/nsXBLPrototypeBinding.cpp
@@ -564,16 +564,24 @@ nsXBLPrototypeBinding::GetRuleProcessor(
{
if (mResources) {
return mResources->GetRuleProcessor();
}
return nullptr;
}
+void
+nsXBLPrototypeBinding::ComputeServoStyleSet(nsPresContext* aPresContext)
+{
+ if (mResources) {
+ mResources->ComputeServoStyleSet(aPresContext);
+ }
+}
+
ServoStyleSet*
nsXBLPrototypeBinding::GetServoStyleSet() const
{
return mResources ? mResources->GetServoStyleSet() : nullptr;
}
void
nsXBLPrototypeBinding::EnsureAttributeTable()
--- a/dom/xbl/nsXBLPrototypeBinding.h
+++ b/dom/xbl/nsXBLPrototypeBinding.h
@@ -126,16 +126,17 @@ public:
void RemoveStyleSheet(mozilla::StyleSheet* aSheet);
void InsertStyleSheetAt(size_t aIndex, mozilla::StyleSheet* aSheet);
mozilla::StyleSheet* StyleSheetAt(size_t aIndex) const;
size_t SheetCount() const;
bool HasStyleSheets() const;
void AppendStyleSheetsTo(nsTArray<mozilla::StyleSheet*>& aResult) const;
nsIStyleRuleProcessor* GetRuleProcessor();
+ void ComputeServoStyleSet(nsPresContext* aPresContext);
mozilla::ServoStyleSet* GetServoStyleSet() const;
nsresult FlushSkinSheets();
nsIAtom* GetBaseTag(int32_t* aNamespaceID);
void SetBaseTag(int32_t aNamespaceID, nsIAtom* aTag);
bool ImplementsInterface(REFNSIID aIID) const;
--- a/layout/style/ServoStyleSet.cpp
+++ b/layout/style/ServoStyleSet.cpp
@@ -104,16 +104,18 @@ ServoStyleSet::~ServoStyleSet()
}
}
}
void
ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager)
{
mPresContext = aPresContext;
+ mPresContextInitXBLStyleSet = aPresContext;
+
mRawSet.reset(Servo_StyleSet_Init(aPresContext));
mBindingManager = aBindingManager;
mPresContext->DeviceContext()->InitFontCache();
// Now that we have an mRawSet, go ahead and notify about whatever stylesheets
// we have so far.
for (auto& sheetArray : mSheets) {
@@ -163,31 +165,51 @@ ServoStyleSet::InvalidateStyleForCSSRule
MOZ_ASSERT(StylistNeedsUpdate());
mPresContext->RestyleManager()->AsServo()->PostRestyleEventForCSSRuleChanges();
}
nsRestyleHint
ServoStyleSet::MediumFeaturesChanged(bool aViewportChanged)
{
bool viewportUnitsUsed = false;
- const OriginFlags rulesChanged = static_cast<OriginFlags>(
- 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;
}
if (viewportUnitsUsed && aViewportChanged) {
return eRestyle_ForceDescendants;
}
return nsRestyleHint(0);
}
+bool
+ServoStyleSet::MediumFeaturesChangedRules(bool* aViewportUnitsUsed)
+{
+ MOZ_ASSERT(aViewportUnitsUsed);
+
+ const OriginFlags rulesChanged = static_cast<OriginFlags>(
+ Servo_StyleSet_MediumFeaturesChanged(mRawSet.get(), aViewportUnitsUsed));
+
+ if (rulesChanged != OriginFlags(0)) {
+ MarkOriginsDirty(rulesChanged);
+ return true;
+ }
+
+ return false;
+}
+
MOZ_DEFINE_MALLOC_SIZE_OF(ServoStyleSetMallocSizeOf)
void
ServoStyleSet::AddSizeOfIncludingThis(nsWindowSizes& aSizes) const
{
MallocSizeOf mallocSizeOf = aSizes.mState.mMallocSizeOf;
aSizes.mLayoutServoStyleSetsOther += mallocSizeOf(this);
@@ -1367,23 +1389,31 @@ ServoStyleSet::ResolveForDeclarations(
aDeclarations).Consume();
}
void
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);
+ 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);
+ }
+
mStylistState = StylistState::NotDirty;
}
void
ServoStyleSet::MaybeGCRuleTree()
{
MOZ_ASSERT(NS_IsMainThread());
Servo_MaybeGCRuleTree(mRawSet.get());
--- a/layout/style/ServoStyleSet.h
+++ b/layout/style/ServoStyleSet.h
@@ -41,28 +41,32 @@ class nsIContent;
class nsIDocument;
class nsPresContext;
struct nsTimingFunction;
struct RawServoRuleNode;
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,
User = 0x02,
Author = 0x04,
All = 0x07,
};
@@ -128,16 +132,19 @@ public:
bool StyleSheetsHaveChanged() const
{
return StylistNeedsUpdate();
}
nsRestyleHint MediumFeaturesChanged(bool aViewportChanged);
+ // aViewportChanged outputs whether any viewport units is used.
+ bool MediumFeaturesChangedRules(bool* aViewportUnitsUsed);
+
void InvalidateStyleForCSSRuleChanges();
void AddSizeOfIncludingThis(nsWindowSizes& aSizes) const;
const RawServoStyleSet* RawSet() const {
return mRawSet.get();
}
bool GetAuthorStyleDisabled() const;
@@ -428,16 +435,21 @@ public:
// Returns the style rule map.
ServoStyleRuleMap* StyleRuleMap();
// Clear mPresContext. This is needed after XBL ServoStyleSet is created.
void ClearPresContext() {
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.
*
* This function allows us to skip taking a an attribute snapshot when
* the modified attribute doesn't appear in an attribute selector in
* a style sheet.
*/
@@ -520,17 +532,22 @@ private:
*/
void MarkOriginsDirty(OriginFlags aChangedOrigins);
/**
* Note that the stylist needs a style flush due to style sheet changes.
*/
void SetStylistStyleSheetsDirty()
{
- mStylistState = StylistState::StyleSheetsDirty;
+ mStylistState |= StylistState::StyleSheetsDirty;
+ }
+
+ void SetStylistXBLStyleSheetsDirty()
+ {
+ mStylistState |= StylistState::XBLStyleSheetsDirty;
}
bool StylistNeedsUpdate() const
{
return mStylistState != StylistState::NotDirty;
}
/**
@@ -560,17 +577,25 @@ private:
void InsertSheetOfType(SheetType aType,
ServoStyleSheet* aSheet,
ServoStyleSheet* aBeforeSheet);
void RemoveSheetOfType(SheetType aType,
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<RawServoStyleSet> mRawSet;
EnumeratedArray<SheetType, SheetType::Count,
nsTArray<RefPtr<ServoStyleSheet>>> mSheets;
bool mAuthorStyleDisabled;
StylistState mStylistState;
uint64_t mUserFontSetUpdateGeneration;
uint32_t mUserFontCacheUpdateGeneration;
--- a/layout/style/test/mochitest.ini
+++ b/layout/style/test/mochitest.ini
@@ -237,17 +237,16 @@ skip-if = !stylo
[test_keyframes_rules.html]
[test_keyframes_vendor_prefix.html]
[test_load_events_on_stylesheets.html]
[test_logical_properties.html]
[test_media_queries.html]
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]
[test_namespace_rule.html]
[test_of_type_selectors.xhtml]
[test_page_parser.html]
[test_parse_eof.html]
[test_parse_ident.html]