1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : * David Hyatt <hyatt@netscape.com>
24 : * Daniel Glazman <glazman@netscape.com>
25 : * L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
26 : *
27 : * Alternatively, the contents of this file may be used under the terms of
28 : * either of the GNU General Public License Version 2 or later (the "GPL"),
29 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
30 : * in which case the provisions of the GPL or the LGPL are applicable instead
31 : * of those above. If you wish to allow use of your version of this file only
32 : * under the terms of either the GPL or the LGPL, and not to allow others to
33 : * use your version of this file under the terms of the MPL, indicate your
34 : * decision by deleting the provisions above and replace them with the notice
35 : * and other provisions required by the GPL or the LGPL. If you do not delete
36 : * the provisions above, a recipient may use your version of this file under
37 : * the terms of any one of the MPL, the GPL or the LGPL.
38 : *
39 : * ***** END LICENSE BLOCK ***** */
40 :
41 : /*
42 : * representation of CSS style rules (selectors+declaration), CSS
43 : * selectors, and DOM objects for style rules, selectors, and
44 : * declarations
45 : */
46 :
47 : #include "mozilla/css/StyleRule.h"
48 : #include "mozilla/css/GroupRule.h"
49 : #include "mozilla/css/Declaration.h"
50 : #include "nsCSSStyleSheet.h"
51 : #include "mozilla/css/Loader.h"
52 : #include "nsIURL.h"
53 : #include "nsIDocument.h"
54 : #include "nsIAtom.h"
55 : #include "nsCRT.h"
56 : #include "nsString.h"
57 : #include "nsStyleConsts.h"
58 : #include "nsStyleUtil.h"
59 : #include "nsIDOMCSSStyleSheet.h"
60 : #include "nsICSSStyleRuleDOMWrapper.h"
61 : #include "nsIDOMCSSStyleDeclaration.h"
62 : #include "nsDOMCSSDeclaration.h"
63 : #include "nsINameSpaceManager.h"
64 : #include "nsXMLNameSpaceMap.h"
65 : #include "nsRuleNode.h"
66 : #include "nsUnicharUtils.h"
67 : #include "nsCSSPseudoElements.h"
68 : #include "nsIPrincipal.h"
69 : #include "nsComponentManagerUtils.h"
70 : #include "nsCSSPseudoClasses.h"
71 : #include "nsCSSAnonBoxes.h"
72 : #include "nsTArray.h"
73 :
74 : #include "nsContentUtils.h"
75 : #include "nsContentErrors.h"
76 : #include "mozAutoDocUpdate.h"
77 :
78 : #include "prlog.h"
79 :
80 : namespace css = mozilla::css;
81 :
82 : #define NS_IF_CLONE(member_) \
83 : PR_BEGIN_MACRO \
84 : if (member_) { \
85 : result->member_ = member_->Clone(); \
86 : if (!result->member_) { \
87 : delete result; \
88 : return nsnull; \
89 : } \
90 : } \
91 : PR_END_MACRO
92 :
93 : #define NS_IF_DELETE(ptr) \
94 : PR_BEGIN_MACRO \
95 : delete ptr; \
96 : ptr = nsnull; \
97 : PR_END_MACRO
98 :
99 : /* ************************************************************************** */
100 :
101 0 : nsAtomList::nsAtomList(nsIAtom* aAtom)
102 : : mAtom(aAtom),
103 0 : mNext(nsnull)
104 : {
105 0 : MOZ_COUNT_CTOR(nsAtomList);
106 0 : }
107 :
108 0 : nsAtomList::nsAtomList(const nsString& aAtomValue)
109 : : mAtom(nsnull),
110 0 : mNext(nsnull)
111 : {
112 0 : MOZ_COUNT_CTOR(nsAtomList);
113 0 : mAtom = do_GetAtom(aAtomValue);
114 0 : }
115 :
116 : nsAtomList*
117 0 : nsAtomList::Clone(bool aDeep) const
118 : {
119 0 : nsAtomList *result = new nsAtomList(mAtom);
120 0 : if (!result)
121 0 : return nsnull;
122 :
123 0 : if (aDeep)
124 0 : NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false));
125 0 : return result;
126 : }
127 :
128 : size_t
129 0 : nsAtomList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
130 : {
131 0 : size_t n = 0;
132 0 : const nsAtomList* a = this;
133 0 : while (a) {
134 0 : n += aMallocSizeOf(a);
135 :
136 : // The following members aren't measured:
137 : // - a->mAtom, because it may be shared
138 :
139 0 : a = a->mNext;
140 : }
141 0 : return n;
142 : }
143 :
144 0 : nsAtomList::~nsAtomList(void)
145 : {
146 0 : MOZ_COUNT_DTOR(nsAtomList);
147 0 : NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext);
148 0 : }
149 :
150 0 : nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType)
151 : : mType(aType),
152 0 : mNext(nsnull)
153 : {
154 0 : NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aType) &&
155 : !nsCSSPseudoClasses::HasNthPairArg(aType),
156 : "unexpected pseudo-class");
157 0 : MOZ_COUNT_CTOR(nsPseudoClassList);
158 0 : u.mMemory = nsnull;
159 0 : }
160 :
161 0 : nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
162 : const PRUnichar* aString)
163 : : mType(aType),
164 0 : mNext(nsnull)
165 : {
166 0 : NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aType),
167 : "unexpected pseudo-class");
168 0 : NS_ASSERTION(aString, "string expected");
169 0 : MOZ_COUNT_CTOR(nsPseudoClassList);
170 0 : u.mString = NS_strdup(aString);
171 0 : }
172 :
173 0 : nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
174 : const PRInt32* aIntPair)
175 : : mType(aType),
176 0 : mNext(nsnull)
177 : {
178 0 : NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aType),
179 : "unexpected pseudo-class");
180 0 : NS_ASSERTION(aIntPair, "integer pair expected");
181 0 : MOZ_COUNT_CTOR(nsPseudoClassList);
182 : u.mNumbers =
183 0 : static_cast<PRInt32*>(nsMemory::Clone(aIntPair, sizeof(PRInt32) * 2));
184 0 : }
185 :
186 : // adopts aSelectorList
187 0 : nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType,
188 : nsCSSSelectorList* aSelectorList)
189 : : mType(aType),
190 0 : mNext(nsnull)
191 : {
192 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType),
193 : "unexpected pseudo-class");
194 0 : NS_ASSERTION(aSelectorList, "selector list expected");
195 0 : MOZ_COUNT_CTOR(nsPseudoClassList);
196 0 : u.mSelectors = aSelectorList;
197 0 : }
198 :
199 : nsPseudoClassList*
200 0 : nsPseudoClassList::Clone(bool aDeep) const
201 : {
202 : nsPseudoClassList *result;
203 0 : if (!u.mMemory) {
204 0 : result = new nsPseudoClassList(mType);
205 0 : } else if (nsCSSPseudoClasses::HasStringArg(mType)) {
206 0 : result = new nsPseudoClassList(mType, u.mString);
207 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(mType)) {
208 0 : result = new nsPseudoClassList(mType, u.mNumbers);
209 : } else {
210 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType),
211 : "unexpected pseudo-class");
212 : // This constructor adopts its selector list argument.
213 0 : result = new nsPseudoClassList(mType, u.mSelectors->Clone());
214 : }
215 :
216 0 : if (aDeep)
217 0 : NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result,
218 : (false));
219 :
220 0 : return result;
221 : }
222 :
223 : size_t
224 0 : nsPseudoClassList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
225 : {
226 0 : size_t n = 0;
227 0 : const nsPseudoClassList* p = this;
228 0 : while (p) {
229 0 : n += aMallocSizeOf(p);
230 0 : if (!p->u.mMemory) {
231 : // do nothing
232 :
233 0 : } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) {
234 0 : n += aMallocSizeOf(p->u.mString);
235 :
236 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) {
237 0 : n += aMallocSizeOf(p->u.mNumbers);
238 :
239 : } else {
240 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType),
241 : "unexpected pseudo-class");
242 0 : n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf);
243 : }
244 0 : p = p->mNext;
245 : }
246 0 : return n;
247 : }
248 :
249 0 : nsPseudoClassList::~nsPseudoClassList(void)
250 : {
251 0 : MOZ_COUNT_DTOR(nsPseudoClassList);
252 0 : if (nsCSSPseudoClasses::HasSelectorListArg(mType)) {
253 0 : delete u.mSelectors;
254 0 : } else if (u.mMemory) {
255 0 : NS_Free(u.mMemory);
256 : }
257 0 : NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext);
258 0 : }
259 :
260 0 : nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, const nsString& aAttr)
261 : : mValue(),
262 : mNext(nsnull),
263 : mLowercaseAttr(nsnull),
264 : mCasedAttr(nsnull),
265 : mNameSpace(aNameSpace),
266 : mFunction(NS_ATTR_FUNC_SET),
267 0 : mCaseSensitive(1)
268 : {
269 0 : MOZ_COUNT_CTOR(nsAttrSelector);
270 :
271 0 : nsAutoString lowercase;
272 0 : nsContentUtils::ASCIIToLower(aAttr, lowercase);
273 :
274 0 : mCasedAttr = do_GetAtom(aAttr);
275 0 : mLowercaseAttr = do_GetAtom(lowercase);
276 0 : }
277 :
278 0 : nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, const nsString& aAttr, PRUint8 aFunction,
279 : const nsString& aValue, bool aCaseSensitive)
280 : : mValue(aValue),
281 : mNext(nsnull),
282 : mLowercaseAttr(nsnull),
283 : mCasedAttr(nsnull),
284 : mNameSpace(aNameSpace),
285 : mFunction(aFunction),
286 0 : mCaseSensitive(aCaseSensitive)
287 : {
288 0 : MOZ_COUNT_CTOR(nsAttrSelector);
289 :
290 0 : nsAutoString lowercase;
291 0 : nsContentUtils::ASCIIToLower(aAttr, lowercase);
292 :
293 0 : mCasedAttr = do_GetAtom(aAttr);
294 0 : mLowercaseAttr = do_GetAtom(lowercase);
295 0 : }
296 :
297 0 : nsAttrSelector::nsAttrSelector(PRInt32 aNameSpace, nsIAtom* aLowercaseAttr,
298 : nsIAtom* aCasedAttr, PRUint8 aFunction,
299 : const nsString& aValue, bool aCaseSensitive)
300 : : mValue(aValue),
301 : mNext(nsnull),
302 : mLowercaseAttr(aLowercaseAttr),
303 : mCasedAttr(aCasedAttr),
304 : mNameSpace(aNameSpace),
305 : mFunction(aFunction),
306 0 : mCaseSensitive(aCaseSensitive)
307 : {
308 0 : MOZ_COUNT_CTOR(nsAttrSelector);
309 0 : }
310 :
311 : nsAttrSelector*
312 0 : nsAttrSelector::Clone(bool aDeep) const
313 : {
314 : nsAttrSelector *result =
315 : new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr,
316 0 : mFunction, mValue, mCaseSensitive);
317 :
318 0 : if (aDeep)
319 0 : NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false));
320 :
321 0 : return result;
322 : }
323 :
324 0 : nsAttrSelector::~nsAttrSelector(void)
325 : {
326 0 : MOZ_COUNT_DTOR(nsAttrSelector);
327 :
328 0 : NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext);
329 0 : }
330 :
331 : // -- nsCSSSelector -------------------------------
332 :
333 220 : nsCSSSelector::nsCSSSelector(void)
334 : : mLowercaseTag(nsnull),
335 : mCasedTag(nsnull),
336 : mIDList(nsnull),
337 : mClassList(nsnull),
338 : mPseudoClassList(nsnull),
339 : mAttrList(nsnull),
340 : mNegations(nsnull),
341 : mNext(nsnull),
342 : mNameSpace(kNameSpaceID_Unknown),
343 : mOperator(0),
344 220 : mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement)
345 : {
346 220 : MOZ_COUNT_CTOR(nsCSSSelector);
347 : MOZ_STATIC_ASSERT(nsCSSPseudoElements::ePseudo_MAX < PR_INT16_MAX,
348 : "nsCSSPseudoElements::Type values overflow mPseudoType");
349 220 : }
350 :
351 : nsCSSSelector*
352 0 : nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const
353 : {
354 0 : nsCSSSelector *result = new nsCSSSelector();
355 0 : if (!result)
356 0 : return nsnull;
357 :
358 0 : result->mNameSpace = mNameSpace;
359 0 : result->mLowercaseTag = mLowercaseTag;
360 0 : result->mCasedTag = mCasedTag;
361 0 : result->mOperator = mOperator;
362 0 : result->mPseudoType = mPseudoType;
363 :
364 0 : NS_IF_CLONE(mIDList);
365 0 : NS_IF_CLONE(mClassList);
366 0 : NS_IF_CLONE(mPseudoClassList);
367 0 : NS_IF_CLONE(mAttrList);
368 :
369 : // No need to worry about multiple levels of recursion since an
370 : // mNegations can't have an mNext.
371 0 : NS_ASSERTION(!mNegations || !mNegations->mNext,
372 : "mNegations can't have non-null mNext");
373 0 : if (aDeepNegations) {
374 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result,
375 : (true, false));
376 : }
377 :
378 0 : if (aDeepNext) {
379 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result,
380 : (false, true));
381 : }
382 :
383 0 : return result;
384 : }
385 :
386 440 : nsCSSSelector::~nsCSSSelector(void)
387 : {
388 220 : MOZ_COUNT_DTOR(nsCSSSelector);
389 220 : Reset();
390 : // No need to worry about multiple levels of recursion since an
391 : // mNegations can't have an mNext.
392 330 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext);
393 220 : }
394 :
395 220 : void nsCSSSelector::Reset(void)
396 : {
397 220 : mNameSpace = kNameSpaceID_Unknown;
398 220 : mLowercaseTag = nsnull;
399 220 : mCasedTag = nsnull;
400 440 : NS_IF_DELETE(mIDList);
401 440 : NS_IF_DELETE(mClassList);
402 440 : NS_IF_DELETE(mPseudoClassList);
403 440 : NS_IF_DELETE(mAttrList);
404 : // No need to worry about multiple levels of recursion since an
405 : // mNegations can't have an mNext.
406 220 : NS_ASSERTION(!mNegations || !mNegations->mNext,
407 : "mNegations can't have non-null mNext");
408 220 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations);
409 220 : mOperator = PRUnichar(0);
410 220 : }
411 :
412 220 : void nsCSSSelector::SetNameSpace(PRInt32 aNameSpace)
413 : {
414 220 : mNameSpace = aNameSpace;
415 220 : }
416 :
417 220 : void nsCSSSelector::SetTag(const nsString& aTag)
418 : {
419 220 : if (aTag.IsEmpty()) {
420 0 : mLowercaseTag = mCasedTag = nsnull;
421 0 : return;
422 : }
423 :
424 220 : mCasedTag = do_GetAtom(aTag);
425 :
426 440 : nsAutoString lowercase;
427 220 : nsContentUtils::ASCIIToLower(aTag, lowercase);
428 220 : mLowercaseTag = do_GetAtom(lowercase);
429 : }
430 :
431 0 : void nsCSSSelector::AddID(const nsString& aID)
432 : {
433 0 : if (!aID.IsEmpty()) {
434 0 : nsAtomList** list = &mIDList;
435 0 : while (nsnull != *list) {
436 0 : list = &((*list)->mNext);
437 : }
438 0 : *list = new nsAtomList(aID);
439 : }
440 0 : }
441 :
442 0 : void nsCSSSelector::AddClass(const nsString& aClass)
443 : {
444 0 : if (!aClass.IsEmpty()) {
445 0 : nsAtomList** list = &mClassList;
446 0 : while (nsnull != *list) {
447 0 : list = &((*list)->mNext);
448 : }
449 0 : *list = new nsAtomList(aClass);
450 : }
451 0 : }
452 :
453 0 : void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType)
454 : {
455 0 : AddPseudoClassInternal(new nsPseudoClassList(aType));
456 0 : }
457 :
458 0 : void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
459 : const PRUnichar* aString)
460 : {
461 0 : AddPseudoClassInternal(new nsPseudoClassList(aType, aString));
462 0 : }
463 :
464 0 : void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
465 : const PRInt32* aIntPair)
466 : {
467 0 : AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair));
468 0 : }
469 :
470 0 : void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType,
471 : nsCSSSelectorList* aSelectorList)
472 : {
473 : // Take ownership of nsCSSSelectorList instead of copying.
474 0 : AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList));
475 0 : }
476 :
477 0 : void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass)
478 : {
479 0 : nsPseudoClassList** list = &mPseudoClassList;
480 0 : while (nsnull != *list) {
481 0 : list = &((*list)->mNext);
482 : }
483 0 : *list = aPseudoClass;
484 0 : }
485 :
486 0 : void nsCSSSelector::AddAttribute(PRInt32 aNameSpace, const nsString& aAttr)
487 : {
488 0 : if (!aAttr.IsEmpty()) {
489 0 : nsAttrSelector** list = &mAttrList;
490 0 : while (nsnull != *list) {
491 0 : list = &((*list)->mNext);
492 : }
493 0 : *list = new nsAttrSelector(aNameSpace, aAttr);
494 : }
495 0 : }
496 :
497 0 : void nsCSSSelector::AddAttribute(PRInt32 aNameSpace, const nsString& aAttr, PRUint8 aFunc,
498 : const nsString& aValue, bool aCaseSensitive)
499 : {
500 0 : if (!aAttr.IsEmpty()) {
501 0 : nsAttrSelector** list = &mAttrList;
502 0 : while (nsnull != *list) {
503 0 : list = &((*list)->mNext);
504 : }
505 0 : *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitive);
506 : }
507 0 : }
508 :
509 110 : void nsCSSSelector::SetOperator(PRUnichar aOperator)
510 : {
511 110 : mOperator = aOperator;
512 110 : }
513 :
514 220 : PRInt32 nsCSSSelector::CalcWeightWithoutNegations() const
515 : {
516 220 : PRInt32 weight = 0;
517 :
518 220 : if (nsnull != mLowercaseTag) {
519 220 : weight += 0x000001;
520 : }
521 220 : nsAtomList* list = mIDList;
522 440 : while (nsnull != list) {
523 0 : weight += 0x010000;
524 0 : list = list->mNext;
525 : }
526 220 : list = mClassList;
527 440 : while (nsnull != list) {
528 0 : weight += 0x000100;
529 0 : list = list->mNext;
530 : }
531 : // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't
532 : // really a pseudo-class. In order to handle :-moz-any() correctly,
533 : // we need to compute specificity after we match, based on which
534 : // option we matched with (and thus also need to try the
535 : // highest-specificity options first).
536 220 : nsPseudoClassList *plist = mPseudoClassList;
537 440 : while (nsnull != plist) {
538 0 : weight += 0x000100;
539 0 : plist = plist->mNext;
540 : }
541 220 : nsAttrSelector* attr = mAttrList;
542 440 : while (nsnull != attr) {
543 0 : weight += 0x000100;
544 0 : attr = attr->mNext;
545 : }
546 220 : return weight;
547 : }
548 :
549 220 : PRInt32 nsCSSSelector::CalcWeight() const
550 : {
551 : // Loop over this selector and all its negations.
552 220 : PRInt32 weight = 0;
553 440 : for (const nsCSSSelector *n = this; n; n = n->mNegations) {
554 220 : weight += n->CalcWeightWithoutNegations();
555 : }
556 220 : return weight;
557 : }
558 :
559 : //
560 : // Builds the textual representation of a selector. Called by DOM 2 CSS
561 : // StyleRule:selectorText
562 : //
563 : void
564 0 : nsCSSSelector::ToString(nsAString& aString, nsCSSStyleSheet* aSheet,
565 : bool aAppend) const
566 : {
567 0 : if (!aAppend)
568 0 : aString.Truncate();
569 :
570 : // selectors are linked from right-to-left, so the next selector in
571 : // the linked list actually precedes this one in the resulting string
572 0 : nsAutoTArray<const nsCSSSelector*, 8> stack;
573 0 : for (const nsCSSSelector *s = this; s; s = s->mNext) {
574 0 : stack.AppendElement(s);
575 : }
576 :
577 0 : while (!stack.IsEmpty()) {
578 0 : PRUint32 index = stack.Length() - 1;
579 0 : const nsCSSSelector *s = stack.ElementAt(index);
580 0 : stack.RemoveElementAt(index);
581 :
582 0 : s->AppendToStringWithoutCombinators(aString, aSheet);
583 :
584 : // Append the combinator, if needed.
585 0 : if (!stack.IsEmpty()) {
586 0 : const nsCSSSelector *next = stack.ElementAt(index - 1);
587 0 : PRUnichar oper = s->mOperator;
588 0 : if (next->IsPseudoElement()) {
589 0 : NS_ASSERTION(oper == PRUnichar('>'),
590 : "improperly chained pseudo element");
591 : } else {
592 0 : NS_ASSERTION(oper != PRUnichar(0),
593 : "compound selector without combinator");
594 :
595 0 : aString.Append(PRUnichar(' '));
596 0 : if (oper != PRUnichar(' ')) {
597 0 : aString.Append(oper);
598 0 : aString.Append(PRUnichar(' '));
599 : }
600 : }
601 : }
602 : }
603 0 : }
604 :
605 : void
606 0 : nsCSSSelector::AppendToStringWithoutCombinators
607 : (nsAString& aString, nsCSSStyleSheet* aSheet) const
608 : {
609 0 : AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false);
610 :
611 0 : for (const nsCSSSelector* negation = mNegations; negation;
612 : negation = negation->mNegations) {
613 0 : aString.AppendLiteral(":not(");
614 : negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet,
615 0 : true);
616 0 : aString.Append(PRUnichar(')'));
617 : }
618 0 : }
619 :
620 : void
621 0 : nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations
622 : (nsAString& aString, nsCSSStyleSheet* aSheet,
623 : bool aIsNegated) const
624 : {
625 0 : nsAutoString temp;
626 0 : bool isPseudoElement = IsPseudoElement();
627 :
628 : // For non-pseudo-element selectors or for lone pseudo-elements, deal with
629 : // namespace prefixes.
630 0 : bool wroteNamespace = false;
631 0 : if (!isPseudoElement || !mNext) {
632 : // append the namespace prefix if needed
633 0 : nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nsnull;
634 :
635 : // sheetNS is non-null if and only if we had an @namespace rule. If it's
636 : // null, that means that the only namespaces we could have are the
637 : // wildcard namespace (which can be implicit in this case) and the "none"
638 : // namespace, which then needs to be explicitly specified.
639 0 : if (!sheetNS) {
640 0 : NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
641 : mNameSpace == kNameSpaceID_None,
642 : "How did we get this namespace?");
643 0 : if (mNameSpace == kNameSpaceID_None) {
644 0 : aString.Append(PRUnichar('|'));
645 0 : wroteNamespace = true;
646 : }
647 0 : } else if (sheetNS->FindNameSpaceID(nsnull) == mNameSpace) {
648 : // We have the default namespace (possibly including the wildcard
649 : // namespace). Do nothing.
650 0 : NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown ||
651 : CanBeNamespaced(aIsNegated),
652 : "How did we end up with this namespace?");
653 0 : } else if (mNameSpace == kNameSpaceID_None) {
654 0 : NS_ASSERTION(CanBeNamespaced(aIsNegated),
655 : "How did we end up with this namespace?");
656 0 : aString.Append(PRUnichar('|'));
657 0 : wroteNamespace = true;
658 0 : } else if (mNameSpace != kNameSpaceID_Unknown) {
659 0 : NS_ASSERTION(CanBeNamespaced(aIsNegated),
660 : "How did we end up with this namespace?");
661 0 : nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace);
662 0 : NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace "
663 : "without a prefix?");
664 0 : nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom),
665 0 : aString);
666 0 : aString.Append(PRUnichar('|'));
667 0 : wroteNamespace = true;
668 : } else {
669 : // A selector for an element in any namespace, while the default
670 : // namespace is something else. :not() is special in that the default
671 : // namespace is not implied for non-type selectors, so if this is a
672 : // negated non-type selector we don't need to output an explicit wildcard
673 : // namespace here, since those default to a wildcard namespace.
674 0 : if (CanBeNamespaced(aIsNegated)) {
675 0 : aString.AppendLiteral("*|");
676 0 : wroteNamespace = true;
677 : }
678 : }
679 : }
680 :
681 0 : if (!mLowercaseTag) {
682 : // Universal selector: avoid writing the universal selector when we
683 : // can avoid it, especially since we're required to avoid it for the
684 : // inside of :not()
685 0 : if (wroteNamespace ||
686 0 : (!mIDList && !mClassList && !mPseudoClassList && !mAttrList &&
687 0 : (aIsNegated || !mNegations))) {
688 0 : aString.Append(PRUnichar('*'));
689 : }
690 : } else {
691 : // Append the tag name
692 0 : nsAutoString tag;
693 0 : (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag);
694 0 : if (isPseudoElement) {
695 0 : if (!mNext) {
696 : // Lone pseudo-element selector -- toss in a wildcard type selector
697 : // XXXldb Why?
698 0 : aString.Append(PRUnichar('*'));
699 : }
700 0 : if (!nsCSSPseudoElements::IsCSS2PseudoElement(mLowercaseTag)) {
701 0 : aString.Append(PRUnichar(':'));
702 : }
703 : // This should not be escaped since (a) the pseudo-element string
704 : // has a ":" that can't be escaped and (b) all pseudo-elements at
705 : // this point are known, and therefore we know they don't need
706 : // escaping.
707 0 : aString.Append(tag);
708 : } else {
709 0 : nsStyleUtil::AppendEscapedCSSIdent(tag, aString);
710 : }
711 : }
712 :
713 : // Append the id, if there is one
714 0 : if (mIDList) {
715 0 : nsAtomList* list = mIDList;
716 0 : while (list != nsnull) {
717 0 : list->mAtom->ToString(temp);
718 0 : aString.Append(PRUnichar('#'));
719 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
720 0 : list = list->mNext;
721 : }
722 : }
723 :
724 : // Append each class in the linked list
725 0 : if (mClassList) {
726 0 : if (isPseudoElement) {
727 : #ifdef MOZ_XUL
728 0 : NS_ABORT_IF_FALSE(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag),
729 : "must be tree pseudo-element");
730 :
731 0 : aString.Append(PRUnichar('('));
732 0 : for (nsAtomList* list = mClassList; list; list = list->mNext) {
733 0 : nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString);
734 0 : aString.Append(PRUnichar(','));
735 : }
736 : // replace the final comma with a close-paren
737 0 : aString.Replace(aString.Length() - 1, 1, PRUnichar(')'));
738 : #else
739 : NS_ERROR("Can't happen");
740 : #endif
741 : } else {
742 0 : nsAtomList* list = mClassList;
743 0 : while (list != nsnull) {
744 0 : list->mAtom->ToString(temp);
745 0 : aString.Append(PRUnichar('.'));
746 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
747 0 : list = list->mNext;
748 : }
749 : }
750 : }
751 :
752 : // Append each attribute selector in the linked list
753 0 : if (mAttrList) {
754 0 : nsAttrSelector* list = mAttrList;
755 0 : while (list != nsnull) {
756 0 : aString.Append(PRUnichar('['));
757 : // Append the namespace prefix
758 0 : if (list->mNameSpace == kNameSpaceID_Unknown) {
759 0 : aString.Append(PRUnichar('*'));
760 0 : aString.Append(PRUnichar('|'));
761 0 : } else if (list->mNameSpace != kNameSpaceID_None) {
762 0 : if (aSheet) {
763 0 : nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap();
764 0 : nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace);
765 : // Default namespaces don't apply to attribute selectors, so
766 : // we must have a useful prefix.
767 0 : NS_ASSERTION(prefixAtom,
768 : "How did we end up with a namespace if the prefix "
769 : "is unknown?");
770 0 : nsAutoString prefix;
771 0 : prefixAtom->ToString(prefix);
772 0 : nsStyleUtil::AppendEscapedCSSIdent(prefix, aString);
773 0 : aString.Append(PRUnichar('|'));
774 : }
775 : }
776 : // Append the attribute name
777 0 : list->mCasedAttr->ToString(temp);
778 0 : nsStyleUtil::AppendEscapedCSSIdent(temp, aString);
779 :
780 0 : if (list->mFunction != NS_ATTR_FUNC_SET) {
781 : // Append the function
782 0 : if (list->mFunction == NS_ATTR_FUNC_INCLUDES)
783 0 : aString.Append(PRUnichar('~'));
784 0 : else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH)
785 0 : aString.Append(PRUnichar('|'));
786 0 : else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH)
787 0 : aString.Append(PRUnichar('^'));
788 0 : else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH)
789 0 : aString.Append(PRUnichar('$'));
790 0 : else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH)
791 0 : aString.Append(PRUnichar('*'));
792 :
793 0 : aString.Append(PRUnichar('='));
794 :
795 : // Append the value
796 0 : nsStyleUtil::AppendEscapedCSSString(list->mValue, aString);
797 : }
798 :
799 0 : aString.Append(PRUnichar(']'));
800 :
801 0 : list = list->mNext;
802 : }
803 : }
804 :
805 : // Append each pseudo-class in the linked list
806 0 : for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) {
807 0 : nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp);
808 : // This should not be escaped since (a) the pseudo-class string
809 : // has a ":" that can't be escaped and (b) all pseudo-classes at
810 : // this point are known, and therefore we know they don't need
811 : // escaping.
812 0 : aString.Append(temp);
813 0 : if (list->u.mMemory) {
814 0 : aString.Append(PRUnichar('('));
815 0 : if (nsCSSPseudoClasses::HasStringArg(list->mType)) {
816 : nsStyleUtil::AppendEscapedCSSIdent(
817 0 : nsDependentString(list->u.mString), aString);
818 0 : } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) {
819 0 : PRInt32 a = list->u.mNumbers[0],
820 0 : b = list->u.mNumbers[1];
821 0 : temp.Truncate();
822 0 : if (a != 0) {
823 0 : if (a == -1) {
824 0 : temp.Append(PRUnichar('-'));
825 0 : } else if (a != 1) {
826 0 : temp.AppendInt(a);
827 : }
828 0 : temp.Append(PRUnichar('n'));
829 : }
830 0 : if (b != 0 || a == 0) {
831 0 : if (b >= 0 && a != 0) // check a != 0 for whether we printed above
832 0 : temp.Append(PRUnichar('+'));
833 0 : temp.AppendInt(b);
834 : }
835 0 : aString.Append(temp);
836 : } else {
837 0 : NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType),
838 : "unexpected pseudo-class");
839 0 : nsString tmp;
840 0 : list->u.mSelectors->ToString(tmp, aSheet);
841 0 : aString.Append(tmp);
842 : }
843 0 : aString.Append(PRUnichar(')'));
844 : }
845 : }
846 0 : }
847 :
848 : bool
849 0 : nsCSSSelector::CanBeNamespaced(bool aIsNegated) const
850 : {
851 0 : return !aIsNegated ||
852 0 : (!mIDList && !mClassList && !mPseudoClassList && !mAttrList);
853 : }
854 :
855 : size_t
856 0 : nsCSSSelector::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
857 : {
858 0 : size_t n = 0;
859 0 : const nsCSSSelector* s = this;
860 0 : while (s) {
861 0 : n += aMallocSizeOf(s);
862 :
863 : #define MEASURE(x) n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0;
864 :
865 0 : MEASURE(s->mIDList);
866 0 : MEASURE(s->mClassList);
867 0 : MEASURE(s->mPseudoClassList);
868 0 : MEASURE(s->mNegations);
869 :
870 : // Measurement of the following members may be added later if DMD finds it is
871 : // worthwhile:
872 : // - s->mAttrList
873 : //
874 : // The following members aren't measured:
875 : // - s->mLowercaseTag, because it's an atom and therefore shared
876 : // - s->mCasedTag, because it's an atom and therefore shared
877 :
878 0 : s = s->mNext;
879 : }
880 0 : return n;
881 : }
882 :
883 : // -- nsCSSSelectorList -------------------------------
884 :
885 110 : nsCSSSelectorList::nsCSSSelectorList(void)
886 : : mSelectors(nsnull),
887 : mWeight(0),
888 110 : mNext(nsnull)
889 : {
890 110 : MOZ_COUNT_CTOR(nsCSSSelectorList);
891 110 : }
892 :
893 110 : nsCSSSelectorList::~nsCSSSelectorList()
894 : {
895 110 : MOZ_COUNT_DTOR(nsCSSSelectorList);
896 110 : delete mSelectors;
897 110 : NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext);
898 110 : }
899 :
900 : nsCSSSelector*
901 220 : nsCSSSelectorList::AddSelector(PRUnichar aOperator)
902 : {
903 220 : nsCSSSelector* newSel = new nsCSSSelector();
904 :
905 220 : if (mSelectors) {
906 110 : NS_ASSERTION(aOperator != PRUnichar(0), "chaining without combinator");
907 110 : mSelectors->SetOperator(aOperator);
908 : } else {
909 110 : NS_ASSERTION(aOperator == PRUnichar(0), "combinator without chaining");
910 : }
911 :
912 220 : newSel->mNext = mSelectors;
913 220 : mSelectors = newSel;
914 220 : return newSel;
915 : }
916 :
917 : void
918 0 : nsCSSSelectorList::ToString(nsAString& aResult, nsCSSStyleSheet* aSheet)
919 : {
920 0 : aResult.Truncate();
921 0 : nsCSSSelectorList *p = this;
922 0 : for (;;) {
923 0 : p->mSelectors->ToString(aResult, aSheet, true);
924 0 : p = p->mNext;
925 0 : if (!p)
926 : break;
927 0 : aResult.AppendLiteral(", ");
928 : }
929 0 : }
930 :
931 : nsCSSSelectorList*
932 0 : nsCSSSelectorList::Clone(bool aDeep) const
933 : {
934 0 : nsCSSSelectorList *result = new nsCSSSelectorList();
935 0 : result->mWeight = mWeight;
936 0 : NS_IF_CLONE(mSelectors);
937 :
938 0 : if (aDeep) {
939 0 : NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result,
940 : (false));
941 : }
942 0 : return result;
943 : }
944 :
945 : size_t
946 0 : nsCSSSelectorList::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
947 : {
948 0 : size_t n = 0;
949 0 : const nsCSSSelectorList* s = this;
950 0 : while (s) {
951 0 : n += aMallocSizeOf(s);
952 0 : n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0;
953 0 : s = s->mNext;
954 : }
955 0 : return n;
956 : }
957 :
958 : // -- ImportantRule ----------------------------------
959 :
960 : namespace mozilla {
961 : namespace css {
962 :
963 0 : ImportantRule::ImportantRule(Declaration* aDeclaration)
964 0 : : mDeclaration(aDeclaration)
965 : {
966 0 : }
967 :
968 0 : ImportantRule::~ImportantRule()
969 : {
970 0 : }
971 :
972 0 : NS_IMPL_ISUPPORTS1(ImportantRule, nsIStyleRule)
973 :
974 : /* virtual */ void
975 0 : ImportantRule::MapRuleInfoInto(nsRuleData* aRuleData)
976 : {
977 0 : mDeclaration->MapImportantRuleInfoInto(aRuleData);
978 0 : }
979 :
980 : #ifdef DEBUG
981 : /* virtual */ void
982 0 : ImportantRule::List(FILE* out, PRInt32 aIndent) const
983 : {
984 : // Indent
985 0 : for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out);
986 :
987 : fprintf(out, "! Important declaration=%p\n",
988 0 : static_cast<void*>(mDeclaration));
989 0 : }
990 : #endif
991 :
992 : } // namespace css
993 : } // namespace mozilla
994 :
995 : // --------------------------------------------------------
996 :
997 : namespace mozilla {
998 : namespace css {
999 : class DOMCSSStyleRule;
1000 : }
1001 : }
1002 :
1003 : class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration
1004 : {
1005 : public:
1006 : DOMCSSDeclarationImpl(css::StyleRule *aRule);
1007 : virtual ~DOMCSSDeclarationImpl(void);
1008 :
1009 : NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent);
1010 : void DropReference(void);
1011 : virtual css::Declaration* GetCSSDeclaration(bool aAllocate);
1012 : virtual nsresult SetCSSDeclaration(css::Declaration* aDecl);
1013 : virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv);
1014 : virtual nsIDocument* DocToUpdate();
1015 :
1016 : // Override |AddRef| and |Release| for being a member of
1017 : // |DOMCSSStyleRule|.
1018 : NS_IMETHOD_(nsrefcnt) AddRef(void);
1019 : NS_IMETHOD_(nsrefcnt) Release(void);
1020 :
1021 0 : virtual nsINode *GetParentObject()
1022 : {
1023 0 : return nsnull;
1024 : }
1025 :
1026 : friend class css::DOMCSSStyleRule;
1027 :
1028 : protected:
1029 : // This reference is not reference-counted. The rule object tells us
1030 : // when it's about to go away.
1031 : css::StyleRule *mRule;
1032 :
1033 : inline css::DOMCSSStyleRule* DomRule();
1034 :
1035 : private:
1036 : // NOT TO BE IMPLEMENTED
1037 : // This object cannot be allocated on its own. It must be a member of
1038 : // DOMCSSStyleRule.
1039 : void* operator new(size_t size) CPP_THROW_NEW;
1040 : };
1041 :
1042 : namespace mozilla {
1043 : namespace css {
1044 :
1045 : class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper
1046 : {
1047 : public:
1048 : DOMCSSStyleRule(StyleRule *aRule);
1049 : virtual ~DOMCSSStyleRule();
1050 :
1051 : NS_DECL_ISUPPORTS
1052 : NS_DECL_NSIDOMCSSRULE
1053 : NS_DECL_NSIDOMCSSSTYLERULE
1054 :
1055 : // nsICSSStyleRuleDOMWrapper
1056 : NS_IMETHOD GetCSSStyleRule(StyleRule **aResult);
1057 :
1058 0 : DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; }
1059 :
1060 : friend class ::DOMCSSDeclarationImpl;
1061 :
1062 : protected:
1063 : DOMCSSDeclarationImpl mDOMDeclaration;
1064 :
1065 0 : StyleRule* Rule() {
1066 0 : return mDOMDeclaration.mRule;
1067 : }
1068 : };
1069 :
1070 : } // namespace css
1071 : } // namespace mozilla
1072 :
1073 0 : DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule)
1074 0 : : mRule(aRule)
1075 : {
1076 0 : MOZ_COUNT_CTOR(DOMCSSDeclarationImpl);
1077 0 : }
1078 :
1079 0 : DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void)
1080 : {
1081 0 : NS_ASSERTION(!mRule, "DropReference not called.");
1082 :
1083 0 : MOZ_COUNT_DTOR(DOMCSSDeclarationImpl);
1084 0 : }
1085 :
1086 0 : inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule()
1087 : {
1088 : return reinterpret_cast<css::DOMCSSStyleRule*>
1089 : (reinterpret_cast<char*>(this) -
1090 0 : offsetof(css::DOMCSSStyleRule, mDOMDeclaration));
1091 : }
1092 :
1093 0 : NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1094 0 : NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule())
1095 :
1096 : void
1097 0 : DOMCSSDeclarationImpl::DropReference(void)
1098 : {
1099 0 : mRule = nsnull;
1100 0 : }
1101 :
1102 : css::Declaration*
1103 0 : DOMCSSDeclarationImpl::GetCSSDeclaration(bool aAllocate)
1104 : {
1105 0 : if (mRule) {
1106 0 : return mRule->GetDeclaration();
1107 : } else {
1108 0 : return nsnull;
1109 : }
1110 : }
1111 :
1112 : void
1113 0 : DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv)
1114 : {
1115 0 : GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv);
1116 0 : }
1117 :
1118 : NS_IMETHODIMP
1119 0 : DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent)
1120 : {
1121 0 : NS_ENSURE_ARG_POINTER(aParent);
1122 :
1123 0 : if (!mRule) {
1124 0 : *aParent = nsnull;
1125 0 : return NS_OK;
1126 : }
1127 :
1128 0 : NS_IF_ADDREF(*aParent = mRule->GetDOMRule());
1129 0 : return NS_OK;
1130 : }
1131 :
1132 : nsresult
1133 0 : DOMCSSDeclarationImpl::SetCSSDeclaration(css::Declaration* aDecl)
1134 : {
1135 0 : NS_PRECONDITION(mRule,
1136 : "can only be called when |GetCSSDeclaration| returned a declaration");
1137 :
1138 0 : nsCOMPtr<nsIDocument> owningDoc;
1139 0 : nsCOMPtr<nsIStyleSheet> sheet = mRule->GetStyleSheet();
1140 0 : if (sheet) {
1141 0 : owningDoc = sheet->GetOwningDocument();
1142 : }
1143 :
1144 0 : mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true);
1145 :
1146 0 : nsRefPtr<css::StyleRule> oldRule = mRule;
1147 0 : mRule = oldRule->DeclarationChanged(aDecl, true).get();
1148 0 : if (!mRule)
1149 0 : return NS_ERROR_OUT_OF_MEMORY;
1150 0 : nsrefcnt cnt = mRule->Release();
1151 0 : if (cnt == 0) {
1152 0 : NS_NOTREACHED("container didn't take ownership");
1153 0 : mRule = nsnull;
1154 0 : return NS_ERROR_UNEXPECTED;
1155 : }
1156 :
1157 0 : if (owningDoc) {
1158 0 : owningDoc->StyleRuleChanged(sheet, oldRule, mRule);
1159 : }
1160 0 : return NS_OK;
1161 : }
1162 :
1163 : nsIDocument*
1164 0 : DOMCSSDeclarationImpl::DocToUpdate()
1165 : {
1166 0 : return nsnull;
1167 : }
1168 :
1169 : // needs to be outside the namespace
1170 : DOMCI_DATA(CSSStyleRule, css::DOMCSSStyleRule)
1171 :
1172 : namespace mozilla {
1173 : namespace css {
1174 :
1175 0 : DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule)
1176 0 : : mDOMDeclaration(aRule)
1177 : {
1178 0 : }
1179 :
1180 0 : DOMCSSStyleRule::~DOMCSSStyleRule()
1181 : {
1182 0 : }
1183 :
1184 0 : NS_INTERFACE_MAP_BEGIN(DOMCSSStyleRule)
1185 0 : NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper)
1186 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule)
1187 0 : NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule)
1188 0 : NS_INTERFACE_MAP_ENTRY(nsISupports)
1189 0 : NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule)
1190 0 : NS_INTERFACE_MAP_END
1191 :
1192 0 : NS_IMPL_ADDREF(DOMCSSStyleRule)
1193 0 : NS_IMPL_RELEASE(DOMCSSStyleRule)
1194 :
1195 : NS_IMETHODIMP
1196 0 : DOMCSSStyleRule::GetType(PRUint16* aType)
1197 : {
1198 0 : *aType = nsIDOMCSSRule::STYLE_RULE;
1199 :
1200 0 : return NS_OK;
1201 : }
1202 :
1203 : NS_IMETHODIMP
1204 0 : DOMCSSStyleRule::GetCssText(nsAString& aCssText)
1205 : {
1206 0 : if (!Rule()) {
1207 0 : aCssText.Truncate();
1208 : } else {
1209 0 : Rule()->GetCssText(aCssText);
1210 : }
1211 0 : return NS_OK;
1212 : }
1213 :
1214 : NS_IMETHODIMP
1215 0 : DOMCSSStyleRule::SetCssText(const nsAString& aCssText)
1216 : {
1217 0 : if (Rule()) {
1218 0 : Rule()->SetCssText(aCssText);
1219 : }
1220 0 : return NS_OK;
1221 : }
1222 :
1223 : NS_IMETHODIMP
1224 0 : DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet)
1225 : {
1226 0 : if (!Rule()) {
1227 0 : *aSheet = nsnull;
1228 0 : return NS_OK;
1229 : }
1230 0 : return Rule()->GetParentStyleSheet(aSheet);
1231 : }
1232 :
1233 : NS_IMETHODIMP
1234 0 : DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule)
1235 : {
1236 0 : if (!Rule()) {
1237 0 : *aParentRule = nsnull;
1238 0 : return NS_OK;
1239 : }
1240 0 : return Rule()->GetParentRule(aParentRule);
1241 : }
1242 :
1243 : NS_IMETHODIMP
1244 0 : DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText)
1245 : {
1246 0 : if (!Rule()) {
1247 0 : aSelectorText.Truncate();
1248 : } else {
1249 0 : Rule()->GetSelectorText(aSelectorText);
1250 : }
1251 0 : return NS_OK;
1252 : }
1253 :
1254 : NS_IMETHODIMP
1255 0 : DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText)
1256 : {
1257 0 : if (Rule()) {
1258 0 : Rule()->SetSelectorText(aSelectorText);
1259 : }
1260 0 : return NS_OK;
1261 : }
1262 :
1263 : NS_IMETHODIMP
1264 0 : DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
1265 : {
1266 0 : *aStyle = &mDOMDeclaration;
1267 0 : NS_ADDREF(*aStyle);
1268 0 : return NS_OK;
1269 : }
1270 :
1271 : NS_IMETHODIMP
1272 0 : DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult)
1273 : {
1274 0 : *aResult = Rule();
1275 0 : NS_IF_ADDREF(*aResult);
1276 0 : return NS_OK;
1277 : }
1278 :
1279 : } // namespace css
1280 : } // namespace mozilla
1281 :
1282 : // -- StyleRule ------------------------------------
1283 :
1284 : namespace mozilla {
1285 : namespace css {
1286 :
1287 0 : StyleRule::StyleRule(nsCSSSelectorList* aSelector,
1288 : Declaration* aDeclaration)
1289 : : Rule(),
1290 : mSelector(aSelector),
1291 : mDeclaration(aDeclaration),
1292 : mImportantRule(nsnull),
1293 : mDOMRule(nsnull),
1294 : mLineNumber(0),
1295 0 : mWasMatched(false)
1296 : {
1297 0 : NS_PRECONDITION(aDeclaration, "must have a declaration");
1298 0 : }
1299 :
1300 : // for |Clone|
1301 0 : StyleRule::StyleRule(const StyleRule& aCopy)
1302 : : Rule(aCopy),
1303 0 : mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nsnull),
1304 0 : mDeclaration(new Declaration(*aCopy.mDeclaration)),
1305 : mImportantRule(nsnull),
1306 : mDOMRule(nsnull),
1307 : mLineNumber(aCopy.mLineNumber),
1308 0 : mWasMatched(false)
1309 : {
1310 : // rest is constructed lazily on existing data
1311 0 : }
1312 :
1313 : // for |SetCSSDeclaration|
1314 0 : StyleRule::StyleRule(StyleRule& aCopy,
1315 : Declaration* aDeclaration)
1316 : : Rule(aCopy),
1317 : mSelector(aCopy.mSelector),
1318 : mDeclaration(aDeclaration),
1319 : mImportantRule(nsnull),
1320 : mDOMRule(aCopy.mDOMRule),
1321 : mLineNumber(aCopy.mLineNumber),
1322 0 : mWasMatched(false)
1323 : {
1324 : // The DOM rule is replacing |aCopy| with |this|, so transfer
1325 : // the reverse pointer as well (and transfer ownership).
1326 0 : aCopy.mDOMRule = nsnull;
1327 :
1328 : // Similarly for the selector.
1329 0 : aCopy.mSelector = nsnull;
1330 :
1331 : // We are probably replacing the old declaration with |aDeclaration|
1332 : // instead of taking ownership of the old declaration; only null out
1333 : // aCopy.mDeclaration if we are taking ownership.
1334 0 : if (mDeclaration == aCopy.mDeclaration) {
1335 : // This should only ever happen if the declaration was modifiable.
1336 0 : mDeclaration->AssertMutable();
1337 0 : aCopy.mDeclaration = nsnull;
1338 : }
1339 0 : }
1340 :
1341 0 : StyleRule::~StyleRule()
1342 : {
1343 0 : delete mSelector;
1344 0 : delete mDeclaration;
1345 0 : NS_IF_RELEASE(mImportantRule);
1346 0 : if (mDOMRule) {
1347 0 : mDOMRule->DOMDeclaration()->DropReference();
1348 0 : NS_RELEASE(mDOMRule);
1349 : }
1350 0 : }
1351 :
1352 : // QueryInterface implementation for StyleRule
1353 0 : NS_INTERFACE_MAP_BEGIN(StyleRule)
1354 0 : if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) {
1355 0 : *aInstancePtr = this;
1356 0 : NS_ADDREF_THIS();
1357 0 : return NS_OK;
1358 : }
1359 : else
1360 0 : NS_INTERFACE_MAP_ENTRY(nsIStyleRule)
1361 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule)
1362 0 : NS_INTERFACE_MAP_END
1363 :
1364 0 : NS_IMPL_ADDREF_INHERITED(StyleRule, Rule)
1365 0 : NS_IMPL_RELEASE_INHERITED(StyleRule, Rule)
1366 :
1367 : void
1368 0 : StyleRule::RuleMatched()
1369 : {
1370 0 : if (!mWasMatched) {
1371 0 : NS_ABORT_IF_FALSE(!mImportantRule, "should not have important rule yet");
1372 :
1373 0 : mWasMatched = true;
1374 0 : mDeclaration->SetImmutable();
1375 0 : if (mDeclaration->HasImportantData()) {
1376 0 : NS_ADDREF(mImportantRule = new ImportantRule(mDeclaration));
1377 : }
1378 : }
1379 0 : }
1380 :
1381 : /* virtual */ PRInt32
1382 0 : StyleRule::GetType() const
1383 : {
1384 0 : return Rule::STYLE_RULE;
1385 : }
1386 :
1387 : /* virtual */ already_AddRefed<Rule>
1388 0 : StyleRule::Clone() const
1389 : {
1390 0 : nsRefPtr<Rule> clone = new StyleRule(*this);
1391 0 : return clone.forget();
1392 : }
1393 :
1394 : /* virtual */ nsIDOMCSSRule*
1395 0 : StyleRule::GetDOMRule()
1396 : {
1397 0 : if (!mSheet) {
1398 : // inline style rules aren't supposed to have a DOM rule object, only
1399 : // a declaration.
1400 0 : return nsnull;
1401 : }
1402 0 : if (!mDOMRule) {
1403 0 : mDOMRule = new DOMCSSStyleRule(this);
1404 0 : NS_ADDREF(mDOMRule);
1405 : }
1406 0 : return mDOMRule;
1407 : }
1408 :
1409 : /* virtual */ already_AddRefed<StyleRule>
1410 0 : StyleRule::DeclarationChanged(Declaration* aDecl,
1411 : bool aHandleContainer)
1412 : {
1413 0 : StyleRule* clone = new StyleRule(*this, aDecl);
1414 0 : if (!clone) {
1415 0 : return nsnull;
1416 : }
1417 :
1418 0 : NS_ADDREF(clone); // for return
1419 :
1420 0 : if (aHandleContainer) {
1421 0 : if (mParentRule) {
1422 0 : if (mSheet) {
1423 0 : mSheet->ReplaceRuleInGroup(mParentRule, this, clone);
1424 : } else {
1425 0 : mParentRule->ReplaceStyleRule(this, clone);
1426 : }
1427 0 : } else if (mSheet) {
1428 0 : mSheet->ReplaceStyleRule(this, clone);
1429 : }
1430 : }
1431 :
1432 0 : return clone;
1433 : }
1434 :
1435 : /* virtual */ void
1436 0 : StyleRule::MapRuleInfoInto(nsRuleData* aRuleData)
1437 : {
1438 0 : NS_ABORT_IF_FALSE(mWasMatched,
1439 : "somebody forgot to call css::StyleRule::RuleMatched");
1440 0 : mDeclaration->MapNormalRuleInfoInto(aRuleData);
1441 0 : }
1442 :
1443 : #ifdef DEBUG
1444 : /* virtual */ void
1445 0 : StyleRule::List(FILE* out, PRInt32 aIndent) const
1446 : {
1447 : // Indent
1448 0 : for (PRInt32 index = aIndent; --index >= 0; ) fputs(" ", out);
1449 :
1450 0 : nsAutoString buffer;
1451 0 : if (mSelector)
1452 0 : mSelector->ToString(buffer, mSheet);
1453 :
1454 0 : buffer.AppendLiteral(" ");
1455 0 : fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out);
1456 0 : if (nsnull != mDeclaration) {
1457 0 : mDeclaration->List(out);
1458 : }
1459 : else {
1460 0 : fputs("{ null declaration }", out);
1461 : }
1462 0 : fputs("\n", out);
1463 0 : }
1464 : #endif
1465 :
1466 : void
1467 0 : StyleRule::GetCssText(nsAString& aCssText)
1468 : {
1469 0 : if (mSelector) {
1470 0 : mSelector->ToString(aCssText, mSheet);
1471 0 : aCssText.Append(PRUnichar(' '));
1472 : }
1473 0 : aCssText.Append(PRUnichar('{'));
1474 0 : aCssText.Append(PRUnichar(' '));
1475 0 : if (mDeclaration)
1476 : {
1477 0 : nsAutoString tempString;
1478 0 : mDeclaration->ToString( tempString );
1479 0 : aCssText.Append( tempString );
1480 : }
1481 0 : aCssText.Append(PRUnichar(' '));
1482 0 : aCssText.Append(PRUnichar('}'));
1483 0 : }
1484 :
1485 : void
1486 0 : StyleRule::SetCssText(const nsAString& aCssText)
1487 : {
1488 : // XXX TBI - need to re-parse rule & declaration
1489 0 : }
1490 :
1491 : void
1492 0 : StyleRule::GetSelectorText(nsAString& aSelectorText)
1493 : {
1494 0 : if (mSelector)
1495 0 : mSelector->ToString(aSelectorText, mSheet);
1496 : else
1497 0 : aSelectorText.Truncate();
1498 0 : }
1499 :
1500 : void
1501 0 : StyleRule::SetSelectorText(const nsAString& aSelectorText)
1502 : {
1503 : // XXX TBI - get a parser and re-parse the selectors,
1504 : // XXX then need to re-compute the cascade
1505 : // XXX and dirty sheet
1506 0 : }
1507 :
1508 : /* virtual */ size_t
1509 0 : StyleRule::SizeOfIncludingThis(nsMallocSizeOfFun aMallocSizeOf) const
1510 : {
1511 0 : size_t n = aMallocSizeOf(this);
1512 0 : n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0;
1513 0 : n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0;
1514 :
1515 : // Measurement of the following members may be added later if DMD finds it is
1516 : // worthwhile:
1517 : // - mImportantRule;
1518 : // - mDOMRule;
1519 :
1520 0 : return n;
1521 : }
1522 :
1523 :
1524 : } // namespace css
1525 : } // namespace mozilla
|