Bug 1315601 part 10 - Make ServoCSSRuleList support being nested. r=heycam
MozReview-Commit-ID: 8IUGxkMZPMj
--- a/layout/style/ServoCSSRuleList.cpp
+++ b/layout/style/ServoCSSRuleList.cpp
@@ -8,20 +8,18 @@
#include "mozilla/ServoCSSRuleList.h"
#include "mozilla/ServoBindings.h"
#include "mozilla/ServoStyleRule.h"
namespace mozilla {
-ServoCSSRuleList::ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
- already_AddRefed<ServoCssRules> aRawRules)
- : mStyleSheet(aStyleSheet)
- , mRawRules(aRawRules)
+ServoCSSRuleList::ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules)
+ : mRawRules(aRawRules)
{
Servo_CssRules_ListTypes(mRawRules, &mRules);
// XXX We may want to eagerly create object for import rule, so that
// we don't lose the reference to child stylesheet when our own
// stylesheet goes away.
}
// QueryInterface implementation for ServoCSSRuleList
@@ -29,35 +27,46 @@ NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_
NS_INTERFACE_MAP_END_INHERITING(dom::CSSRuleList)
NS_IMPL_ADDREF_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
NS_IMPL_RELEASE_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
NS_IMPL_CYCLE_COLLECTION_CLASS(ServoCSSRuleList)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ServoCSSRuleList)
- for (uintptr_t& rule : tmp->mRules) {
- if (rule > kMaxRuleType) {
- CastToPtr(rule)->Release();
- // Safest to set it to zero, in case someone else pokes at it
- // during their own unlinking process.
- rule = 0;
- }
- }
+ tmp->DropAllRules();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(dom::CSSRuleList)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(ServoCSSRuleList,
dom::CSSRuleList)
tmp->EnumerateInstantiatedRules([&](css::Rule* aRule) {
if (!aRule->IsCCLeaf()) {
NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mRules[i]");
cb.NoteXPCOMChild(aRule);
}
});
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+void
+ServoCSSRuleList::SetParentRule(css::GroupRule* aParentRule)
+{
+ mParentRule = aParentRule;
+ EnumerateInstantiatedRules([aParentRule](css::Rule* rule) {
+ rule->SetParentRule(aParentRule);
+ });
+}
+
+void
+ServoCSSRuleList::SetStyleSheet(StyleSheet* aStyleSheet)
+{
+ mStyleSheet = aStyleSheet ? aStyleSheet->AsServo() : nullptr;
+ EnumerateInstantiatedRules([aStyleSheet](css::Rule* rule) {
+ rule->SetStyleSheet(aStyleSheet);
+ });
+}
+
css::Rule*
ServoCSSRuleList::GetRule(uint32_t aIndex)
{
uintptr_t rule = mRules[aIndex];
if (rule <= kMaxRuleType) {
RefPtr<css::Rule> ruleObj = nullptr;
switch (rule) {
case nsIDOMCSSRule::STYLE_RULE: {
@@ -70,16 +79,17 @@ ServoCSSRuleList::GetRule(uint32_t aInde
case nsIDOMCSSRule::KEYFRAMES_RULE:
case nsIDOMCSSRule::NAMESPACE_RULE:
// XXX create corresponding rules
default:
NS_WARNING("stylo: not implemented yet");
return nullptr;
}
ruleObj->SetStyleSheet(mStyleSheet);
+ ruleObj->SetParentRule(mParentRule);
rule = CastToUint(ruleObj.forget().take());
mRules[aIndex] = rule;
}
return CastToPtr(rule);
}
css::Rule*
ServoCSSRuleList::IndexedGetter(uint32_t aIndex, bool& aFound)
@@ -98,53 +108,67 @@ ServoCSSRuleList::EnumerateInstantiatedR
{
for (uintptr_t rule : mRules) {
if (rule > kMaxRuleType) {
aCallback(CastToPtr(rule));
}
}
}
+static void
+DropRule(already_AddRefed<css::Rule> aRule)
+{
+ RefPtr<css::Rule> rule = aRule;
+ rule->SetStyleSheet(nullptr);
+ rule->SetParentRule(nullptr);
+}
+
+void
+ServoCSSRuleList::DropAllRules()
+{
+ EnumerateInstantiatedRules([](css::Rule* rule) {
+ DropRule(already_AddRefed<css::Rule>(rule));
+ });
+ mRules.Clear();
+}
+
void
ServoCSSRuleList::DropReference()
{
mStyleSheet = nullptr;
- EnumerateInstantiatedRules([](css::Rule* rule) {
- rule->SetStyleSheet(nullptr);
- });
+ mParentRule = nullptr;
+ DropAllRules();
}
nsresult
ServoCSSRuleList::InsertRule(const nsAString& aRule, uint32_t aIndex)
{
NS_ConvertUTF16toUTF8 rule(aRule);
- // XXX This needs to actually reflect whether it is nested when we
- // support using CSSRuleList in CSSGroupingRules.
- bool nested = false;
+ bool nested = !!mParentRule;
uint16_t type;
nsresult rv = Servo_CssRules_InsertRule(mRawRules, mStyleSheet->RawSheet(),
&rule, aIndex, nested, &type);
if (!NS_FAILED(rv)) {
mRules.InsertElementAt(aIndex, type);
}
return rv;
}
nsresult
ServoCSSRuleList::DeleteRule(uint32_t aIndex)
{
nsresult rv = Servo_CssRules_DeleteRule(mRawRules, aIndex);
if (!NS_FAILED(rv)) {
uintptr_t rule = mRules[aIndex];
if (rule > kMaxRuleType) {
- CastToPtr(rule)->Release();
+ DropRule(already_AddRefed<css::Rule>(CastToPtr(rule)));
}
mRules.RemoveElementAt(aIndex);
}
return rv;
}
ServoCSSRuleList::~ServoCSSRuleList()
{
- EnumerateInstantiatedRules([](css::Rule* rule) { rule->Release(); });
+ DropAllRules();
}
} // namespace mozilla
--- a/layout/style/ServoCSSRuleList.h
+++ b/layout/style/ServoCSSRuleList.h
@@ -11,24 +11,26 @@
#include "mozilla/ServoBindingTypes.h"
#include "mozilla/dom/CSSRuleList.h"
namespace mozilla {
class ServoStyleSheet;
namespace css {
+class GroupRule;
class Rule;
} // namespace css
class ServoCSSRuleList final : public dom::CSSRuleList
{
public:
- ServoCSSRuleList(ServoStyleSheet* aStyleSheet,
- already_AddRefed<ServoCssRules> aRawRules);
+ explicit ServoCSSRuleList(already_AddRefed<ServoCssRules> aRawRules);
+ void SetParentRule(css::GroupRule* aParentRule);
+ void SetStyleSheet(StyleSheet* aSheet);
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ServoCSSRuleList, dom::CSSRuleList)
ServoStyleSheet* GetParentObject() final { return mStyleSheet; }
css::Rule* IndexedGetter(uint32_t aIndex, bool& aFound) final;
uint32_t Length() final { return mRules.Length(); }
@@ -52,18 +54,22 @@ private:
static css::Rule* CastToPtr(uintptr_t aInt) {
MOZ_ASSERT(aInt > kMaxRuleType);
return reinterpret_cast<css::Rule*>(aInt);
}
template<typename Func>
void EnumerateInstantiatedRules(Func aCallback);
+ void DropAllRules();
+
// mStyleSheet may be nullptr when it drops the reference to us.
- ServoStyleSheet* mStyleSheet;
+ ServoStyleSheet* mStyleSheet = nullptr;
+ // mParentRule is nullptr if it isn't a nested rule list.
+ css::GroupRule* mParentRule = nullptr;
RefPtr<ServoCssRules> mRawRules;
// Array stores either a number indicating rule type, or a pointer to
// css::Rule. If the value is less than kMaxRuleType, the given rule
// instance has not been constructed, and the value means the type
// of the rule. Otherwise, it is a pointer.
nsTArray<uintptr_t> mRules;
};
--- a/layout/style/ServoStyleSheet.cpp
+++ b/layout/style/ServoStyleSheet.cpp
@@ -146,17 +146,18 @@ ServoStyleSheet::Clone(StyleSheet* aClon
}
CSSRuleList*
ServoStyleSheet::GetCssRulesInternal(ErrorResult& aRv)
{
if (!mRuleList) {
RefPtr<ServoCssRules> rawRules =
Servo_StyleSheet_GetRules(Inner()->mSheet).Consume();
- mRuleList = new ServoCSSRuleList(this, rawRules.forget());
+ mRuleList = new ServoCSSRuleList(rawRules.forget());
+ mRuleList->SetStyleSheet(this);
}
return mRuleList;
}
uint32_t
ServoStyleSheet::InsertRuleInternal(const nsAString& aRule,
uint32_t aIndex, ErrorResult& aRv)
{