Bug 1315601 part 9 - Split Gecko-specific GroupRule logic into a separate struct. r=heycam

MozReview-Commit-ID: 7CkGO2KgJN3

--HG--
extra : rebase_source : 04cb9ea11e01a4f57497b4edf148adbd4fc1311b
This commit is contained in:
Xidorn Quan 2017-03-09 22:02:26 +11:00
Родитель 0e11635123
Коммит 5155993e83
3 изменённых файлов: 202 добавлений и 110 удалений

Просмотреть файл

@ -18,6 +18,12 @@ using namespace mozilla::dom;
namespace mozilla { namespace mozilla {
namespace css { namespace css {
// TODO The other branch should be changed to Servo rule.
#define CALL_INNER(inner_, call_) \
((inner_).is<GeckoGroupRuleRules>() \
? (inner_).as<GeckoGroupRuleRules>().call_ \
: (inner_).as<GeckoGroupRuleRules>().call_)
// ------------------------------- // -------------------------------
// Style Rule List for group rules // Style Rule List for group rules
// //
@ -91,27 +97,29 @@ GroupRuleRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
} }
// ------------------------------- // -------------------------------
// GroupRule // GeckoGroupRuleRules
// //
GroupRule::GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber) GeckoGroupRuleRules::GeckoGroupRuleRules()
: Rule(aLineNumber, aColumnNumber)
{ {
} }
GroupRule::GroupRule(const GroupRule& aCopy) GeckoGroupRuleRules::GeckoGroupRuleRules(GeckoGroupRuleRules&& aOther)
: Rule(aCopy) : mRules(Move(aOther.mRules))
, mRuleCollection(Move(aOther.mRuleCollection))
{
}
GeckoGroupRuleRules::GeckoGroupRuleRules(const GeckoGroupRuleRules& aCopy)
{ {
for (const Rule* rule : aCopy.mRules) { for (const Rule* rule : aCopy.mRules) {
RefPtr<Rule> clone = rule->Clone(); RefPtr<Rule> clone = rule->Clone();
mRules.AppendObject(clone); mRules.AppendObject(clone);
clone->SetParentRule(this);
} }
} }
GroupRule::~GroupRule() GeckoGroupRuleRules::~GeckoGroupRuleRules()
{ {
MOZ_ASSERT(!mSheet, "SetStyleSheet should have been called");
for (Rule* rule : mRules) { for (Rule* rule : mRules) {
rule->SetParentRule(nullptr); rule->SetParentRule(nullptr);
} }
@ -120,6 +128,95 @@ GroupRule::~GroupRule()
} }
} }
void
GeckoGroupRuleRules::Clear()
{
mRules.Clear();
if (mRuleCollection) {
mRuleCollection->DropReference();
mRuleCollection = nullptr;
}
}
void
GeckoGroupRuleRules::Traverse(nsCycleCollectionTraversalCallback& cb)
{
IncrementalClearCOMRuleArray& rules = mRules;
for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
if (!rules[i]->IsCCLeaf()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
cb.NoteXPCOMChild(rules[i]);
}
}
ImplCycleCollectionTraverse(cb, mRuleCollection, "mRuleCollection");
}
#ifdef DEBUG
void
GeckoGroupRuleRules::List(FILE* out, int32_t aIndent) const
{
for (const Rule* rule : mRules) {
rule->List(out, aIndent + 1);
}
}
#endif
nsresult
GeckoGroupRuleRules::DeleteStyleRuleAt(uint32_t aIndex)
{
Rule* rule = mRules.SafeObjectAt(aIndex);
if (rule) {
rule->SetStyleSheet(nullptr);
rule->SetParentRule(nullptr);
}
return mRules.RemoveObjectAt(aIndex) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
}
CSSRuleList*
GeckoGroupRuleRules::CssRules(GroupRule* aParentRule)
{
if (!mRuleCollection) {
mRuleCollection = new GroupRuleRuleList(aParentRule);
}
return mRuleCollection;
}
size_t
GeckoGroupRuleRules::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = mRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (const Rule* rule : mRules) {
n += rule->SizeOfIncludingThis(aMallocSizeOf);
}
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mRuleCollection
return n;
}
// -------------------------------
// GroupRule
//
GroupRule::GroupRule(uint32_t aLineNumber, uint32_t aColumnNumber)
: Rule(aLineNumber, aColumnNumber)
, mInner(GeckoGroupRuleRules())
{
}
GroupRule::GroupRule(const GroupRule& aCopy)
: Rule(aCopy)
, mInner(aCopy.mInner)
{
CALL_INNER(mInner, SetParentRule(this));
}
GroupRule::~GroupRule()
{
MOZ_ASSERT(!mSheet, "SetStyleSheet should have been called");
}
NS_IMPL_ADDREF_INHERITED(GroupRule, Rule) NS_IMPL_ADDREF_INHERITED(GroupRule, Rule)
NS_IMPL_RELEASE_INHERITED(GroupRule, Rule) NS_IMPL_RELEASE_INHERITED(GroupRule, Rule)
@ -136,9 +233,7 @@ GroupRule::IsCCLeaf() const
NS_IMPL_CYCLE_COLLECTION_CLASS(GroupRule) NS_IMPL_CYCLE_COLLECTION_CLASS(GroupRule)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
for (Rule* rule : tmp->mRules) { CALL_INNER(tmp->mInner, SetParentRule(nullptr));
rule->SetParentRule(nullptr);
}
// If tmp does not have a stylesheet, neither do its descendants. In that // If tmp does not have a stylesheet, neither do its descendants. In that
// case, don't try to null out their stylesheet, to avoid O(N^2) behavior in // case, don't try to null out their stylesheet, to avoid O(N^2) behavior in
// depth of group rule nesting. But if tmp _does_ have a stylesheet (which // depth of group rule nesting. But if tmp _does_ have a stylesheet (which
@ -146,26 +241,13 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(GroupRule, Rule)
// need to null out the stylesheet pointer on descendants now, before we clear // need to null out the stylesheet pointer on descendants now, before we clear
// tmp->mRules. // tmp->mRules.
if (tmp->GetStyleSheet()) { if (tmp->GetStyleSheet()) {
for (Rule* rule : tmp->mRules) { CALL_INNER(tmp->mInner, SetStyleSheet(nullptr));
rule->SetStyleSheet(nullptr);
}
}
tmp->mRules.Clear();
if (tmp->mRuleCollection) {
tmp->mRuleCollection->DropReference();
tmp->mRuleCollection = nullptr;
} }
CALL_INNER(tmp->mInner, Clear());
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GroupRule, Rule) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(GroupRule, Rule)
const nsCOMArray<Rule>& rules = tmp->mRules; CALL_INNER(tmp->mInner, Traverse(cb));
for (int32_t i = 0, count = rules.Count(); i < count; ++i) {
if (!rules[i]->IsCCLeaf()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
cb.NoteXPCOMChild(rules[i]);
}
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
/* virtual */ void /* virtual */ void
@ -176,27 +258,15 @@ GroupRule::SetStyleSheet(StyleSheet* aSheet)
// depth when seting the sheet to null during unlink, if we happen to unlin in // depth when seting the sheet to null during unlink, if we happen to unlin in
// order from most nested rule up to least nested rule. // order from most nested rule up to least nested rule.
if (aSheet != GetStyleSheet()) { if (aSheet != GetStyleSheet()) {
for (Rule* rule : mRules) { CALL_INNER(mInner, SetStyleSheet(aSheet));
rule->SetStyleSheet(aSheet);
}
Rule::SetStyleSheet(aSheet); Rule::SetStyleSheet(aSheet);
} }
} }
#ifdef DEBUG
/* virtual */ void
GroupRule::List(FILE* out, int32_t aIndent) const
{
for (int32_t index = 0, count = mRules.Count(); index < count; ++index) {
mRules.ObjectAt(index)->List(out, aIndent + 1);
}
}
#endif
void void
GroupRule::AppendStyleRule(Rule* aRule) GroupRule::AppendStyleRule(Rule* aRule)
{ {
mRules.AppendObject(aRule); GeckoRules().AppendObject(aRule);
StyleSheet* sheet = GetStyleSheet(); StyleSheet* sheet = GetStyleSheet();
aRule->SetStyleSheet(sheet); aRule->SetStyleSheet(sheet);
aRule->SetParentRule(this); aRule->SetParentRule(this);
@ -205,16 +275,10 @@ GroupRule::AppendStyleRule(Rule* aRule)
} }
} }
Rule*
GroupRule::GetStyleRuleAt(int32_t aIndex) const
{
return mRules.SafeObjectAt(aIndex);
}
bool bool
GroupRule::EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const GroupRule::EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const
{ {
for (const Rule* rule : mRules) { for (const Rule* rule : GeckoRules()) {
if (!aFunc(const_cast<Rule*>(rule), aData)) { if (!aFunc(const_cast<Rule*>(rule), aData)) {
return false; return false;
} }
@ -222,29 +286,12 @@ GroupRule::EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const
return true; return true;
} }
/*
* The next two methods (DeleteStyleRuleAt and InsertStyleRuleAt)
* should never be called unless you have first called WillDirty() on
* the parents stylesheet. After they are called, DidDirty() needs to
* be called on the sheet
*/
nsresult
GroupRule::DeleteStyleRuleAt(uint32_t aIndex)
{
Rule* rule = mRules.SafeObjectAt(aIndex);
if (rule) {
rule->SetStyleSheet(nullptr);
rule->SetParentRule(nullptr);
}
return mRules.RemoveObjectAt(aIndex) ? NS_OK : NS_ERROR_ILLEGAL_VALUE;
}
nsresult nsresult
GroupRule::InsertStyleRuleAt(uint32_t aIndex, Rule* aRule) GroupRule::InsertStyleRuleAt(uint32_t aIndex, Rule* aRule)
{ {
aRule->SetStyleSheet(GetStyleSheet()); aRule->SetStyleSheet(GetStyleSheet());
aRule->SetParentRule(this); aRule->SetParentRule(this);
if (! mRules.InsertObjectAt(aRule, aIndex)) { if (!GeckoRules().InsertObjectAt(aRule, aIndex)) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
return NS_OK; return NS_OK;
@ -254,17 +301,13 @@ void
GroupRule::AppendRulesToCssText(nsAString& aCssText) const GroupRule::AppendRulesToCssText(nsAString& aCssText) const
{ {
aCssText.AppendLiteral(" {\n"); aCssText.AppendLiteral(" {\n");
for (const Rule* rule : GeckoRules()) {
// get all the rules
for (int32_t index = 0, count = mRules.Count(); index < count; ++index) {
Rule* rule = mRules.ObjectAt(index);
nsAutoString cssText; nsAutoString cssText;
rule->GetCssText(cssText); rule->GetCssText(cssText);
aCssText.AppendLiteral(" "); aCssText.AppendLiteral(" ");
aCssText.Append(cssText); aCssText.Append(cssText);
aCssText.Append('\n'); aCssText.Append('\n');
} }
aCssText.Append('}'); aCssText.Append('}');
} }
@ -279,11 +322,7 @@ GroupRule::GetCssRules(nsIDOMCSSRuleList* *aRuleList)
CSSRuleList* CSSRuleList*
GroupRule::CssRules() GroupRule::CssRules()
{ {
if (!mRuleCollection) { return CALL_INNER(mInner, CssRules(this));
mRuleCollection = new css::GroupRuleRuleList(this);
}
return mRuleCollection;
} }
nsresult nsresult
@ -303,13 +342,13 @@ GroupRule::InsertRule(const nsAString& aRule, uint32_t aIndex, ErrorResult& aRv)
return 0; return 0;
} }
if (aIndex > uint32_t(mRules.Count())) { uint32_t count = StyleRuleCount();
if (aIndex > count) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return 0; return 0;
} }
NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX, NS_ASSERTION(count <= INT32_MAX, "Too many style rules!");
"Too many style rules!");
uint32_t retval; uint32_t retval;
nsresult rv = nsresult rv =
@ -338,13 +377,13 @@ GroupRule::DeleteRule(uint32_t aIndex, ErrorResult& aRv)
return; return;
} }
if (aIndex >= uint32_t(mRules.Count())) { uint32_t count = StyleRuleCount();
if (aIndex >= count) {
aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR); aRv.Throw(NS_ERROR_DOM_INDEX_SIZE_ERR);
return; return;
} }
NS_ASSERTION(uint32_t(mRules.Count()) <= INT32_MAX, NS_ASSERTION(count <= INT32_MAX, "Too many style rules!");
"Too many style rules!");
nsresult rv = sheet->AsGecko()->DeleteRuleFromGroup(this, aIndex); nsresult rv = sheet->AsGecko()->DeleteRuleFromGroup(this, aIndex);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
@ -352,20 +391,7 @@ GroupRule::DeleteRule(uint32_t aIndex, ErrorResult& aRv)
} }
} }
/* virtual */ size_t #undef CALL_INNER
GroupRule::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = mRules.ShallowSizeOfExcludingThis(aMallocSizeOf);
for (size_t i = 0; i < mRules.Length(); i++) {
n += mRules[i]->SizeOfIncludingThis(aMallocSizeOf);
}
// Measurement of the following members may be added later if DMD finds it is
// worthwhile:
// - mRuleCollection
return n;
}
} // namespace css } // namespace css
} // namespace mozill } // namespace mozilla

Просмотреть файл

@ -15,6 +15,7 @@
#include "mozilla/ErrorResult.h" #include "mozilla/ErrorResult.h"
#include "mozilla/IncrementalClearCOMRuleArray.h" #include "mozilla/IncrementalClearCOMRuleArray.h"
#include "mozilla/MemoryReporting.h" #include "mozilla/MemoryReporting.h"
#include "mozilla/Variant.h"
#include "mozilla/css/Rule.h" #include "mozilla/css/Rule.h"
#include "nsCycleCollectionParticipant.h" #include "nsCycleCollectionParticipant.h"
@ -31,8 +32,52 @@ class CSSRuleList;
namespace css { namespace css {
class GroupRule;
class GroupRuleRuleList; class GroupRuleRuleList;
struct GeckoGroupRuleRules
{
GeckoGroupRuleRules();
GeckoGroupRuleRules(GeckoGroupRuleRules&& aOther);
GeckoGroupRuleRules(const GeckoGroupRuleRules& aCopy);
~GeckoGroupRuleRules();
void SetParentRule(GroupRule* aParentRule) {
for (Rule* rule : mRules) {
rule->SetParentRule(aParentRule);
}
}
void SetStyleSheet(StyleSheet* aSheet) {
for (Rule* rule : mRules) {
rule->SetStyleSheet(aSheet);
}
}
void Clear();
void Traverse(nsCycleCollectionTraversalCallback& cb);
#ifdef DEBUG
void List(FILE* out, int32_t aIndent) const;
#endif
int32_t StyleRuleCount() const { return mRules.Count(); }
Rule* GetStyleRuleAt(int32_t aIndex) const {
return mRules.SafeObjectAt(aIndex);
}
nsresult DeleteStyleRuleAt(uint32_t aIndex);
dom::CSSRuleList* CssRules(GroupRule* aParentRule);
size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const;
IncrementalClearCOMRuleArray mRules;
RefPtr<GroupRuleRuleList> mRuleCollection; // lazily constructed
};
#define REDIRECT_TO_INNER(call_) \
return mInner.as<GeckoGroupRuleRules>().call_;
// inherits from Rule so it can be shared between // inherits from Rule so it can be shared between
// MediaRule and DocumentRule // MediaRule and DocumentRule
class GroupRule : public Rule class GroupRule : public Rule
@ -48,32 +93,42 @@ public:
virtual bool IsCCLeaf() const override; virtual bool IsCCLeaf() const override;
#ifdef DEBUG #ifdef DEBUG
virtual void List(FILE* out = stdout, int32_t aIndent = 0) const override; void List(FILE* out = stdout, int32_t aIndent = 0) const override {
REDIRECT_TO_INNER(List(out, aIndent))
}
#endif #endif
virtual void SetStyleSheet(StyleSheet* aSheet) override; virtual void SetStyleSheet(StyleSheet* aSheet) override;
public: public:
void AppendStyleRule(Rule* aRule); void AppendStyleRule(Rule* aRule);
int32_t StyleRuleCount() const { return mRules.Count(); } int32_t StyleRuleCount() const {
Rule* GetStyleRuleAt(int32_t aIndex) const; REDIRECT_TO_INNER(StyleRuleCount())
}
Rule* GetStyleRuleAt(uint32_t aIndex) const {
REDIRECT_TO_INNER(GetStyleRuleAt(aIndex))
}
typedef bool (*RuleEnumFunc)(Rule* aElement, void* aData); typedef bool (*RuleEnumFunc)(Rule* aElement, void* aData);
bool EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const; bool EnumerateRulesForwards(RuleEnumFunc aFunc, void * aData) const;
/* /*
* The next three methods should never be called unless you have first * The next two methods should never be called unless you have first
* called WillDirty() on the parent stylesheet. After they are * called WillDirty() on the parent stylesheet. After they are
* called, DidDirty() needs to be called on the sheet. * called, DidDirty() needs to be called on the sheet.
*/ */
nsresult DeleteStyleRuleAt(uint32_t aIndex); nsresult DeleteStyleRuleAt(uint32_t aIndex) {
REDIRECT_TO_INNER(DeleteStyleRuleAt(aIndex));
}
nsresult InsertStyleRuleAt(uint32_t aIndex, Rule* aRule); nsresult InsertStyleRuleAt(uint32_t aIndex, Rule* aRule);
virtual bool UseForPresentation(nsPresContext* aPresContext, virtual bool UseForPresentation(nsPresContext* aPresContext,
nsMediaQueryResultCacheKey& aKey) = 0; nsMediaQueryResultCacheKey& aKey) = 0;
// non-virtual -- it is only called by subclasses // non-virtual -- it is only called by subclasses
size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const; size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const {
REDIRECT_TO_INNER(SizeOfExcludingThis(aMallocSizeOf))
}
virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override = 0; virtual size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override = 0;
// WebIDL API // WebIDL API
@ -93,10 +148,20 @@ protected:
uint32_t* _retval); uint32_t* _retval);
nsresult DeleteRule(uint32_t aIndex); nsresult DeleteRule(uint32_t aIndex);
IncrementalClearCOMRuleArray mRules; // Must only be called if this is a Gecko GroupRule.
RefPtr<GroupRuleRuleList> mRuleCollection; // lazily constructed IncrementalClearCOMRuleArray& GeckoRules() {
return mInner.as<GeckoGroupRuleRules>().mRules;
}
const IncrementalClearCOMRuleArray& GeckoRules() const {
return mInner.as<GeckoGroupRuleRules>().mRules;
}
private:
Variant<GeckoGroupRuleRules> mInner;
}; };
#undef REDIRECT_TO_INNER
// Implementation of WebIDL CSSConditionRule. // Implementation of WebIDL CSSConditionRule.
class ConditionRule : public GroupRule class ConditionRule : public GroupRule
{ {

Просмотреть файл

@ -1998,8 +1998,8 @@ nsCSSKeyframesRule::GetCssTextImpl(nsAString& aCssText) const
aCssText.Append(mName); aCssText.Append(mName);
aCssText.AppendLiteral(" {\n"); aCssText.AppendLiteral(" {\n");
nsAutoString tmp; nsAutoString tmp;
for (uint32_t i = 0, i_end = mRules.Count(); i != i_end; ++i) { for (const Rule* rule : GeckoRules()) {
static_cast<nsCSSKeyframeRule*>(mRules[i])->GetCssText(tmp); static_cast<const nsCSSKeyframeRule*>(rule)->GetCssText(tmp);
aCssText.Append(tmp); aCssText.Append(tmp);
aCssText.Append('\n'); aCssText.Append('\n');
} }
@ -2079,13 +2079,14 @@ nsCSSKeyframesRule::FindRuleIndexForKey(const nsAString& aKey)
InfallibleTArray<float> keys; InfallibleTArray<float> keys;
// FIXME: pass filename and line number // FIXME: pass filename and line number
if (parser.ParseKeyframeSelectorString(aKey, nullptr, 0, keys)) { if (parser.ParseKeyframeSelectorString(aKey, nullptr, 0, keys)) {
IncrementalClearCOMRuleArray& rules = GeckoRules();
// The spec isn't clear, but we'll match on the key list, which // The spec isn't clear, but we'll match on the key list, which
// mostly matches what WebKit does, except we'll do last-match // mostly matches what WebKit does, except we'll do last-match
// instead of first-match, and handling parsing differences better. // instead of first-match, and handling parsing differences better.
// http://lists.w3.org/Archives/Public/www-style/2011Apr/0036.html // http://lists.w3.org/Archives/Public/www-style/2011Apr/0036.html
// http://lists.w3.org/Archives/Public/www-style/2011Apr/0037.html // http://lists.w3.org/Archives/Public/www-style/2011Apr/0037.html
for (uint32_t i = mRules.Count(); i-- != 0; ) { for (uint32_t i = rules.Count(); i-- != 0; ) {
if (static_cast<nsCSSKeyframeRule*>(mRules[i])->GetKeys() == keys) { if (static_cast<nsCSSKeyframeRule*>(rules[i])->GetKeys() == keys) {
return i; return i;
} }
} }
@ -2130,7 +2131,7 @@ nsCSSKeyframesRule::FindRule(const nsAString& aKey)
if (index == RULE_NOT_FOUND) { if (index == RULE_NOT_FOUND) {
return nullptr; return nullptr;
} }
return static_cast<nsCSSKeyframeRule*>(mRules[index]); return static_cast<nsCSSKeyframeRule*>(GeckoRules()[index]);
} }
// GroupRule interface // GroupRule interface