Line data Source code
1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : /*
7 : * representation of CSS style rules (selectors+declaration) and CSS
8 : * selectors
9 : */
10 :
11 : #ifndef mozilla_css_StyleRule_h__
12 : #define mozilla_css_StyleRule_h__
13 :
14 : #include "mozilla/Attributes.h"
15 : #include "mozilla/BindingStyleRule.h"
16 : #include "mozilla/MemoryReporting.h"
17 : #include "mozilla/StyleSetHandle.h"
18 : #include "mozilla/UniquePtr.h"
19 :
20 : #include "nsString.h"
21 : #include "nsCOMPtr.h"
22 : #include "nsCSSPseudoElements.h"
23 : #include "nsIStyleRule.h"
24 : #include "nsICSSStyleRuleDOMWrapper.h"
25 :
26 : class nsIAtom;
27 : struct nsCSSSelectorList;
28 :
29 : namespace mozilla {
30 : enum class CSSPseudoClassType : uint8_t;
31 : class CSSStyleSheet;
32 : } // namespace mozilla
33 :
34 : struct nsAtomList {
35 : public:
36 : explicit nsAtomList(nsIAtom* aAtom);
37 : explicit nsAtomList(const nsString& aAtomValue);
38 : ~nsAtomList(void);
39 :
40 : /** Do a deep clone. Should be used only on the first in the linked list. */
41 0 : nsAtomList* Clone() const { return Clone(true); }
42 :
43 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
44 :
45 : nsCOMPtr<nsIAtom> mAtom;
46 : nsAtomList* mNext;
47 : private:
48 : nsAtomList* Clone(bool aDeep) const;
49 :
50 : nsAtomList(const nsAtomList& aCopy) = delete;
51 : nsAtomList& operator=(const nsAtomList& aCopy) = delete;
52 : };
53 :
54 : struct nsPseudoClassList {
55 : public:
56 : typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
57 :
58 : explicit nsPseudoClassList(CSSPseudoClassType aType);
59 : nsPseudoClassList(CSSPseudoClassType aType, const char16_t *aString);
60 : nsPseudoClassList(CSSPseudoClassType aType, const int32_t *aIntPair);
61 : nsPseudoClassList(CSSPseudoClassType aType,
62 : nsCSSSelectorList *aSelectorList /* takes ownership */);
63 : ~nsPseudoClassList(void);
64 :
65 : /** Do a deep clone. Should be used only on the first in the linked list. */
66 0 : nsPseudoClassList* Clone() const { return Clone(true); }
67 :
68 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
69 :
70 : union {
71 : // For a given value of mType, we have either:
72 : // a. no value, which means mMemory is always null
73 : // (if none of the conditions for (b), (c), or (d) is true)
74 : // b. a string value, which means mString/mMemory is non-null
75 : // (if nsCSSPseudoClasses::HasStringArg(mType))
76 : // c. an integer pair value, which means mNumbers/mMemory is non-null
77 : // (if nsCSSPseudoClasses::HasNthPairArg(mType))
78 : // d. a selector list, which means mSelectors is non-null
79 : // (if nsCSSPseudoClasses::HasSelectorListArg(mType))
80 : void* mMemory; // mString and mNumbers use moz_xmalloc/free
81 : char16_t* mString;
82 : int32_t* mNumbers;
83 : nsCSSSelectorList* mSelectors;
84 : } u;
85 : CSSPseudoClassType mType;
86 : nsPseudoClassList* mNext;
87 : private:
88 : nsPseudoClassList* Clone(bool aDeep) const;
89 :
90 : nsPseudoClassList(const nsPseudoClassList& aCopy) = delete;
91 : nsPseudoClassList& operator=(const nsPseudoClassList& aCopy) = delete;
92 : };
93 :
94 : #define NS_ATTR_FUNC_SET 0 // [attr]
95 : #define NS_ATTR_FUNC_EQUALS 1 // [attr=value]
96 : #define NS_ATTR_FUNC_INCLUDES 2 // [attr~=value] (space separated)
97 : #define NS_ATTR_FUNC_DASHMATCH 3 // [attr|=value] ('-' truncated)
98 : #define NS_ATTR_FUNC_BEGINSMATCH 4 // [attr^=value] (begins with)
99 : #define NS_ATTR_FUNC_ENDSMATCH 5 // [attr$=value] (ends with)
100 : #define NS_ATTR_FUNC_CONTAINSMATCH 6 // [attr*=value] (contains substring)
101 :
102 : struct nsAttrSelector {
103 : public:
104 : enum class ValueCaseSensitivity : uint8_t {
105 : CaseSensitive,
106 : CaseInsensitive,
107 : CaseInsensitiveInHTML
108 : };
109 :
110 : nsAttrSelector(int32_t aNameSpace, const nsString& aAttr);
111 : nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
112 : const nsString& aValue,
113 : ValueCaseSensitivity aValueCaseSensitivity);
114 : nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr,
115 : nsIAtom* aCasedAttr, uint8_t aFunction,
116 : const nsString& aValue,
117 : ValueCaseSensitivity aValueCaseSensitivity);
118 : ~nsAttrSelector(void);
119 :
120 : /** Do a deep clone. Should be used only on the first in the linked list. */
121 0 : nsAttrSelector* Clone() const { return Clone(true); }
122 :
123 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
124 :
125 42644 : bool IsValueCaseSensitive(bool aInHTML) const {
126 89034 : return mValueCaseSensitivity == ValueCaseSensitivity::CaseSensitive ||
127 7492 : (!aInHTML &&
128 46390 : mValueCaseSensitivity == ValueCaseSensitivity::CaseInsensitiveInHTML);
129 : }
130 :
131 : nsString mValue;
132 : nsAttrSelector* mNext;
133 : nsCOMPtr<nsIAtom> mLowercaseAttr;
134 : nsCOMPtr<nsIAtom> mCasedAttr;
135 : int32_t mNameSpace;
136 : uint8_t mFunction;
137 : ValueCaseSensitivity mValueCaseSensitivity;
138 :
139 : private:
140 : nsAttrSelector* Clone(bool aDeep) const;
141 :
142 : nsAttrSelector(const nsAttrSelector& aCopy) = delete;
143 : nsAttrSelector& operator=(const nsAttrSelector& aCopy) = delete;
144 : };
145 :
146 : struct nsCSSSelector {
147 : public:
148 : typedef mozilla::CSSPseudoClassType CSSPseudoClassType;
149 :
150 : nsCSSSelector(void);
151 : ~nsCSSSelector(void);
152 :
153 : /** Do a deep clone. Should be used only on the first in the linked list. */
154 0 : nsCSSSelector* Clone() const { return Clone(true, true); }
155 :
156 : void Reset(void);
157 : void SetNameSpace(int32_t aNameSpace);
158 : void SetTag(const nsString& aTag);
159 : void AddID(const nsString& aID);
160 : void AddClass(const nsString& aClass);
161 : void AddPseudoClass(CSSPseudoClassType aType);
162 : void AddPseudoClass(CSSPseudoClassType aType, const char16_t* aString);
163 : void AddPseudoClass(CSSPseudoClassType aType, const int32_t* aIntPair);
164 : // takes ownership of aSelectorList
165 : void AddPseudoClass(CSSPseudoClassType aType,
166 : nsCSSSelectorList* aSelectorList);
167 : void AddAttribute(int32_t aNameSpace, const nsString& aAttr);
168 : void AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
169 : const nsString& aValue,
170 : nsAttrSelector::ValueCaseSensitivity aValueCaseSensitivity);
171 : void SetOperator(char16_t aOperator);
172 :
173 0 : inline bool HasTagSelector() const {
174 0 : return !!mCasedTag;
175 : }
176 :
177 751627 : inline bool IsPseudoElement() const {
178 751627 : return mLowercaseTag && !mCasedTag;
179 : }
180 :
181 : // Calculate the specificity of this selector (not including its mNext!).
182 : int32_t CalcWeight() const;
183 :
184 : void ToString(nsAString& aString, mozilla::CSSStyleSheet* aSheet,
185 : bool aAppend = false) const;
186 :
187 15691 : bool IsRestrictedSelector() const {
188 15691 : return PseudoType() == mozilla::CSSPseudoElementType::NotPseudo;
189 : }
190 :
191 : #ifdef DEBUG
192 : nsCString RestrictedSelectorToString() const;
193 : #endif
194 :
195 : private:
196 : void AddPseudoClassInternal(nsPseudoClassList *aPseudoClass);
197 : nsCSSSelector* Clone(bool aDeepNext, bool aDeepNegations) const;
198 :
199 : void AppendToStringWithoutCombinators(
200 : nsAString& aString,
201 : mozilla::CSSStyleSheet* aSheet,
202 : bool aUseStandardNamespacePrefixes) const;
203 : void AppendToStringWithoutCombinatorsOrNegations(
204 : nsAString& aString,
205 : mozilla::CSSStyleSheet* aSheet,
206 : bool aIsNegated,
207 : bool aUseStandardNamespacePrefixes) const;
208 : // Returns true if this selector can have a namespace specified (which
209 : // happens if and only if the default namespace would apply to this
210 : // selector).
211 : bool CanBeNamespaced(bool aIsNegated) const;
212 : // Calculate the specificity of this selector (not including its mNext
213 : // or its mNegations).
214 : int32_t CalcWeightWithoutNegations() const;
215 :
216 : public:
217 : // Get and set the selector's pseudo type
218 42016 : mozilla::CSSPseudoElementType PseudoType() const { return mPseudoType; }
219 356 : void SetPseudoType(mozilla::CSSPseudoElementType aType) {
220 356 : mPseudoType = aType;
221 356 : }
222 :
223 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
224 :
225 : // For case-sensitive documents, mLowercaseTag is the same as mCasedTag,
226 : // but in case-insensitive documents (HTML) mLowercaseTag is lowercase.
227 : // Also, for pseudo-elements mCasedTag will be null but mLowercaseTag
228 : // contains their name.
229 : nsCOMPtr<nsIAtom> mLowercaseTag;
230 : nsCOMPtr<nsIAtom> mCasedTag;
231 : nsAtomList* mIDList;
232 : nsAtomList* mClassList;
233 : nsPseudoClassList* mPseudoClassList; // atom for the pseudo, string for
234 : // the argument to functional pseudos
235 : nsAttrSelector* mAttrList;
236 : nsCSSSelector* mNegations;
237 : nsCSSSelector* mNext;
238 : int32_t mNameSpace;
239 : char16_t mOperator;
240 : private:
241 : // The underlying type of CSSPseudoElementType is uint8_t and
242 : // it packs well with mOperator. (char16_t + uint8_t is less than 32bits.)
243 : mozilla::CSSPseudoElementType mPseudoType;
244 :
245 : nsCSSSelector(const nsCSSSelector& aCopy) = delete;
246 : nsCSSSelector& operator=(const nsCSSSelector& aCopy) = delete;
247 : };
248 :
249 : /**
250 : * A selector list is the unit of selectors that each style rule has.
251 : * For example, "P B, H1 B { ... }" would be a selector list with two
252 : * items (where each |nsCSSSelectorList| object's |mSelectors| has
253 : * an |mNext| for the P or H1). We represent them as linked lists.
254 : */
255 : namespace mozilla {
256 : namespace css {
257 : class StyleRule;
258 : } // namespace css
259 : } // namespace mozilla
260 :
261 : struct nsCSSSelectorList {
262 : nsCSSSelectorList(void);
263 : ~nsCSSSelectorList(void);
264 :
265 : /**
266 : * Create a new selector and push it onto the beginning of |mSelectors|,
267 : * setting its |mNext| to the current value of |mSelectors|. If there is an
268 : * earlier selector, set its |mOperator| to |aOperator|; else |aOperator|
269 : * must be char16_t(0).
270 : * Returns the new selector.
271 : * The list owns the new selector.
272 : * The caller is responsible for updating |mWeight|.
273 : */
274 : nsCSSSelector* AddSelector(char16_t aOperator);
275 :
276 : /**
277 : * Point |mSelectors| to its |mNext|, and delete the first node in the old
278 : * |mSelectors|.
279 : * Should only be used on a list with more than one selector in it.
280 : */
281 : void RemoveRightmostSelector();
282 :
283 : /**
284 : * Should be used only on the first in the list
285 : */
286 : void ToString(nsAString& aResult, mozilla::CSSStyleSheet* aSheet);
287 :
288 : /**
289 : * Do a deep clone. Should be used only on the first in the list.
290 : */
291 0 : nsCSSSelectorList* Clone() const { return Clone(true); }
292 :
293 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const;
294 :
295 : nsCSSSelector* mSelectors;
296 : int32_t mWeight;
297 : nsCSSSelectorList* mNext;
298 : protected:
299 : friend class mozilla::css::StyleRule;
300 : nsCSSSelectorList* Clone(bool aDeep) const;
301 :
302 : private:
303 : nsCSSSelectorList(const nsCSSSelectorList& aCopy) = delete;
304 : nsCSSSelectorList& operator=(const nsCSSSelectorList& aCopy) = delete;
305 : };
306 :
307 : // 464bab7a-2fce-4f30-ab44-b7a5f3aae57d
308 : #define NS_CSS_STYLE_RULE_IMPL_CID \
309 : { 0x464bab7a, 0x2fce, 0x4f30, \
310 : { 0xab, 0x44, 0xb7, 0xa5, 0xf3, 0xaa, 0xe5, 0x7d } }
311 :
312 : class DOMCSSDeclarationImpl;
313 :
314 : namespace mozilla {
315 : namespace css {
316 :
317 : class Declaration;
318 :
319 : class StyleRule final : public BindingStyleRule
320 : , public nsICSSStyleRuleDOMWrapper
321 : {
322 : public:
323 : StyleRule(nsCSSSelectorList* aSelector,
324 : Declaration *aDeclaration,
325 : uint32_t aLineNumber, uint32_t aColumnNumber);
326 : private:
327 : // for |Clone|
328 : StyleRule(const StyleRule& aCopy);
329 : public:
330 : NS_DECLARE_STATIC_IID_ACCESSOR(NS_CSS_STYLE_RULE_IMPL_CID)
331 :
332 : NS_DECL_ISUPPORTS_INHERITED
333 3061 : NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(StyleRule, Rule)
334 : bool IsCCLeaf() const override;
335 :
336 : NS_DECL_NSIDOMCSSSTYLERULE
337 :
338 : // nsICSSStyleRuleDOMWrapper
339 : NS_IMETHOD GetCSSStyleRule(BindingStyleRule **aResult) override;
340 :
341 : uint32_t GetSelectorCount() override;
342 : nsresult GetSelectorText(uint32_t aSelectorIndex,
343 : nsAString& aText) override;
344 : nsresult GetSpecificity(uint32_t aSelectorIndex,
345 : uint64_t* aSpecificity) override;
346 : nsresult SelectorMatchesElement(dom::Element* aElement,
347 : uint32_t aSelectorIndex,
348 : const nsAString& aPseudo,
349 : bool* aMatches) override;
350 :
351 : // WebIDL interface
352 : uint16_t Type() const override;
353 : void GetCssTextImpl(nsAString& aCssText) const override;
354 : nsICSSDeclaration* Style() override;
355 :
356 : // null for style attribute
357 8667 : nsCSSSelectorList* Selector() { return mSelector; }
358 :
359 10680 : Declaration* GetDeclaration() const { return mDeclaration; }
360 :
361 : void SetDeclaration(Declaration* aDecl);
362 :
363 : int32_t GetType() const override;
364 : using Rule::GetType;
365 :
366 0 : CSSStyleSheet* GetStyleSheet() const
367 : {
368 0 : StyleSheet* sheet = Rule::GetStyleSheet();
369 0 : return sheet ? sheet->AsGecko() : nullptr;
370 : }
371 :
372 : already_AddRefed<Rule> Clone() const override;
373 :
374 : #ifdef DEBUG
375 : void List(FILE* out = stdout, int32_t aIndent = 0) const override;
376 : #endif
377 :
378 : size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const override;
379 :
380 : private:
381 : ~StyleRule();
382 :
383 : // Drop our references to mDeclaration and mRule, and let them know we're
384 : // doing that.
385 : void DropReferences();
386 :
387 : nsCSSSelectorList*
388 : GetSelectorAtIndex(uint32_t aIndex, ErrorResult& rv);
389 :
390 : private:
391 : nsCSSSelectorList* mSelector; // null for style attribute
392 : RefPtr<Declaration> mDeclaration;
393 :
394 : // We own it, and it aggregates its refcount with us.
395 : UniquePtr<DOMCSSDeclarationImpl> mDOMDeclaration;
396 :
397 : private:
398 : StyleRule& operator=(const StyleRule& aCopy) = delete;
399 : };
400 :
401 : NS_DEFINE_STATIC_IID_ACCESSOR(StyleRule, NS_CSS_STYLE_RULE_IMPL_CID)
402 :
403 : } // namespace css
404 : } // namespace mozilla
405 :
406 : #endif /* mozilla_css_StyleRule_h__ */
|