Bug 1420762: Make StyleSheets notify directly to their StyleSets. r=heycam

This also makes the rule map not process all the stylesheets for the document,
which would be a mess with shadow DOM.

Far from the final, ideal state, but hey, progress.

MozReview-Commit-ID: 7TrifME9VZ
This commit is contained in:
Emilio Cobos Álvarez 2017-11-28 01:50:45 +01:00
parent 51d751d63c
commit f28656c543
25 changed files with 295 additions and 391 deletions

View File

@ -4733,6 +4733,8 @@ nsDocument::SetStyleSheetApplicableState(StyleSheet* aSheet,
NS_PRECONDITION(aSheet, "null arg");
// If we're actually in the document style sheet list
//
// FIXME(emilio): Shadow DOM.
MOZ_DIAGNOSTIC_ASSERT(aSheet->IsServo() == IsStyledByServo());
if (mStyleSheets.IndexOf(aSheet) != mStyleSheets.NoIndex) {
if (aApplicable) {
@ -5755,45 +5757,42 @@ nsDocument::DocumentStatesChanged(EventStates aStateMask)
}
void
nsDocument::StyleRuleChanged(StyleSheet* aSheet,
css::Rule* aStyleRule)
nsDocument::StyleRuleChanged(StyleSheet* aSheet, css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleChanged, (aSheet, aStyleRule));
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleChanged",
mRule,
aStyleRule);
if (!StyleSheetChangeEventsEnabled()) {
return;
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleChanged",
mRule,
aStyleRule);
}
void
nsDocument::StyleRuleAdded(StyleSheet* aSheet,
css::Rule* aStyleRule)
nsDocument::StyleRuleAdded(StyleSheet* aSheet, css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleAdded, (aSheet, aStyleRule));
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleAdded",
mRule,
aStyleRule);
if (!StyleSheetChangeEventsEnabled()) {
return;
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleAdded",
mRule,
aStyleRule);
}
void
nsDocument::StyleRuleRemoved(StyleSheet* aSheet,
css::Rule* aStyleRule)
nsDocument::StyleRuleRemoved(StyleSheet* aSheet, css::Rule* aStyleRule)
{
NS_DOCUMENT_NOTIFY_OBSERVERS(StyleRuleRemoved, (aSheet, aStyleRule));
if (StyleSheetChangeEventsEnabled()) {
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleRemoved",
mRule,
aStyleRule);
if (!StyleSheetChangeEventsEnabled()) {
return;
}
DO_STYLESHEET_NOTIFICATION(StyleRuleChangeEvent,
"StyleRuleRemoved",
mRule,
aStyleRule);
}
#undef DO_STYLESHEET_NOTIFICATION

View File

@ -14,12 +14,6 @@
class nsIContent;
class nsIDocument;
namespace mozilla {
namespace css {
class Rule;
} // namespace css
} // namespace mozilla
#define NS_IDOCUMENT_OBSERVER_IID \
{ 0x71041fa3, 0x6dd7, 0x4cde, \
{ 0xbb, 0x76, 0xae, 0xcc, 0x69, 0xe1, 0x75, 0x78 } }
@ -126,45 +120,6 @@ public:
* @param aStyleSheet the StyleSheet that has changed state
*/
virtual void StyleSheetApplicableStateChanged(mozilla::StyleSheet* aStyleSheet) = 0;
/**
* A StyleRule has just been modified within a style sheet.
* This method is called automatically when the rule gets
* modified. The style sheet passes this notification to
* the document. The notification is passed on to all of
* the document observers.
*
* @param aStyleSheet the StyleSheet that contians the rule
* @param aStyleRule the changed rule
*/
virtual void StyleRuleChanged(mozilla::StyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
/**
* A StyleRule has just been added to a style sheet.
* This method is called automatically when the rule gets
* added to the sheet. The style sheet passes this
* notification to the document. The notification is passed on
* to all of the document observers.
*
* @param aStyleSheet the StyleSheet that has been modified
* @param aStyleRule the added rule
*/
virtual void StyleRuleAdded(mozilla::StyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
/**
* A StyleRule has just been removed from a style sheet.
* This method is called automatically when the rule gets
* removed from the sheet. The style sheet passes this
* notification to the document. The notification is passed on
* to all of the document observers.
*
* @param aStyleSheet the StyleSheet that has been modified
* @param aStyleRule the removed rule
*/
virtual void StyleRuleRemoved(mozilla::StyleSheet* aStyleSheet,
mozilla::css::Rule* aStyleRule) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
@ -203,18 +158,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
virtual void StyleSheetApplicableStateChanged( \
mozilla::StyleSheet* aStyleSheet) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \
virtual void StyleRuleChanged(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \
virtual void StyleRuleAdded(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED \
virtual void StyleRuleRemoved(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) override;
#define NS_DECL_NSIDOCUMENTOBSERVER \
NS_DECL_NSIDOCUMENTOBSERVER_BEGINUPDATE \
NS_DECL_NSIDOCUMENTOBSERVER_ENDUPDATE \
@ -225,9 +168,6 @@ NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentObserver, NS_IDOCUMENT_OBSERVER_IID)
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED \
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED \
NS_DECL_NSIMUTATIONOBSERVER
@ -284,20 +224,5 @@ void \
_class::StyleSheetApplicableStateChanged(mozilla::StyleSheet* aStyleSheet)\
{ \
} \
void \
_class::StyleRuleChanged(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \
} \
void \
_class::StyleRuleAdded(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \
} \
void \
_class::StyleRuleRemoved(mozilla::StyleSheet* aStyleSheet, \
mozilla::css::Rule* aStyleRule) \
{ \
}
#endif /* nsIDocumentObserver_h___ */

View File

@ -4653,24 +4653,6 @@ PresShell::StyleSheetApplicableStateChanged(StyleSheet* aStyleSheet)
}
}
void
PresShell::StyleRuleChanged(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
{
RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleChanged);
}
void
PresShell::StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
{
RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleAdded);
}
void
PresShell::StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule)
{
RecordStyleSheetChange(aStyleSheet, StyleSheet::ChangeType::RuleRemoved);
}
nsresult
PresShell::RenderDocument(const nsRect& aRect, uint32_t aFlags,
nscolor aBackgroundColor,

View File

@ -299,9 +299,6 @@ public:
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETADDED
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETREMOVED
NS_DECL_NSIDOCUMENTOBSERVER_STYLESHEETAPPLICABLESTATECHANGED
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULECHANGED
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEADDED
NS_DECL_NSIDOCUMENTOBSERVER_STYLERULEREMOVED
// nsIMutationObserver
NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED

View File

@ -27,8 +27,6 @@ ServoStyleRuleMap::~ServoStyleRuleMap()
{
}
NS_IMPL_ISUPPORTS(ServoStyleRuleMap, nsIDocumentObserver, nsICSSLoaderObserver)
void
ServoStyleRuleMap::EnsureTable()
{
@ -38,23 +36,21 @@ ServoStyleRuleMap::EnsureTable()
mStyleSet->EnumerateStyleSheetArrays(
[this](const nsTArray<RefPtr<ServoStyleSheet>>& aArray) {
for (auto& sheet : aArray) {
FillTableFromStyleSheet(sheet);
FillTableFromStyleSheet(*sheet);
}
});
}
void
ServoStyleRuleMap::StyleSheetAdded(StyleSheet* aStyleSheet,
bool aDocumentSheet)
ServoStyleRuleMap::SheetAdded(ServoStyleSheet& aStyleSheet)
{
if (!IsEmpty()) {
FillTableFromStyleSheet(aStyleSheet->AsServo());
FillTableFromStyleSheet(aStyleSheet);
}
}
void
ServoStyleRuleMap::StyleSheetRemoved(StyleSheet* aStyleSheet,
bool aDocumentSheet)
ServoStyleRuleMap::SheetRemoved(ServoStyleSheet& aStyleSheet)
{
// Invalidate all data inside. This isn't strictly necessary since
// we should always get update from document before new queries come.
@ -66,18 +62,7 @@ ServoStyleRuleMap::StyleSheetRemoved(StyleSheet* aStyleSheet,
}
void
ServoStyleRuleMap::StyleSheetApplicableStateChanged(StyleSheet* aStyleSheet)
{
// We don't care if the stylesheet is disabled. Not removing no longer
// applicable stylesheets wouldn't make anything wrong.
if (!IsEmpty() && aStyleSheet->IsApplicable()) {
FillTableFromStyleSheet(aStyleSheet->AsServo());
}
}
void
ServoStyleRuleMap::StyleRuleAdded(StyleSheet* aStyleSheet,
css::Rule* aStyleRule)
ServoStyleRuleMap::RuleAdded(ServoStyleSheet& aStyleSheet, css::Rule& aStyleRule)
{
if (!IsEmpty()) {
FillTableFromRule(aStyleRule);
@ -85,17 +70,17 @@ ServoStyleRuleMap::StyleRuleAdded(StyleSheet* aStyleSheet,
}
void
ServoStyleRuleMap::StyleRuleRemoved(StyleSheet* aStyleSheet,
css::Rule* aStyleRule)
ServoStyleRuleMap::RuleRemoved(ServoStyleSheet& aStyleSheet,
css::Rule& aStyleRule)
{
if (IsEmpty()) {
return;
}
switch (aStyleRule->Type()) {
switch (aStyleRule.Type()) {
case nsIDOMCSSRule::STYLE_RULE: {
auto rule = static_cast<ServoStyleRule*>(aStyleRule);
mTable.Remove(rule->Raw());
auto& rule = static_cast<ServoStyleRule&>(aStyleRule);
mTable.Remove(rule.Raw());
break;
}
case nsIDOMCSSRule::IMPORT_RULE:
@ -119,18 +104,6 @@ ServoStyleRuleMap::StyleRuleRemoved(StyleSheet* aStyleSheet,
}
}
NS_IMETHODIMP
ServoStyleRuleMap::StyleSheetLoaded(StyleSheet* aSheet,
bool aWasAlternate,
nsresult aStatus)
{
MOZ_ASSERT(aSheet->IsServo());
if (!IsEmpty()) {
FillTableFromStyleSheet(aSheet->AsServo());
}
return NS_OK;
}
size_t
ServoStyleRuleMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
@ -140,43 +113,44 @@ ServoStyleRuleMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
}
void
ServoStyleRuleMap::FillTableFromRule(css::Rule* aRule)
ServoStyleRuleMap::FillTableFromRule(css::Rule& aRule)
{
switch (aRule->Type()) {
switch (aRule.Type()) {
case nsIDOMCSSRule::STYLE_RULE: {
auto rule = static_cast<ServoStyleRule*>(aRule);
mTable.Put(rule->Raw(), rule);
auto& rule = static_cast<ServoStyleRule&>(aRule);
mTable.Put(rule.Raw(), &rule);
break;
}
case nsIDOMCSSRule::MEDIA_RULE:
case nsIDOMCSSRule::SUPPORTS_RULE:
case nsIDOMCSSRule::DOCUMENT_RULE: {
auto rule = static_cast<css::GroupRule*>(aRule);
auto ruleList = static_cast<ServoCSSRuleList*>(rule->CssRules());
FillTableFromRuleList(ruleList);
auto& rule = static_cast<css::GroupRule&>(aRule);
auto ruleList = static_cast<ServoCSSRuleList*>(rule.CssRules());
FillTableFromRuleList(*ruleList);
break;
}
case nsIDOMCSSRule::IMPORT_RULE: {
auto rule = static_cast<ServoImportRule*>(aRule);
FillTableFromStyleSheet(rule->GetStyleSheet()->AsServo());
auto& rule = static_cast<ServoImportRule&>(aRule);
MOZ_ASSERT(aRule.GetStyleSheet());
FillTableFromStyleSheet(*rule.GetStyleSheet()->AsServo());
break;
}
}
}
void
ServoStyleRuleMap::FillTableFromRuleList(ServoCSSRuleList* aRuleList)
ServoStyleRuleMap::FillTableFromRuleList(ServoCSSRuleList& aRuleList)
{
for (uint32_t i : IntegerRange(aRuleList->Length())) {
FillTableFromRule(aRuleList->GetRule(i));
for (uint32_t i : IntegerRange(aRuleList.Length())) {
FillTableFromRule(*aRuleList.GetRule(i));
}
}
void
ServoStyleRuleMap::FillTableFromStyleSheet(ServoStyleSheet* aSheet)
ServoStyleRuleMap::FillTableFromStyleSheet(ServoStyleSheet& aSheet)
{
if (aSheet->IsComplete()) {
FillTableFromRuleList(aSheet->GetCssRulesInternal());
if (aSheet.IsComplete()) {
FillTableFromRuleList(*aSheet.GetCssRulesInternal());
}
}

View File

@ -10,8 +10,6 @@
#include "mozilla/ServoStyleRule.h"
#include "nsDataHashtable.h"
#include "nsICSSLoaderObserver.h"
#include "nsStubDocumentObserver.h"
struct RawServoStyleRule;
@ -22,12 +20,9 @@ namespace css {
class Rule;
} // namespace css
class ServoStyleRuleMap final : public nsStubDocumentObserver
, public nsICSSLoaderObserver
class ServoStyleRuleMap
{
public:
NS_DECL_ISUPPORTS
explicit ServoStyleRuleMap(ServoStyleSet* aStyleSet);
void EnsureTable();
@ -35,30 +30,25 @@ public:
return mTable.Get(aRawRule);
}
// nsIDocumentObserver methods
void StyleSheetAdded(StyleSheet* aStyleSheet, bool aDocumentSheet) final;
void StyleSheetRemoved(StyleSheet* aStyleSheet, bool aDocumentSheet) final;
void StyleSheetApplicableStateChanged(StyleSheet* aStyleSheet) final;
void StyleRuleAdded(StyleSheet* aStyleSheet, css::Rule* aStyleRule) final;
void StyleRuleRemoved(StyleSheet* aStyleSheet, css::Rule* aStyleRule) final;
void SheetAdded(ServoStyleSheet& aStyleSheet);
void SheetRemoved(ServoStyleSheet& aStyleSheet);
// nsICSSLoaderObserver
NS_IMETHOD StyleSheetLoaded(StyleSheet* aSheet,
bool aWasAlternate, nsresult aStatus) final;
void RuleAdded(ServoStyleSheet& aStyleSheet, css::Rule&);
void RuleRemoved(ServoStyleSheet& aStyleSheet, css::Rule& aStyleRule);
size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const;
private:
~ServoStyleRuleMap();
private:
// Since we would never have a document which contains no style rule,
// we use IsEmpty as an indication whether we need to walk through
// all stylesheets to fill the table.
bool IsEmpty() const { return mTable.Count() == 0; }
void FillTableFromRule(css::Rule* aRule);
void FillTableFromRuleList(ServoCSSRuleList* aRuleList);
void FillTableFromStyleSheet(ServoStyleSheet* aSheet);
void FillTableFromRule(css::Rule& aRule);
void FillTableFromRuleList(ServoCSSRuleList& aRuleList);
void FillTableFromStyleSheet(ServoStyleSheet& aSheet);
typedef nsDataHashtable<nsPtrHashKey<const RawServoStyleRule>,
WeakPtr<ServoStyleRule>> Hashtable;

View File

@ -766,9 +766,8 @@ CSSStyleSheet::InsertRuleInternal(const nsAString& aRule,
// We don't notify immediately for @import rules, but rather when
// the sheet the rule is importing is loaded (see StyleSheetLoaded)
if ((type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) &&
mDocument) {
mDocument->StyleRuleAdded(this, rule);
if (type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) {
RuleAdded(*rule);
}
return aIndex;
@ -795,11 +794,7 @@ CSSStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
if (rule) {
Inner()->mOrderedRules.RemoveObjectAt(aIndex);
rule->SetStyleSheet(nullptr);
DidDirty();
if (mDocument) {
mDocument->StyleRuleRemoved(this, rule);
}
RuleRemoved(*rule);
}
}
@ -865,12 +860,9 @@ CSSStyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
NS_ASSERTION(this == sheet->GetParentSheet(),
"We are being notified of a sheet load for a sheet that is not our child!");
if (mDocument && NS_SUCCEEDED(aStatus)) {
if (NS_SUCCEEDED(aStatus)) {
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
// XXXldb @import rules shouldn't even implement nsIStyleRule (but
// they do)!
mDocument->StyleRuleAdded(this, sheet->GetOwnerRule());
RuleAdded(*sheet->GetOwnerRule());
}
return NS_OK;
@ -917,9 +909,7 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
reusableSheets.AddReusableSheet(cssSheet);
}
}
if (mDocument) {
mDocument->StyleRuleRemoved(this, rule);
}
RuleRemoved(*rule);
}
// nuke child sheets list and current namespace map
@ -949,15 +939,13 @@ CSSStyleSheet::ReparseSheet(const nsAString& aInput)
NS_ENSURE_SUCCESS(rv, rv);
// notify document of all new rules
if (mDocument) {
for (int32_t index = 0; index < Inner()->mOrderedRules.Count(); ++index) {
RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(index);
if (rule->GetType() == css::Rule::IMPORT_RULE &&
RuleHasPendingChildSheet(rule)) {
continue; // notify when loaded (see StyleSheetLoaded)
}
mDocument->StyleRuleAdded(this, rule);
for (int32_t index = 0; index < Inner()->mOrderedRules.Count(); ++index) {
RefPtr<css::Rule> rule = Inner()->mOrderedRules.ObjectAt(index);
if (rule->GetType() == css::Rule::IMPORT_RULE &&
RuleHasPendingChildSheet(rule)) {
continue; // notify when loaded (see StyleSheetLoaded)
}
RuleAdded(*rule);
}
return NS_OK;
}

View File

@ -120,12 +120,6 @@ public:
nsIDocument* aCloneDocument,
nsINode* aCloneOwningNode) const final;
void SetModifiedByChildRule() {
NS_ASSERTION(mDirty,
"sheet must be marked dirty before handing out child rules");
DidDirty();
}
nsresult AddRuleProcessor(nsCSSRuleProcessor* aProcessor);
nsresult DropRuleProcessor(nsCSSRuleProcessor* aProcessor);

View File

@ -304,7 +304,7 @@ GroupRule::AppendStyleRule(Rule* aRule)
aRule->SetStyleSheet(sheet);
aRule->SetParentRule(this);
if (sheet) {
sheet->AsGecko()->SetModifiedByChildRule();
sheet->RuleChanged(this);
}
}

View File

@ -62,12 +62,12 @@ MediaList::DoMediaChange(Func aCallback)
}
if (mStyleSheet) {
mStyleSheet->DidDirty();
}
/* XXXldb Pass something meaningful? */
if (doc) {
doc->StyleRuleChanged(mStyleSheet, nullptr);
// FIXME(emilio): We should discern between "owned by a rule" (as in @media)
// and "owned by a sheet" (as in <style media>), and then pass something
// meaningful here.
mStyleSheet->RuleChanged(nullptr);
}
return rv;
}

View File

@ -174,10 +174,7 @@ ServoKeyframeRule::UpdateRule(Func aCallback)
aCallback();
if (StyleSheet* sheet = GetStyleSheet()) {
// FIXME sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}

View File

@ -252,10 +252,7 @@ ServoKeyframesRule::UpdateRule(Func aCallback)
aCallback();
if (StyleSheet* sheet = GetStyleSheet()) {
// FIXME sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}

View File

@ -81,9 +81,7 @@ ServoStyleRuleDeclaration::SetCSSDeclaration(DeclarationBlock* aDecl)
mDecls = decls.forget();
mDecls->SetOwningRule(rule);
}
if (doc) {
doc->StyleRuleChanged(sheet, rule);
}
sheet->RuleChanged(rule);
}
return NS_OK;
}

View File

@ -171,19 +171,6 @@ ServoStyleSet::Init(nsPresContext* aPresContext, nsBindingManager* aBindingManag
SetStylistStyleSheetsDirty();
}
void
ServoStyleSet::BeginShutdown()
{
nsIDocument* doc = mPresContext->Document();
// Remove the style rule map from document's observer and drop it.
if (mStyleRuleMap) {
doc->RemoveObserver(mStyleRuleMap);
doc->CSSLoader()->RemoveObserver(mStyleRuleMap);
mStyleRuleMap = nullptr;
}
}
void
ServoStyleSet::Shutdown()
{
@ -191,6 +178,7 @@ ServoStyleSet::Shutdown()
// starts going away.
ClearNonInheritingStyleContexts();
mRawSet = nullptr;
mStyleRuleMap = nullptr;
}
void
@ -685,6 +673,10 @@ ServoStyleSet::AppendStyleSheet(SheetType aType,
SetStylistStyleSheetsDirty();
}
if (mStyleRuleMap) {
mStyleRuleMap->SheetAdded(*aSheet);
}
return NS_OK;
}
@ -709,6 +701,10 @@ ServoStyleSet::PrependStyleSheet(SheetType aType,
SetStylistStyleSheetsDirty();
}
if (mStyleRuleMap) {
mStyleRuleMap->SheetAdded(*aSheet);
}
return NS_OK;
}
@ -726,6 +722,10 @@ ServoStyleSet::RemoveStyleSheet(SheetType aType,
SetStylistStyleSheetsDirty();
}
if (mStyleRuleMap) {
mStyleRuleMap->SheetRemoved(*aSheet);
}
return NS_OK;
}
@ -758,6 +758,9 @@ ServoStyleSet::ReplaceSheets(SheetType aType,
}
}
// Just don't bother calling SheetRemoved / SheetAdded, and recreate the rule
// map when needed.
mStyleRuleMap = nullptr;
return NS_OK;
}
@ -785,6 +788,10 @@ ServoStyleSet::InsertStyleSheetBefore(SheetType aType,
SetStylistStyleSheetsDirty();
}
if (mStyleRuleMap) {
mStyleRuleMap->SheetAdded(*aNewSheet);
}
return NS_OK;
}
@ -851,6 +858,10 @@ ServoStyleSet::AddDocStyleSheet(ServoStyleSheet* aSheet,
}
}
if (mStyleRuleMap) {
mStyleRuleMap->SheetAdded(*aSheet);
}
return NS_OK;
}
@ -1026,24 +1037,32 @@ ServoStyleSet::MarkOriginsDirty(OriginFlags aChangedOrigins)
}
void
ServoStyleSet::RecordStyleSheetChange(
ServoStyleSheet* aSheet,
StyleSheet::ChangeType aChangeType)
ServoStyleSet::RuleAdded(ServoStyleSheet& aSheet, css::Rule& aRule)
{
switch (aChangeType) {
case StyleSheet::ChangeType::RuleAdded:
case StyleSheet::ChangeType::RuleRemoved:
case StyleSheet::ChangeType::RuleChanged:
case StyleSheet::ChangeType::ReparsedFromInspector:
// FIXME(emilio): We can presumably do better in a bunch of these.
return MarkOriginsDirty(aSheet->GetOrigin());
case StyleSheet::ChangeType::ApplicableStateChanged:
case StyleSheet::ChangeType::Added:
case StyleSheet::ChangeType::Removed:
// Do nothing, we've already recorded the change in the
// Append/Remove/Replace methods, etc, and will act consequently.
return;
if (mStyleRuleMap) {
mStyleRuleMap->RuleAdded(aSheet, aRule);
}
// FIXME(emilio): Could be more granular based on aRule.
MarkOriginsDirty(aSheet.GetOrigin());
}
void
ServoStyleSet::RuleRemoved(ServoStyleSheet& aSheet, css::Rule& aRule)
{
if (mStyleRuleMap) {
mStyleRuleMap->RuleRemoved(aSheet, aRule);
}
// FIXME(emilio): Could be more granular based on aRule.
MarkOriginsDirty(aSheet.GetOrigin());
}
void
ServoStyleSet::RuleChanged(ServoStyleSheet& aSheet, css::Rule* aRule)
{
// FIXME(emilio): Could be more granular based on aRule.
MarkOriginsDirty(aSheet.GetOrigin());
}
#ifdef DEBUG
@ -1431,14 +1450,9 @@ ServoStyleRuleMap*
ServoStyleSet::StyleRuleMap()
{
if (!mStyleRuleMap) {
mStyleRuleMap = new ServoStyleRuleMap(this);
if (mPresContext) {
nsIDocument* doc = mPresContext->Document();
doc->AddObserver(mStyleRuleMap);
doc->CSSLoader()->AddObserver(mStyleRuleMap);
}
mStyleRuleMap = MakeUnique<ServoStyleRuleMap>(this);
}
return mStyleRuleMap;
return mStyleRuleMap.get();
}
bool

View File

@ -133,12 +133,20 @@ public:
const nsTArray<RefPtr<ServoStyleSheet>>& aNewSheets);
void Init(nsPresContext* aPresContext, nsBindingManager* aBindingManager);
void BeginShutdown();
void BeginShutdown() {}
void Shutdown();
void RecordStyleSheetChange(mozilla::ServoStyleSheet*, StyleSheet::ChangeType);
// Called when a rules in a stylesheet in this set, or a child sheet of that,
// are mutated from CSSOM.
void RuleAdded(ServoStyleSheet&, css::Rule&);
void RuleRemoved(ServoStyleSheet&, css::Rule&);
void RuleChanged(ServoStyleSheet& aSheet, css::Rule* aRule);
void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot) {
// All the relevant changes are handled in RuleAdded / RuleRemoved / etc, and
// the relevant AppendSheet / RemoveSheet...
void RecordStyleSheetChange(ServoStyleSheet*, StyleSheet::ChangeType) {}
void RecordShadowStyleChange(dom::ShadowRoot* aShadowRoot) {
// FIXME(emilio): When we properly support shadow dom we'll need to do
// better.
MarkOriginsDirty(OriginFlags::All);
@ -286,7 +294,7 @@ public:
// check whether there is ::before/::after style for an element
already_AddRefed<ServoStyleContext>
ProbePseudoElementStyle(dom::Element* aOriginatingElement,
mozilla::CSSPseudoElementType aType,
CSSPseudoElementType aType,
ServoStyleContext* aParentContext);
/**
@ -442,7 +450,6 @@ public:
// Called by StyleSheet::EnsureUniqueInner to let us know it cloned
// its inner.
void SetNeedsRestyleAfterEnsureUniqueInner() {
MOZ_ASSERT(!IsForXBL(), "Should not be cloning things for XBL stylesheet");
mNeedsRestyleAfterEnsureUniqueInner = true;
}
@ -631,7 +638,7 @@ private:
// Map from raw Servo style rule to Gecko's wrapper object.
// Constructed lazily when requested by devtools.
RefPtr<ServoStyleRuleMap> mStyleRuleMap;
UniquePtr<ServoStyleRuleMap> mStyleRuleMap;
// This can be null if we are used to hold XBL style sheets.
RefPtr<nsBindingManager> mBindingManager;

View File

@ -281,9 +281,8 @@ ServoStyleSheet::ReparseSheet(const nsAString& aInput)
}
}
// Notify mDocument that all our rules are removed.
if (mDocument) {
// Get the rule list.
// Notify to the stylesets about the old rules going away.
{
ServoCSSRuleList* ruleList = GetCssRulesInternal();
MOZ_ASSERT(ruleList);
@ -295,13 +294,7 @@ ServoStyleSheet::ReparseSheet(const nsAString& aInput)
RuleHasPendingChildSheet(rule)) {
continue; // notify when loaded (see StyleSheetLoaded)
}
mDocument->StyleRuleRemoved(this, rule);
// Document observers could possibly detach document from this sheet.
if (!mDocument) {
// If detached, don't process any more rules.
break;
}
RuleRemoved(*rule);
}
}
@ -318,8 +311,8 @@ ServoStyleSheet::ReparseSheet(const nsAString& aInput)
DidDirty();
NS_ENSURE_SUCCESS(rv, rv);
// Notify mDocument that all our new rules are added.
if (mDocument) {
// Notify the stylesets about the new rules.
{
// Get the rule list (which will need to be regenerated after ParseSheet).
ServoCSSRuleList* ruleList = GetCssRulesInternal();
MOZ_ASSERT(ruleList);
@ -333,29 +326,10 @@ ServoStyleSheet::ReparseSheet(const nsAString& aInput)
continue; // notify when loaded (see StyleSheetLoaded)
}
mDocument->StyleRuleAdded(this, rule);
// Document observers could possibly detach document from this sheet.
if (!mDocument) {
// If detached, don't process any more rules.
break;
}
RuleAdded(*rule);
}
}
// FIXME(emilio): This is kind-of a hack for bug 1420713. As you may notice,
// there's nothing that triggers a style flush or anything similar (neither
// here or in the relevant Gecko path inside DidDirty).
//
// The tl;dr is: if we want to make sure scripted changes to sheets not
// associated with any document get properly reflected, we need to rejigger a
// fair amount of stuff. I'm probably doing that work as part of the shadow
// DOM stuff.
for (StyleSetHandle handle : mStyleSets) {
handle->AsServo()->RecordStyleSheetChange(
this, StyleSheet::ChangeType::ReparsedFromInspector);
}
return NS_OK;
}
@ -369,15 +343,15 @@ ServoStyleSheet::StyleSheetLoaded(StyleSheet* aSheet,
"why we were called back with a CSSStyleSheet?");
ServoStyleSheet* sheet = aSheet->AsServo();
if (sheet->GetParentSheet() == nullptr) {
if (!sheet->GetParentSheet()) {
return NS_OK; // ignore if sheet has been detached already
}
NS_ASSERTION(this == sheet->GetParentSheet(),
"We are being notified of a sheet load for a sheet that is not our child!");
if (mDocument && NS_SUCCEEDED(aStatus)) {
if (NS_SUCCEEDED(aStatus)) {
mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true);
mDocument->StyleRuleAdded(this, sheet->GetOwnerRule());
RuleAdded(*sheet->GetOwnerRule());
}
return NS_OK;
@ -432,14 +406,15 @@ ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
if (aRv.Failed()) {
return 0;
}
if (mDocument) {
if (mRuleList->GetDOMCSSRuleType(aIndex) != nsIDOMCSSRule::IMPORT_RULE ||
!RuleHasPendingChildSheet(mRuleList->GetRule(aIndex))) {
// XXX We may not want to get the rule when stylesheet change event
// is not enabled.
mDocument->StyleRuleAdded(this, mRuleList->GetRule(aIndex));
}
// XXX We may not want to get the rule when stylesheet change event
// is not enabled.
css::Rule* rule = mRuleList->GetRule(aIndex);
if (rule->GetType() != css::Rule::IMPORT_RULE ||
!RuleHasPendingChildSheet(rule)) {
RuleAdded(*rule);
}
return aIndex;
}
@ -461,8 +436,8 @@ ServoStyleSheet::DeleteRuleInternal(uint32_t aIndex, ErrorResult& aRv)
aRv = mRuleList->DeleteRule(aIndex);
MOZ_ASSERT(!aRv.ErrorCodeIs(NS_ERROR_DOM_INDEX_SIZE_ERR),
"IndexSizeError should have been handled earlier");
if (!aRv.Failed() && mDocument) {
mDocument->StyleRuleRemoved(this, rule);
if (!aRv.Failed()) {
RuleRemoved(*rule);
}
}

View File

@ -1162,11 +1162,7 @@ DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
mRule->SetDeclaration(aDecl->AsGecko());
if (sheet) {
sheet->DidDirty();
}
if (doc) {
doc->StyleRuleChanged(sheet, mRule);
sheet->RuleChanged(mRule);
}
return NS_OK;
}

View File

@ -18,14 +18,6 @@
#include "nsCSSPseudoElements.h"
#include "nsTArray.h"
namespace mozilla {
class CSSStyleSheet;
class ServoStyleSet;
namespace dom {
class Element;
class ShadowRoot;
} // namespace dom
} // namespace mozilla
class nsBindingManager;
class nsCSSCounterStyleRule;
struct nsFontFaceRuleContainer;
@ -41,6 +33,16 @@ struct TreeMatchContext;
namespace mozilla {
class CSSStyleSheet;
class ServoStyleSet;
namespace dom {
class Element;
class ShadowRoot;
} // namespace dom
namespace css {
class Rule;
} // namespace css
#define SERVO_BIT 0x1
/**
@ -166,6 +168,12 @@ public:
inline void AppendAllXBLStyleSheets(nsTArray<StyleSheet*>& aArray) const;
inline nsresult RemoveDocStyleSheet(StyleSheet* aSheet);
inline nsresult AddDocStyleSheet(StyleSheet* aSheet, nsIDocument* aDocument);
inline void RuleRemoved(StyleSheet&, css::Rule&);
inline void RuleAdded(StyleSheet&, css::Rule&);
inline void RuleChanged(StyleSheet&, css::Rule*);
// TODO(emilio): Remove in favor of Rule* methods.
inline void RecordStyleSheetChange(StyleSheet* aSheet, StyleSheet::ChangeType);
inline void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);
inline bool StyleSheetsHaveChanged() const;

View File

@ -249,6 +249,27 @@ StyleSetHandle::Ptr::AddDocStyleSheet(StyleSheet* aSheet,
(aSheet->AsServo(), aDocument));
}
void
StyleSetHandle::Ptr::RuleRemoved(StyleSheet& aSheet, css::Rule& aRule)
{
FORWARD_CONCRETE(RuleRemoved, (*aSheet.AsGecko(), aRule),
(*aSheet.AsServo(), aRule));
}
void
StyleSetHandle::Ptr::RuleAdded(StyleSheet& aSheet, css::Rule& aRule)
{
FORWARD_CONCRETE(RuleAdded, (*aSheet.AsGecko(), aRule),
(*aSheet.AsServo(), aRule));
}
void
StyleSetHandle::Ptr::RuleChanged(StyleSheet& aSheet, css::Rule* aRule)
{
FORWARD_CONCRETE(RuleChanged, (*aSheet.AsGecko(), aRule),
(*aSheet.AsServo(), aRule));
}
void
StyleSetHandle::Ptr::RecordStyleSheetChange(StyleSheet* aSheet,
StyleSheet::ChangeType aChangeType)

View File

@ -454,12 +454,18 @@ StyleSheet::EnsureUniqueInner()
// already unique
return;
}
// If this stylesheet is for XBL with Servo, don't bother cloning
// it, as it may break ServoStyleRuleMap. XBL stylesheets are not
// supposed to change anyway.
//
// The mDocument check is used as a fast reject path because no
// XBL stylesheets would have associated document, but in normal
// cases, content stylesheets should usually have one.
//
// FIXME(emilio): Shadow DOM definitely modifies stylesheets! Right now all of
// them are unique anyway because we don't support <link>, but that needs to
// change.
if (!mDocument && IsServo() &&
mStyleSets.Length() == 1 &&
mStyleSets[0]->AsServo()->IsForXBL()) {
@ -603,14 +609,51 @@ StyleSheet::DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex)
NS_ENSURE_SUCCESS(result, result);
rule->SetStyleSheet(nullptr);
RuleRemoved(*rule);
return NS_OK;
}
#define NOTIFY_STYLE_SETS(function_, args_) do { \
StyleSheet* current = this; \
do { \
for (StyleSetHandle handle : current->mStyleSets) { \
handle->function_ args_; \
} \
current = current->mParent; \
} while (current); \
} while (0)
void
StyleSheet::RuleAdded(css::Rule& aRule)
{
DidDirty();
NOTIFY_STYLE_SETS(RuleAdded, (*this, aRule));
if (mDocument) {
mDocument->StyleRuleRemoved(this, rule);
mDocument->StyleRuleAdded(this, &aRule);
}
}
return NS_OK;
void
StyleSheet::RuleRemoved(css::Rule& aRule)
{
DidDirty();
NOTIFY_STYLE_SETS(RuleRemoved, (*this, aRule));
if (mDocument) {
mDocument->StyleRuleRemoved(this, &aRule);
}
}
void
StyleSheet::RuleChanged(css::Rule* aRule)
{
DidDirty();
NOTIFY_STYLE_SETS(RuleChanged, (*this, aRule));
if (mDocument) {
mDocument->StyleRuleChanged(this, aRule);
}
}
nsresult
@ -636,12 +679,7 @@ StyleSheet::InsertRuleIntoGroup(const nsAString& aRule,
result = AsServo()->InsertRuleIntoGroupInternal(aRule, aGroup, aIndex);
}
NS_ENSURE_SUCCESS(result, result);
DidDirty();
if (mDocument) {
mDocument->StyleRuleAdded(this, aGroup->GetStyleRuleAt(aIndex));
}
RuleAdded(*aGroup->GetStyleRuleAt(aIndex));
return NS_OK;
}

View File

@ -77,7 +77,6 @@ public:
RuleAdded,
RuleRemoved,
RuleChanged,
ReparsedFromInspector,
};
void SetOwningNode(nsINode* aOwningNode)
@ -262,6 +261,12 @@ public:
void WillDirty();
virtual void DidDirty() {}
// Called when a rule changes from CSSOM.
//
// FIXME(emilio): This shouldn't allow null, but MediaList doesn't know about
// it's owning media rule, plus it's used for the stylesheet media itself.
void RuleChanged(css::Rule*);
void AddStyleSet(const StyleSetHandle& aStyleSet);
void DropStyleSet(const StyleSetHandle& aStyleSet);
@ -293,6 +298,15 @@ private:
ErrorResult& aRv);
protected:
// Called when a rule is removed from the sheet from CSSOM.
void RuleAdded(css::Rule&);
// Called when a rule is added to the sheet from CSSOM.
void RuleRemoved(css::Rule&);
// Called from SetEnabled when the enabled state changed.
void EnabledStateChanged();
struct ChildSheetListBuilder {
RefPtr<StyleSheet>* sheetSlot;
StyleSheet* parent;
@ -317,9 +331,6 @@ protected:
// Drop our reference to mMedia
void DropMedia();
// Called from SetEnabled when the enabled state changed.
void EnabledStateChanged();
// Unlink our inner, if needed, for cycle collection
virtual void UnlinkInner();
// Traverse our inner, if needed, for cycle collection

View File

@ -140,12 +140,7 @@ nsCSSCounterStyleRule::SetName(const nsAString& aName)
mName = name;
if (StyleSheet* sheet = GetStyleSheet()) {
if (sheet->IsGecko()) {
sheet->AsGecko()->SetModifiedByChildRule();
}
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}
return NS_OK;
@ -187,12 +182,7 @@ nsCSSCounterStyleRule::SetDesc(nsCSSCounterDesc aDescID, const nsCSSValue& aValu
mGeneration++;
if (StyleSheet* sheet = GetStyleSheet()) {
if (sheet->IsGecko()) {
sheet->AsGecko()->SetModifiedByChildRule();
}
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}

View File

@ -1151,10 +1151,7 @@ nsCSSKeyframeRule::SetKeyText(const nsAString& aKeyText)
newSelectors.SwapElements(mKeys);
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
return NS_OK;
@ -1185,10 +1182,7 @@ nsCSSKeyframeRule::ChangeDeclaration(css::Declaration* aDeclaration)
}
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}
@ -1288,10 +1282,7 @@ nsCSSKeyframesRule::SetName(const nsAString& aName)
mName = NS_Atomize(aName);
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
return NS_OK;
@ -1315,10 +1306,7 @@ nsCSSKeyframesRule::AppendRule(const nsAString& aRule)
AppendStyleRule(rule);
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}
@ -1362,11 +1350,7 @@ nsCSSKeyframesRule::DeleteRule(const nsAString& aKey)
DeleteStyleRuleAt(index);
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
if (doc) {
doc->StyleRuleChanged(sheet, this);
}
sheet->RuleChanged(this);
}
}
return NS_OK;
@ -1573,7 +1557,7 @@ nsCSSPageRule::ChangeDeclaration(css::Declaration* aDeclaration)
}
if (StyleSheet* sheet = GetStyleSheet()) {
sheet->AsGecko()->SetModifiedByChildRule();
sheet->RuleChanged(this);
}
}

View File

@ -2354,8 +2354,7 @@ nsStyleSet::Shutdown()
}
void
nsStyleSet::RecordStyleSheetChange(CSSStyleSheet* aStyleSheet,
StyleSheet::ChangeType)
nsStyleSet::SheetChanged(CSSStyleSheet& aStyleSheet)
{
MOZ_ASSERT(mBatching != 0, "Should be in an update");
@ -2363,7 +2362,7 @@ nsStyleSet::RecordStyleSheetChange(CSSStyleSheet* aStyleSheet,
return;
}
if (Element* scopeElement = aStyleSheet->GetScopeElement()) {
if (Element* scopeElement = aStyleSheet.GetScopeElement()) {
mChangedScopeStyleRoots.AppendElement(scopeElement);
return;
}

View File

@ -341,9 +341,29 @@ class nsStyleSet final
// Free all of the data associated with this style set.
void Shutdown();
void RuleAdded(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&)
{
SheetChanged(aSheet);
}
void RuleRemoved(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule&)
{
SheetChanged(aSheet);
}
void RuleChanged(mozilla::CSSStyleSheet& aSheet, mozilla::css::Rule*)
{
SheetChanged(aSheet);
}
// Notes that a style sheet has changed.
void RecordStyleSheetChange(mozilla::CSSStyleSheet* aStyleSheet,
mozilla::StyleSheet::ChangeType);
void RecordStyleSheetChange(mozilla::CSSStyleSheet* aSheet,
mozilla::StyleSheet::ChangeType)
{
SheetChanged(*aSheet);
}
void SheetChanged(mozilla::CSSStyleSheet&);
// Notes that style sheets have changed in a shadow root.
void RecordShadowStyleChange(mozilla::dom::ShadowRoot* aShadowRoot);