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), CSS
8 : * selectors, and DOM objects for style rules, selectors, and
9 : * declarations
10 : */
11 :
12 : #include "mozilla/css/StyleRule.h"
13 :
14 : #include "mozilla/DeclarationBlockInlines.h"
15 : #include "mozilla/StyleSheetInlines.h"
16 : #include "mozilla/MemoryReporting.h"
17 : #include "mozilla/css/GroupRule.h"
18 : #include "mozilla/css/Declaration.h"
19 : #include "mozilla/dom/CSSStyleRuleBinding.h"
20 : #include "nsIDocument.h"
21 : #include "nsIAtom.h"
22 : #include "nsString.h"
23 : #include "nsStyleUtil.h"
24 : #include "nsDOMCSSDeclaration.h"
25 : #include "nsNameSpaceManager.h"
26 : #include "nsXMLNameSpaceMap.h"
27 : #include "nsCSSPseudoClasses.h"
28 : #include "nsCSSAnonBoxes.h"
29 : #include "nsTArray.h"
30 : #include "nsContentUtils.h"
31 : #include "nsError.h"
32 : #include "mozAutoDocUpdate.h"
33 : #include "nsRuleProcessorData.h"
34 :
35 : class nsIDOMCSSStyleDeclaration;
36 : class nsIDOMCSSStyleSheet;
37 :
38 : using namespace mozilla;
39 :
40 : #define NS_IF_CLONE(member_) \
41 : PR_BEGIN_MACRO \
42 : if (member_) { \
43 : result->member_ = member_->Clone(); \
44 : if (!result->member_) { \
45 : delete result; \
46 : return nullptr; \
47 : } \
48 : } \
49 : PR_END_MACRO
50 :
51 : #define NS_IF_DELETE(ptr) \
52 : PR_BEGIN_MACRO \
53 : delete ptr; \
54 : ptr = nullptr; \
55 : PR_END_MACRO
56 :
57 : /* ************************************************************************** */
58 :
59 0 : nsAtomList::nsAtomList(nsIAtom* aAtom)
60 : : mAtom(aAtom),
61 0 : mNext(nullptr)
62 : {
63 0 : MOZ_COUNT_CTOR(nsAtomList);
64 0 : }
65 :
66 4554 : nsAtomList::nsAtomList(const nsString& aAtomValue)
67 : : mAtom(nullptr),
68 4554 : mNext(nullptr)
69 : {
70 4554 : MOZ_COUNT_CTOR(nsAtomList);
71 4554 : mAtom = NS_Atomize(aAtomValue);
72 4554 : }
73 :
74 : nsAtomList*
75 0 : nsAtomList::Clone(bool aDeep) const
76 : {
77 0 : nsAtomList *result = new nsAtomList(mAtom);
78 0 : if (!result)
79 0 : return nullptr;
80 :
81 0 : if (aDeep)
82 0 : NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
83 0 : return result;
84 : }
85 :
86 : size_t
87 12 : nsAtomList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
88 : {
89 12 : size_t n = 0;
90 12 : const nsAtomList* a = this;
91 36 : while (a) {
92 12 : n += aMallocSizeOf(a);
93 :
94 : // The following members aren't measured:
95 : // - a->mAtom, because it may be shared
96 :
97 12 : a = a->mNext;
98 : }
99 12 : return n;
100 : }
101 :
102 0 : nsAtomList::~nsAtomList(void)
103 : {
104 0 : MOZ_COUNT_DTOR(nsAtomList);
105 0 : NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
106 0 : }
107 :
108 1588 : nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType)
109 : : mType(aType),
110 1588 : mNext(nullptr)
111 : {
112 1588 : NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aType) &&
113 : !nsCSSPseudoClasses::HasNthPairArg(aType),
114 : "unexpected pseudo-class");
115 1588 : MOZ_COUNT_CTOR(nsPseudoClassList);
116 1588 : u.mMemory = nullptr;
117 1588 : }
118 :
119 176 : nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
120 176 : const char16_t* aString)
121 : : mType(aType),
122 176 : mNext(nullptr)
123 : {
124 176 : NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aType),
125 : "unexpected pseudo-class");
126 176 : NS_ASSERTION(aString, "string expected");
127 176 : MOZ_COUNT_CTOR(nsPseudoClassList);
128 176 : u.mString = NS_strdup(aString);
129 176 : }
130 :
131 1 : nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
132 1 : const int32_t* aIntPair)
133 : : mType(aType),
134 1 : mNext(nullptr)
135 : {
136 1 : NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aType),
137 : "unexpected pseudo-class");
138 1 : NS_ASSERTION(aIntPair, "integer pair expected");
139 1 : MOZ_COUNT_CTOR(nsPseudoClassList);
140 1 : u.mNumbers =
141 1 : static_cast<int32_t*>(nsMemory::Clone(aIntPair, sizeof(int32_t) * 2));
142 1 : }
143 :
144 : // adopts aSelectorList
145 162 : nsPseudoClassList::nsPseudoClassList(CSSPseudoClassType aType,
146 162 : nsCSSSelectorList* aSelectorList)
147 : : mType(aType),
148 162 : mNext(nullptr)
149 : {
150 162 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType),
151 : "unexpected pseudo-class");
152 162 : NS_ASSERTION(aSelectorList, "selector list expected");
153 162 : MOZ_COUNT_CTOR(nsPseudoClassList);
154 162 : u.mSelectors = aSelectorList;
155 162 : }
156 :
157 : nsPseudoClassList*
158 0 : nsPseudoClassList::Clone(bool aDeep) const
159 : {
160 : nsPseudoClassList *result;
161 0 : if (!u.mMemory) {
162 0 : result = new nsPseudoClassList(mType);
163 0 : } else if (nsCSSPseudoClasses::HasStringArg(mType)) {
164 0 : result = new nsPseudoClassList(mType, u.mString);
165 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(mType)) {
166 0 : result = new nsPseudoClassList(mType, u.mNumbers);
167 : } else {
168 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType),
169 : "unexpected pseudo-class");
170 : // This constructor adopts its selector list argument.
171 0 : result = new nsPseudoClassList(mType, u.mSelectors->Clone());
172 : }
173 :
174 0 : if (aDeep)
175 0 : NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
176 : (false));
177 :
178 0 : return result;
179 : }
180 :
181 : size_t
182 5 : nsPseudoClassList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
183 : {
184 5 : size_t n = 0;
185 5 : const nsPseudoClassList* p = this;
186 15 : while (p) {
187 5 : n += aMallocSizeOf(p);
188 5 : if (!p->u.mMemory) {
189 : // do nothing
190 :
191 0 : } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
192 0 : n += aMallocSizeOf(p->u.mString);
193 :
194 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
195 0 : n += aMallocSizeOf(p->u.mNumbers);
196 :
197 : } else {
198 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType),
199 : "unexpected pseudo-class");
200 0 : n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf);
201 : }
202 5 : p = p->mNext;
203 : }
204 5 : return n;
205 : }
206 :
207 0 : nsPseudoClassList::~nsPseudoClassList(void)
208 : {
209 0 : MOZ_COUNT_DTOR(nsPseudoClassList);
210 0 : if (nsCSSPseudoClasses::HasSelectorListArg(mType)) {
211 0 : delete u.mSelectors;
212 0 : } else if (u.mMemory) {
213 0 : free(u.mMemory);
214 : }
215 0 : NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext);
216 0 : }
217 :
218 737 : nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr)
219 : : mValue(),
220 : mNext(nullptr),
221 : mLowercaseAttr(nullptr),
222 : mCasedAttr(nullptr),
223 : mNameSpace(aNameSpace),
224 : mFunction(NS_ATTR_FUNC_SET),
225 : // mValueCaseSensitivity doesn't matter; we have no value.
226 737 : mValueCaseSensitivity(ValueCaseSensitivity::CaseSensitive)
227 : {
228 737 : MOZ_COUNT_CTOR(nsAttrSelector);
229 :
230 1474 : nsAutoString lowercase;
231 737 : nsContentUtils::ASCIIToLower(aAttr, lowercase);
232 :
233 737 : mCasedAttr = NS_Atomize(aAttr);
234 737 : mLowercaseAttr = NS_Atomize(lowercase);
235 737 : }
236 :
237 1645 : nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction,
238 : const nsString& aValue,
239 1645 : ValueCaseSensitivity aValueCaseSensitivity)
240 : : mValue(aValue),
241 : mNext(nullptr),
242 : mLowercaseAttr(nullptr),
243 : mCasedAttr(nullptr),
244 : mNameSpace(aNameSpace),
245 : mFunction(aFunction),
246 1645 : mValueCaseSensitivity(aValueCaseSensitivity)
247 : {
248 1645 : MOZ_COUNT_CTOR(nsAttrSelector);
249 :
250 3290 : nsAutoString lowercase;
251 1645 : nsContentUtils::ASCIIToLower(aAttr, lowercase);
252 :
253 1645 : mCasedAttr = NS_Atomize(aAttr);
254 1645 : mLowercaseAttr = NS_Atomize(lowercase);
255 1645 : }
256 :
257 0 : nsAttrSelector::nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr,
258 : nsIAtom* aCasedAttr, uint8_t aFunction,
259 : const nsString& aValue,
260 0 : ValueCaseSensitivity aValueCaseSensitivity)
261 : : mValue(aValue),
262 : mNext(nullptr),
263 : mLowercaseAttr(aLowercaseAttr),
264 : mCasedAttr(aCasedAttr),
265 : mNameSpace(aNameSpace),
266 : mFunction(aFunction),
267 0 : mValueCaseSensitivity(aValueCaseSensitivity)
268 : {
269 0 : MOZ_COUNT_CTOR(nsAttrSelector);
270 0 : }
271 :
272 : nsAttrSelector*
273 0 : nsAttrSelector::Clone(bool aDeep) const
274 : {
275 : nsAttrSelector *result =
276 0 : new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr,
277 0 : mFunction, mValue, mValueCaseSensitivity);
278 :
279 0 : if (aDeep)
280 0 : NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false));
281 :
282 0 : return result;
283 : }
284 :
285 0 : nsAttrSelector::~nsAttrSelector(void)
286 : {
287 0 : MOZ_COUNT_DTOR(nsAttrSelector);
288 :
289 0 : NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext);
290 0 : }
291 :
292 : size_t
293 0 : nsAttrSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
294 : {
295 0 : size_t n = 0;
296 0 : const nsAttrSelector* p = this;
297 0 : while (p) {
298 0 : n += aMallocSizeOf(p);
299 0 : n += p->mValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
300 0 : p = p->mNext;
301 : }
302 0 : return n;
303 : }
304 :
305 : // -- nsCSSSelector -------------------------------
306 :
307 9242 : nsCSSSelector::nsCSSSelector(void)
308 : : mLowercaseTag(nullptr),
309 : mCasedTag(nullptr),
310 : mIDList(nullptr),
311 : mClassList(nullptr),
312 : mPseudoClassList(nullptr),
313 : mAttrList(nullptr),
314 : mNegations(nullptr),
315 : mNext(nullptr),
316 : mNameSpace(kNameSpaceID_Unknown),
317 : mOperator(0),
318 9242 : mPseudoType(CSSPseudoElementType::NotPseudo)
319 : {
320 9242 : MOZ_COUNT_CTOR(nsCSSSelector);
321 9242 : }
322 :
323 : nsCSSSelector*
324 0 : nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
325 : {
326 0 : nsCSSSelector *result = new nsCSSSelector();
327 0 : if (!result)
328 0 : return nullptr;
329 :
330 0 : result->mNameSpace = mNameSpace;
331 0 : result->mLowercaseTag = mLowercaseTag;
332 0 : result->mCasedTag = mCasedTag;
333 0 : result->mOperator = mOperator;
334 0 : result->mPseudoType = mPseudoType;
335 :
336 0 : NS_IF_CLONE(mIDList);
337 0 : NS_IF_CLONE(mClassList);
338 0 : NS_IF_CLONE(mPseudoClassList);
339 0 : NS_IF_CLONE(mAttrList);
340 :
341 : // No need to worry about multiple levels of recursion since an
342 : // mNegations can't have an mNext.
343 0 : NS_ASSERTION(!mNegations || !mNegations->mNext,
344 : "mNegations can't have non-null mNext");
345 0 : if (aDeepNegations) {
346 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result,
347 : (true, false));
348 : }
349 :
350 0 : if (aDeepNext) {
351 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result,
352 : (false, true));
353 : }
354 :
355 0 : return result;
356 : }
357 :
358 90 : nsCSSSelector::~nsCSSSelector(void)
359 : {
360 45 : MOZ_COUNT_DTOR(nsCSSSelector);
361 45 : Reset();
362 : // No need to worry about multiple levels of recursion since an
363 : // mNegations can't have an mNext.
364 45 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext);
365 45 : }
366 :
367 45 : void nsCSSSelector::Reset(void)
368 : {
369 45 : mNameSpace = kNameSpaceID_Unknown;
370 45 : mLowercaseTag = nullptr;
371 45 : mCasedTag = nullptr;
372 90 : NS_IF_DELETE(mIDList);
373 90 : NS_IF_DELETE(mClassList);
374 90 : NS_IF_DELETE(mPseudoClassList);
375 90 : NS_IF_DELETE(mAttrList);
376 : // No need to worry about multiple levels of recursion since an
377 : // mNegations can't have an mNext.
378 45 : NS_ASSERTION(!mNegations || !mNegations->mNext,
379 : "mNegations can't have non-null mNext");
380 45 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations);
381 45 : mOperator = char16_t(0);
382 45 : }
383 :
384 8389 : void nsCSSSelector::SetNameSpace(int32_t aNameSpace)
385 : {
386 8389 : mNameSpace = aNameSpace;
387 8389 : }
388 :
389 3619 : void nsCSSSelector::SetTag(const nsString& aTag)
390 : {
391 3619 : if (aTag.IsEmpty()) {
392 0 : mLowercaseTag = mCasedTag = nullptr;
393 0 : return;
394 : }
395 :
396 3619 : mCasedTag = NS_Atomize(aTag);
397 :
398 7238 : nsAutoString lowercase;
399 3619 : nsContentUtils::ASCIIToLower(aTag, lowercase);
400 3619 : mLowercaseTag = NS_Atomize(lowercase);
401 : }
402 :
403 1963 : void nsCSSSelector::AddID(const nsString& aID)
404 : {
405 1963 : if (!aID.IsEmpty()) {
406 1963 : nsAtomList** list = &mIDList;
407 1963 : while (nullptr != *list) {
408 0 : list = &((*list)->mNext);
409 : }
410 1963 : *list = new nsAtomList(aID);
411 : }
412 1963 : }
413 :
414 2591 : void nsCSSSelector::AddClass(const nsString& aClass)
415 : {
416 2591 : if (!aClass.IsEmpty()) {
417 2591 : nsAtomList** list = &mClassList;
418 2891 : while (nullptr != *list) {
419 150 : list = &((*list)->mNext);
420 : }
421 2591 : *list = new nsAtomList(aClass);
422 : }
423 2591 : }
424 :
425 1588 : void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType)
426 : {
427 1588 : AddPseudoClassInternal(new nsPseudoClassList(aType));
428 1588 : }
429 :
430 176 : void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
431 : const char16_t* aString)
432 : {
433 176 : AddPseudoClassInternal(new nsPseudoClassList(aType, aString));
434 176 : }
435 :
436 1 : void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
437 : const int32_t* aIntPair)
438 : {
439 1 : AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair));
440 1 : }
441 :
442 162 : void nsCSSSelector::AddPseudoClass(CSSPseudoClassType aType,
443 : nsCSSSelectorList* aSelectorList)
444 : {
445 : // Take ownership of nsCSSSelectorList instead of copying.
446 162 : AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList));
447 162 : }
448 :
449 1927 : void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass)
450 : {
451 1927 : nsPseudoClassList** list = &mPseudoClassList;
452 2647 : while (nullptr != *list) {
453 360 : list = &((*list)->mNext);
454 : }
455 1927 : *list = aPseudoClass;
456 1927 : }
457 :
458 737 : void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr)
459 : {
460 737 : if (!aAttr.IsEmpty()) {
461 737 : nsAttrSelector** list = &mAttrList;
462 841 : while (nullptr != *list) {
463 52 : list = &((*list)->mNext);
464 : }
465 737 : *list = new nsAttrSelector(aNameSpace, aAttr);
466 : }
467 737 : }
468 :
469 1645 : void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc,
470 : const nsString& aValue,
471 : nsAttrSelector::ValueCaseSensitivity aCaseSensitivity)
472 : {
473 1645 : if (!aAttr.IsEmpty()) {
474 1645 : nsAttrSelector** list = &mAttrList;
475 1927 : while (nullptr != *list) {
476 141 : list = &((*list)->mNext);
477 : }
478 1645 : *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitivity);
479 : }
480 1645 : }
481 :
482 3067 : void nsCSSSelector::SetOperator(char16_t aOperator)
483 : {
484 3067 : mOperator = aOperator;
485 3067 : }
486 :
487 9105 : int32_t nsCSSSelector::CalcWeightWithoutNegations() const
488 : {
489 9105 : int32_t weight = 0;
490 :
491 : #ifdef MOZ_XUL
492 9105 : MOZ_ASSERT(!(IsPseudoElement() &&
493 : PseudoType() != CSSPseudoElementType::XULTree &&
494 : mClassList),
495 : "If non-XUL-tree pseudo-elements can have class selectors "
496 : "after them, specificity calculation must be updated");
497 : #else
498 : MOZ_ASSERT(!(IsPseudoElement() && mClassList),
499 : "If pseudo-elements can have class selectors "
500 : "after them, specificity calculation must be updated");
501 : #endif
502 9105 : MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)),
503 : "If pseudo-elements can have id or attribute selectors "
504 : "after them, specificity calculation must be updated");
505 :
506 9105 : if (nullptr != mCasedTag) {
507 3619 : weight += 0x000001;
508 : }
509 9105 : nsAtomList* list = mIDList;
510 13031 : while (nullptr != list) {
511 1963 : weight += 0x010000;
512 1963 : list = list->mNext;
513 : }
514 9105 : list = mClassList;
515 : #ifdef MOZ_XUL
516 : // XUL tree pseudo-elements abuse mClassList to store some private
517 : // data; ignore that.
518 9105 : if (PseudoType() == CSSPseudoElementType::XULTree) {
519 70 : list = nullptr;
520 : }
521 : #endif
522 14099 : while (nullptr != list) {
523 2497 : weight += 0x000100;
524 2497 : list = list->mNext;
525 : }
526 : // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't
527 : // really a pseudo-class. In order to handle :-moz-any() correctly,
528 : // we need to compute specificity after we match, based on which
529 : // option we matched with (and thus also need to try the
530 : // highest-specificity options first).
531 9105 : nsPseudoClassList *plist = mPseudoClassList;
532 12959 : while (nullptr != plist) {
533 1927 : weight += 0x000100;
534 1927 : plist = plist->mNext;
535 : }
536 9105 : nsAttrSelector* attr = mAttrList;
537 13869 : while (nullptr != attr) {
538 2382 : weight += 0x000100;
539 2382 : attr = attr->mNext;
540 : }
541 9105 : return weight;
542 : }
543 :
544 8531 : int32_t nsCSSSelector::CalcWeight() const
545 : {
546 : // Loop over this selector and all its negations.
547 8531 : int32_t weight = 0;
548 17636 : for (const nsCSSSelector *n = this; n; n = n->mNegations) {
549 9105 : weight += n->CalcWeightWithoutNegations();
550 : }
551 8531 : return weight;
552 : }
553 :
554 : //
555 : // Builds the textual representation of a selector. Called by DOM 2 CSS
556 : // StyleRule:selectorText
557 : //
558 : void
559 0 : nsCSSSelector::ToString(nsAString& aString, CSSStyleSheet* aSheet,
560 : bool aAppend) const
561 : {
562 0 : if (!aAppend)
563 0 : aString.Truncate();
564 :
565 : // selectors are linked from right-to-left, so the next selector in
566 : // the linked list actually precedes this one in the resulting string
567 0 : AutoTArray<const nsCSSSelector*, 8> stack;
568 0 : for (const nsCSSSelector *s = this; s; s = s->mNext) {
569 0 : stack.AppendElement(s);
570 : }
571 :
572 0 : while (!stack.IsEmpty()) {
573 0 : uint32_t index = stack.Length() - 1;
574 0 : const nsCSSSelector *s = stack.ElementAt(index);
575 0 : stack.RemoveElementAt(index);
576 :
577 0 : s->AppendToStringWithoutCombinators(aString, aSheet, false);
578 :
579 : // Append the combinator, if needed.
580 0 : if (!stack.IsEmpty()) {
581 0 : const nsCSSSelector *next = stack.ElementAt(index - 1);
582 0 : char16_t oper = s->mOperator;
583 0 : if (next->IsPseudoElement()) {
584 0 : NS_ASSERTION(oper == char16_t(':'),
585 : "improperly chained pseudo element");
586 : } else {
587 0 : NS_ASSERTION(oper != char16_t(0),
588 : "compound selector without combinator");
589 :
590 0 : aString.Append(char16_t(' '));
591 0 : if (oper != char16_t(' ')) {
592 0 : aString.Append(oper);
593 0 : aString.Append(char16_t(' '));
594 : }
595 : }
596 : }
597 : }
598 0 : }
599 :
600 : void
601 0 : nsCSSSelector::AppendToStringWithoutCombinators(
602 : nsAString& aString,
603 : CSSStyleSheet* aSheet,
604 : bool aUseStandardNamespacePrefixes) const
605 : {
606 0 : AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false,
607 0 : aUseStandardNamespacePrefixes);
608 :
609 0 : for (const nsCSSSelector* negation = mNegations; negation;
610 0 : negation = negation->mNegations) {
611 0 : aString.AppendLiteral(":not(");
612 0 : negation->AppendToStringWithoutCombinatorsOrNegations(
613 0 : aString, aSheet, true, aUseStandardNamespacePrefixes);
614 0 : aString.Append(char16_t(')'));
615 : }
616 0 : }
617 :
618 : #ifdef DEBUG
619 : nsCString
620 0 : nsCSSSelector::RestrictedSelectorToString() const
621 : {
622 0 : MOZ_ASSERT(IsRestrictedSelector());
623 :
624 0 : nsString result;
625 0 : AppendToStringWithoutCombinators(result, nullptr, true);
626 0 : return NS_ConvertUTF16toUTF8(result);
627 : }
628 :
629 : static bool
630 0 : AppendStandardNamespacePrefixToString(nsAString& aString, int32_t aNameSpace)
631 : {
632 0 : if (aNameSpace == kNameSpaceID_Unknown) {
633 : // Wildcard namespace; no prefix to write.
634 0 : return false;
635 : }
636 0 : switch (aNameSpace) {
637 : case kNameSpaceID_None:
638 0 : break;
639 : case kNameSpaceID_XML:
640 0 : aString.AppendLiteral("xml");
641 0 : break;
642 : case kNameSpaceID_XHTML:
643 0 : aString.AppendLiteral("html");
644 0 : break;
645 : case kNameSpaceID_XLink:
646 0 : aString.AppendLiteral("xlink");
647 0 : break;
648 : case kNameSpaceID_XSLT:
649 0 : aString.AppendLiteral("xsl");
650 0 : break;
651 : case kNameSpaceID_XBL:
652 0 : aString.AppendLiteral("xbl");
653 0 : break;
654 : case kNameSpaceID_MathML:
655 0 : aString.AppendLiteral("math");
656 0 : break;
657 : case kNameSpaceID_RDF:
658 0 : aString.AppendLiteral("rdf");
659 0 : break;
660 : case kNameSpaceID_XUL:
661 0 : aString.AppendLiteral("xul");
662 0 : break;
663 : case kNameSpaceID_SVG:
664 0 : aString.AppendLiteral("svg");
665 0 : break;
666 : default:
667 0 : aString.AppendLiteral("ns");
668 0 : aString.AppendInt(aNameSpace);
669 0 : break;
670 : }
671 0 : return true;
672 : }
673 : #endif
674 :
675 : void
676 0 : nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
677 : (nsAString& aString, CSSStyleSheet* aSheet,
678 : bool aIsNegated,
679 : bool aUseStandardNamespacePrefixes) const
680 : {
681 0 : nsAutoString temp;
682 0 : bool isPseudoElement = IsPseudoElement();
683 :
684 : // For non-pseudo-element selectors or for lone pseudo-elements, deal with
685 : // namespace prefixes.
686 0 : bool wroteNamespace = false;
687 0 : if (!isPseudoElement || !mNext) {
688 : // append the namespace prefix if needed
689 0 : nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr;
690 :
691 : // sheetNS is non-null if and only if we had an @namespace rule. If it's
692 : // null, that means that the only namespaces we could have are the
693 : // wildcard namespace (which can be implicit in this case) and the "none"
694 : // namespace, which then needs to be explicitly specified.
695 0 : if (aUseStandardNamespacePrefixes) {
696 : #ifdef DEBUG
697 : // We have no sheet to look up prefix information from. This is
698 : // only for debugging, so use some "standard" prefixes that
699 : // are recognizable.
700 : wroteNamespace =
701 0 : AppendStandardNamespacePrefixToString(aString, mNameSpace);
702 0 : if (wroteNamespace) {
703 0 : aString.Append(char16_t('|'));
704 : }
705 : #endif
706 0 : } else if (!sheetNS) {
707 0 : NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
708 : mNameSpace == kNameSpaceID_None,
709 : "How did we get this namespace?");
710 0 : if (mNameSpace == kNameSpaceID_None) {
711 0 : aString.Append(char16_t('|'));
712 0 : wroteNamespace = true;
713 : }
714 0 : } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) {
715 : // We have the default namespace (possibly including the wildcard
716 : // namespace). Do nothing.
717 0 : NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
718 : CanBeNamespaced(aIsNegated),
719 : "How did we end up with this namespace?");
720 0 : } else if (mNameSpace == kNameSpaceID_None) {
721 0 : NS_ASSERTION(CanBeNamespaced(aIsNegated),
722 : "How did we end up with this namespace?");
723 0 : aString.Append(char16_t('|'));
724 0 : wroteNamespace = true;
725 0 : } else if (mNameSpace != kNameSpaceID_Unknown) {
726 0 : NS_ASSERTION(CanBeNamespaced(aIsNegated),
727 : "How did we end up with this namespace?");
728 0 : nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
729 0 : NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
730 : "without a prefix?");
731 0 : nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom),
732 0 : aString);
733 0 : aString.Append(char16_t('|'));
734 0 : wroteNamespace = true;
735 : } else {
736 : // A selector for an element in any namespace, while the default
737 : // namespace is something else. :not() is special in that the default
738 : // namespace is not implied for non-type selectors, so if this is a
739 : // negated non-type selector we don't need to output an explicit wildcard
740 : // namespace here, since those default to a wildcard namespace.
741 0 : if (CanBeNamespaced(aIsNegated)) {
742 0 : aString.AppendLiteral("*|");
743 0 : wroteNamespace = true;
744 : }
745 : }
746 : }
747 :
748 0 : if (!mLowercaseTag) {
749 : // Universal selector: avoid writing the universal selector when we
750 : // can avoid it, especially since we're required to avoid it for the
751 : // inside of :not()
752 0 : if (wroteNamespace ||
753 0 : (!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
754 0 : (aIsNegated || !mNegations))) {
755 0 : aString.Append(char16_t('*'));
756 : }
757 : } else {
758 : // Append the tag name
759 0 : nsAutoString tag;
760 0 : (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
761 0 : if (isPseudoElement) {
762 0 : if (!mNext) {
763 : // Lone pseudo-element selector -- toss in a wildcard type selector
764 : // XXXldb Why?
765 0 : aString.Append(char16_t('*'));
766 : }
767 : // While our atoms use one colon, most pseudo-elements require two
768 : // colons (those not in CSS level 2) and all pseudo-elements allow
769 : // two colons. So serialize to the non-deprecated two colon syntax.
770 0 : aString.Append(char16_t(':'));
771 : // This should not be escaped since (a) the pseudo-element string
772 : // has a ":" that can't be escaped and (b) all pseudo-elements at
773 : // this point are known, and therefore we know they don't need
774 : // escaping.
775 0 : aString.Append(tag);
776 : } else {
777 0 : nsStyleUtil::AppendEscapedCSSIdent(tag, aString);
778 : }
779 : }
780 :
781 : // Append the id, if there is one
782 0 : if (mIDList) {
783 0 : nsAtomList* list = mIDList;
784 0 : while (list != nullptr) {
785 0 : list->mAtom->ToString(temp);
786 0 : aString.Append(char16_t('#'));
787 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
788 0 : list = list->mNext;
789 : }
790 : }
791 :
792 : // Append each class in the linked list
793 0 : if (mClassList) {
794 0 : if (isPseudoElement) {
795 : #ifdef MOZ_XUL
796 0 : MOZ_ASSERT(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag),
797 : "must be tree pseudo-element");
798 :
799 0 : aString.Append(char16_t('('));
800 0 : for (nsAtomList* list = mClassList; list; list = list->mNext) {
801 0 : nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString);
802 0 : aString.Append(char16_t(','));
803 : }
804 : // replace the final comma with a close-paren
805 0 : aString.Replace(aString.Length() - 1, 1, char16_t(')'));
806 : #else
807 : NS_ERROR("Can't happen");
808 : #endif
809 : } else {
810 0 : nsAtomList* list = mClassList;
811 0 : while (list != nullptr) {
812 0 : list->mAtom->ToString(temp);
813 0 : aString.Append(char16_t('.'));
814 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
815 0 : list = list->mNext;
816 : }
817 : }
818 : }
819 :
820 : // Append each attribute selector in the linked list
821 0 : if (mAttrList) {
822 0 : nsAttrSelector* list = mAttrList;
823 0 : while (list != nullptr) {
824 0 : aString.Append(char16_t('['));
825 : // Append the namespace prefix
826 0 : if (list->mNameSpace == kNameSpaceID_Unknown) {
827 0 : aString.Append(char16_t('*'));
828 0 : aString.Append(char16_t('|'));
829 0 : } else if (list->mNameSpace != kNameSpaceID_None) {
830 0 : if (aUseStandardNamespacePrefixes) {
831 : #ifdef DEBUG
832 0 : AppendStandardNamespacePrefixToString(aString, list->mNameSpace);
833 0 : aString.Append(char16_t('|'));
834 : #endif
835 0 : } else if (aSheet) {
836 0 : nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
837 0 : nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
838 : // Default namespaces don't apply to attribute selectors, so
839 : // we must have a useful prefix.
840 0 : NS_ASSERTION(prefixAtom,
841 : "How did we end up with a namespace if the prefix "
842 : "is unknown?");
843 0 : nsAutoString prefix;
844 0 : prefixAtom->ToString(prefix);
845 0 : nsStyleUtil::AppendEscapedCSSIdent(prefix, aString);
846 0 : aString.Append(char16_t('|'));
847 : }
848 : }
849 : // Append the attribute name
850 0 : list->mCasedAttr->ToString(temp);
851 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
852 :
853 0 : if (list->mFunction != NS_ATTR_FUNC_SET) {
854 : // Append the function
855 0 : if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
856 0 : aString.Append(char16_t('~'));
857 0 : else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
858 0 : aString.Append(char16_t('|'));
859 0 : else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
860 0 : aString.Append(char16_t('^'));
861 0 : else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
862 0 : aString.Append(char16_t('$'));
863 0 : else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
864 0 : aString.Append(char16_t('*'));
865 :
866 0 : aString.Append(char16_t('='));
867 :
868 : // Append the value
869 0 : nsStyleUtil::AppendEscapedCSSString(list->mValue, aString);
870 :
871 0 : if (list->mValueCaseSensitivity ==
872 : nsAttrSelector::ValueCaseSensitivity::CaseInsensitive) {
873 0 : aString.Append(NS_LITERAL_STRING(" i"));
874 : }
875 : }
876 :
877 0 : aString.Append(char16_t(']'));
878 :
879 0 : list = list->mNext;
880 : }
881 : }
882 :
883 : // Append each pseudo-class in the linked list
884 0 : for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) {
885 0 : nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp);
886 : // This should not be escaped since (a) the pseudo-class string
887 : // has a ":" that can't be escaped and (b) all pseudo-classes at
888 : // this point are known, and therefore we know they don't need
889 : // escaping.
890 0 : aString.Append(temp);
891 0 : if (list->u.mMemory) {
892 0 : aString.Append(char16_t('('));
893 0 : if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
894 : nsStyleUtil::AppendEscapedCSSIdent(
895 0 : nsDependentString(list->u.mString), aString);
896 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) {
897 0 : int32_t a = list->u.mNumbers[0],
898 0 : b = list->u.mNumbers[1];
899 0 : temp.Truncate();
900 0 : if (a != 0) {
901 0 : if (a == -1) {
902 0 : temp.Append(char16_t('-'));
903 0 : } else if (a != 1) {
904 0 : temp.AppendInt(a);
905 : }
906 0 : temp.Append(char16_t('n'));
907 : }
908 0 : if (b != 0 || a == 0) {
909 0 : if (b >= 0 && a != 0) // check a != 0 for whether we printed above
910 0 : temp.Append(char16_t('+'));
911 0 : temp.AppendInt(b);
912 : }
913 0 : aString.Append(temp);
914 : } else {
915 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType),
916 : "unexpected pseudo-class");
917 0 : nsString tmp;
918 0 : list->u.mSelectors->ToString(tmp, aSheet);
919 0 : aString.Append(tmp);
920 : }
921 0 : aString.Append(char16_t(')'));
922 : }
923 : }
924 0 : }
925 :
926 : bool
927 0 : nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
928 : {
929 0 : return !aIsNegated ||
930 0 : (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
931 : }
932 :
933 : size_t
934 18 : nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
935 : {
936 18 : size_t n = 0;
937 18 : const nsCSSSelector* s = this;
938 58 : while (s) {
939 20 : n += aMallocSizeOf(s);
940 :
941 : #define MEASURE(x) n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
942 :
943 20 : MEASURE(s->mIDList);
944 20 : MEASURE(s->mClassList);
945 20 : MEASURE(s->mPseudoClassList);
946 20 : MEASURE(s->mNegations);
947 20 : MEASURE(s->mAttrList);
948 :
949 : // The following members aren't measured:
950 : // - s->mLowercaseTag, because it's an atom and therefore shared
951 : // - s->mCasedTag, because it's an atom and therefore shared
952 :
953 20 : s = s->mNext;
954 : }
955 18 : return n;
956 : }
957 :
958 : // -- nsCSSSelectorList -------------------------------
959 :
960 5556 : nsCSSSelectorList::nsCSSSelectorList(void)
961 : : mSelectors(nullptr),
962 : mWeight(0),
963 5556 : mNext(nullptr)
964 : {
965 5556 : MOZ_COUNT_CTOR(nsCSSSelectorList);
966 5556 : }
967 :
968 0 : nsCSSSelectorList::~nsCSSSelectorList()
969 : {
970 0 : MOZ_COUNT_DTOR(nsCSSSelectorList);
971 0 : delete mSelectors;
972 0 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext);
973 0 : }
974 :
975 : nsCSSSelector*
976 8623 : nsCSSSelectorList::AddSelector(char16_t aOperator)
977 : {
978 8623 : nsCSSSelector* newSel = new nsCSSSelector();
979 :
980 8623 : if (mSelectors) {
981 3067 : NS_ASSERTION(aOperator != char16_t(0), "chaining without combinator");
982 3067 : mSelectors->SetOperator(aOperator);
983 : } else {
984 5556 : NS_ASSERTION(aOperator == char16_t(0), "combinator without chaining");
985 : }
986 :
987 8623 : newSel->mNext = mSelectors;
988 8623 : mSelectors = newSel;
989 8623 : return newSel;
990 : }
991 :
992 : void
993 0 : nsCSSSelectorList::RemoveRightmostSelector()
994 : {
995 0 : nsCSSSelector* current = mSelectors;
996 0 : mSelectors = mSelectors->mNext;
997 0 : MOZ_ASSERT(mSelectors,
998 : "Rightmost selector has been removed, but now "
999 : "mSelectors is null");
1000 0 : mSelectors->SetOperator(char16_t(0));
1001 :
1002 : // Make sure that deleting current won't delete the whole list.
1003 0 : current->mNext = nullptr;
1004 0 : delete current;
1005 0 : }
1006 :
1007 : void
1008 0 : nsCSSSelectorList::ToString(nsAString& aResult, CSSStyleSheet* aSheet)
1009 : {
1010 0 : aResult.Truncate();
1011 0 : nsCSSSelectorList *p = this;
1012 : for (;;) {
1013 0 : p->mSelectors->ToString(aResult, aSheet, true);
1014 0 : p = p->mNext;
1015 0 : if (!p)
1016 0 : break;
1017 0 : aResult.AppendLiteral(", ");
1018 : }
1019 0 : }
1020 :
1021 : nsCSSSelectorList*
1022 0 : nsCSSSelectorList::Clone(bool aDeep) const
1023 : {
1024 0 : nsCSSSelectorList *result = new nsCSSSelectorList();
1025 0 : result->mWeight = mWeight;
1026 0 : NS_IF_CLONE(mSelectors);
1027 :
1028 0 : if (aDeep) {
1029 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
1030 : (false));
1031 : }
1032 0 : return result;
1033 : }
1034 :
1035 : size_t
1036 14 : nsCSSSelectorList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1037 : {
1038 14 : size_t n = 0;
1039 14 : const nsCSSSelectorList* s = this;
1040 44 : while (s) {
1041 15 : n += aMallocSizeOf(s);
1042 15 : n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
1043 15 : s = s->mNext;
1044 : }
1045 14 : return n;
1046 : }
1047 :
1048 : // --------------------------------------------------------
1049 :
1050 : class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
1051 : {
1052 : protected:
1053 : // Needs to be protected so we can use NS_IMPL_ADDREF_USING_AGGREGATOR.
1054 : virtual ~DOMCSSDeclarationImpl(void);
1055 :
1056 : // But we need to allow UniquePtr to delete us.
1057 : friend class mozilla::DefaultDelete<DOMCSSDeclarationImpl>;
1058 :
1059 : public:
1060 : explicit DOMCSSDeclarationImpl(css::StyleRule *aRule);
1061 :
1062 : NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) override;
1063 : virtual DeclarationBlock* GetCSSDeclaration(Operation aOperation) override;
1064 : virtual nsresult SetCSSDeclaration(DeclarationBlock* aDecl) override;
1065 : virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) override;
1066 : nsDOMCSSDeclaration::ServoCSSParsingEnvironment GetServoCSSParsingEnvironment() const final;
1067 : virtual nsIDocument* DocToUpdate() override;
1068 :
1069 : // Override |AddRef| and |Release| for being owned by StyleRule. Also, we
1070 : // need to forward QI for cycle collection things to StyleRule.
1071 : NS_DECL_ISUPPORTS_INHERITED
1072 :
1073 0 : virtual nsINode *GetParentObject() override
1074 : {
1075 0 : return mRule ? mRule->GetDocument() : nullptr;
1076 : }
1077 :
1078 : protected:
1079 : // This reference is not reference-counted. The rule object owns us and we go
1080 : // away when it does.
1081 : css::StyleRule *mRule;
1082 : };
1083 :
1084 0 : DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
1085 0 : : mRule(aRule)
1086 : {
1087 0 : }
1088 :
1089 0 : DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
1090 : {
1091 0 : }
1092 :
1093 0 : NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, mRule)
1094 0 : NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, mRule)
1095 :
1096 0 : NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl)
1097 0 : NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
1098 : // We forward the cycle collection interfaces to mRule, which is
1099 : // never null.
1100 0 : if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) ||
1101 0 : aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) {
1102 0 : return mRule->QueryInterface(aIID, aInstancePtr);
1103 : }
1104 : else
1105 0 : NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration)
1106 :
1107 : DeclarationBlock*
1108 0 : DOMCSSDeclarationImpl::GetCSSDeclaration(Operation aOperation)
1109 : {
1110 0 : if (aOperation != eOperation_Read) {
1111 0 : RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
1112 0 : if (sheet) {
1113 0 : sheet->WillDirty();
1114 : }
1115 : }
1116 0 : return mRule->GetDeclaration();
1117 : }
1118 :
1119 : void
1120 0 : DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
1121 : {
1122 0 : GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
1123 0 : }
1124 :
1125 : nsDOMCSSDeclaration::ServoCSSParsingEnvironment
1126 0 : DOMCSSDeclarationImpl::GetServoCSSParsingEnvironment() const
1127 : {
1128 0 : MOZ_CRASH("GetURLData shouldn't be calling on a Gecko rule");
1129 : }
1130 :
1131 : NS_IMETHODIMP
1132 0 : DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
1133 : {
1134 0 : NS_ENSURE_ARG_POINTER(aParent);
1135 :
1136 0 : NS_IF_ADDREF(*aParent = mRule);
1137 0 : return NS_OK;
1138 : }
1139 :
1140 : nsresult
1141 0 : DOMCSSDeclarationImpl::SetCSSDeclaration(DeclarationBlock* aDecl)
1142 : {
1143 0 : NS_PRECONDITION(mRule,
1144 : "can only be called when |GetCSSDeclaration| returned a declaration");
1145 :
1146 0 : nsCOMPtr<nsIDocument> doc;
1147 0 : RefPtr<CSSStyleSheet> sheet = mRule->GetStyleSheet();
1148 0 : if (sheet) {
1149 0 : doc = sheet->GetAssociatedDocument();
1150 : }
1151 :
1152 0 : mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true);
1153 :
1154 0 : mRule->SetDeclaration(aDecl->AsGecko());
1155 :
1156 0 : if (sheet) {
1157 0 : sheet->DidDirty();
1158 : }
1159 :
1160 0 : if (doc) {
1161 0 : doc->StyleRuleChanged(sheet, mRule);
1162 : }
1163 0 : return NS_OK;
1164 : }
1165 :
1166 : nsIDocument*
1167 0 : DOMCSSDeclarationImpl::DocToUpdate()
1168 : {
1169 0 : return nullptr;
1170 : }
1171 :
1172 : // -- StyleRule ------------------------------------
1173 :
1174 : namespace mozilla {
1175 : namespace css {
1176 :
1177 : uint16_t
1178 0 : StyleRule::Type() const
1179 : {
1180 0 : return nsIDOMCSSRule::STYLE_RULE;
1181 : }
1182 :
1183 : NS_IMETHODIMP
1184 0 : StyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
1185 : {
1186 0 : NS_ADDREF(*aStyle = Style());
1187 0 : return NS_OK;
1188 : }
1189 :
1190 : nsICSSDeclaration*
1191 0 : StyleRule::Style()
1192 : {
1193 0 : if (!mDOMDeclaration) {
1194 0 : mDOMDeclaration.reset(new DOMCSSDeclarationImpl(this));
1195 : }
1196 0 : return mDOMDeclaration.get();
1197 : }
1198 :
1199 : NS_IMETHODIMP
1200 0 : StyleRule::GetCSSStyleRule(BindingStyleRule **aResult)
1201 : {
1202 0 : *aResult = this;
1203 0 : NS_ADDREF(*aResult);
1204 0 : return NS_OK;
1205 : }
1206 :
1207 2933 : StyleRule::StyleRule(nsCSSSelectorList* aSelector,
1208 : Declaration* aDeclaration,
1209 : uint32_t aLineNumber,
1210 2933 : uint32_t aColumnNumber)
1211 : : BindingStyleRule(aLineNumber, aColumnNumber),
1212 : mSelector(aSelector),
1213 2933 : mDeclaration(aDeclaration)
1214 : {
1215 2933 : NS_PRECONDITION(aDeclaration, "must have a declaration");
1216 :
1217 2933 : mDeclaration->SetOwningRule(this);
1218 2933 : }
1219 :
1220 : // for |Clone|
1221 0 : StyleRule::StyleRule(const StyleRule& aCopy)
1222 : : BindingStyleRule(aCopy),
1223 0 : mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr),
1224 0 : mDeclaration(new Declaration(*aCopy.mDeclaration))
1225 : {
1226 0 : mDeclaration->SetOwningRule(this);
1227 : // rest is constructed lazily on existing data
1228 0 : }
1229 :
1230 48 : StyleRule::~StyleRule()
1231 : {
1232 16 : delete mSelector;
1233 16 : DropReferences();
1234 48 : }
1235 :
1236 : void
1237 16 : StyleRule::DropReferences()
1238 : {
1239 16 : if (mDeclaration) {
1240 16 : mDeclaration->SetOwningRule(nullptr);
1241 : }
1242 16 : }
1243 :
1244 : // QueryInterface implementation for StyleRule
1245 3061 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(StyleRule)
1246 64 : if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
1247 0 : *aInstancePtr = this;
1248 0 : NS_ADDREF_THIS();
1249 0 : return NS_OK;
1250 : }
1251 : else
1252 64 : NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
1253 64 : NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
1254 64 : NS_INTERFACE_MAP_END_INHERITING(Rule)
1255 :
1256 5850 : NS_IMPL_ADDREF_INHERITED(StyleRule, Rule)
1257 2933 : NS_IMPL_RELEASE_INHERITED(StyleRule, Rule)
1258 :
1259 : NS_IMPL_CYCLE_COLLECTION_CLASS(StyleRule)
1260 16 : NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(StyleRule, Rule)
1261 : // Keep this in sync with IsCCLeaf.
1262 : // Trace the wrapper for our declaration. This just expands out
1263 : // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use
1264 : // directly because the wrapper is on the declaration, not on us.
1265 16 : if (tmp->mDOMDeclaration) {
1266 0 : tmp->mDOMDeclaration->TraceWrapper(aCallbacks, aClosure);
1267 : }
1268 16 : NS_IMPL_CYCLE_COLLECTION_TRACE_END
1269 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(StyleRule, Rule)
1270 : // Unlink the wrapper for our declaraton. This just expands out
1271 : // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use
1272 : // directly because the wrapper is on the declaration, not on us.
1273 0 : if (tmp->mDOMDeclaration) {
1274 0 : tmp->mDOMDeclaration->ReleaseWrapper(static_cast<nsISupports*>(p));
1275 : }
1276 0 : tmp->DropReferences();
1277 0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
1278 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(StyleRule, Rule)
1279 : // Keep this in sync with IsCCLeaf.
1280 0 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
1281 :
1282 : bool
1283 0 : StyleRule::IsCCLeaf() const
1284 : {
1285 0 : if (!Rule::IsCCLeaf()) {
1286 0 : return false;
1287 : }
1288 :
1289 0 : return !mDOMDeclaration || !mDOMDeclaration->PreservingWrapper();
1290 : }
1291 :
1292 : /* virtual */ int32_t
1293 11579 : StyleRule::GetType() const
1294 : {
1295 11579 : return Rule::STYLE_RULE;
1296 : }
1297 :
1298 : /* virtual */ already_AddRefed<Rule>
1299 0 : StyleRule::Clone() const
1300 : {
1301 0 : RefPtr<Rule> clone = new StyleRule(*this);
1302 0 : return clone.forget();
1303 : }
1304 :
1305 : void
1306 0 : StyleRule::SetDeclaration(Declaration* aDecl)
1307 : {
1308 0 : if (aDecl == mDeclaration) {
1309 0 : return;
1310 : }
1311 0 : mDeclaration->SetOwningRule(nullptr);
1312 0 : mDeclaration = aDecl;
1313 0 : mDeclaration->SetOwningRule(this);
1314 : }
1315 :
1316 : #ifdef DEBUG
1317 : /* virtual */ void
1318 0 : StyleRule::List(FILE* out, int32_t aIndent) const
1319 : {
1320 0 : nsAutoCString str;
1321 : // Indent
1322 0 : for (int32_t index = aIndent; --index >= 0; ) {
1323 0 : str.AppendLiteral(" ");
1324 : }
1325 :
1326 0 : if (mSelector) {
1327 0 : nsAutoString buffer;
1328 0 : mSelector->ToString(buffer, GetStyleSheet());
1329 0 : AppendUTF16toUTF8(buffer, str);
1330 0 : str.Append(' ');
1331 : }
1332 :
1333 0 : if (nullptr != mDeclaration) {
1334 0 : nsAutoString buffer;
1335 0 : str.AppendLiteral("{ ");
1336 0 : mDeclaration->ToString(buffer);
1337 0 : AppendUTF16toUTF8(buffer, str);
1338 0 : str.Append('}');
1339 0 : CSSStyleSheet* sheet = GetStyleSheet();
1340 0 : if (sheet) {
1341 0 : nsIURI* uri = sheet->GetSheetURI();
1342 0 : if (uri) {
1343 0 : str.Append(" /* ");
1344 0 : str.Append(uri->GetSpecOrDefault());
1345 0 : str.Append(':');
1346 0 : str.AppendInt(mLineNumber);
1347 0 : str.Append(" */");
1348 : }
1349 : }
1350 : }
1351 : else {
1352 0 : str.AppendLiteral("{ null declaration }");
1353 : }
1354 0 : str.Append('\n');
1355 0 : fprintf_stderr(out, "%s", str.get());
1356 0 : }
1357 : #endif
1358 :
1359 : void
1360 0 : StyleRule::GetCssTextImpl(nsAString& aCssText) const
1361 : {
1362 0 : if (mSelector) {
1363 0 : mSelector->ToString(aCssText, GetStyleSheet());
1364 0 : aCssText.Append(char16_t(' '));
1365 : }
1366 0 : aCssText.Append(char16_t('{'));
1367 0 : aCssText.Append(char16_t(' '));
1368 0 : if (mDeclaration)
1369 : {
1370 0 : nsAutoString tempString;
1371 0 : mDeclaration->ToString( tempString );
1372 0 : aCssText.Append( tempString );
1373 : }
1374 0 : aCssText.Append(char16_t(' '));
1375 0 : aCssText.Append(char16_t('}'));
1376 0 : }
1377 :
1378 : NS_IMETHODIMP
1379 0 : StyleRule::GetSelectorText(nsAString& aSelectorText)
1380 : {
1381 0 : if (mSelector)
1382 0 : mSelector->ToString(aSelectorText, GetStyleSheet());
1383 : else
1384 0 : aSelectorText.Truncate();
1385 0 : return NS_OK;
1386 : }
1387 :
1388 : NS_IMETHODIMP
1389 0 : StyleRule::SetSelectorText(const nsAString& aSelectorText)
1390 : {
1391 : // XXX TBI - get a parser and re-parse the selectors,
1392 : // XXX then need to re-compute the cascade
1393 : // XXX and dirty sheet
1394 0 : return NS_OK;
1395 : }
1396 :
1397 : /* virtual */ size_t
1398 14 : StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const
1399 : {
1400 14 : size_t n = aMallocSizeOf(this);
1401 14 : n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
1402 14 : n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
1403 :
1404 : // Measurement of the following members may be added later if DMD finds it is
1405 : // worthwhile:
1406 : // - mDOMRule;
1407 :
1408 14 : return n;
1409 : }
1410 :
1411 : nsCSSSelectorList*
1412 0 : StyleRule::GetSelectorAtIndex(uint32_t aIndex, ErrorResult& rv)
1413 : {
1414 :
1415 0 : for (nsCSSSelectorList* sel = mSelector; sel;
1416 0 : sel = sel->mNext, --aIndex) {
1417 0 : if (aIndex == 0) {
1418 0 : return sel;
1419 : }
1420 : }
1421 :
1422 : // Ran out of selectors
1423 0 : rv.Throw(NS_ERROR_INVALID_ARG);
1424 0 : return nullptr;
1425 : }
1426 :
1427 : uint32_t
1428 0 : StyleRule::GetSelectorCount()
1429 : {
1430 0 : uint32_t count = 0;
1431 0 : for (nsCSSSelectorList* sel = mSelector; sel; sel = sel->mNext) {
1432 0 : ++count;
1433 : }
1434 0 : return count;
1435 : }
1436 :
1437 : nsresult
1438 0 : StyleRule::GetSelectorText(uint32_t aSelectorIndex, nsAString& aText)
1439 : {
1440 0 : ErrorResult rv;
1441 0 : nsCSSSelectorList* sel = GetSelectorAtIndex(aSelectorIndex, rv);
1442 0 : if (rv.Failed()) {
1443 0 : return rv.StealNSResult();
1444 : }
1445 :
1446 0 : sel->mSelectors->ToString(aText, GetStyleSheet(), false);
1447 :
1448 0 : return NS_OK;
1449 : }
1450 :
1451 : nsresult
1452 0 : StyleRule::GetSpecificity(uint32_t aSelectorIndex, uint64_t* aSpecificity)
1453 : {
1454 0 : ErrorResult rv;
1455 0 : nsCSSSelectorList* sel = GetSelectorAtIndex(aSelectorIndex, rv);
1456 0 : if (rv.Failed()) {
1457 0 : return rv.StealNSResult();
1458 : }
1459 :
1460 0 : *aSpecificity = sel->mWeight;
1461 0 : return NS_OK;
1462 : }
1463 :
1464 : nsresult
1465 0 : StyleRule::SelectorMatchesElement(Element* aElement,
1466 : uint32_t aSelectorIndex,
1467 : const nsAString& aPseudo,
1468 : bool* aMatches)
1469 : {
1470 0 : ErrorResult rv;
1471 0 : nsCSSSelectorList* tail = GetSelectorAtIndex(aSelectorIndex, rv);
1472 0 : if (rv.Failed()) {
1473 0 : return rv.StealNSResult();
1474 : }
1475 :
1476 : // We want just the one list item, not the whole list tail
1477 0 : nsAutoPtr<nsCSSSelectorList> sel(tail->Clone(false));
1478 :
1479 : // Do not attempt to match if a pseudo element is requested and this is not
1480 : // a pseudo element selector, or vice versa.
1481 0 : if (aPseudo.IsEmpty() == sel->mSelectors->IsPseudoElement()) {
1482 0 : *aMatches = false;
1483 0 : return NS_OK;
1484 : }
1485 :
1486 0 : if (!aPseudo.IsEmpty()) {
1487 : // We need to make sure that the requested pseudo element type
1488 : // matches the selector pseudo element type before proceeding.
1489 0 : nsCOMPtr<nsIAtom> pseudoElt = NS_Atomize(aPseudo);
1490 0 : if (sel->mSelectors->PseudoType() != nsCSSPseudoElements::
1491 0 : GetPseudoType(pseudoElt, CSSEnabledState::eIgnoreEnabledState)) {
1492 0 : *aMatches = false;
1493 0 : return NS_OK;
1494 : }
1495 :
1496 : // We have a matching pseudo element, now remove it so we can compare
1497 : // directly against |element| when proceeding into SelectorListMatches.
1498 : // It's OK to do this - we just cloned sel and nothing else is using it.
1499 0 : sel->RemoveRightmostSelector();
1500 : }
1501 :
1502 : // XXXbz what exactly should we do with visited state here? If we ever start
1503 : // caring about it, remember to do FlushPendingLinkUpdates().
1504 : TreeMatchContext matchingContext(false,
1505 : nsRuleWalker::eRelevantLinkUnvisited,
1506 : aElement->OwnerDoc(),
1507 0 : TreeMatchContext::eNeverMatchVisited);
1508 0 : *aMatches = nsCSSRuleProcessor::SelectorListMatches(aElement, matchingContext,
1509 : sel);
1510 0 : return NS_OK;
1511 : }
1512 :
1513 : } // namespace css
1514 : } // namespace mozilla
|