1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "mozilla/dom/CSSStyleRule.h"
8 #include "mozilla/dom/CSSStyleRuleBinding.h"
10 #include "mozilla/CSSEnabledState.h"
11 #include "mozilla/DeclarationBlock.h"
12 #include "mozilla/PseudoStyleType.h"
13 #include "mozilla/ServoBindings.h"
14 #include "mozilla/dom/ShadowRoot.h"
15 #include "nsCSSPseudoElements.h"
17 #include "nsISupports.h"
19 namespace mozilla::dom
{
21 // -- CSSStyleRuleDeclaration ---------------------------------------
23 CSSStyleRuleDeclaration::CSSStyleRuleDeclaration(
24 already_AddRefed
<StyleLockedDeclarationBlock
> aDecls
)
25 : mDecls(new DeclarationBlock(std::move(aDecls
))) {
26 mDecls
->SetOwningRule(Rule());
29 CSSStyleRuleDeclaration::~CSSStyleRuleDeclaration() {
30 mDecls
->SetOwningRule(nullptr);
33 // QueryInterface implementation for CSSStyleRuleDeclaration
34 NS_INTERFACE_MAP_BEGIN(CSSStyleRuleDeclaration
)
35 NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
36 // We forward the cycle collection interfaces to Rule(), which is
37 // never null (in fact, we're part of that object!)
38 if (aIID
.Equals(NS_GET_IID(nsCycleCollectionISupports
)) ||
39 aIID
.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant
))) {
40 return Rule()->QueryInterface(aIID
, aInstancePtr
);
42 NS_INTERFACE_MAP_END_INHERITING(nsDOMCSSDeclaration
)
44 NS_IMPL_ADDREF_USING_AGGREGATOR(CSSStyleRuleDeclaration
, Rule())
45 NS_IMPL_RELEASE_USING_AGGREGATOR(CSSStyleRuleDeclaration
, Rule())
47 /* nsDOMCSSDeclaration implementation */
49 css::Rule
* CSSStyleRuleDeclaration::GetParentRule() { return Rule(); }
51 nsINode
* CSSStyleRuleDeclaration::GetAssociatedNode() const {
52 return Rule()->GetAssociatedDocumentOrShadowRoot();
55 nsISupports
* CSSStyleRuleDeclaration::GetParentObject() const {
56 return Rule()->GetParentObject();
59 DeclarationBlock
* CSSStyleRuleDeclaration::GetOrCreateCSSDeclaration(
60 Operation aOperation
, DeclarationBlock
** aCreated
) {
61 if (aOperation
!= Operation::Read
) {
62 if (StyleSheet
* sheet
= Rule()->GetStyleSheet()) {
69 void CSSStyleRuleDeclaration::SetRawAfterClone(
70 RefPtr
<StyleLockedDeclarationBlock
> aRaw
) {
71 auto block
= MakeRefPtr
<DeclarationBlock
>(aRaw
.forget());
72 mDecls
->SetOwningRule(nullptr);
73 mDecls
= std::move(block
);
74 mDecls
->SetOwningRule(Rule());
77 void CSSStyleRule::SetRawAfterClone(RefPtr
<StyleLockedStyleRule
> aRaw
) {
78 mRawRule
= std::move(aRaw
);
79 mDecls
.SetRawAfterClone(Servo_StyleRule_GetStyle(mRawRule
).Consume());
80 GroupRule::DidSetRawAfterClone();
83 already_AddRefed
<StyleLockedCssRules
> CSSStyleRule::GetOrCreateRawRules() {
84 return Servo_StyleRule_EnsureRules(mRawRule
, IsReadOnly()).Consume();
87 nsresult
CSSStyleRuleDeclaration::SetCSSDeclaration(
88 DeclarationBlock
* aDecl
, MutationClosureData
* aClosureData
) {
89 CSSStyleRule
* rule
= Rule();
91 if (StyleSheet
* sheet
= rule
->GetStyleSheet()) {
92 if (aDecl
!= mDecls
) {
93 mDecls
->SetOwningRule(nullptr);
94 RefPtr
<DeclarationBlock
> decls
= aDecl
;
95 Servo_StyleRule_SetStyle(rule
->Raw(), decls
->Raw());
96 mDecls
= std::move(decls
);
97 mDecls
->SetOwningRule(rule
);
99 sheet
->RuleChanged(rule
, StyleRuleChangeKind::StyleRuleDeclarations
);
104 nsDOMCSSDeclaration::ParsingEnvironment
105 CSSStyleRuleDeclaration::GetParsingEnvironment(nsIPrincipal
*) const {
106 return GetParsingEnvironmentForRule(Rule(), StyleCssRuleType::Style
);
109 // -- CSSStyleRule --------------------------------------------------
111 CSSStyleRule::CSSStyleRule(already_AddRefed
<StyleLockedStyleRule
> aRawRule
,
112 StyleSheet
* aSheet
, css::Rule
* aParentRule
,
113 uint32_t aLine
, uint32_t aColumn
)
114 : GroupRule(aSheet
, aParentRule
, aLine
, aColumn
),
116 mDecls(Servo_StyleRule_GetStyle(mRawRule
).Consume()) {}
118 NS_IMPL_ISUPPORTS_CYCLE_COLLECTION_INHERITED_0(CSSStyleRule
, GroupRule
)
120 NS_IMPL_CYCLE_COLLECTION_CLASS(CSSStyleRule
)
122 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(CSSStyleRule
, GroupRule
)
123 // Keep this in sync with IsCCLeaf.
125 // Trace the wrapper for our declaration. This just expands out
126 // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
127 // directly because the wrapper is on the declaration, not on us.
128 tmp
->mDecls
.TraceWrapper(aCallbacks
, aClosure
);
129 NS_IMPL_CYCLE_COLLECTION_TRACE_END
131 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CSSStyleRule
)
132 // Keep this in sync with IsCCLeaf.
134 // Unlink the wrapper for our declaration.
136 // Note that this has to happen before unlinking css::Rule.
137 tmp
->UnlinkDeclarationWrapper(tmp
->mDecls
);
138 NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_PTR
139 NS_IMPL_CYCLE_COLLECTION_UNLINK_END_INHERITED(GroupRule
)
141 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(CSSStyleRule
, GroupRule
)
142 // Keep this in sync with IsCCLeaf.
143 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
145 bool CSSStyleRule::IsCCLeaf() const {
146 if (!GroupRule::IsCCLeaf()) {
149 return !mDecls
.PreservingWrapper();
152 size_t CSSStyleRule::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf
) const {
153 size_t n
= aMallocSizeOf(this);
155 // Measurement of the following members may be added later if DMD finds it
164 void CSSStyleRule::List(FILE* out
, int32_t aIndent
) const {
166 for (int32_t i
= 0; i
< aIndent
; i
++) {
167 str
.AppendLiteral(" ");
169 Servo_StyleRule_Debug(mRawRule
, &str
);
170 fprintf_stderr(out
, "%s\n", str
.get());
174 /* CSSRule implementation */
176 StyleCssRuleType
CSSStyleRule::Type() const { return StyleCssRuleType::Style
; }
178 void CSSStyleRule::GetCssText(nsACString
& aCssText
) const {
179 Servo_StyleRule_GetCssText(mRawRule
, &aCssText
);
182 /* CSSStyleRule implementation */
184 StyleLockedDeclarationBlock
* CSSStyleRule::RawStyle() const {
185 return mDecls
.mDecls
->Raw();
188 void CSSStyleRule::GetSelectorText(nsACString
& aSelectorText
) {
189 Servo_StyleRule_GetSelectorText(mRawRule
, &aSelectorText
);
192 void CSSStyleRule::SetSelectorText(const nsACString
& aSelectorText
) {
197 StyleSheet
* sheet
= GetStyleSheet();
203 auto state
= ContainingRuleState::From(mParentRule
);
205 // TODO(emilio): May actually be more efficient to handle this as rule
206 // removal + addition, from the point of view of invalidation...
207 const StyleStylesheetContents
* contents
= sheet
->RawContents();
208 if (Servo_StyleRule_SetSelectorText(
209 contents
, mRawRule
, &aSelectorText
,
210 state
.mParseRelativeType
.ptrOr(nullptr))) {
211 sheet
->RuleChanged(this, StyleRuleChangeKind::Generic
);
215 uint32_t CSSStyleRule::SelectorCount() const {
216 return Servo_StyleRule_GetSelectorCount(mRawRule
);
219 static void CollectStyleRules(CSSStyleRule
& aDeepestRule
, bool aDesugared
,
220 nsTArray
<const StyleLockedStyleRule
*>& aResult
) {
221 aResult
.AppendElement(aDeepestRule
.Raw());
223 for (auto* rule
= aDeepestRule
.GetParentRule(); rule
;
224 rule
= rule
->GetParentRule()) {
225 if (rule
->Type() == StyleCssRuleType::Style
) {
226 aResult
.AppendElement(static_cast<CSSStyleRule
*>(rule
)->Raw());
232 void CSSStyleRule::GetSelectorDataAtIndex(uint32_t aSelectorIndex
,
233 bool aDesugared
, nsACString
* aText
,
234 uint64_t* aSpecificity
) {
235 AutoTArray
<const StyleLockedStyleRule
*, 8> rules
;
236 CollectStyleRules(*this, aDesugared
, rules
);
237 Servo_StyleRule_GetSelectorDataAtIndex(&rules
, aSelectorIndex
, aText
,
241 void CSSStyleRule::SelectorTextAt(uint32_t aSelectorIndex
, bool aDesugared
,
243 GetSelectorDataAtIndex(aSelectorIndex
, aDesugared
, &aText
, nullptr);
246 uint64_t CSSStyleRule::SelectorSpecificityAt(uint32_t aSelectorIndex
,
249 GetSelectorDataAtIndex(aSelectorIndex
, aDesugared
, nullptr, &s
);
253 bool CSSStyleRule::SelectorMatchesElement(uint32_t aSelectorIndex
,
255 const nsAString
& aPseudo
,
256 bool aRelevantLinkVisited
) {
257 Maybe
<PseudoStyleType
> pseudoType
= nsCSSPseudoElements::GetPseudoType(
258 aPseudo
, CSSEnabledState::IgnoreEnabledState
);
263 auto* host
= [&]() -> Element
* {
264 auto* sheet
= GetStyleSheet();
268 if (auto* owner
= sheet
->GetAssociatedDocumentOrShadowRoot()) {
269 if (auto* shadow
= ShadowRoot::FromNode(owner
->AsNode())) {
270 return shadow
->Host();
273 for (auto* adopter
: sheet
->SelfOrAncestorAdopters()) {
274 // Try to guess. This is not fully correct but it's the best we can do
275 // with the info at hand...
276 auto* shadow
= ShadowRoot::FromNode(adopter
->AsNode());
280 if (shadow
->Host() == &aElement
||
281 shadow
== aElement
.GetContainingShadow()) {
282 return shadow
->Host();
288 AutoTArray
<const StyleLockedStyleRule
*, 8> rules
;
289 CollectStyleRules(*this, /* aDesugared = */ true, rules
);
291 return Servo_StyleRule_SelectorMatchesElement(
292 &rules
, &aElement
, aSelectorIndex
, host
, *pseudoType
,
293 aRelevantLinkVisited
);
296 SelectorWarningKind
ToWebIDLSelectorWarningKind(
297 StyleSelectorWarningKind aKind
) {
299 case StyleSelectorWarningKind::UnconstraintedRelativeSelector
:
300 return SelectorWarningKind::UnconstrainedHas
;
302 MOZ_ASSERT_UNREACHABLE("Unhandled selector warning kind");
303 // Return something for assert-disabled builds.
304 return SelectorWarningKind::UnconstrainedHas
;
307 void CSSStyleRule::GetSelectorWarnings(
308 nsTArray
<SelectorWarning
>& aResult
) const {
309 nsTArray
<StyleSelectorWarningData
> result
;
310 Servo_GetSelectorWarnings(mRawRule
, &result
);
311 for (const auto& warning
: result
) {
312 auto& entry
= *aResult
.AppendElement();
313 entry
.mIndex
= warning
.index
;
314 entry
.mKind
= ToWebIDLSelectorWarningKind(warning
.kind
);
318 already_AddRefed
<nsINodeList
> CSSStyleRule::QuerySelectorAll(nsINode
& aRoot
) {
319 AutoTArray
<const StyleLockedStyleRule
*, 8> rules
;
320 CollectStyleRules(*this, /* aDesugared = */ true, rules
);
321 StyleSelectorList
* list
= Servo_StyleRule_GetSelectorList(&rules
);
323 auto contentList
= MakeRefPtr
<nsSimpleContentList
>(&aRoot
);
324 Servo_SelectorList_QueryAll(&aRoot
, list
, contentList
.get(),
325 /* useInvalidation */ false);
326 Servo_SelectorList_Drop(list
);
327 return contentList
.forget();
331 JSObject
* CSSStyleRule::WrapObject(JSContext
* aCx
,
332 JS::Handle
<JSObject
*> aGivenProto
) {
333 return CSSStyleRule_Binding::Wrap(aCx
, this, aGivenProto
);
336 } // namespace mozilla::dom