1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/StyleRule.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,1546 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +/* 1.10 + * representation of CSS style rules (selectors+declaration), CSS 1.11 + * selectors, and DOM objects for style rules, selectors, and 1.12 + * declarations 1.13 + */ 1.14 + 1.15 +#include "mozilla/css/StyleRule.h" 1.16 + 1.17 +#include "mozilla/MemoryReporting.h" 1.18 +#include "mozilla/css/GroupRule.h" 1.19 +#include "mozilla/css/Declaration.h" 1.20 +#include "nsCSSStyleSheet.h" 1.21 +#include "nsIDocument.h" 1.22 +#include "nsIAtom.h" 1.23 +#include "nsString.h" 1.24 +#include "nsStyleUtil.h" 1.25 +#include "nsICSSStyleRuleDOMWrapper.h" 1.26 +#include "nsDOMCSSDeclaration.h" 1.27 +#include "nsNameSpaceManager.h" 1.28 +#include "nsXMLNameSpaceMap.h" 1.29 +#include "nsCSSPseudoElements.h" 1.30 +#include "nsCSSPseudoClasses.h" 1.31 +#include "nsCSSAnonBoxes.h" 1.32 +#include "nsTArray.h" 1.33 +#include "nsDOMClassInfoID.h" 1.34 +#include "nsContentUtils.h" 1.35 +#include "nsError.h" 1.36 +#include "mozAutoDocUpdate.h" 1.37 + 1.38 +class nsIDOMCSSStyleDeclaration; 1.39 +class nsIDOMCSSStyleSheet; 1.40 + 1.41 +using namespace mozilla; 1.42 + 1.43 +#define NS_IF_CLONE(member_) \ 1.44 + PR_BEGIN_MACRO \ 1.45 + if (member_) { \ 1.46 + result->member_ = member_->Clone(); \ 1.47 + if (!result->member_) { \ 1.48 + delete result; \ 1.49 + return nullptr; \ 1.50 + } \ 1.51 + } \ 1.52 + PR_END_MACRO 1.53 + 1.54 +#define NS_IF_DELETE(ptr) \ 1.55 + PR_BEGIN_MACRO \ 1.56 + delete ptr; \ 1.57 + ptr = nullptr; \ 1.58 + PR_END_MACRO 1.59 + 1.60 +/* ************************************************************************** */ 1.61 + 1.62 +nsAtomList::nsAtomList(nsIAtom* aAtom) 1.63 + : mAtom(aAtom), 1.64 + mNext(nullptr) 1.65 +{ 1.66 + MOZ_COUNT_CTOR(nsAtomList); 1.67 +} 1.68 + 1.69 +nsAtomList::nsAtomList(const nsString& aAtomValue) 1.70 + : mAtom(nullptr), 1.71 + mNext(nullptr) 1.72 +{ 1.73 + MOZ_COUNT_CTOR(nsAtomList); 1.74 + mAtom = do_GetAtom(aAtomValue); 1.75 +} 1.76 + 1.77 +nsAtomList* 1.78 +nsAtomList::Clone(bool aDeep) const 1.79 +{ 1.80 + nsAtomList *result = new nsAtomList(mAtom); 1.81 + if (!result) 1.82 + return nullptr; 1.83 + 1.84 + if (aDeep) 1.85 + NS_CSS_CLONE_LIST_MEMBER(nsAtomList, this, mNext, result, (false)); 1.86 + return result; 1.87 +} 1.88 + 1.89 +size_t 1.90 +nsAtomList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.91 +{ 1.92 + size_t n = 0; 1.93 + const nsAtomList* a = this; 1.94 + while (a) { 1.95 + n += aMallocSizeOf(a); 1.96 + 1.97 + // The following members aren't measured: 1.98 + // - a->mAtom, because it may be shared 1.99 + 1.100 + a = a->mNext; 1.101 + } 1.102 + return n; 1.103 +} 1.104 + 1.105 +nsAtomList::~nsAtomList(void) 1.106 +{ 1.107 + MOZ_COUNT_DTOR(nsAtomList); 1.108 + NS_CSS_DELETE_LIST_MEMBER(nsAtomList, this, mNext); 1.109 +} 1.110 + 1.111 +nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType) 1.112 + : mType(aType), 1.113 + mNext(nullptr) 1.114 +{ 1.115 + NS_ASSERTION(!nsCSSPseudoClasses::HasStringArg(aType) && 1.116 + !nsCSSPseudoClasses::HasNthPairArg(aType), 1.117 + "unexpected pseudo-class"); 1.118 + MOZ_COUNT_CTOR(nsPseudoClassList); 1.119 + u.mMemory = nullptr; 1.120 +} 1.121 + 1.122 +nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType, 1.123 + const char16_t* aString) 1.124 + : mType(aType), 1.125 + mNext(nullptr) 1.126 +{ 1.127 + NS_ASSERTION(nsCSSPseudoClasses::HasStringArg(aType), 1.128 + "unexpected pseudo-class"); 1.129 + NS_ASSERTION(aString, "string expected"); 1.130 + MOZ_COUNT_CTOR(nsPseudoClassList); 1.131 + u.mString = NS_strdup(aString); 1.132 +} 1.133 + 1.134 +nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType, 1.135 + const int32_t* aIntPair) 1.136 + : mType(aType), 1.137 + mNext(nullptr) 1.138 +{ 1.139 + NS_ASSERTION(nsCSSPseudoClasses::HasNthPairArg(aType), 1.140 + "unexpected pseudo-class"); 1.141 + NS_ASSERTION(aIntPair, "integer pair expected"); 1.142 + MOZ_COUNT_CTOR(nsPseudoClassList); 1.143 + u.mNumbers = 1.144 + static_cast<int32_t*>(nsMemory::Clone(aIntPair, sizeof(int32_t) * 2)); 1.145 +} 1.146 + 1.147 +// adopts aSelectorList 1.148 +nsPseudoClassList::nsPseudoClassList(nsCSSPseudoClasses::Type aType, 1.149 + nsCSSSelectorList* aSelectorList) 1.150 + : mType(aType), 1.151 + mNext(nullptr) 1.152 +{ 1.153 + NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(aType), 1.154 + "unexpected pseudo-class"); 1.155 + NS_ASSERTION(aSelectorList, "selector list expected"); 1.156 + MOZ_COUNT_CTOR(nsPseudoClassList); 1.157 + u.mSelectors = aSelectorList; 1.158 +} 1.159 + 1.160 +nsPseudoClassList* 1.161 +nsPseudoClassList::Clone(bool aDeep) const 1.162 +{ 1.163 + nsPseudoClassList *result; 1.164 + if (!u.mMemory) { 1.165 + result = new nsPseudoClassList(mType); 1.166 + } else if (nsCSSPseudoClasses::HasStringArg(mType)) { 1.167 + result = new nsPseudoClassList(mType, u.mString); 1.168 + } else if (nsCSSPseudoClasses::HasNthPairArg(mType)) { 1.169 + result = new nsPseudoClassList(mType, u.mNumbers); 1.170 + } else { 1.171 + NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(mType), 1.172 + "unexpected pseudo-class"); 1.173 + // This constructor adopts its selector list argument. 1.174 + result = new nsPseudoClassList(mType, u.mSelectors->Clone()); 1.175 + } 1.176 + 1.177 + if (aDeep) 1.178 + NS_CSS_CLONE_LIST_MEMBER(nsPseudoClassList, this, mNext, result, 1.179 + (false)); 1.180 + 1.181 + return result; 1.182 +} 1.183 + 1.184 +size_t 1.185 +nsPseudoClassList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.186 +{ 1.187 + size_t n = 0; 1.188 + const nsPseudoClassList* p = this; 1.189 + while (p) { 1.190 + n += aMallocSizeOf(p); 1.191 + if (!p->u.mMemory) { 1.192 + // do nothing 1.193 + 1.194 + } else if (nsCSSPseudoClasses::HasStringArg(p->mType)) { 1.195 + n += aMallocSizeOf(p->u.mString); 1.196 + 1.197 + } else if (nsCSSPseudoClasses::HasNthPairArg(p->mType)) { 1.198 + n += aMallocSizeOf(p->u.mNumbers); 1.199 + 1.200 + } else { 1.201 + NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(p->mType), 1.202 + "unexpected pseudo-class"); 1.203 + n += p->u.mSelectors->SizeOfIncludingThis(aMallocSizeOf); 1.204 + } 1.205 + p = p->mNext; 1.206 + } 1.207 + return n; 1.208 +} 1.209 + 1.210 +nsPseudoClassList::~nsPseudoClassList(void) 1.211 +{ 1.212 + MOZ_COUNT_DTOR(nsPseudoClassList); 1.213 + if (nsCSSPseudoClasses::HasSelectorListArg(mType)) { 1.214 + delete u.mSelectors; 1.215 + } else if (u.mMemory) { 1.216 + NS_Free(u.mMemory); 1.217 + } 1.218 + NS_CSS_DELETE_LIST_MEMBER(nsPseudoClassList, this, mNext); 1.219 +} 1.220 + 1.221 +nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr) 1.222 + : mValue(), 1.223 + mNext(nullptr), 1.224 + mLowercaseAttr(nullptr), 1.225 + mCasedAttr(nullptr), 1.226 + mNameSpace(aNameSpace), 1.227 + mFunction(NS_ATTR_FUNC_SET), 1.228 + mCaseSensitive(1) 1.229 +{ 1.230 + MOZ_COUNT_CTOR(nsAttrSelector); 1.231 + 1.232 + nsAutoString lowercase; 1.233 + nsContentUtils::ASCIIToLower(aAttr, lowercase); 1.234 + 1.235 + mCasedAttr = do_GetAtom(aAttr); 1.236 + mLowercaseAttr = do_GetAtom(lowercase); 1.237 +} 1.238 + 1.239 +nsAttrSelector::nsAttrSelector(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunction, 1.240 + const nsString& aValue, bool aCaseSensitive) 1.241 + : mValue(aValue), 1.242 + mNext(nullptr), 1.243 + mLowercaseAttr(nullptr), 1.244 + mCasedAttr(nullptr), 1.245 + mNameSpace(aNameSpace), 1.246 + mFunction(aFunction), 1.247 + mCaseSensitive(aCaseSensitive) 1.248 +{ 1.249 + MOZ_COUNT_CTOR(nsAttrSelector); 1.250 + 1.251 + nsAutoString lowercase; 1.252 + nsContentUtils::ASCIIToLower(aAttr, lowercase); 1.253 + 1.254 + mCasedAttr = do_GetAtom(aAttr); 1.255 + mLowercaseAttr = do_GetAtom(lowercase); 1.256 +} 1.257 + 1.258 +nsAttrSelector::nsAttrSelector(int32_t aNameSpace, nsIAtom* aLowercaseAttr, 1.259 + nsIAtom* aCasedAttr, uint8_t aFunction, 1.260 + const nsString& aValue, bool aCaseSensitive) 1.261 + : mValue(aValue), 1.262 + mNext(nullptr), 1.263 + mLowercaseAttr(aLowercaseAttr), 1.264 + mCasedAttr(aCasedAttr), 1.265 + mNameSpace(aNameSpace), 1.266 + mFunction(aFunction), 1.267 + mCaseSensitive(aCaseSensitive) 1.268 +{ 1.269 + MOZ_COUNT_CTOR(nsAttrSelector); 1.270 +} 1.271 + 1.272 +nsAttrSelector* 1.273 +nsAttrSelector::Clone(bool aDeep) const 1.274 +{ 1.275 + nsAttrSelector *result = 1.276 + new nsAttrSelector(mNameSpace, mLowercaseAttr, mCasedAttr, 1.277 + mFunction, mValue, mCaseSensitive); 1.278 + 1.279 + if (aDeep) 1.280 + NS_CSS_CLONE_LIST_MEMBER(nsAttrSelector, this, mNext, result, (false)); 1.281 + 1.282 + return result; 1.283 +} 1.284 + 1.285 +nsAttrSelector::~nsAttrSelector(void) 1.286 +{ 1.287 + MOZ_COUNT_DTOR(nsAttrSelector); 1.288 + 1.289 + NS_CSS_DELETE_LIST_MEMBER(nsAttrSelector, this, mNext); 1.290 +} 1.291 + 1.292 +// -- nsCSSSelector ------------------------------- 1.293 + 1.294 +nsCSSSelector::nsCSSSelector(void) 1.295 + : mLowercaseTag(nullptr), 1.296 + mCasedTag(nullptr), 1.297 + mIDList(nullptr), 1.298 + mClassList(nullptr), 1.299 + mPseudoClassList(nullptr), 1.300 + mAttrList(nullptr), 1.301 + mNegations(nullptr), 1.302 + mNext(nullptr), 1.303 + mNameSpace(kNameSpaceID_Unknown), 1.304 + mOperator(0), 1.305 + mPseudoType(nsCSSPseudoElements::ePseudo_NotPseudoElement) 1.306 +{ 1.307 + MOZ_COUNT_CTOR(nsCSSSelector); 1.308 + static_assert(nsCSSPseudoElements::ePseudo_MAX < INT16_MAX, 1.309 + "nsCSSPseudoElements::Type values overflow mPseudoType"); 1.310 +} 1.311 + 1.312 +nsCSSSelector* 1.313 +nsCSSSelector::Clone(bool aDeepNext, bool aDeepNegations) const 1.314 +{ 1.315 + nsCSSSelector *result = new nsCSSSelector(); 1.316 + if (!result) 1.317 + return nullptr; 1.318 + 1.319 + result->mNameSpace = mNameSpace; 1.320 + result->mLowercaseTag = mLowercaseTag; 1.321 + result->mCasedTag = mCasedTag; 1.322 + result->mOperator = mOperator; 1.323 + result->mPseudoType = mPseudoType; 1.324 + 1.325 + NS_IF_CLONE(mIDList); 1.326 + NS_IF_CLONE(mClassList); 1.327 + NS_IF_CLONE(mPseudoClassList); 1.328 + NS_IF_CLONE(mAttrList); 1.329 + 1.330 + // No need to worry about multiple levels of recursion since an 1.331 + // mNegations can't have an mNext. 1.332 + NS_ASSERTION(!mNegations || !mNegations->mNext, 1.333 + "mNegations can't have non-null mNext"); 1.334 + if (aDeepNegations) { 1.335 + NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNegations, result, 1.336 + (true, false)); 1.337 + } 1.338 + 1.339 + if (aDeepNext) { 1.340 + NS_CSS_CLONE_LIST_MEMBER(nsCSSSelector, this, mNext, result, 1.341 + (false, true)); 1.342 + } 1.343 + 1.344 + return result; 1.345 +} 1.346 + 1.347 +nsCSSSelector::~nsCSSSelector(void) 1.348 +{ 1.349 + MOZ_COUNT_DTOR(nsCSSSelector); 1.350 + Reset(); 1.351 + // No need to worry about multiple levels of recursion since an 1.352 + // mNegations can't have an mNext. 1.353 + NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNext); 1.354 +} 1.355 + 1.356 +void nsCSSSelector::Reset(void) 1.357 +{ 1.358 + mNameSpace = kNameSpaceID_Unknown; 1.359 + mLowercaseTag = nullptr; 1.360 + mCasedTag = nullptr; 1.361 + NS_IF_DELETE(mIDList); 1.362 + NS_IF_DELETE(mClassList); 1.363 + NS_IF_DELETE(mPseudoClassList); 1.364 + NS_IF_DELETE(mAttrList); 1.365 + // No need to worry about multiple levels of recursion since an 1.366 + // mNegations can't have an mNext. 1.367 + NS_ASSERTION(!mNegations || !mNegations->mNext, 1.368 + "mNegations can't have non-null mNext"); 1.369 + NS_CSS_DELETE_LIST_MEMBER(nsCSSSelector, this, mNegations); 1.370 + mOperator = char16_t(0); 1.371 +} 1.372 + 1.373 +void nsCSSSelector::SetNameSpace(int32_t aNameSpace) 1.374 +{ 1.375 + mNameSpace = aNameSpace; 1.376 +} 1.377 + 1.378 +void nsCSSSelector::SetTag(const nsString& aTag) 1.379 +{ 1.380 + if (aTag.IsEmpty()) { 1.381 + mLowercaseTag = mCasedTag = nullptr; 1.382 + return; 1.383 + } 1.384 + 1.385 + mCasedTag = do_GetAtom(aTag); 1.386 + 1.387 + nsAutoString lowercase; 1.388 + nsContentUtils::ASCIIToLower(aTag, lowercase); 1.389 + mLowercaseTag = do_GetAtom(lowercase); 1.390 +} 1.391 + 1.392 +void nsCSSSelector::AddID(const nsString& aID) 1.393 +{ 1.394 + if (!aID.IsEmpty()) { 1.395 + nsAtomList** list = &mIDList; 1.396 + while (nullptr != *list) { 1.397 + list = &((*list)->mNext); 1.398 + } 1.399 + *list = new nsAtomList(aID); 1.400 + } 1.401 +} 1.402 + 1.403 +void nsCSSSelector::AddClass(const nsString& aClass) 1.404 +{ 1.405 + if (!aClass.IsEmpty()) { 1.406 + nsAtomList** list = &mClassList; 1.407 + while (nullptr != *list) { 1.408 + list = &((*list)->mNext); 1.409 + } 1.410 + *list = new nsAtomList(aClass); 1.411 + } 1.412 +} 1.413 + 1.414 +void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType) 1.415 +{ 1.416 + AddPseudoClassInternal(new nsPseudoClassList(aType)); 1.417 +} 1.418 + 1.419 +void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType, 1.420 + const char16_t* aString) 1.421 +{ 1.422 + AddPseudoClassInternal(new nsPseudoClassList(aType, aString)); 1.423 +} 1.424 + 1.425 +void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType, 1.426 + const int32_t* aIntPair) 1.427 +{ 1.428 + AddPseudoClassInternal(new nsPseudoClassList(aType, aIntPair)); 1.429 +} 1.430 + 1.431 +void nsCSSSelector::AddPseudoClass(nsCSSPseudoClasses::Type aType, 1.432 + nsCSSSelectorList* aSelectorList) 1.433 +{ 1.434 + // Take ownership of nsCSSSelectorList instead of copying. 1.435 + AddPseudoClassInternal(new nsPseudoClassList(aType, aSelectorList)); 1.436 +} 1.437 + 1.438 +void nsCSSSelector::AddPseudoClassInternal(nsPseudoClassList *aPseudoClass) 1.439 +{ 1.440 + nsPseudoClassList** list = &mPseudoClassList; 1.441 + while (nullptr != *list) { 1.442 + list = &((*list)->mNext); 1.443 + } 1.444 + *list = aPseudoClass; 1.445 +} 1.446 + 1.447 +void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr) 1.448 +{ 1.449 + if (!aAttr.IsEmpty()) { 1.450 + nsAttrSelector** list = &mAttrList; 1.451 + while (nullptr != *list) { 1.452 + list = &((*list)->mNext); 1.453 + } 1.454 + *list = new nsAttrSelector(aNameSpace, aAttr); 1.455 + } 1.456 +} 1.457 + 1.458 +void nsCSSSelector::AddAttribute(int32_t aNameSpace, const nsString& aAttr, uint8_t aFunc, 1.459 + const nsString& aValue, bool aCaseSensitive) 1.460 +{ 1.461 + if (!aAttr.IsEmpty()) { 1.462 + nsAttrSelector** list = &mAttrList; 1.463 + while (nullptr != *list) { 1.464 + list = &((*list)->mNext); 1.465 + } 1.466 + *list = new nsAttrSelector(aNameSpace, aAttr, aFunc, aValue, aCaseSensitive); 1.467 + } 1.468 +} 1.469 + 1.470 +void nsCSSSelector::SetOperator(char16_t aOperator) 1.471 +{ 1.472 + mOperator = aOperator; 1.473 +} 1.474 + 1.475 +int32_t nsCSSSelector::CalcWeightWithoutNegations() const 1.476 +{ 1.477 + int32_t weight = 0; 1.478 + 1.479 +#ifdef MOZ_XUL 1.480 + MOZ_ASSERT(!(IsPseudoElement() && 1.481 + PseudoType() != nsCSSPseudoElements::ePseudo_XULTree && 1.482 + mClassList), 1.483 + "If non-XUL-tree pseudo-elements can have class selectors " 1.484 + "after them, specificity calculation must be updated"); 1.485 +#else 1.486 + MOZ_ASSERT(!(IsPseudoElement() && mClassList), 1.487 + "If pseudo-elements can have class selectors " 1.488 + "after them, specificity calculation must be updated"); 1.489 +#endif 1.490 + MOZ_ASSERT(!(IsPseudoElement() && (mIDList || mAttrList)), 1.491 + "If pseudo-elements can have id or attribute selectors " 1.492 + "after them, specificity calculation must be updated"); 1.493 + 1.494 + if (nullptr != mCasedTag) { 1.495 + weight += 0x000001; 1.496 + } 1.497 + nsAtomList* list = mIDList; 1.498 + while (nullptr != list) { 1.499 + weight += 0x010000; 1.500 + list = list->mNext; 1.501 + } 1.502 + list = mClassList; 1.503 +#ifdef MOZ_XUL 1.504 + // XUL tree pseudo-elements abuse mClassList to store some private 1.505 + // data; ignore that. 1.506 + if (PseudoType() == nsCSSPseudoElements::ePseudo_XULTree) { 1.507 + list = nullptr; 1.508 + } 1.509 +#endif 1.510 + while (nullptr != list) { 1.511 + weight += 0x000100; 1.512 + list = list->mNext; 1.513 + } 1.514 + // FIXME (bug 561154): This is incorrect for :-moz-any(), which isn't 1.515 + // really a pseudo-class. In order to handle :-moz-any() correctly, 1.516 + // we need to compute specificity after we match, based on which 1.517 + // option we matched with (and thus also need to try the 1.518 + // highest-specificity options first). 1.519 + nsPseudoClassList *plist = mPseudoClassList; 1.520 + while (nullptr != plist) { 1.521 + weight += 0x000100; 1.522 + plist = plist->mNext; 1.523 + } 1.524 + nsAttrSelector* attr = mAttrList; 1.525 + while (nullptr != attr) { 1.526 + weight += 0x000100; 1.527 + attr = attr->mNext; 1.528 + } 1.529 + return weight; 1.530 +} 1.531 + 1.532 +int32_t nsCSSSelector::CalcWeight() const 1.533 +{ 1.534 + // Loop over this selector and all its negations. 1.535 + int32_t weight = 0; 1.536 + for (const nsCSSSelector *n = this; n; n = n->mNegations) { 1.537 + weight += n->CalcWeightWithoutNegations(); 1.538 + } 1.539 + return weight; 1.540 +} 1.541 + 1.542 +// 1.543 +// Builds the textual representation of a selector. Called by DOM 2 CSS 1.544 +// StyleRule:selectorText 1.545 +// 1.546 +void 1.547 +nsCSSSelector::ToString(nsAString& aString, nsCSSStyleSheet* aSheet, 1.548 + bool aAppend) const 1.549 +{ 1.550 + if (!aAppend) 1.551 + aString.Truncate(); 1.552 + 1.553 + // selectors are linked from right-to-left, so the next selector in 1.554 + // the linked list actually precedes this one in the resulting string 1.555 + nsAutoTArray<const nsCSSSelector*, 8> stack; 1.556 + for (const nsCSSSelector *s = this; s; s = s->mNext) { 1.557 + stack.AppendElement(s); 1.558 + } 1.559 + 1.560 + while (!stack.IsEmpty()) { 1.561 + uint32_t index = stack.Length() - 1; 1.562 + const nsCSSSelector *s = stack.ElementAt(index); 1.563 + stack.RemoveElementAt(index); 1.564 + 1.565 + s->AppendToStringWithoutCombinators(aString, aSheet); 1.566 + 1.567 + // Append the combinator, if needed. 1.568 + if (!stack.IsEmpty()) { 1.569 + const nsCSSSelector *next = stack.ElementAt(index - 1); 1.570 + char16_t oper = s->mOperator; 1.571 + if (next->IsPseudoElement()) { 1.572 + NS_ASSERTION(oper == char16_t(':'), 1.573 + "improperly chained pseudo element"); 1.574 + } else { 1.575 + NS_ASSERTION(oper != char16_t(0), 1.576 + "compound selector without combinator"); 1.577 + 1.578 + aString.Append(char16_t(' ')); 1.579 + if (oper != char16_t(' ')) { 1.580 + aString.Append(oper); 1.581 + aString.Append(char16_t(' ')); 1.582 + } 1.583 + } 1.584 + } 1.585 + } 1.586 +} 1.587 + 1.588 +void 1.589 +nsCSSSelector::AppendToStringWithoutCombinators 1.590 + (nsAString& aString, nsCSSStyleSheet* aSheet) const 1.591 +{ 1.592 + AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, false); 1.593 + 1.594 + for (const nsCSSSelector* negation = mNegations; negation; 1.595 + negation = negation->mNegations) { 1.596 + aString.AppendLiteral(":not("); 1.597 + negation->AppendToStringWithoutCombinatorsOrNegations(aString, aSheet, 1.598 + true); 1.599 + aString.Append(char16_t(')')); 1.600 + } 1.601 +} 1.602 + 1.603 +void 1.604 +nsCSSSelector::AppendToStringWithoutCombinatorsOrNegations 1.605 + (nsAString& aString, nsCSSStyleSheet* aSheet, 1.606 + bool aIsNegated) const 1.607 +{ 1.608 + nsAutoString temp; 1.609 + bool isPseudoElement = IsPseudoElement(); 1.610 + 1.611 + // For non-pseudo-element selectors or for lone pseudo-elements, deal with 1.612 + // namespace prefixes. 1.613 + bool wroteNamespace = false; 1.614 + if (!isPseudoElement || !mNext) { 1.615 + // append the namespace prefix if needed 1.616 + nsXMLNameSpaceMap *sheetNS = aSheet ? aSheet->GetNameSpaceMap() : nullptr; 1.617 + 1.618 + // sheetNS is non-null if and only if we had an @namespace rule. If it's 1.619 + // null, that means that the only namespaces we could have are the 1.620 + // wildcard namespace (which can be implicit in this case) and the "none" 1.621 + // namespace, which then needs to be explicitly specified. 1.622 + if (!sheetNS) { 1.623 + NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown || 1.624 + mNameSpace == kNameSpaceID_None, 1.625 + "How did we get this namespace?"); 1.626 + if (mNameSpace == kNameSpaceID_None) { 1.627 + aString.Append(char16_t('|')); 1.628 + wroteNamespace = true; 1.629 + } 1.630 + } else if (sheetNS->FindNameSpaceID(nullptr) == mNameSpace) { 1.631 + // We have the default namespace (possibly including the wildcard 1.632 + // namespace). Do nothing. 1.633 + NS_ASSERTION(mNameSpace == kNameSpaceID_Unknown || 1.634 + CanBeNamespaced(aIsNegated), 1.635 + "How did we end up with this namespace?"); 1.636 + } else if (mNameSpace == kNameSpaceID_None) { 1.637 + NS_ASSERTION(CanBeNamespaced(aIsNegated), 1.638 + "How did we end up with this namespace?"); 1.639 + aString.Append(char16_t('|')); 1.640 + wroteNamespace = true; 1.641 + } else if (mNameSpace != kNameSpaceID_Unknown) { 1.642 + NS_ASSERTION(CanBeNamespaced(aIsNegated), 1.643 + "How did we end up with this namespace?"); 1.644 + nsIAtom *prefixAtom = sheetNS->FindPrefix(mNameSpace); 1.645 + NS_ASSERTION(prefixAtom, "how'd we get a non-default namespace " 1.646 + "without a prefix?"); 1.647 + nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(prefixAtom), 1.648 + aString); 1.649 + aString.Append(char16_t('|')); 1.650 + wroteNamespace = true; 1.651 + } else { 1.652 + // A selector for an element in any namespace, while the default 1.653 + // namespace is something else. :not() is special in that the default 1.654 + // namespace is not implied for non-type selectors, so if this is a 1.655 + // negated non-type selector we don't need to output an explicit wildcard 1.656 + // namespace here, since those default to a wildcard namespace. 1.657 + if (CanBeNamespaced(aIsNegated)) { 1.658 + aString.AppendLiteral("*|"); 1.659 + wroteNamespace = true; 1.660 + } 1.661 + } 1.662 + } 1.663 + 1.664 + if (!mLowercaseTag) { 1.665 + // Universal selector: avoid writing the universal selector when we 1.666 + // can avoid it, especially since we're required to avoid it for the 1.667 + // inside of :not() 1.668 + if (wroteNamespace || 1.669 + (!mIDList && !mClassList && !mPseudoClassList && !mAttrList && 1.670 + (aIsNegated || !mNegations))) { 1.671 + aString.Append(char16_t('*')); 1.672 + } 1.673 + } else { 1.674 + // Append the tag name 1.675 + nsAutoString tag; 1.676 + (isPseudoElement ? mLowercaseTag : mCasedTag)->ToString(tag); 1.677 + if (isPseudoElement) { 1.678 + if (!mNext) { 1.679 + // Lone pseudo-element selector -- toss in a wildcard type selector 1.680 + // XXXldb Why? 1.681 + aString.Append(char16_t('*')); 1.682 + } 1.683 + if (!nsCSSPseudoElements::IsCSS2PseudoElement(mLowercaseTag)) { 1.684 + aString.Append(char16_t(':')); 1.685 + } 1.686 + // This should not be escaped since (a) the pseudo-element string 1.687 + // has a ":" that can't be escaped and (b) all pseudo-elements at 1.688 + // this point are known, and therefore we know they don't need 1.689 + // escaping. 1.690 + aString.Append(tag); 1.691 + } else { 1.692 + nsStyleUtil::AppendEscapedCSSIdent(tag, aString); 1.693 + } 1.694 + } 1.695 + 1.696 + // Append the id, if there is one 1.697 + if (mIDList) { 1.698 + nsAtomList* list = mIDList; 1.699 + while (list != nullptr) { 1.700 + list->mAtom->ToString(temp); 1.701 + aString.Append(char16_t('#')); 1.702 + nsStyleUtil::AppendEscapedCSSIdent(temp, aString); 1.703 + list = list->mNext; 1.704 + } 1.705 + } 1.706 + 1.707 + // Append each class in the linked list 1.708 + if (mClassList) { 1.709 + if (isPseudoElement) { 1.710 +#ifdef MOZ_XUL 1.711 + NS_ABORT_IF_FALSE(nsCSSAnonBoxes::IsTreePseudoElement(mLowercaseTag), 1.712 + "must be tree pseudo-element"); 1.713 + 1.714 + aString.Append(char16_t('(')); 1.715 + for (nsAtomList* list = mClassList; list; list = list->mNext) { 1.716 + nsStyleUtil::AppendEscapedCSSIdent(nsDependentAtomString(list->mAtom), aString); 1.717 + aString.Append(char16_t(',')); 1.718 + } 1.719 + // replace the final comma with a close-paren 1.720 + aString.Replace(aString.Length() - 1, 1, char16_t(')')); 1.721 +#else 1.722 + NS_ERROR("Can't happen"); 1.723 +#endif 1.724 + } else { 1.725 + nsAtomList* list = mClassList; 1.726 + while (list != nullptr) { 1.727 + list->mAtom->ToString(temp); 1.728 + aString.Append(char16_t('.')); 1.729 + nsStyleUtil::AppendEscapedCSSIdent(temp, aString); 1.730 + list = list->mNext; 1.731 + } 1.732 + } 1.733 + } 1.734 + 1.735 + // Append each attribute selector in the linked list 1.736 + if (mAttrList) { 1.737 + nsAttrSelector* list = mAttrList; 1.738 + while (list != nullptr) { 1.739 + aString.Append(char16_t('[')); 1.740 + // Append the namespace prefix 1.741 + if (list->mNameSpace == kNameSpaceID_Unknown) { 1.742 + aString.Append(char16_t('*')); 1.743 + aString.Append(char16_t('|')); 1.744 + } else if (list->mNameSpace != kNameSpaceID_None) { 1.745 + if (aSheet) { 1.746 + nsXMLNameSpaceMap *sheetNS = aSheet->GetNameSpaceMap(); 1.747 + nsIAtom *prefixAtom = sheetNS->FindPrefix(list->mNameSpace); 1.748 + // Default namespaces don't apply to attribute selectors, so 1.749 + // we must have a useful prefix. 1.750 + NS_ASSERTION(prefixAtom, 1.751 + "How did we end up with a namespace if the prefix " 1.752 + "is unknown?"); 1.753 + nsAutoString prefix; 1.754 + prefixAtom->ToString(prefix); 1.755 + nsStyleUtil::AppendEscapedCSSIdent(prefix, aString); 1.756 + aString.Append(char16_t('|')); 1.757 + } 1.758 + } 1.759 + // Append the attribute name 1.760 + list->mCasedAttr->ToString(temp); 1.761 + nsStyleUtil::AppendEscapedCSSIdent(temp, aString); 1.762 + 1.763 + if (list->mFunction != NS_ATTR_FUNC_SET) { 1.764 + // Append the function 1.765 + if (list->mFunction == NS_ATTR_FUNC_INCLUDES) 1.766 + aString.Append(char16_t('~')); 1.767 + else if (list->mFunction == NS_ATTR_FUNC_DASHMATCH) 1.768 + aString.Append(char16_t('|')); 1.769 + else if (list->mFunction == NS_ATTR_FUNC_BEGINSMATCH) 1.770 + aString.Append(char16_t('^')); 1.771 + else if (list->mFunction == NS_ATTR_FUNC_ENDSMATCH) 1.772 + aString.Append(char16_t('$')); 1.773 + else if (list->mFunction == NS_ATTR_FUNC_CONTAINSMATCH) 1.774 + aString.Append(char16_t('*')); 1.775 + 1.776 + aString.Append(char16_t('=')); 1.777 + 1.778 + // Append the value 1.779 + nsStyleUtil::AppendEscapedCSSString(list->mValue, aString); 1.780 + } 1.781 + 1.782 + aString.Append(char16_t(']')); 1.783 + 1.784 + list = list->mNext; 1.785 + } 1.786 + } 1.787 + 1.788 + // Append each pseudo-class in the linked list 1.789 + for (nsPseudoClassList* list = mPseudoClassList; list; list = list->mNext) { 1.790 + nsCSSPseudoClasses::PseudoTypeToString(list->mType, temp); 1.791 + // This should not be escaped since (a) the pseudo-class string 1.792 + // has a ":" that can't be escaped and (b) all pseudo-classes at 1.793 + // this point are known, and therefore we know they don't need 1.794 + // escaping. 1.795 + aString.Append(temp); 1.796 + if (list->u.mMemory) { 1.797 + aString.Append(char16_t('(')); 1.798 + if (nsCSSPseudoClasses::HasStringArg(list->mType)) { 1.799 + nsStyleUtil::AppendEscapedCSSIdent( 1.800 + nsDependentString(list->u.mString), aString); 1.801 + } else if (nsCSSPseudoClasses::HasNthPairArg(list->mType)) { 1.802 + int32_t a = list->u.mNumbers[0], 1.803 + b = list->u.mNumbers[1]; 1.804 + temp.Truncate(); 1.805 + if (a != 0) { 1.806 + if (a == -1) { 1.807 + temp.Append(char16_t('-')); 1.808 + } else if (a != 1) { 1.809 + temp.AppendInt(a); 1.810 + } 1.811 + temp.Append(char16_t('n')); 1.812 + } 1.813 + if (b != 0 || a == 0) { 1.814 + if (b >= 0 && a != 0) // check a != 0 for whether we printed above 1.815 + temp.Append(char16_t('+')); 1.816 + temp.AppendInt(b); 1.817 + } 1.818 + aString.Append(temp); 1.819 + } else { 1.820 + NS_ASSERTION(nsCSSPseudoClasses::HasSelectorListArg(list->mType), 1.821 + "unexpected pseudo-class"); 1.822 + nsString tmp; 1.823 + list->u.mSelectors->ToString(tmp, aSheet); 1.824 + aString.Append(tmp); 1.825 + } 1.826 + aString.Append(char16_t(')')); 1.827 + } 1.828 + } 1.829 +} 1.830 + 1.831 +bool 1.832 +nsCSSSelector::CanBeNamespaced(bool aIsNegated) const 1.833 +{ 1.834 + return !aIsNegated || 1.835 + (!mIDList && !mClassList && !mPseudoClassList && !mAttrList); 1.836 +} 1.837 + 1.838 +size_t 1.839 +nsCSSSelector::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.840 +{ 1.841 + size_t n = 0; 1.842 + const nsCSSSelector* s = this; 1.843 + while (s) { 1.844 + n += aMallocSizeOf(s); 1.845 + 1.846 + #define MEASURE(x) n += x ? x->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.847 + 1.848 + MEASURE(s->mIDList); 1.849 + MEASURE(s->mClassList); 1.850 + MEASURE(s->mPseudoClassList); 1.851 + MEASURE(s->mNegations); 1.852 + 1.853 + // Measurement of the following members may be added later if DMD finds it is 1.854 + // worthwhile: 1.855 + // - s->mAttrList 1.856 + // 1.857 + // The following members aren't measured: 1.858 + // - s->mLowercaseTag, because it's an atom and therefore shared 1.859 + // - s->mCasedTag, because it's an atom and therefore shared 1.860 + 1.861 + s = s->mNext; 1.862 + } 1.863 + return n; 1.864 +} 1.865 + 1.866 +// -- nsCSSSelectorList ------------------------------- 1.867 + 1.868 +nsCSSSelectorList::nsCSSSelectorList(void) 1.869 + : mSelectors(nullptr), 1.870 + mWeight(0), 1.871 + mNext(nullptr) 1.872 +{ 1.873 + MOZ_COUNT_CTOR(nsCSSSelectorList); 1.874 +} 1.875 + 1.876 +nsCSSSelectorList::~nsCSSSelectorList() 1.877 +{ 1.878 + MOZ_COUNT_DTOR(nsCSSSelectorList); 1.879 + delete mSelectors; 1.880 + NS_CSS_DELETE_LIST_MEMBER(nsCSSSelectorList, this, mNext); 1.881 +} 1.882 + 1.883 +nsCSSSelector* 1.884 +nsCSSSelectorList::AddSelector(char16_t aOperator) 1.885 +{ 1.886 + nsCSSSelector* newSel = new nsCSSSelector(); 1.887 + 1.888 + if (mSelectors) { 1.889 + NS_ASSERTION(aOperator != char16_t(0), "chaining without combinator"); 1.890 + mSelectors->SetOperator(aOperator); 1.891 + } else { 1.892 + NS_ASSERTION(aOperator == char16_t(0), "combinator without chaining"); 1.893 + } 1.894 + 1.895 + newSel->mNext = mSelectors; 1.896 + mSelectors = newSel; 1.897 + return newSel; 1.898 +} 1.899 + 1.900 +void 1.901 +nsCSSSelectorList::ToString(nsAString& aResult, nsCSSStyleSheet* aSheet) 1.902 +{ 1.903 + aResult.Truncate(); 1.904 + nsCSSSelectorList *p = this; 1.905 + for (;;) { 1.906 + p->mSelectors->ToString(aResult, aSheet, true); 1.907 + p = p->mNext; 1.908 + if (!p) 1.909 + break; 1.910 + aResult.AppendLiteral(", "); 1.911 + } 1.912 +} 1.913 + 1.914 +nsCSSSelectorList* 1.915 +nsCSSSelectorList::Clone(bool aDeep) const 1.916 +{ 1.917 + nsCSSSelectorList *result = new nsCSSSelectorList(); 1.918 + result->mWeight = mWeight; 1.919 + NS_IF_CLONE(mSelectors); 1.920 + 1.921 + if (aDeep) { 1.922 + NS_CSS_CLONE_LIST_MEMBER(nsCSSSelectorList, this, mNext, result, 1.923 + (false)); 1.924 + } 1.925 + return result; 1.926 +} 1.927 + 1.928 +size_t 1.929 +nsCSSSelectorList::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.930 +{ 1.931 + size_t n = 0; 1.932 + const nsCSSSelectorList* s = this; 1.933 + while (s) { 1.934 + n += aMallocSizeOf(s); 1.935 + n += s->mSelectors ? s->mSelectors->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.936 + s = s->mNext; 1.937 + } 1.938 + return n; 1.939 +} 1.940 + 1.941 +// -- ImportantRule ---------------------------------- 1.942 + 1.943 +namespace mozilla { 1.944 +namespace css { 1.945 + 1.946 +ImportantRule::ImportantRule(Declaration* aDeclaration) 1.947 + : mDeclaration(aDeclaration) 1.948 +{ 1.949 +} 1.950 + 1.951 +ImportantRule::~ImportantRule() 1.952 +{ 1.953 +} 1.954 + 1.955 +NS_IMPL_ISUPPORTS(ImportantRule, nsIStyleRule) 1.956 + 1.957 +/* virtual */ void 1.958 +ImportantRule::MapRuleInfoInto(nsRuleData* aRuleData) 1.959 +{ 1.960 + mDeclaration->MapImportantRuleInfoInto(aRuleData); 1.961 +} 1.962 + 1.963 +#ifdef DEBUG 1.964 +/* virtual */ void 1.965 +ImportantRule::List(FILE* out, int32_t aIndent) const 1.966 +{ 1.967 + // Indent 1.968 + for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); 1.969 + 1.970 + fprintf(out, "! Important declaration=%p\n", 1.971 + static_cast<void*>(mDeclaration)); 1.972 +} 1.973 +#endif 1.974 + 1.975 +} // namespace css 1.976 +} // namespace mozilla 1.977 + 1.978 +// -------------------------------------------------------- 1.979 + 1.980 +namespace mozilla { 1.981 +namespace css { 1.982 +class DOMCSSStyleRule; 1.983 +} 1.984 +} 1.985 + 1.986 +class DOMCSSDeclarationImpl : public nsDOMCSSDeclaration 1.987 +{ 1.988 +public: 1.989 + DOMCSSDeclarationImpl(css::StyleRule *aRule); 1.990 + virtual ~DOMCSSDeclarationImpl(void); 1.991 + 1.992 + NS_IMETHOD GetParentRule(nsIDOMCSSRule **aParent) MOZ_OVERRIDE; 1.993 + void DropReference(void); 1.994 + virtual css::Declaration* GetCSSDeclaration(bool aAllocate) MOZ_OVERRIDE; 1.995 + virtual nsresult SetCSSDeclaration(css::Declaration* aDecl) MOZ_OVERRIDE; 1.996 + virtual void GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) MOZ_OVERRIDE; 1.997 + virtual nsIDocument* DocToUpdate() MOZ_OVERRIDE; 1.998 + 1.999 + // Override |AddRef| and |Release| for being a member of 1.1000 + // |DOMCSSStyleRule|. Also, we need to forward QI for cycle 1.1001 + // collection things to DOMCSSStyleRule. 1.1002 + NS_DECL_ISUPPORTS_INHERITED 1.1003 + 1.1004 + virtual nsINode *GetParentObject() MOZ_OVERRIDE 1.1005 + { 1.1006 + return mRule ? mRule->GetDocument() : nullptr; 1.1007 + } 1.1008 + 1.1009 + friend class css::DOMCSSStyleRule; 1.1010 + 1.1011 +protected: 1.1012 + // This reference is not reference-counted. The rule object tells us 1.1013 + // when it's about to go away. 1.1014 + css::StyleRule *mRule; 1.1015 + 1.1016 + inline css::DOMCSSStyleRule* DomRule(); 1.1017 + 1.1018 +private: 1.1019 + // NOT TO BE IMPLEMENTED 1.1020 + // This object cannot be allocated on its own. It must be a member of 1.1021 + // DOMCSSStyleRule. 1.1022 + void* operator new(size_t size) CPP_THROW_NEW; 1.1023 +}; 1.1024 + 1.1025 +namespace mozilla { 1.1026 +namespace css { 1.1027 + 1.1028 +class DOMCSSStyleRule : public nsICSSStyleRuleDOMWrapper 1.1029 +{ 1.1030 +public: 1.1031 + DOMCSSStyleRule(StyleRule *aRule); 1.1032 + virtual ~DOMCSSStyleRule(); 1.1033 + 1.1034 + NS_DECL_CYCLE_COLLECTING_ISUPPORTS 1.1035 + NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(DOMCSSStyleRule) 1.1036 + NS_DECL_NSIDOMCSSRULE 1.1037 + NS_DECL_NSIDOMCSSSTYLERULE 1.1038 + 1.1039 + // nsICSSStyleRuleDOMWrapper 1.1040 + NS_IMETHOD GetCSSStyleRule(StyleRule **aResult); 1.1041 + 1.1042 + DOMCSSDeclarationImpl* DOMDeclaration() { return &mDOMDeclaration; } 1.1043 + 1.1044 + friend class ::DOMCSSDeclarationImpl; 1.1045 + 1.1046 +protected: 1.1047 + DOMCSSDeclarationImpl mDOMDeclaration; 1.1048 + 1.1049 + StyleRule* Rule() { 1.1050 + return mDOMDeclaration.mRule; 1.1051 + } 1.1052 +}; 1.1053 + 1.1054 +} // namespace css 1.1055 +} // namespace mozilla 1.1056 + 1.1057 +DOMCSSDeclarationImpl::DOMCSSDeclarationImpl(css::StyleRule *aRule) 1.1058 + : mRule(aRule) 1.1059 +{ 1.1060 + MOZ_COUNT_CTOR(DOMCSSDeclarationImpl); 1.1061 +} 1.1062 + 1.1063 +DOMCSSDeclarationImpl::~DOMCSSDeclarationImpl(void) 1.1064 +{ 1.1065 + NS_ASSERTION(!mRule, "DropReference not called."); 1.1066 + 1.1067 + MOZ_COUNT_DTOR(DOMCSSDeclarationImpl); 1.1068 +} 1.1069 + 1.1070 +inline css::DOMCSSStyleRule* DOMCSSDeclarationImpl::DomRule() 1.1071 +{ 1.1072 + return reinterpret_cast<css::DOMCSSStyleRule*> 1.1073 + (reinterpret_cast<char*>(this) - 1.1074 + offsetof(css::DOMCSSStyleRule, mDOMDeclaration)); 1.1075 +} 1.1076 + 1.1077 +NS_IMPL_ADDREF_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule()) 1.1078 +NS_IMPL_RELEASE_USING_AGGREGATOR(DOMCSSDeclarationImpl, DomRule()) 1.1079 + 1.1080 +NS_INTERFACE_MAP_BEGIN(DOMCSSDeclarationImpl) 1.1081 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.1082 + // We forward the cycle collection interfaces to DomRule(), which is 1.1083 + // never null (in fact, we're part of that object!) 1.1084 + if (aIID.Equals(NS_GET_IID(nsCycleCollectionISupports)) || 1.1085 + aIID.Equals(NS_GET_IID(nsXPCOMCycleCollectionParticipant))) { 1.1086 + return DomRule()->QueryInterface(aIID, aInstancePtr); 1.1087 + } 1.1088 + else 1.1089 +NS_IMPL_QUERY_TAIL_INHERITING(nsDOMCSSDeclaration) 1.1090 + 1.1091 +void 1.1092 +DOMCSSDeclarationImpl::DropReference(void) 1.1093 +{ 1.1094 + mRule = nullptr; 1.1095 +} 1.1096 + 1.1097 +css::Declaration* 1.1098 +DOMCSSDeclarationImpl::GetCSSDeclaration(bool aAllocate) 1.1099 +{ 1.1100 + if (mRule) { 1.1101 + return mRule->GetDeclaration(); 1.1102 + } else { 1.1103 + return nullptr; 1.1104 + } 1.1105 +} 1.1106 + 1.1107 +void 1.1108 +DOMCSSDeclarationImpl::GetCSSParsingEnvironment(CSSParsingEnvironment& aCSSParseEnv) 1.1109 +{ 1.1110 + GetCSSParsingEnvironmentForRule(mRule, aCSSParseEnv); 1.1111 +} 1.1112 + 1.1113 +NS_IMETHODIMP 1.1114 +DOMCSSDeclarationImpl::GetParentRule(nsIDOMCSSRule **aParent) 1.1115 +{ 1.1116 + NS_ENSURE_ARG_POINTER(aParent); 1.1117 + 1.1118 + if (!mRule) { 1.1119 + *aParent = nullptr; 1.1120 + return NS_OK; 1.1121 + } 1.1122 + 1.1123 + NS_IF_ADDREF(*aParent = mRule->GetDOMRule()); 1.1124 + return NS_OK; 1.1125 +} 1.1126 + 1.1127 +nsresult 1.1128 +DOMCSSDeclarationImpl::SetCSSDeclaration(css::Declaration* aDecl) 1.1129 +{ 1.1130 + NS_PRECONDITION(mRule, 1.1131 + "can only be called when |GetCSSDeclaration| returned a declaration"); 1.1132 + 1.1133 + nsCOMPtr<nsIDocument> owningDoc; 1.1134 + nsCOMPtr<nsIStyleSheet> sheet = mRule->GetStyleSheet(); 1.1135 + if (sheet) { 1.1136 + owningDoc = sheet->GetOwningDocument(); 1.1137 + } 1.1138 + 1.1139 + mozAutoDocUpdate updateBatch(owningDoc, UPDATE_STYLE, true); 1.1140 + 1.1141 + nsRefPtr<css::StyleRule> oldRule = mRule; 1.1142 + mRule = oldRule->DeclarationChanged(aDecl, true).take(); 1.1143 + if (!mRule) 1.1144 + return NS_ERROR_OUT_OF_MEMORY; 1.1145 + nsrefcnt cnt = mRule->Release(); 1.1146 + if (cnt == 0) { 1.1147 + NS_NOTREACHED("container didn't take ownership"); 1.1148 + mRule = nullptr; 1.1149 + return NS_ERROR_UNEXPECTED; 1.1150 + } 1.1151 + 1.1152 + if (owningDoc) { 1.1153 + owningDoc->StyleRuleChanged(sheet, oldRule, mRule); 1.1154 + } 1.1155 + return NS_OK; 1.1156 +} 1.1157 + 1.1158 +nsIDocument* 1.1159 +DOMCSSDeclarationImpl::DocToUpdate() 1.1160 +{ 1.1161 + return nullptr; 1.1162 +} 1.1163 + 1.1164 +// needs to be outside the namespace 1.1165 +DOMCI_DATA(CSSStyleRule, css::DOMCSSStyleRule) 1.1166 + 1.1167 +namespace mozilla { 1.1168 +namespace css { 1.1169 + 1.1170 +DOMCSSStyleRule::DOMCSSStyleRule(StyleRule* aRule) 1.1171 + : mDOMDeclaration(aRule) 1.1172 +{ 1.1173 +} 1.1174 + 1.1175 +DOMCSSStyleRule::~DOMCSSStyleRule() 1.1176 +{ 1.1177 +} 1.1178 + 1.1179 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMCSSStyleRule) 1.1180 + NS_INTERFACE_MAP_ENTRY(nsICSSStyleRuleDOMWrapper) 1.1181 + NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleRule) 1.1182 + NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRule) 1.1183 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.1184 + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleRule) 1.1185 +NS_INTERFACE_MAP_END 1.1186 + 1.1187 +NS_IMPL_CYCLE_COLLECTING_ADDREF(DOMCSSStyleRule) 1.1188 +NS_IMPL_CYCLE_COLLECTING_RELEASE(DOMCSSStyleRule) 1.1189 + 1.1190 +NS_IMPL_CYCLE_COLLECTION_CLASS(DOMCSSStyleRule) 1.1191 + 1.1192 +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(DOMCSSStyleRule) 1.1193 + // Trace the wrapper for our declaration. This just expands out 1.1194 + // NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER which we can't use 1.1195 + // directly because the wrapper is on the declaration, not on us. 1.1196 + tmp->DOMDeclaration()->TraceWrapper(aCallbacks, aClosure); 1.1197 +NS_IMPL_CYCLE_COLLECTION_TRACE_END 1.1198 + 1.1199 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(DOMCSSStyleRule) 1.1200 + // Unlink the wrapper for our declaraton. This just expands out 1.1201 + // NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER which we can't use 1.1202 + // directly because the wrapper is on the declaration, not on us. 1.1203 + tmp->DOMDeclaration()->ReleaseWrapper(static_cast<nsISupports*>(p)); 1.1204 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.1205 + 1.1206 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(DOMCSSStyleRule) 1.1207 + // Just NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS here: that will call 1.1208 + // into our Trace hook, where we do the right thing with declarations 1.1209 + // already. 1.1210 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.1211 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.1212 + 1.1213 +NS_IMETHODIMP 1.1214 +DOMCSSStyleRule::GetType(uint16_t* aType) 1.1215 +{ 1.1216 + *aType = nsIDOMCSSRule::STYLE_RULE; 1.1217 + 1.1218 + return NS_OK; 1.1219 +} 1.1220 + 1.1221 +NS_IMETHODIMP 1.1222 +DOMCSSStyleRule::GetCssText(nsAString& aCssText) 1.1223 +{ 1.1224 + if (!Rule()) { 1.1225 + aCssText.Truncate(); 1.1226 + } else { 1.1227 + Rule()->GetCssText(aCssText); 1.1228 + } 1.1229 + return NS_OK; 1.1230 +} 1.1231 + 1.1232 +NS_IMETHODIMP 1.1233 +DOMCSSStyleRule::SetCssText(const nsAString& aCssText) 1.1234 +{ 1.1235 + if (Rule()) { 1.1236 + Rule()->SetCssText(aCssText); 1.1237 + } 1.1238 + return NS_OK; 1.1239 +} 1.1240 + 1.1241 +NS_IMETHODIMP 1.1242 +DOMCSSStyleRule::GetParentStyleSheet(nsIDOMCSSStyleSheet** aSheet) 1.1243 +{ 1.1244 + if (!Rule()) { 1.1245 + *aSheet = nullptr; 1.1246 + return NS_OK; 1.1247 + } 1.1248 + return Rule()->GetParentStyleSheet(aSheet); 1.1249 +} 1.1250 + 1.1251 +NS_IMETHODIMP 1.1252 +DOMCSSStyleRule::GetParentRule(nsIDOMCSSRule** aParentRule) 1.1253 +{ 1.1254 + if (!Rule()) { 1.1255 + *aParentRule = nullptr; 1.1256 + return NS_OK; 1.1257 + } 1.1258 + return Rule()->GetParentRule(aParentRule); 1.1259 +} 1.1260 + 1.1261 +NS_IMETHODIMP 1.1262 +DOMCSSStyleRule::GetSelectorText(nsAString& aSelectorText) 1.1263 +{ 1.1264 + if (!Rule()) { 1.1265 + aSelectorText.Truncate(); 1.1266 + } else { 1.1267 + Rule()->GetSelectorText(aSelectorText); 1.1268 + } 1.1269 + return NS_OK; 1.1270 +} 1.1271 + 1.1272 +NS_IMETHODIMP 1.1273 +DOMCSSStyleRule::SetSelectorText(const nsAString& aSelectorText) 1.1274 +{ 1.1275 + if (Rule()) { 1.1276 + Rule()->SetSelectorText(aSelectorText); 1.1277 + } 1.1278 + return NS_OK; 1.1279 +} 1.1280 + 1.1281 +NS_IMETHODIMP 1.1282 +DOMCSSStyleRule::GetStyle(nsIDOMCSSStyleDeclaration** aStyle) 1.1283 +{ 1.1284 + *aStyle = &mDOMDeclaration; 1.1285 + NS_ADDREF(*aStyle); 1.1286 + return NS_OK; 1.1287 +} 1.1288 + 1.1289 +NS_IMETHODIMP 1.1290 +DOMCSSStyleRule::GetCSSStyleRule(StyleRule **aResult) 1.1291 +{ 1.1292 + *aResult = Rule(); 1.1293 + NS_IF_ADDREF(*aResult); 1.1294 + return NS_OK; 1.1295 +} 1.1296 + 1.1297 +} // namespace css 1.1298 +} // namespace mozilla 1.1299 + 1.1300 +// -- StyleRule ------------------------------------ 1.1301 + 1.1302 +namespace mozilla { 1.1303 +namespace css { 1.1304 + 1.1305 +StyleRule::StyleRule(nsCSSSelectorList* aSelector, 1.1306 + Declaration* aDeclaration) 1.1307 + : Rule(), 1.1308 + mSelector(aSelector), 1.1309 + mDeclaration(aDeclaration), 1.1310 + mImportantRule(nullptr), 1.1311 + mDOMRule(nullptr), 1.1312 + mLineNumber(0), 1.1313 + mColumnNumber(0), 1.1314 + mWasMatched(false) 1.1315 +{ 1.1316 + NS_PRECONDITION(aDeclaration, "must have a declaration"); 1.1317 +} 1.1318 + 1.1319 +// for |Clone| 1.1320 +StyleRule::StyleRule(const StyleRule& aCopy) 1.1321 + : Rule(aCopy), 1.1322 + mSelector(aCopy.mSelector ? aCopy.mSelector->Clone() : nullptr), 1.1323 + mDeclaration(new Declaration(*aCopy.mDeclaration)), 1.1324 + mImportantRule(nullptr), 1.1325 + mDOMRule(nullptr), 1.1326 + mLineNumber(aCopy.mLineNumber), 1.1327 + mColumnNumber(aCopy.mColumnNumber), 1.1328 + mWasMatched(false) 1.1329 +{ 1.1330 + // rest is constructed lazily on existing data 1.1331 +} 1.1332 + 1.1333 +// for |SetCSSDeclaration| 1.1334 +StyleRule::StyleRule(StyleRule& aCopy, 1.1335 + Declaration* aDeclaration) 1.1336 + : Rule(aCopy), 1.1337 + mSelector(aCopy.mSelector), 1.1338 + mDeclaration(aDeclaration), 1.1339 + mImportantRule(nullptr), 1.1340 + mDOMRule(aCopy.mDOMRule), 1.1341 + mLineNumber(aCopy.mLineNumber), 1.1342 + mColumnNumber(aCopy.mColumnNumber), 1.1343 + mWasMatched(false) 1.1344 +{ 1.1345 + // The DOM rule is replacing |aCopy| with |this|, so transfer 1.1346 + // the reverse pointer as well (and transfer ownership). 1.1347 + aCopy.mDOMRule = nullptr; 1.1348 + 1.1349 + // Similarly for the selector. 1.1350 + aCopy.mSelector = nullptr; 1.1351 + 1.1352 + // We are probably replacing the old declaration with |aDeclaration| 1.1353 + // instead of taking ownership of the old declaration; only null out 1.1354 + // aCopy.mDeclaration if we are taking ownership. 1.1355 + if (mDeclaration == aCopy.mDeclaration) { 1.1356 + // This should only ever happen if the declaration was modifiable. 1.1357 + mDeclaration->AssertMutable(); 1.1358 + aCopy.mDeclaration = nullptr; 1.1359 + } 1.1360 +} 1.1361 + 1.1362 +StyleRule::~StyleRule() 1.1363 +{ 1.1364 + delete mSelector; 1.1365 + delete mDeclaration; 1.1366 + NS_IF_RELEASE(mImportantRule); 1.1367 + if (mDOMRule) { 1.1368 + mDOMRule->DOMDeclaration()->DropReference(); 1.1369 + NS_RELEASE(mDOMRule); 1.1370 + } 1.1371 +} 1.1372 + 1.1373 +// QueryInterface implementation for StyleRule 1.1374 +NS_INTERFACE_MAP_BEGIN(StyleRule) 1.1375 + if (aIID.Equals(NS_GET_IID(mozilla::css::StyleRule))) { 1.1376 + *aInstancePtr = this; 1.1377 + NS_ADDREF_THIS(); 1.1378 + return NS_OK; 1.1379 + } 1.1380 + else 1.1381 + NS_INTERFACE_MAP_ENTRY(nsIStyleRule) 1.1382 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleRule) 1.1383 +NS_INTERFACE_MAP_END 1.1384 + 1.1385 +NS_IMPL_ADDREF(StyleRule) 1.1386 +NS_IMPL_RELEASE(StyleRule) 1.1387 + 1.1388 +void 1.1389 +StyleRule::RuleMatched() 1.1390 +{ 1.1391 + if (!mWasMatched) { 1.1392 + NS_ABORT_IF_FALSE(!mImportantRule, "should not have important rule yet"); 1.1393 + 1.1394 + mWasMatched = true; 1.1395 + mDeclaration->SetImmutable(); 1.1396 + if (mDeclaration->HasImportantData()) { 1.1397 + NS_ADDREF(mImportantRule = new ImportantRule(mDeclaration)); 1.1398 + } 1.1399 + } 1.1400 +} 1.1401 + 1.1402 +/* virtual */ int32_t 1.1403 +StyleRule::GetType() const 1.1404 +{ 1.1405 + return Rule::STYLE_RULE; 1.1406 +} 1.1407 + 1.1408 +/* virtual */ already_AddRefed<Rule> 1.1409 +StyleRule::Clone() const 1.1410 +{ 1.1411 + nsRefPtr<Rule> clone = new StyleRule(*this); 1.1412 + return clone.forget(); 1.1413 +} 1.1414 + 1.1415 +/* virtual */ nsIDOMCSSRule* 1.1416 +StyleRule::GetDOMRule() 1.1417 +{ 1.1418 + if (!mDOMRule) { 1.1419 + if (!GetStyleSheet()) { 1.1420 + // Inline style rules aren't supposed to have a DOM rule object, only 1.1421 + // a declaration. But if we do have one already, from a style sheet 1.1422 + // rule that used to be in a document, we still want to return it. 1.1423 + return nullptr; 1.1424 + } 1.1425 + mDOMRule = new DOMCSSStyleRule(this); 1.1426 + NS_ADDREF(mDOMRule); 1.1427 + } 1.1428 + return mDOMRule; 1.1429 +} 1.1430 + 1.1431 +/* virtual */ nsIDOMCSSRule* 1.1432 +StyleRule::GetExistingDOMRule() 1.1433 +{ 1.1434 + return mDOMRule; 1.1435 +} 1.1436 + 1.1437 +/* virtual */ already_AddRefed<StyleRule> 1.1438 +StyleRule::DeclarationChanged(Declaration* aDecl, 1.1439 + bool aHandleContainer) 1.1440 +{ 1.1441 + nsRefPtr<StyleRule> clone = new StyleRule(*this, aDecl); 1.1442 + 1.1443 + if (aHandleContainer) { 1.1444 + nsCSSStyleSheet* sheet = GetStyleSheet(); 1.1445 + if (mParentRule) { 1.1446 + if (sheet) { 1.1447 + sheet->ReplaceRuleInGroup(mParentRule, this, clone); 1.1448 + } else { 1.1449 + mParentRule->ReplaceStyleRule(this, clone); 1.1450 + } 1.1451 + } else if (sheet) { 1.1452 + sheet->ReplaceStyleRule(this, clone); 1.1453 + } 1.1454 + } 1.1455 + 1.1456 + return clone.forget(); 1.1457 +} 1.1458 + 1.1459 +/* virtual */ void 1.1460 +StyleRule::MapRuleInfoInto(nsRuleData* aRuleData) 1.1461 +{ 1.1462 + NS_ABORT_IF_FALSE(mWasMatched, 1.1463 + "somebody forgot to call css::StyleRule::RuleMatched"); 1.1464 + mDeclaration->MapNormalRuleInfoInto(aRuleData); 1.1465 +} 1.1466 + 1.1467 +#ifdef DEBUG 1.1468 +/* virtual */ void 1.1469 +StyleRule::List(FILE* out, int32_t aIndent) const 1.1470 +{ 1.1471 + // Indent 1.1472 + for (int32_t index = aIndent; --index >= 0; ) fputs(" ", out); 1.1473 + 1.1474 + nsAutoString buffer; 1.1475 + if (mSelector) 1.1476 + mSelector->ToString(buffer, GetStyleSheet()); 1.1477 + 1.1478 + buffer.AppendLiteral(" "); 1.1479 + fputs(NS_LossyConvertUTF16toASCII(buffer).get(), out); 1.1480 + if (nullptr != mDeclaration) { 1.1481 + mDeclaration->List(out); 1.1482 + } 1.1483 + else { 1.1484 + fputs("{ null declaration }", out); 1.1485 + } 1.1486 + fputs("\n", out); 1.1487 +} 1.1488 +#endif 1.1489 + 1.1490 +void 1.1491 +StyleRule::GetCssText(nsAString& aCssText) 1.1492 +{ 1.1493 + if (mSelector) { 1.1494 + mSelector->ToString(aCssText, GetStyleSheet()); 1.1495 + aCssText.Append(char16_t(' ')); 1.1496 + } 1.1497 + aCssText.Append(char16_t('{')); 1.1498 + aCssText.Append(char16_t(' ')); 1.1499 + if (mDeclaration) 1.1500 + { 1.1501 + nsAutoString tempString; 1.1502 + mDeclaration->ToString( tempString ); 1.1503 + aCssText.Append( tempString ); 1.1504 + } 1.1505 + aCssText.Append(char16_t(' ')); 1.1506 + aCssText.Append(char16_t('}')); 1.1507 +} 1.1508 + 1.1509 +void 1.1510 +StyleRule::SetCssText(const nsAString& aCssText) 1.1511 +{ 1.1512 + // XXX TBI - need to re-parse rule & declaration 1.1513 +} 1.1514 + 1.1515 +void 1.1516 +StyleRule::GetSelectorText(nsAString& aSelectorText) 1.1517 +{ 1.1518 + if (mSelector) 1.1519 + mSelector->ToString(aSelectorText, GetStyleSheet()); 1.1520 + else 1.1521 + aSelectorText.Truncate(); 1.1522 +} 1.1523 + 1.1524 +void 1.1525 +StyleRule::SetSelectorText(const nsAString& aSelectorText) 1.1526 +{ 1.1527 + // XXX TBI - get a parser and re-parse the selectors, 1.1528 + // XXX then need to re-compute the cascade 1.1529 + // XXX and dirty sheet 1.1530 +} 1.1531 + 1.1532 +/* virtual */ size_t 1.1533 +StyleRule::SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf) const 1.1534 +{ 1.1535 + size_t n = aMallocSizeOf(this); 1.1536 + n += mSelector ? mSelector->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.1537 + n += mDeclaration ? mDeclaration->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.1538 + 1.1539 + // Measurement of the following members may be added later if DMD finds it is 1.1540 + // worthwhile: 1.1541 + // - mImportantRule; 1.1542 + // - mDOMRule; 1.1543 + 1.1544 + return n; 1.1545 +} 1.1546 + 1.1547 + 1.1548 +} // namespace css 1.1549 +} // namespace mozilla