1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsCSSStyleSheet.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,2205 @@ 1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 1.5 +// vim:cindent:tabstop=2:expandtab:shiftwidth=2: 1.6 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.7 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.8 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.9 + 1.10 +/* representation of a CSS style sheet */ 1.11 + 1.12 +#include "nsCSSStyleSheet.h" 1.13 + 1.14 +#include "nsIAtom.h" 1.15 +#include "nsCSSRuleProcessor.h" 1.16 +#include "mozilla/MemoryReporting.h" 1.17 +#include "mozilla/dom/Element.h" 1.18 +#include "mozilla/dom/MediaListBinding.h" 1.19 +#include "mozilla/css/NameSpaceRule.h" 1.20 +#include "mozilla/css/GroupRule.h" 1.21 +#include "mozilla/css/ImportRule.h" 1.22 +#include "nsIMediaList.h" 1.23 +#include "nsIDocument.h" 1.24 +#include "nsPresContext.h" 1.25 +#include "nsGkAtoms.h" 1.26 +#include "nsString.h" 1.27 +#include "nsTArray.h" 1.28 +#include "nsIDOMCSSStyleSheet.h" 1.29 +#include "nsICSSRuleList.h" 1.30 +#include "nsIDOMMediaList.h" 1.31 +#include "nsIDOMNode.h" 1.32 +#include "nsError.h" 1.33 +#include "nsCSSParser.h" 1.34 +#include "mozilla/css/Loader.h" 1.35 +#include "nsICSSLoaderObserver.h" 1.36 +#include "nsNameSpaceManager.h" 1.37 +#include "nsXMLNameSpaceMap.h" 1.38 +#include "nsCOMPtr.h" 1.39 +#include "nsContentUtils.h" 1.40 +#include "nsIScriptSecurityManager.h" 1.41 +#include "mozAutoDocUpdate.h" 1.42 +#include "nsRuleNode.h" 1.43 +#include "nsMediaFeatures.h" 1.44 +#include "nsDOMClassInfoID.h" 1.45 +#include "mozilla/Likely.h" 1.46 +#include "mozilla/dom/CSSStyleSheetBinding.h" 1.47 +#include "nsComponentManagerUtils.h" 1.48 + 1.49 +using namespace mozilla; 1.50 +using namespace mozilla::dom; 1.51 + 1.52 + 1.53 +// ------------------------------- 1.54 +// Style Rule List for the DOM 1.55 +// 1.56 +class CSSRuleListImpl : public nsICSSRuleList 1.57 +{ 1.58 +public: 1.59 + CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet); 1.60 + 1.61 + NS_DECL_ISUPPORTS 1.62 + 1.63 + virtual nsIDOMCSSRule* 1.64 + IndexedGetter(uint32_t aIndex, bool& aFound) MOZ_OVERRIDE; 1.65 + virtual uint32_t 1.66 + Length() MOZ_OVERRIDE; 1.67 + 1.68 + void DropReference() { mStyleSheet = nullptr; } 1.69 + 1.70 +protected: 1.71 + virtual ~CSSRuleListImpl(); 1.72 + 1.73 + nsCSSStyleSheet* mStyleSheet; 1.74 +}; 1.75 + 1.76 +CSSRuleListImpl::CSSRuleListImpl(nsCSSStyleSheet *aStyleSheet) 1.77 +{ 1.78 + // Not reference counted to avoid circular references. 1.79 + // The style sheet will tell us when its going away. 1.80 + mStyleSheet = aStyleSheet; 1.81 +} 1.82 + 1.83 +CSSRuleListImpl::~CSSRuleListImpl() 1.84 +{ 1.85 +} 1.86 + 1.87 +DOMCI_DATA(CSSRuleList, CSSRuleListImpl) 1.88 + 1.89 +// QueryInterface implementation for CSSRuleList 1.90 +NS_INTERFACE_MAP_BEGIN(CSSRuleListImpl) 1.91 + NS_INTERFACE_MAP_ENTRY(nsICSSRuleList) 1.92 + NS_INTERFACE_MAP_ENTRY(nsIDOMCSSRuleList) 1.93 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.94 + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSRuleList) 1.95 +NS_INTERFACE_MAP_END 1.96 + 1.97 + 1.98 +NS_IMPL_ADDREF(CSSRuleListImpl) 1.99 +NS_IMPL_RELEASE(CSSRuleListImpl) 1.100 + 1.101 + 1.102 +uint32_t 1.103 +CSSRuleListImpl::Length() 1.104 +{ 1.105 + if (!mStyleSheet) { 1.106 + return 0; 1.107 + } 1.108 + 1.109 + return SafeCast<uint32_t>(mStyleSheet->StyleRuleCount()); 1.110 +} 1.111 + 1.112 +nsIDOMCSSRule* 1.113 +CSSRuleListImpl::IndexedGetter(uint32_t aIndex, bool& aFound) 1.114 +{ 1.115 + aFound = false; 1.116 + 1.117 + if (mStyleSheet) { 1.118 + // ensure rules have correct parent 1.119 + mStyleSheet->EnsureUniqueInner(); 1.120 + css::Rule* rule = mStyleSheet->GetStyleRuleAt(aIndex); 1.121 + if (rule) { 1.122 + aFound = true; 1.123 + return rule->GetDOMRule(); 1.124 + } 1.125 + } 1.126 + 1.127 + // Per spec: "Return Value ... null if ... not a valid index." 1.128 + return nullptr; 1.129 +} 1.130 + 1.131 +template <class Numeric> 1.132 +int32_t DoCompare(Numeric a, Numeric b) 1.133 +{ 1.134 + if (a == b) 1.135 + return 0; 1.136 + if (a < b) 1.137 + return -1; 1.138 + return 1; 1.139 +} 1.140 + 1.141 +bool 1.142 +nsMediaExpression::Matches(nsPresContext *aPresContext, 1.143 + const nsCSSValue& aActualValue) const 1.144 +{ 1.145 + const nsCSSValue& actual = aActualValue; 1.146 + const nsCSSValue& required = mValue; 1.147 + 1.148 + // If we don't have the feature, the match fails. 1.149 + if (actual.GetUnit() == eCSSUnit_Null) { 1.150 + return false; 1.151 + } 1.152 + 1.153 + // If the expression had no value to match, the match succeeds, 1.154 + // unless the value is an integer 0 or a zero length. 1.155 + if (required.GetUnit() == eCSSUnit_Null) { 1.156 + if (actual.GetUnit() == eCSSUnit_Integer) 1.157 + return actual.GetIntValue() != 0; 1.158 + if (actual.IsLengthUnit()) 1.159 + return actual.GetFloatValue() != 0; 1.160 + return true; 1.161 + } 1.162 + 1.163 + NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxAllowed || 1.164 + mRange == nsMediaExpression::eEqual, "yikes"); 1.165 + int32_t cmp; // -1 (actual < required) 1.166 + // 0 (actual == required) 1.167 + // 1 (actual > required) 1.168 + switch (mFeature->mValueType) { 1.169 + case nsMediaFeature::eLength: 1.170 + { 1.171 + NS_ASSERTION(actual.IsLengthUnit(), "bad actual value"); 1.172 + NS_ASSERTION(required.IsLengthUnit(), "bad required value"); 1.173 + nscoord actualCoord = nsRuleNode::CalcLengthWithInitialFont( 1.174 + aPresContext, actual); 1.175 + nscoord requiredCoord = nsRuleNode::CalcLengthWithInitialFont( 1.176 + aPresContext, required); 1.177 + cmp = DoCompare(actualCoord, requiredCoord); 1.178 + } 1.179 + break; 1.180 + case nsMediaFeature::eInteger: 1.181 + case nsMediaFeature::eBoolInteger: 1.182 + { 1.183 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Integer, 1.184 + "bad actual value"); 1.185 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Integer, 1.186 + "bad required value"); 1.187 + NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger || 1.188 + actual.GetIntValue() == 0 || actual.GetIntValue() == 1, 1.189 + "bad actual bool integer value"); 1.190 + NS_ASSERTION(mFeature->mValueType != nsMediaFeature::eBoolInteger || 1.191 + required.GetIntValue() == 0 || required.GetIntValue() == 1, 1.192 + "bad required bool integer value"); 1.193 + cmp = DoCompare(actual.GetIntValue(), required.GetIntValue()); 1.194 + } 1.195 + break; 1.196 + case nsMediaFeature::eFloat: 1.197 + { 1.198 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Number, 1.199 + "bad actual value"); 1.200 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Number, 1.201 + "bad required value"); 1.202 + cmp = DoCompare(actual.GetFloatValue(), required.GetFloatValue()); 1.203 + } 1.204 + break; 1.205 + case nsMediaFeature::eIntRatio: 1.206 + { 1.207 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Array && 1.208 + actual.GetArrayValue()->Count() == 2 && 1.209 + actual.GetArrayValue()->Item(0).GetUnit() == 1.210 + eCSSUnit_Integer && 1.211 + actual.GetArrayValue()->Item(1).GetUnit() == 1.212 + eCSSUnit_Integer, 1.213 + "bad actual value"); 1.214 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Array && 1.215 + required.GetArrayValue()->Count() == 2 && 1.216 + required.GetArrayValue()->Item(0).GetUnit() == 1.217 + eCSSUnit_Integer && 1.218 + required.GetArrayValue()->Item(1).GetUnit() == 1.219 + eCSSUnit_Integer, 1.220 + "bad required value"); 1.221 + // Convert to int64_t so we can multiply without worry. Note 1.222 + // that while the spec requires that both halves of |required| 1.223 + // be positive, the numerator or denominator of |actual| might 1.224 + // be zero (e.g., when testing 'aspect-ratio' on a 0-width or 1.225 + // 0-height iframe). 1.226 + int64_t actualNum = actual.GetArrayValue()->Item(0).GetIntValue(), 1.227 + actualDen = actual.GetArrayValue()->Item(1).GetIntValue(), 1.228 + requiredNum = required.GetArrayValue()->Item(0).GetIntValue(), 1.229 + requiredDen = required.GetArrayValue()->Item(1).GetIntValue(); 1.230 + cmp = DoCompare(actualNum * requiredDen, requiredNum * actualDen); 1.231 + } 1.232 + break; 1.233 + case nsMediaFeature::eResolution: 1.234 + { 1.235 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Inch || 1.236 + actual.GetUnit() == eCSSUnit_Pixel || 1.237 + actual.GetUnit() == eCSSUnit_Centimeter, 1.238 + "bad actual value"); 1.239 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Inch || 1.240 + required.GetUnit() == eCSSUnit_Pixel || 1.241 + required.GetUnit() == eCSSUnit_Centimeter, 1.242 + "bad required value"); 1.243 + float actualDPI = actual.GetFloatValue(); 1.244 + if (actual.GetUnit() == eCSSUnit_Centimeter) { 1.245 + actualDPI = actualDPI * 2.54f; 1.246 + } else if (actual.GetUnit() == eCSSUnit_Pixel) { 1.247 + actualDPI = actualDPI * 96.0f; 1.248 + } 1.249 + float requiredDPI = required.GetFloatValue(); 1.250 + if (required.GetUnit() == eCSSUnit_Centimeter) { 1.251 + requiredDPI = requiredDPI * 2.54f; 1.252 + } else if (required.GetUnit() == eCSSUnit_Pixel) { 1.253 + requiredDPI = requiredDPI * 96.0f; 1.254 + } 1.255 + cmp = DoCompare(actualDPI, requiredDPI); 1.256 + } 1.257 + break; 1.258 + case nsMediaFeature::eEnumerated: 1.259 + { 1.260 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Enumerated, 1.261 + "bad actual value"); 1.262 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Enumerated, 1.263 + "bad required value"); 1.264 + NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed, 1.265 + "bad range"); // we asserted above about mRange 1.266 + // We don't really need DoCompare, but it doesn't hurt (and 1.267 + // maybe the compiler will condense this case with eInteger). 1.268 + cmp = DoCompare(actual.GetIntValue(), required.GetIntValue()); 1.269 + } 1.270 + break; 1.271 + case nsMediaFeature::eIdent: 1.272 + { 1.273 + NS_ASSERTION(actual.GetUnit() == eCSSUnit_Ident, 1.274 + "bad actual value"); 1.275 + NS_ASSERTION(required.GetUnit() == eCSSUnit_Ident, 1.276 + "bad required value"); 1.277 + NS_ASSERTION(mFeature->mRangeType == nsMediaFeature::eMinMaxNotAllowed, 1.278 + "bad range"); 1.279 + cmp = !(actual == required); // string comparison 1.280 + } 1.281 + break; 1.282 + } 1.283 + switch (mRange) { 1.284 + case nsMediaExpression::eMin: 1.285 + return cmp != -1; 1.286 + case nsMediaExpression::eMax: 1.287 + return cmp != 1; 1.288 + case nsMediaExpression::eEqual: 1.289 + return cmp == 0; 1.290 + } 1.291 + NS_NOTREACHED("unexpected mRange"); 1.292 + return false; 1.293 +} 1.294 + 1.295 +void 1.296 +nsMediaQueryResultCacheKey::AddExpression(const nsMediaExpression* aExpression, 1.297 + bool aExpressionMatches) 1.298 +{ 1.299 + const nsMediaFeature *feature = aExpression->mFeature; 1.300 + FeatureEntry *entry = nullptr; 1.301 + for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) { 1.302 + if (mFeatureCache[i].mFeature == feature) { 1.303 + entry = &mFeatureCache[i]; 1.304 + break; 1.305 + } 1.306 + } 1.307 + if (!entry) { 1.308 + entry = mFeatureCache.AppendElement(); 1.309 + if (!entry) { 1.310 + return; /* out of memory */ 1.311 + } 1.312 + entry->mFeature = feature; 1.313 + } 1.314 + 1.315 + ExpressionEntry eentry = { *aExpression, aExpressionMatches }; 1.316 + entry->mExpressions.AppendElement(eentry); 1.317 +} 1.318 + 1.319 +bool 1.320 +nsMediaQueryResultCacheKey::Matches(nsPresContext* aPresContext) const 1.321 +{ 1.322 + if (aPresContext->Medium() != mMedium) { 1.323 + return false; 1.324 + } 1.325 + 1.326 + for (uint32_t i = 0; i < mFeatureCache.Length(); ++i) { 1.327 + const FeatureEntry *entry = &mFeatureCache[i]; 1.328 + nsCSSValue actual; 1.329 + nsresult rv = 1.330 + (entry->mFeature->mGetter)(aPresContext, entry->mFeature, actual); 1.331 + NS_ENSURE_SUCCESS(rv, false); // any better ideas? 1.332 + 1.333 + for (uint32_t j = 0; j < entry->mExpressions.Length(); ++j) { 1.334 + const ExpressionEntry &eentry = entry->mExpressions[j]; 1.335 + if (eentry.mExpression.Matches(aPresContext, actual) != 1.336 + eentry.mExpressionMatches) { 1.337 + return false; 1.338 + } 1.339 + } 1.340 + } 1.341 + 1.342 + return true; 1.343 +} 1.344 + 1.345 +void 1.346 +nsMediaQuery::AppendToString(nsAString& aString) const 1.347 +{ 1.348 + if (mHadUnknownExpression) { 1.349 + aString.AppendLiteral("not all"); 1.350 + return; 1.351 + } 1.352 + 1.353 + NS_ASSERTION(!mNegated || !mHasOnly, "can't have not and only"); 1.354 + NS_ASSERTION(!mTypeOmitted || (!mNegated && !mHasOnly), 1.355 + "can't have not or only when type is omitted"); 1.356 + if (!mTypeOmitted) { 1.357 + if (mNegated) { 1.358 + aString.AppendLiteral("not "); 1.359 + } else if (mHasOnly) { 1.360 + aString.AppendLiteral("only "); 1.361 + } 1.362 + aString.Append(nsDependentAtomString(mMediaType)); 1.363 + } 1.364 + 1.365 + for (uint32_t i = 0, i_end = mExpressions.Length(); i < i_end; ++i) { 1.366 + if (i > 0 || !mTypeOmitted) 1.367 + aString.AppendLiteral(" and "); 1.368 + aString.AppendLiteral("("); 1.369 + 1.370 + const nsMediaExpression &expr = mExpressions[i]; 1.371 + if (expr.mRange == nsMediaExpression::eMin) { 1.372 + aString.AppendLiteral("min-"); 1.373 + } else if (expr.mRange == nsMediaExpression::eMax) { 1.374 + aString.AppendLiteral("max-"); 1.375 + } 1.376 + 1.377 + const nsMediaFeature *feature = expr.mFeature; 1.378 + aString.Append(nsDependentAtomString(*feature->mName)); 1.379 + 1.380 + if (expr.mValue.GetUnit() != eCSSUnit_Null) { 1.381 + aString.AppendLiteral(": "); 1.382 + switch (feature->mValueType) { 1.383 + case nsMediaFeature::eLength: 1.384 + NS_ASSERTION(expr.mValue.IsLengthUnit(), "bad unit"); 1.385 + // Use 'width' as a property that takes length values 1.386 + // written in the normal way. 1.387 + expr.mValue.AppendToString(eCSSProperty_width, aString, 1.388 + nsCSSValue::eNormalized); 1.389 + break; 1.390 + case nsMediaFeature::eInteger: 1.391 + case nsMediaFeature::eBoolInteger: 1.392 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Integer, 1.393 + "bad unit"); 1.394 + // Use 'z-index' as a property that takes integer values 1.395 + // written without anything extra. 1.396 + expr.mValue.AppendToString(eCSSProperty_z_index, aString, 1.397 + nsCSSValue::eNormalized); 1.398 + break; 1.399 + case nsMediaFeature::eFloat: 1.400 + { 1.401 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Number, 1.402 + "bad unit"); 1.403 + // Use 'line-height' as a property that takes float values 1.404 + // written in the normal way. 1.405 + expr.mValue.AppendToString(eCSSProperty_line_height, aString, 1.406 + nsCSSValue::eNormalized); 1.407 + } 1.408 + break; 1.409 + case nsMediaFeature::eIntRatio: 1.410 + { 1.411 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Array, 1.412 + "bad unit"); 1.413 + nsCSSValue::Array *array = expr.mValue.GetArrayValue(); 1.414 + NS_ASSERTION(array->Count() == 2, "unexpected length"); 1.415 + NS_ASSERTION(array->Item(0).GetUnit() == eCSSUnit_Integer, 1.416 + "bad unit"); 1.417 + NS_ASSERTION(array->Item(1).GetUnit() == eCSSUnit_Integer, 1.418 + "bad unit"); 1.419 + array->Item(0).AppendToString(eCSSProperty_z_index, aString, 1.420 + nsCSSValue::eNormalized); 1.421 + aString.AppendLiteral("/"); 1.422 + array->Item(1).AppendToString(eCSSProperty_z_index, aString, 1.423 + nsCSSValue::eNormalized); 1.424 + } 1.425 + break; 1.426 + case nsMediaFeature::eResolution: 1.427 + { 1.428 + aString.AppendFloat(expr.mValue.GetFloatValue()); 1.429 + if (expr.mValue.GetUnit() == eCSSUnit_Inch) { 1.430 + aString.AppendLiteral("dpi"); 1.431 + } else if (expr.mValue.GetUnit() == eCSSUnit_Pixel) { 1.432 + aString.AppendLiteral("dppx"); 1.433 + } else { 1.434 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Centimeter, 1.435 + "bad unit"); 1.436 + aString.AppendLiteral("dpcm"); 1.437 + } 1.438 + } 1.439 + break; 1.440 + case nsMediaFeature::eEnumerated: 1.441 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Enumerated, 1.442 + "bad unit"); 1.443 + AppendASCIItoUTF16( 1.444 + nsCSSProps::ValueToKeyword(expr.mValue.GetIntValue(), 1.445 + feature->mData.mKeywordTable), 1.446 + aString); 1.447 + break; 1.448 + case nsMediaFeature::eIdent: 1.449 + NS_ASSERTION(expr.mValue.GetUnit() == eCSSUnit_Ident, 1.450 + "bad unit"); 1.451 + aString.Append(expr.mValue.GetStringBufferValue()); 1.452 + break; 1.453 + } 1.454 + } 1.455 + 1.456 + aString.AppendLiteral(")"); 1.457 + } 1.458 +} 1.459 + 1.460 +nsMediaQuery* 1.461 +nsMediaQuery::Clone() const 1.462 +{ 1.463 + return new nsMediaQuery(*this); 1.464 +} 1.465 + 1.466 +bool 1.467 +nsMediaQuery::Matches(nsPresContext* aPresContext, 1.468 + nsMediaQueryResultCacheKey* aKey) const 1.469 +{ 1.470 + if (mHadUnknownExpression) 1.471 + return false; 1.472 + 1.473 + bool match = 1.474 + mMediaType == aPresContext->Medium() || mMediaType == nsGkAtoms::all; 1.475 + for (uint32_t i = 0, i_end = mExpressions.Length(); match && i < i_end; ++i) { 1.476 + const nsMediaExpression &expr = mExpressions[i]; 1.477 + nsCSSValue actual; 1.478 + nsresult rv = 1.479 + (expr.mFeature->mGetter)(aPresContext, expr.mFeature, actual); 1.480 + NS_ENSURE_SUCCESS(rv, false); // any better ideas? 1.481 + 1.482 + match = expr.Matches(aPresContext, actual); 1.483 + if (aKey) { 1.484 + aKey->AddExpression(&expr, match); 1.485 + } 1.486 + } 1.487 + 1.488 + return match == !mNegated; 1.489 +} 1.490 + 1.491 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsMediaList) 1.492 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.493 + NS_INTERFACE_MAP_ENTRY(nsIDOMMediaList) 1.494 + NS_INTERFACE_MAP_ENTRY(nsISupports) 1.495 +NS_INTERFACE_MAP_END 1.496 + 1.497 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsMediaList) 1.498 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsMediaList) 1.499 + 1.500 +NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE_0(nsMediaList) 1.501 + 1.502 +nsMediaList::nsMediaList() 1.503 + : mStyleSheet(nullptr) 1.504 +{ 1.505 + SetIsDOMBinding(); 1.506 +} 1.507 + 1.508 +nsMediaList::~nsMediaList() 1.509 +{ 1.510 +} 1.511 + 1.512 +/* virtual */ JSObject* 1.513 +nsMediaList::WrapObject(JSContext* aCx) 1.514 +{ 1.515 + return MediaListBinding::Wrap(aCx, this); 1.516 +} 1.517 + 1.518 +void 1.519 +nsMediaList::GetText(nsAString& aMediaText) 1.520 +{ 1.521 + aMediaText.Truncate(); 1.522 + 1.523 + for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) { 1.524 + nsMediaQuery* query = mArray[i]; 1.525 + 1.526 + query->AppendToString(aMediaText); 1.527 + 1.528 + if (i + 1 < i_end) { 1.529 + aMediaText.AppendLiteral(", "); 1.530 + } 1.531 + } 1.532 +} 1.533 + 1.534 +// XXXbz this is so ill-defined in the spec, it's not clear quite what 1.535 +// it should be doing.... 1.536 +void 1.537 +nsMediaList::SetText(const nsAString& aMediaText) 1.538 +{ 1.539 + nsCSSParser parser; 1.540 + 1.541 + bool htmlMode = mStyleSheet && mStyleSheet->GetOwnerNode(); 1.542 + 1.543 + parser.ParseMediaList(aMediaText, nullptr, 0, this, htmlMode); 1.544 +} 1.545 + 1.546 +bool 1.547 +nsMediaList::Matches(nsPresContext* aPresContext, 1.548 + nsMediaQueryResultCacheKey* aKey) 1.549 +{ 1.550 + for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) { 1.551 + if (mArray[i]->Matches(aPresContext, aKey)) { 1.552 + return true; 1.553 + } 1.554 + } 1.555 + return mArray.IsEmpty(); 1.556 +} 1.557 + 1.558 +nsresult 1.559 +nsMediaList::SetStyleSheet(nsCSSStyleSheet *aSheet) 1.560 +{ 1.561 + NS_ASSERTION(aSheet == mStyleSheet || !aSheet || !mStyleSheet, 1.562 + "multiple style sheets competing for one media list"); 1.563 + mStyleSheet = aSheet; 1.564 + return NS_OK; 1.565 +} 1.566 + 1.567 +already_AddRefed<nsMediaList> 1.568 +nsMediaList::Clone() 1.569 +{ 1.570 + nsRefPtr<nsMediaList> result = new nsMediaList(); 1.571 + result->mArray.AppendElements(mArray.Length()); 1.572 + for (uint32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) { 1.573 + result->mArray[i] = mArray[i]->Clone(); 1.574 + MOZ_ASSERT(result->mArray[i]); 1.575 + } 1.576 + return result.forget(); 1.577 +} 1.578 + 1.579 +NS_IMETHODIMP 1.580 +nsMediaList::GetMediaText(nsAString& aMediaText) 1.581 +{ 1.582 + GetText(aMediaText); 1.583 + return NS_OK; 1.584 +} 1.585 + 1.586 +// "sheet" should be an nsCSSStyleSheet and "doc" should be an 1.587 +// nsCOMPtr<nsIDocument> 1.588 +#define BEGIN_MEDIA_CHANGE(sheet, doc) \ 1.589 + if (sheet) { \ 1.590 + doc = sheet->GetOwningDocument(); \ 1.591 + } \ 1.592 + mozAutoDocUpdate updateBatch(doc, UPDATE_STYLE, true); \ 1.593 + if (sheet) { \ 1.594 + sheet->WillDirty(); \ 1.595 + } 1.596 + 1.597 +#define END_MEDIA_CHANGE(sheet, doc) \ 1.598 + if (sheet) { \ 1.599 + sheet->DidDirty(); \ 1.600 + } \ 1.601 + /* XXXldb Pass something meaningful? */ \ 1.602 + if (doc) { \ 1.603 + doc->StyleRuleChanged(sheet, nullptr, nullptr); \ 1.604 + } 1.605 + 1.606 + 1.607 +NS_IMETHODIMP 1.608 +nsMediaList::SetMediaText(const nsAString& aMediaText) 1.609 +{ 1.610 + nsCOMPtr<nsIDocument> doc; 1.611 + 1.612 + BEGIN_MEDIA_CHANGE(mStyleSheet, doc) 1.613 + 1.614 + SetText(aMediaText); 1.615 + 1.616 + END_MEDIA_CHANGE(mStyleSheet, doc) 1.617 + 1.618 + return NS_OK; 1.619 +} 1.620 + 1.621 +NS_IMETHODIMP 1.622 +nsMediaList::GetLength(uint32_t* aLength) 1.623 +{ 1.624 + NS_ENSURE_ARG_POINTER(aLength); 1.625 + 1.626 + *aLength = Length(); 1.627 + return NS_OK; 1.628 +} 1.629 + 1.630 +NS_IMETHODIMP 1.631 +nsMediaList::Item(uint32_t aIndex, nsAString& aReturn) 1.632 +{ 1.633 + bool dummy; 1.634 + IndexedGetter(aIndex, dummy, aReturn); 1.635 + return NS_OK; 1.636 +} 1.637 + 1.638 +void 1.639 +nsMediaList::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aReturn) 1.640 +{ 1.641 + if (aIndex < Length()) { 1.642 + aFound = true; 1.643 + aReturn.Truncate(); 1.644 + mArray[aIndex]->AppendToString(aReturn); 1.645 + } else { 1.646 + aFound = false; 1.647 + SetDOMStringToNull(aReturn); 1.648 + } 1.649 +} 1.650 + 1.651 +NS_IMETHODIMP 1.652 +nsMediaList::DeleteMedium(const nsAString& aOldMedium) 1.653 +{ 1.654 + nsresult rv = NS_OK; 1.655 + nsCOMPtr<nsIDocument> doc; 1.656 + 1.657 + BEGIN_MEDIA_CHANGE(mStyleSheet, doc) 1.658 + 1.659 + rv = Delete(aOldMedium); 1.660 + if (NS_FAILED(rv)) 1.661 + return rv; 1.662 + 1.663 + END_MEDIA_CHANGE(mStyleSheet, doc) 1.664 + 1.665 + return rv; 1.666 +} 1.667 + 1.668 +NS_IMETHODIMP 1.669 +nsMediaList::AppendMedium(const nsAString& aNewMedium) 1.670 +{ 1.671 + nsresult rv = NS_OK; 1.672 + nsCOMPtr<nsIDocument> doc; 1.673 + 1.674 + BEGIN_MEDIA_CHANGE(mStyleSheet, doc) 1.675 + 1.676 + rv = Append(aNewMedium); 1.677 + if (NS_FAILED(rv)) 1.678 + return rv; 1.679 + 1.680 + END_MEDIA_CHANGE(mStyleSheet, doc) 1.681 + 1.682 + return rv; 1.683 +} 1.684 + 1.685 +nsresult 1.686 +nsMediaList::Delete(const nsAString& aOldMedium) 1.687 +{ 1.688 + if (aOldMedium.IsEmpty()) 1.689 + return NS_ERROR_DOM_NOT_FOUND_ERR; 1.690 + 1.691 + for (int32_t i = 0, i_end = mArray.Length(); i < i_end; ++i) { 1.692 + nsMediaQuery* query = mArray[i]; 1.693 + 1.694 + nsAutoString buf; 1.695 + query->AppendToString(buf); 1.696 + if (buf == aOldMedium) { 1.697 + mArray.RemoveElementAt(i); 1.698 + return NS_OK; 1.699 + } 1.700 + } 1.701 + 1.702 + return NS_ERROR_DOM_NOT_FOUND_ERR; 1.703 +} 1.704 + 1.705 +nsresult 1.706 +nsMediaList::Append(const nsAString& aNewMedium) 1.707 +{ 1.708 + if (aNewMedium.IsEmpty()) 1.709 + return NS_ERROR_DOM_NOT_FOUND_ERR; 1.710 + 1.711 + Delete(aNewMedium); 1.712 + 1.713 + nsresult rv = NS_OK; 1.714 + nsTArray<nsAutoPtr<nsMediaQuery> > buf; 1.715 + mArray.SwapElements(buf); 1.716 + SetText(aNewMedium); 1.717 + if (mArray.Length() == 1) { 1.718 + nsMediaQuery *query = mArray[0].forget(); 1.719 + if (!buf.AppendElement(query)) { 1.720 + delete query; 1.721 + rv = NS_ERROR_OUT_OF_MEMORY; 1.722 + } 1.723 + } 1.724 + 1.725 + mArray.SwapElements(buf); 1.726 + return rv; 1.727 +} 1.728 + 1.729 +// ------------------------------- 1.730 +// CSS Style Sheet Inner Data Container 1.731 +// 1.732 + 1.733 + 1.734 +nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheet* aPrimarySheet, 1.735 + CORSMode aCORSMode) 1.736 + : mSheets(), 1.737 + mCORSMode(aCORSMode), 1.738 + mComplete(false) 1.739 +#ifdef DEBUG 1.740 + , mPrincipalSet(false) 1.741 +#endif 1.742 +{ 1.743 + MOZ_COUNT_CTOR(nsCSSStyleSheetInner); 1.744 + mSheets.AppendElement(aPrimarySheet); 1.745 + 1.746 + mPrincipal = do_CreateInstance("@mozilla.org/nullprincipal;1"); 1.747 + if (!mPrincipal) { 1.748 + NS_RUNTIMEABORT("OOM"); 1.749 + } 1.750 +} 1.751 + 1.752 +static bool SetStyleSheetReference(css::Rule* aRule, void* aSheet) 1.753 +{ 1.754 + if (aRule) { 1.755 + aRule->SetStyleSheet(static_cast<nsCSSStyleSheet*>(aSheet)); 1.756 + } 1.757 + return true; 1.758 +} 1.759 + 1.760 +struct ChildSheetListBuilder { 1.761 + nsRefPtr<nsCSSStyleSheet>* sheetSlot; 1.762 + nsCSSStyleSheet* parent; 1.763 + 1.764 + void SetParentLinks(nsCSSStyleSheet* aSheet) { 1.765 + aSheet->mParent = parent; 1.766 + aSheet->SetOwningDocument(parent->mDocument); 1.767 + } 1.768 + 1.769 + static void ReparentChildList(nsCSSStyleSheet* aPrimarySheet, 1.770 + nsCSSStyleSheet* aFirstChild) 1.771 + { 1.772 + for (nsCSSStyleSheet *child = aFirstChild; child; child = child->mNext) { 1.773 + child->mParent = aPrimarySheet; 1.774 + child->SetOwningDocument(aPrimarySheet->mDocument); 1.775 + } 1.776 + } 1.777 +}; 1.778 + 1.779 +bool 1.780 +nsCSSStyleSheet::RebuildChildList(css::Rule* aRule, void* aBuilder) 1.781 +{ 1.782 + int32_t type = aRule->GetType(); 1.783 + if (type < css::Rule::IMPORT_RULE) { 1.784 + // Keep going till we get to the import rules. 1.785 + return true; 1.786 + } 1.787 + 1.788 + if (type != css::Rule::IMPORT_RULE) { 1.789 + // We're past all the import rules; stop the enumeration. 1.790 + return false; 1.791 + } 1.792 + 1.793 + ChildSheetListBuilder* builder = 1.794 + static_cast<ChildSheetListBuilder*>(aBuilder); 1.795 + 1.796 + // XXXbz We really need to decomtaminate all this stuff. Is there a reason 1.797 + // that I can't just QI to ImportRule and get an nsCSSStyleSheet 1.798 + // directly from it? 1.799 + nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(aRule)); 1.800 + NS_ASSERTION(importRule, "GetType lied"); 1.801 + 1.802 + nsCOMPtr<nsIDOMCSSStyleSheet> childSheet; 1.803 + importRule->GetStyleSheet(getter_AddRefs(childSheet)); 1.804 + 1.805 + // Have to do this QI to be safe, since XPConnect can fake 1.806 + // nsIDOMCSSStyleSheets 1.807 + nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(childSheet); 1.808 + if (!cssSheet) { 1.809 + return true; 1.810 + } 1.811 + 1.812 + (*builder->sheetSlot) = cssSheet; 1.813 + builder->SetParentLinks(*builder->sheetSlot); 1.814 + builder->sheetSlot = &(*builder->sheetSlot)->mNext; 1.815 + return true; 1.816 +} 1.817 + 1.818 +size_t 1.819 +nsCSSStyleSheet::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const 1.820 +{ 1.821 + size_t n = 0; 1.822 + const nsCSSStyleSheet* s = this; 1.823 + while (s) { 1.824 + n += aMallocSizeOf(s); 1.825 + 1.826 + // Each inner can be shared by multiple sheets. So we only count the inner 1.827 + // if this sheet is the first one in the list of those sharing it. As a 1.828 + // result, the first such sheet takes all the blame for the memory 1.829 + // consumption of the inner, which isn't ideal but it's better than 1.830 + // double-counting the inner. 1.831 + if (s->mInner->mSheets[0] == s) { 1.832 + n += s->mInner->SizeOfIncludingThis(aMallocSizeOf); 1.833 + } 1.834 + 1.835 + // Measurement of the following members may be added later if DMD finds it 1.836 + // is worthwhile: 1.837 + // - s->mTitle 1.838 + // - s->mMedia 1.839 + // - s->mRuleCollection 1.840 + // - s->mRuleProcessors 1.841 + // 1.842 + // The following members are not measured: 1.843 + // - s->mOwnerRule, because it's non-owning 1.844 + 1.845 + s = s->mNext; 1.846 + } 1.847 + return n; 1.848 +} 1.849 + 1.850 +nsCSSStyleSheetInner::nsCSSStyleSheetInner(nsCSSStyleSheetInner& aCopy, 1.851 + nsCSSStyleSheet* aPrimarySheet) 1.852 + : mSheets(), 1.853 + mSheetURI(aCopy.mSheetURI), 1.854 + mOriginalSheetURI(aCopy.mOriginalSheetURI), 1.855 + mBaseURI(aCopy.mBaseURI), 1.856 + mPrincipal(aCopy.mPrincipal), 1.857 + mCORSMode(aCopy.mCORSMode), 1.858 + mComplete(aCopy.mComplete) 1.859 +#ifdef DEBUG 1.860 + , mPrincipalSet(aCopy.mPrincipalSet) 1.861 +#endif 1.862 +{ 1.863 + MOZ_COUNT_CTOR(nsCSSStyleSheetInner); 1.864 + AddSheet(aPrimarySheet); 1.865 + aCopy.mOrderedRules.EnumerateForwards(css::GroupRule::CloneRuleInto, &mOrderedRules); 1.866 + mOrderedRules.EnumerateForwards(SetStyleSheetReference, aPrimarySheet); 1.867 + 1.868 + ChildSheetListBuilder builder = { &mFirstChild, aPrimarySheet }; 1.869 + mOrderedRules.EnumerateForwards(nsCSSStyleSheet::RebuildChildList, &builder); 1.870 + 1.871 + RebuildNameSpaces(); 1.872 +} 1.873 + 1.874 +nsCSSStyleSheetInner::~nsCSSStyleSheetInner() 1.875 +{ 1.876 + MOZ_COUNT_DTOR(nsCSSStyleSheetInner); 1.877 + mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr); 1.878 +} 1.879 + 1.880 +nsCSSStyleSheetInner* 1.881 +nsCSSStyleSheetInner::CloneFor(nsCSSStyleSheet* aPrimarySheet) 1.882 +{ 1.883 + return new nsCSSStyleSheetInner(*this, aPrimarySheet); 1.884 +} 1.885 + 1.886 +void 1.887 +nsCSSStyleSheetInner::AddSheet(nsCSSStyleSheet* aSheet) 1.888 +{ 1.889 + mSheets.AppendElement(aSheet); 1.890 +} 1.891 + 1.892 +void 1.893 +nsCSSStyleSheetInner::RemoveSheet(nsCSSStyleSheet* aSheet) 1.894 +{ 1.895 + if (1 == mSheets.Length()) { 1.896 + NS_ASSERTION(aSheet == mSheets.ElementAt(0), "bad parent"); 1.897 + delete this; 1.898 + return; 1.899 + } 1.900 + if (aSheet == mSheets.ElementAt(0)) { 1.901 + mSheets.RemoveElementAt(0); 1.902 + NS_ASSERTION(mSheets.Length(), "no parents"); 1.903 + mOrderedRules.EnumerateForwards(SetStyleSheetReference, 1.904 + mSheets.ElementAt(0)); 1.905 + 1.906 + ChildSheetListBuilder::ReparentChildList(mSheets[0], mFirstChild); 1.907 + } 1.908 + else { 1.909 + mSheets.RemoveElement(aSheet); 1.910 + } 1.911 +} 1.912 + 1.913 +static void 1.914 +AddNamespaceRuleToMap(css::Rule* aRule, nsXMLNameSpaceMap* aMap) 1.915 +{ 1.916 + NS_ASSERTION(aRule->GetType() == css::Rule::NAMESPACE_RULE, "Bogus rule type"); 1.917 + 1.918 + nsRefPtr<css::NameSpaceRule> nameSpaceRule = do_QueryObject(aRule); 1.919 + 1.920 + nsAutoString urlSpec; 1.921 + nameSpaceRule->GetURLSpec(urlSpec); 1.922 + 1.923 + aMap->AddPrefix(nameSpaceRule->GetPrefix(), urlSpec); 1.924 +} 1.925 + 1.926 +static bool 1.927 +CreateNameSpace(css::Rule* aRule, void* aNameSpacePtr) 1.928 +{ 1.929 + int32_t type = aRule->GetType(); 1.930 + if (css::Rule::NAMESPACE_RULE == type) { 1.931 + AddNamespaceRuleToMap(aRule, 1.932 + static_cast<nsXMLNameSpaceMap*>(aNameSpacePtr)); 1.933 + return true; 1.934 + } 1.935 + // stop if not namespace, import or charset because namespace can't follow 1.936 + // anything else 1.937 + return (css::Rule::CHARSET_RULE == type || css::Rule::IMPORT_RULE == type); 1.938 +} 1.939 + 1.940 +void 1.941 +nsCSSStyleSheetInner::RebuildNameSpaces() 1.942 +{ 1.943 + // Just nuke our existing namespace map, if any 1.944 + if (NS_SUCCEEDED(CreateNamespaceMap())) { 1.945 + mOrderedRules.EnumerateForwards(CreateNameSpace, mNameSpaceMap); 1.946 + } 1.947 +} 1.948 + 1.949 +nsresult 1.950 +nsCSSStyleSheetInner::CreateNamespaceMap() 1.951 +{ 1.952 + mNameSpaceMap = nsXMLNameSpaceMap::Create(false); 1.953 + NS_ENSURE_TRUE(mNameSpaceMap, NS_ERROR_OUT_OF_MEMORY); 1.954 + // Override the default namespace map behavior for the null prefix to 1.955 + // return the wildcard namespace instead of the null namespace. 1.956 + mNameSpaceMap->AddPrefix(nullptr, kNameSpaceID_Unknown); 1.957 + return NS_OK; 1.958 +} 1.959 + 1.960 +size_t 1.961 +nsCSSStyleSheetInner::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const 1.962 +{ 1.963 + size_t n = aMallocSizeOf(this); 1.964 + n += mOrderedRules.SizeOfExcludingThis(css::Rule::SizeOfCOMArrayElementIncludingThis, 1.965 + aMallocSizeOf); 1.966 + n += mFirstChild ? mFirstChild->SizeOfIncludingThis(aMallocSizeOf) : 0; 1.967 + 1.968 + // Measurement of the following members may be added later if DMD finds it is 1.969 + // worthwhile: 1.970 + // - mSheetURI 1.971 + // - mOriginalSheetURI 1.972 + // - mBaseURI 1.973 + // - mPrincipal 1.974 + // - mNameSpaceMap 1.975 + // 1.976 + // The following members are not measured: 1.977 + // - mSheets, because it's non-owning 1.978 + 1.979 + return n; 1.980 +} 1.981 + 1.982 +// ------------------------------- 1.983 +// CSS Style Sheet 1.984 +// 1.985 + 1.986 +nsCSSStyleSheet::nsCSSStyleSheet(CORSMode aCORSMode) 1.987 + : mTitle(), 1.988 + mParent(nullptr), 1.989 + mOwnerRule(nullptr), 1.990 + mDocument(nullptr), 1.991 + mOwningNode(nullptr), 1.992 + mDisabled(false), 1.993 + mDirty(false), 1.994 + mScopeElement(nullptr), 1.995 + mRuleProcessors(nullptr) 1.996 +{ 1.997 + mInner = new nsCSSStyleSheetInner(this, aCORSMode); 1.998 + 1.999 + SetIsDOMBinding(); 1.1000 +} 1.1001 + 1.1002 +nsCSSStyleSheet::nsCSSStyleSheet(const nsCSSStyleSheet& aCopy, 1.1003 + nsCSSStyleSheet* aParentToUse, 1.1004 + css::ImportRule* aOwnerRuleToUse, 1.1005 + nsIDocument* aDocumentToUse, 1.1006 + nsINode* aOwningNodeToUse) 1.1007 + : mTitle(aCopy.mTitle), 1.1008 + mParent(aParentToUse), 1.1009 + mOwnerRule(aOwnerRuleToUse), 1.1010 + mDocument(aDocumentToUse), 1.1011 + mOwningNode(aOwningNodeToUse), 1.1012 + mDisabled(aCopy.mDisabled), 1.1013 + mDirty(aCopy.mDirty), 1.1014 + mScopeElement(nullptr), 1.1015 + mInner(aCopy.mInner), 1.1016 + mRuleProcessors(nullptr) 1.1017 +{ 1.1018 + 1.1019 + mInner->AddSheet(this); 1.1020 + 1.1021 + if (mDirty) { // CSSOM's been there, force full copy now 1.1022 + NS_ASSERTION(mInner->mComplete, "Why have rules been accessed on an incomplete sheet?"); 1.1023 + // FIXME: handle failure? 1.1024 + EnsureUniqueInner(); 1.1025 + } 1.1026 + 1.1027 + if (aCopy.mMedia) { 1.1028 + // XXX This is wrong; we should be keeping @import rules and 1.1029 + // sheets in sync! 1.1030 + mMedia = aCopy.mMedia->Clone(); 1.1031 + } 1.1032 + 1.1033 + SetIsDOMBinding(); 1.1034 +} 1.1035 + 1.1036 +nsCSSStyleSheet::~nsCSSStyleSheet() 1.1037 +{ 1.1038 + for (nsCSSStyleSheet* child = mInner->mFirstChild; 1.1039 + child; 1.1040 + child = child->mNext) { 1.1041 + // XXXbz this is a little bogus; see the XXX comment where we 1.1042 + // declare mFirstChild. 1.1043 + if (child->mParent == this) { 1.1044 + child->mParent = nullptr; 1.1045 + child->mDocument = nullptr; 1.1046 + } 1.1047 + } 1.1048 + DropRuleCollection(); 1.1049 + DropMedia(); 1.1050 + mInner->RemoveSheet(this); 1.1051 + // XXX The document reference is not reference counted and should 1.1052 + // not be released. The document will let us know when it is going 1.1053 + // away. 1.1054 + if (mRuleProcessors) { 1.1055 + NS_ASSERTION(mRuleProcessors->Length() == 0, "destructing sheet with rule processor reference"); 1.1056 + delete mRuleProcessors; // weak refs, should be empty here anyway 1.1057 + } 1.1058 +} 1.1059 + 1.1060 +void 1.1061 +nsCSSStyleSheet::DropRuleCollection() 1.1062 +{ 1.1063 + if (mRuleCollection) { 1.1064 + mRuleCollection->DropReference(); 1.1065 + mRuleCollection = nullptr; 1.1066 + } 1.1067 +} 1.1068 + 1.1069 +void 1.1070 +nsCSSStyleSheet::DropMedia() 1.1071 +{ 1.1072 + if (mMedia) { 1.1073 + mMedia->SetStyleSheet(nullptr); 1.1074 + mMedia = nullptr; 1.1075 + } 1.1076 +} 1.1077 + 1.1078 +void 1.1079 +nsCSSStyleSheet::UnlinkInner() 1.1080 +{ 1.1081 + // We can only have a cycle through our inner if we have a unique inner, 1.1082 + // because otherwise there are no JS wrappers for anything in the inner. 1.1083 + if (mInner->mSheets.Length() != 1) { 1.1084 + return; 1.1085 + } 1.1086 + 1.1087 + mInner->mOrderedRules.EnumerateForwards(SetStyleSheetReference, nullptr); 1.1088 + mInner->mOrderedRules.Clear(); 1.1089 + 1.1090 + // Have to be a bit careful with child sheets, because we want to 1.1091 + // drop their mNext pointers and null out their mParent and 1.1092 + // mDocument, but don't want to work with deleted objects. And we 1.1093 + // don't want to do any addrefing in the process, just to make sure 1.1094 + // we don't confuse the cycle collector (though on the face of it, 1.1095 + // addref/release pairs during unlink should probably be ok). 1.1096 + nsRefPtr<nsCSSStyleSheet> child; 1.1097 + child.swap(mInner->mFirstChild); 1.1098 + while (child) { 1.1099 + MOZ_ASSERT(child->mParent == this, "We have a unique inner!"); 1.1100 + child->mParent = nullptr; 1.1101 + child->mDocument = nullptr; 1.1102 + nsRefPtr<nsCSSStyleSheet> next; 1.1103 + // Null out child->mNext, but don't let it die yet 1.1104 + next.swap(child->mNext); 1.1105 + // Switch to looking at the old value of child->mNext next iteration 1.1106 + child.swap(next); 1.1107 + // "next" is now our previous value of child; it'll get released 1.1108 + // as we loop around. 1.1109 + } 1.1110 +} 1.1111 + 1.1112 +void 1.1113 +nsCSSStyleSheet::TraverseInner(nsCycleCollectionTraversalCallback &cb) 1.1114 +{ 1.1115 + // We can only have a cycle through our inner if we have a unique inner, 1.1116 + // because otherwise there are no JS wrappers for anything in the inner. 1.1117 + if (mInner->mSheets.Length() != 1) { 1.1118 + return; 1.1119 + } 1.1120 + 1.1121 + nsRefPtr<nsCSSStyleSheet>* childSheetSlot = &mInner->mFirstChild; 1.1122 + while (*childSheetSlot) { 1.1123 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "child sheet"); 1.1124 + cb.NoteXPCOMChild(NS_ISUPPORTS_CAST(nsIStyleSheet*, childSheetSlot->get())); 1.1125 + childSheetSlot = &(*childSheetSlot)->mNext; 1.1126 + } 1.1127 + 1.1128 + const nsCOMArray<css::Rule>& rules = mInner->mOrderedRules; 1.1129 + for (int32_t i = 0, count = rules.Count(); i < count; ++i) { 1.1130 + NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mOrderedRules[i]"); 1.1131 + cb.NoteXPCOMChild(rules[i]->GetExistingDOMRule()); 1.1132 + } 1.1133 +} 1.1134 + 1.1135 +DOMCI_DATA(CSSStyleSheet, nsCSSStyleSheet) 1.1136 + 1.1137 +// QueryInterface implementation for nsCSSStyleSheet 1.1138 +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsCSSStyleSheet) 1.1139 + NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY 1.1140 + NS_INTERFACE_MAP_ENTRY(nsIStyleSheet) 1.1141 + NS_INTERFACE_MAP_ENTRY(nsIDOMStyleSheet) 1.1142 + NS_INTERFACE_MAP_ENTRY(nsIDOMCSSStyleSheet) 1.1143 + NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver) 1.1144 + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIStyleSheet) 1.1145 + NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(CSSStyleSheet) 1.1146 + if (aIID.Equals(NS_GET_IID(nsCSSStyleSheet))) 1.1147 + foundInterface = reinterpret_cast<nsISupports*>(this); 1.1148 + else 1.1149 +NS_INTERFACE_MAP_END 1.1150 + 1.1151 + 1.1152 +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsCSSStyleSheet) 1.1153 +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsCSSStyleSheet) 1.1154 + 1.1155 +NS_IMPL_CYCLE_COLLECTION_CLASS(nsCSSStyleSheet) 1.1156 + 1.1157 +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsCSSStyleSheet) 1.1158 + tmp->DropMedia(); 1.1159 + // We do not unlink mNext; our parent will handle that. If we 1.1160 + // unlinked it here, our parent would not be able to walk its list 1.1161 + // of child sheets and null out the back-references to it, if we got 1.1162 + // unlinked before it does. 1.1163 + tmp->DropRuleCollection(); 1.1164 + tmp->UnlinkInner(); 1.1165 + tmp->mScopeElement = nullptr; 1.1166 + NS_IMPL_CYCLE_COLLECTION_UNLINK_PRESERVED_WRAPPER 1.1167 +NS_IMPL_CYCLE_COLLECTION_UNLINK_END 1.1168 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsCSSStyleSheet) 1.1169 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mMedia) 1.1170 + // We do not traverse mNext; our parent will handle that. See 1.1171 + // comments in Unlink for why. 1.1172 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mRuleCollection) 1.1173 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScopeElement) 1.1174 + tmp->TraverseInner(cb); 1.1175 + NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS 1.1176 +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END 1.1177 +NS_IMPL_CYCLE_COLLECTION_TRACE_WRAPPERCACHE(nsCSSStyleSheet) 1.1178 + 1.1179 +nsresult 1.1180 +nsCSSStyleSheet::AddRuleProcessor(nsCSSRuleProcessor* aProcessor) 1.1181 +{ 1.1182 + if (! mRuleProcessors) { 1.1183 + mRuleProcessors = new nsAutoTArray<nsCSSRuleProcessor*, 8>(); 1.1184 + if (!mRuleProcessors) 1.1185 + return NS_ERROR_OUT_OF_MEMORY; 1.1186 + } 1.1187 + NS_ASSERTION(mRuleProcessors->NoIndex == mRuleProcessors->IndexOf(aProcessor), 1.1188 + "processor already registered"); 1.1189 + mRuleProcessors->AppendElement(aProcessor); // weak ref 1.1190 + return NS_OK; 1.1191 +} 1.1192 + 1.1193 +nsresult 1.1194 +nsCSSStyleSheet::DropRuleProcessor(nsCSSRuleProcessor* aProcessor) 1.1195 +{ 1.1196 + if (!mRuleProcessors) 1.1197 + return NS_ERROR_FAILURE; 1.1198 + return mRuleProcessors->RemoveElement(aProcessor) 1.1199 + ? NS_OK 1.1200 + : NS_ERROR_FAILURE; 1.1201 +} 1.1202 + 1.1203 + 1.1204 +void 1.1205 +nsCSSStyleSheet::SetURIs(nsIURI* aSheetURI, nsIURI* aOriginalSheetURI, 1.1206 + nsIURI* aBaseURI) 1.1207 +{ 1.1208 + NS_PRECONDITION(aSheetURI && aBaseURI, "null ptr"); 1.1209 + 1.1210 + NS_ASSERTION(mInner->mOrderedRules.Count() == 0 && !mInner->mComplete, 1.1211 + "Can't call SetURL on sheets that are complete or have rules"); 1.1212 + 1.1213 + mInner->mSheetURI = aSheetURI; 1.1214 + mInner->mOriginalSheetURI = aOriginalSheetURI; 1.1215 + mInner->mBaseURI = aBaseURI; 1.1216 +} 1.1217 + 1.1218 +void 1.1219 +nsCSSStyleSheet::SetPrincipal(nsIPrincipal* aPrincipal) 1.1220 +{ 1.1221 + NS_PRECONDITION(!mInner->mPrincipalSet, 1.1222 + "Should have an inner whose principal has not yet been set"); 1.1223 + if (aPrincipal) { 1.1224 + mInner->mPrincipal = aPrincipal; 1.1225 +#ifdef DEBUG 1.1226 + mInner->mPrincipalSet = true; 1.1227 +#endif 1.1228 + } 1.1229 +} 1.1230 + 1.1231 +/* virtual */ nsIURI* 1.1232 +nsCSSStyleSheet::GetSheetURI() const 1.1233 +{ 1.1234 + return mInner->mSheetURI; 1.1235 +} 1.1236 + 1.1237 +/* virtual */ nsIURI* 1.1238 +nsCSSStyleSheet::GetBaseURI() const 1.1239 +{ 1.1240 + return mInner->mBaseURI; 1.1241 +} 1.1242 + 1.1243 +/* virtual */ void 1.1244 +nsCSSStyleSheet::GetType(nsString& aType) const 1.1245 +{ 1.1246 + aType.AssignLiteral("text/css"); 1.1247 +} 1.1248 + 1.1249 +bool 1.1250 +nsCSSStyleSheet::UseForPresentation(nsPresContext* aPresContext, 1.1251 + nsMediaQueryResultCacheKey& aKey) const 1.1252 +{ 1.1253 + if (mMedia) { 1.1254 + return mMedia->Matches(aPresContext, &aKey); 1.1255 + } 1.1256 + return true; 1.1257 +} 1.1258 + 1.1259 + 1.1260 +void 1.1261 +nsCSSStyleSheet::SetMedia(nsMediaList* aMedia) 1.1262 +{ 1.1263 + mMedia = aMedia; 1.1264 +} 1.1265 + 1.1266 +/* virtual */ bool 1.1267 +nsCSSStyleSheet::HasRules() const 1.1268 +{ 1.1269 + return StyleRuleCount() != 0; 1.1270 +} 1.1271 + 1.1272 +/* virtual */ bool 1.1273 +nsCSSStyleSheet::IsApplicable() const 1.1274 +{ 1.1275 + return !mDisabled && mInner->mComplete; 1.1276 +} 1.1277 + 1.1278 +/* virtual */ void 1.1279 +nsCSSStyleSheet::SetEnabled(bool aEnabled) 1.1280 +{ 1.1281 + // Internal method, so callers must handle BeginUpdate/EndUpdate 1.1282 + bool oldDisabled = mDisabled; 1.1283 + mDisabled = !aEnabled; 1.1284 + 1.1285 + if (mInner->mComplete && oldDisabled != mDisabled) { 1.1286 + ClearRuleCascades(); 1.1287 + 1.1288 + if (mDocument) { 1.1289 + mDocument->SetStyleSheetApplicableState(this, !mDisabled); 1.1290 + } 1.1291 + } 1.1292 +} 1.1293 + 1.1294 +/* virtual */ bool 1.1295 +nsCSSStyleSheet::IsComplete() const 1.1296 +{ 1.1297 + return mInner->mComplete; 1.1298 +} 1.1299 + 1.1300 +/* virtual */ void 1.1301 +nsCSSStyleSheet::SetComplete() 1.1302 +{ 1.1303 + NS_ASSERTION(!mDirty, "Can't set a dirty sheet complete!"); 1.1304 + mInner->mComplete = true; 1.1305 + if (mDocument && !mDisabled) { 1.1306 + // Let the document know 1.1307 + mDocument->BeginUpdate(UPDATE_STYLE); 1.1308 + mDocument->SetStyleSheetApplicableState(this, true); 1.1309 + mDocument->EndUpdate(UPDATE_STYLE); 1.1310 + } 1.1311 +} 1.1312 + 1.1313 +/* virtual */ nsIStyleSheet* 1.1314 +nsCSSStyleSheet::GetParentSheet() const 1.1315 +{ 1.1316 + return mParent; 1.1317 +} 1.1318 + 1.1319 +/* virtual */ nsIDocument* 1.1320 +nsCSSStyleSheet::GetOwningDocument() const 1.1321 +{ 1.1322 + return mDocument; 1.1323 +} 1.1324 + 1.1325 +/* virtual */ void 1.1326 +nsCSSStyleSheet::SetOwningDocument(nsIDocument* aDocument) 1.1327 +{ // not ref counted 1.1328 + mDocument = aDocument; 1.1329 + // Now set the same document on all our child sheets.... 1.1330 + // XXXbz this is a little bogus; see the XXX comment where we 1.1331 + // declare mFirstChild. 1.1332 + for (nsCSSStyleSheet* child = mInner->mFirstChild; 1.1333 + child; child = child->mNext) { 1.1334 + if (child->mParent == this) { 1.1335 + child->SetOwningDocument(aDocument); 1.1336 + } 1.1337 + } 1.1338 +} 1.1339 + 1.1340 +uint64_t 1.1341 +nsCSSStyleSheet::FindOwningWindowInnerID() const 1.1342 +{ 1.1343 + uint64_t windowID = 0; 1.1344 + if (mDocument) { 1.1345 + windowID = mDocument->InnerWindowID(); 1.1346 + } 1.1347 + 1.1348 + if (windowID == 0 && mOwningNode) { 1.1349 + windowID = mOwningNode->OwnerDoc()->InnerWindowID(); 1.1350 + } 1.1351 + 1.1352 + if (windowID == 0 && mOwnerRule) { 1.1353 + nsCOMPtr<nsIStyleSheet> sheet = static_cast<css::Rule*>(mOwnerRule)->GetStyleSheet(); 1.1354 + if (sheet) { 1.1355 + nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(sheet); 1.1356 + if (cssSheet) { 1.1357 + windowID = cssSheet->FindOwningWindowInnerID(); 1.1358 + } 1.1359 + } 1.1360 + } 1.1361 + 1.1362 + if (windowID == 0 && mParent) { 1.1363 + windowID = mParent->FindOwningWindowInnerID(); 1.1364 + } 1.1365 + 1.1366 + return windowID; 1.1367 +} 1.1368 + 1.1369 +void 1.1370 +nsCSSStyleSheet::AppendStyleSheet(nsCSSStyleSheet* aSheet) 1.1371 +{ 1.1372 + NS_PRECONDITION(nullptr != aSheet, "null arg"); 1.1373 + 1.1374 + WillDirty(); 1.1375 + nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild; 1.1376 + while (*tail) { 1.1377 + tail = &(*tail)->mNext; 1.1378 + } 1.1379 + *tail = aSheet; 1.1380 + 1.1381 + // This is not reference counted. Our parent tells us when 1.1382 + // it's going away. 1.1383 + aSheet->mParent = this; 1.1384 + aSheet->mDocument = mDocument; 1.1385 + DidDirty(); 1.1386 +} 1.1387 + 1.1388 +void 1.1389 +nsCSSStyleSheet::InsertStyleSheetAt(nsCSSStyleSheet* aSheet, int32_t aIndex) 1.1390 +{ 1.1391 + NS_PRECONDITION(nullptr != aSheet, "null arg"); 1.1392 + 1.1393 + WillDirty(); 1.1394 + nsRefPtr<nsCSSStyleSheet>* tail = &mInner->mFirstChild; 1.1395 + while (*tail && aIndex) { 1.1396 + --aIndex; 1.1397 + tail = &(*tail)->mNext; 1.1398 + } 1.1399 + aSheet->mNext = *tail; 1.1400 + *tail = aSheet; 1.1401 + 1.1402 + // This is not reference counted. Our parent tells us when 1.1403 + // it's going away. 1.1404 + aSheet->mParent = this; 1.1405 + aSheet->mDocument = mDocument; 1.1406 + DidDirty(); 1.1407 +} 1.1408 + 1.1409 +void 1.1410 +nsCSSStyleSheet::PrependStyleRule(css::Rule* aRule) 1.1411 +{ 1.1412 + NS_PRECONDITION(nullptr != aRule, "null arg"); 1.1413 + 1.1414 + WillDirty(); 1.1415 + mInner->mOrderedRules.InsertObjectAt(aRule, 0); 1.1416 + aRule->SetStyleSheet(this); 1.1417 + DidDirty(); 1.1418 + 1.1419 + if (css::Rule::NAMESPACE_RULE == aRule->GetType()) { 1.1420 + // no api to prepend a namespace (ugh), release old ones and re-create them all 1.1421 + mInner->RebuildNameSpaces(); 1.1422 + } 1.1423 +} 1.1424 + 1.1425 +void 1.1426 +nsCSSStyleSheet::AppendStyleRule(css::Rule* aRule) 1.1427 +{ 1.1428 + NS_PRECONDITION(nullptr != aRule, "null arg"); 1.1429 + 1.1430 + WillDirty(); 1.1431 + mInner->mOrderedRules.AppendObject(aRule); 1.1432 + aRule->SetStyleSheet(this); 1.1433 + DidDirty(); 1.1434 + 1.1435 + if (css::Rule::NAMESPACE_RULE == aRule->GetType()) { 1.1436 +#ifdef DEBUG 1.1437 + nsresult rv = 1.1438 +#endif 1.1439 + RegisterNamespaceRule(aRule); 1.1440 + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), 1.1441 + "RegisterNamespaceRule returned error"); 1.1442 + } 1.1443 +} 1.1444 + 1.1445 +void 1.1446 +nsCSSStyleSheet::ReplaceStyleRule(css::Rule* aOld, css::Rule* aNew) 1.1447 +{ 1.1448 + NS_PRECONDITION(mInner->mOrderedRules.Count() != 0, "can't have old rule"); 1.1449 + NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!"); 1.1450 + 1.1451 + WillDirty(); 1.1452 + int32_t index = mInner->mOrderedRules.IndexOf(aOld); 1.1453 + if (MOZ_UNLIKELY(index == -1)) { 1.1454 + NS_NOTREACHED("Couldn't find old rule"); 1.1455 + return; 1.1456 + } 1.1457 + mInner->mOrderedRules.ReplaceObjectAt(aNew, index); 1.1458 + 1.1459 + aNew->SetStyleSheet(this); 1.1460 + aOld->SetStyleSheet(nullptr); 1.1461 + DidDirty(); 1.1462 + NS_ASSERTION(css::Rule::NAMESPACE_RULE != aNew->GetType(), "not yet implemented"); 1.1463 + NS_ASSERTION(css::Rule::NAMESPACE_RULE != aOld->GetType(), "not yet implemented"); 1.1464 +} 1.1465 + 1.1466 +int32_t 1.1467 +nsCSSStyleSheet::StyleRuleCount() const 1.1468 +{ 1.1469 + return mInner->mOrderedRules.Count(); 1.1470 +} 1.1471 + 1.1472 +css::Rule* 1.1473 +nsCSSStyleSheet::GetStyleRuleAt(int32_t aIndex) const 1.1474 +{ 1.1475 + // Important: If this function is ever made scriptable, we must add 1.1476 + // a security check here. See GetCssRules below for an example. 1.1477 + return mInner->mOrderedRules.SafeObjectAt(aIndex); 1.1478 +} 1.1479 + 1.1480 +int32_t 1.1481 +nsCSSStyleSheet::StyleSheetCount() const 1.1482 +{ 1.1483 + // XXX Far from an ideal way to do this, but the hope is that 1.1484 + // it won't be done too often. If it is, we might want to 1.1485 + // consider storing the children in an array. 1.1486 + int32_t count = 0; 1.1487 + 1.1488 + const nsCSSStyleSheet* child = mInner->mFirstChild; 1.1489 + while (child) { 1.1490 + count++; 1.1491 + child = child->mNext; 1.1492 + } 1.1493 + 1.1494 + return count; 1.1495 +} 1.1496 + 1.1497 +nsCSSStyleSheet::EnsureUniqueInnerResult 1.1498 +nsCSSStyleSheet::EnsureUniqueInner() 1.1499 +{ 1.1500 + mDirty = true; 1.1501 + 1.1502 + NS_ABORT_IF_FALSE(mInner->mSheets.Length() != 0, 1.1503 + "unexpected number of outers"); 1.1504 + if (mInner->mSheets.Length() == 1) { 1.1505 + return eUniqueInner_AlreadyUnique; 1.1506 + } 1.1507 + nsCSSStyleSheetInner* clone = mInner->CloneFor(this); 1.1508 + MOZ_ASSERT(clone); 1.1509 + mInner->RemoveSheet(this); 1.1510 + mInner = clone; 1.1511 + 1.1512 + // otherwise the rule processor has pointers to the old rules 1.1513 + ClearRuleCascades(); 1.1514 + 1.1515 + return eUniqueInner_ClonedInner; 1.1516 +} 1.1517 + 1.1518 +void 1.1519 +nsCSSStyleSheet::AppendAllChildSheets(nsTArray<nsCSSStyleSheet*>& aArray) 1.1520 +{ 1.1521 + for (nsCSSStyleSheet* child = mInner->mFirstChild; child; 1.1522 + child = child->mNext) { 1.1523 + aArray.AppendElement(child); 1.1524 + } 1.1525 +} 1.1526 + 1.1527 +already_AddRefed<nsCSSStyleSheet> 1.1528 +nsCSSStyleSheet::Clone(nsCSSStyleSheet* aCloneParent, 1.1529 + css::ImportRule* aCloneOwnerRule, 1.1530 + nsIDocument* aCloneDocument, 1.1531 + nsINode* aCloneOwningNode) const 1.1532 +{ 1.1533 + nsRefPtr<nsCSSStyleSheet> clone = new nsCSSStyleSheet(*this, 1.1534 + aCloneParent, 1.1535 + aCloneOwnerRule, 1.1536 + aCloneDocument, 1.1537 + aCloneOwningNode); 1.1538 + return clone.forget(); 1.1539 +} 1.1540 + 1.1541 +#ifdef DEBUG 1.1542 +static void 1.1543 +ListRules(const nsCOMArray<css::Rule>& aRules, FILE* aOut, int32_t aIndent) 1.1544 +{ 1.1545 + for (int32_t index = aRules.Count() - 1; index >= 0; --index) { 1.1546 + aRules.ObjectAt(index)->List(aOut, aIndent); 1.1547 + } 1.1548 +} 1.1549 + 1.1550 +struct ListEnumData { 1.1551 + ListEnumData(FILE* aOut, int32_t aIndent) 1.1552 + : mOut(aOut), 1.1553 + mIndent(aIndent) 1.1554 + { 1.1555 + } 1.1556 + FILE* mOut; 1.1557 + int32_t mIndent; 1.1558 +}; 1.1559 + 1.1560 +/* virtual */ void 1.1561 +nsCSSStyleSheet::List(FILE* out, int32_t aIndent) const 1.1562 +{ 1.1563 + 1.1564 + int32_t index; 1.1565 + 1.1566 + // Indent 1.1567 + for (index = aIndent; --index >= 0; ) fputs(" ", out); 1.1568 + 1.1569 + fputs("CSS Style Sheet: ", out); 1.1570 + nsAutoCString urlSpec; 1.1571 + nsresult rv = mInner->mSheetURI->GetSpec(urlSpec); 1.1572 + if (NS_SUCCEEDED(rv) && !urlSpec.IsEmpty()) { 1.1573 + fputs(urlSpec.get(), out); 1.1574 + } 1.1575 + 1.1576 + if (mMedia) { 1.1577 + fputs(" media: ", out); 1.1578 + nsAutoString buffer; 1.1579 + mMedia->GetText(buffer); 1.1580 + fputs(NS_ConvertUTF16toUTF8(buffer).get(), out); 1.1581 + } 1.1582 + fputs("\n", out); 1.1583 + 1.1584 + for (const nsCSSStyleSheet* child = mInner->mFirstChild; 1.1585 + child; 1.1586 + child = child->mNext) { 1.1587 + child->List(out, aIndent + 1); 1.1588 + } 1.1589 + 1.1590 + fputs("Rules in source order:\n", out); 1.1591 + ListRules(mInner->mOrderedRules, out, aIndent); 1.1592 +} 1.1593 +#endif 1.1594 + 1.1595 +void 1.1596 +nsCSSStyleSheet::ClearRuleCascades() 1.1597 +{ 1.1598 + if (mRuleProcessors) { 1.1599 + nsCSSRuleProcessor **iter = mRuleProcessors->Elements(), 1.1600 + **end = iter + mRuleProcessors->Length(); 1.1601 + for(; iter != end; ++iter) { 1.1602 + (*iter)->ClearRuleCascades(); 1.1603 + } 1.1604 + } 1.1605 + if (mParent) { 1.1606 + nsCSSStyleSheet* parent = (nsCSSStyleSheet*)mParent; 1.1607 + parent->ClearRuleCascades(); 1.1608 + } 1.1609 +} 1.1610 + 1.1611 +void 1.1612 +nsCSSStyleSheet::WillDirty() 1.1613 +{ 1.1614 + if (mInner->mComplete) { 1.1615 + EnsureUniqueInner(); 1.1616 + } 1.1617 +} 1.1618 + 1.1619 +void 1.1620 +nsCSSStyleSheet::DidDirty() 1.1621 +{ 1.1622 + NS_ABORT_IF_FALSE(!mInner->mComplete || mDirty, 1.1623 + "caller must have called WillDirty()"); 1.1624 + ClearRuleCascades(); 1.1625 +} 1.1626 + 1.1627 +nsresult 1.1628 +nsCSSStyleSheet::SubjectSubsumesInnerPrincipal() 1.1629 +{ 1.1630 + // Get the security manager and do the subsumes check 1.1631 + nsIScriptSecurityManager *securityManager = 1.1632 + nsContentUtils::GetSecurityManager(); 1.1633 + 1.1634 + nsCOMPtr<nsIPrincipal> subjectPrincipal; 1.1635 + nsresult rv = securityManager->GetSubjectPrincipal(getter_AddRefs(subjectPrincipal)); 1.1636 + NS_ENSURE_SUCCESS(rv, rv); 1.1637 + 1.1638 + if (!subjectPrincipal) { 1.1639 + return NS_ERROR_DOM_SECURITY_ERR; 1.1640 + } 1.1641 + 1.1642 + bool subsumes; 1.1643 + rv = subjectPrincipal->Subsumes(mInner->mPrincipal, &subsumes); 1.1644 + NS_ENSURE_SUCCESS(rv, rv); 1.1645 + 1.1646 + if (subsumes) { 1.1647 + return NS_OK; 1.1648 + } 1.1649 + 1.1650 + if (!nsContentUtils::IsCallerChrome()) { 1.1651 + // Allow access only if CORS mode is not NONE 1.1652 + if (GetCORSMode() == CORS_NONE) { 1.1653 + return NS_ERROR_DOM_SECURITY_ERR; 1.1654 + } 1.1655 + 1.1656 + // Now make sure we set the principal of our inner to the 1.1657 + // subjectPrincipal. That means we need a unique inner, of 1.1658 + // course. But we don't want to do that if we're not complete 1.1659 + // yet. Luckily, all the callers of this method throw anyway if 1.1660 + // not complete, so we can just do that here too. 1.1661 + if (!mInner->mComplete) { 1.1662 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.1663 + } 1.1664 + 1.1665 + WillDirty(); 1.1666 + 1.1667 + mInner->mPrincipal = subjectPrincipal; 1.1668 + 1.1669 + DidDirty(); 1.1670 + } 1.1671 + 1.1672 + return NS_OK; 1.1673 +} 1.1674 + 1.1675 +nsresult 1.1676 +nsCSSStyleSheet::RegisterNamespaceRule(css::Rule* aRule) 1.1677 +{ 1.1678 + if (!mInner->mNameSpaceMap) { 1.1679 + nsresult rv = mInner->CreateNamespaceMap(); 1.1680 + NS_ENSURE_SUCCESS(rv, rv); 1.1681 + } 1.1682 + 1.1683 + AddNamespaceRuleToMap(aRule, mInner->mNameSpaceMap); 1.1684 + return NS_OK; 1.1685 +} 1.1686 + 1.1687 + // nsIDOMStyleSheet interface 1.1688 +NS_IMETHODIMP 1.1689 +nsCSSStyleSheet::GetType(nsAString& aType) 1.1690 +{ 1.1691 + aType.AssignLiteral("text/css"); 1.1692 + return NS_OK; 1.1693 +} 1.1694 + 1.1695 +NS_IMETHODIMP 1.1696 +nsCSSStyleSheet::GetDisabled(bool* aDisabled) 1.1697 +{ 1.1698 + *aDisabled = Disabled(); 1.1699 + return NS_OK; 1.1700 +} 1.1701 + 1.1702 +NS_IMETHODIMP 1.1703 +nsCSSStyleSheet::SetDisabled(bool aDisabled) 1.1704 +{ 1.1705 + // DOM method, so handle BeginUpdate/EndUpdate 1.1706 + MOZ_AUTO_DOC_UPDATE(mDocument, UPDATE_STYLE, true); 1.1707 + nsCSSStyleSheet::SetEnabled(!aDisabled); 1.1708 + return NS_OK; 1.1709 +} 1.1710 + 1.1711 +NS_IMETHODIMP 1.1712 +nsCSSStyleSheet::GetOwnerNode(nsIDOMNode** aOwnerNode) 1.1713 +{ 1.1714 + nsCOMPtr<nsIDOMNode> ownerNode = do_QueryInterface(GetOwnerNode()); 1.1715 + ownerNode.forget(aOwnerNode); 1.1716 + return NS_OK; 1.1717 +} 1.1718 + 1.1719 +NS_IMETHODIMP 1.1720 +nsCSSStyleSheet::GetParentStyleSheet(nsIDOMStyleSheet** aParentStyleSheet) 1.1721 +{ 1.1722 + NS_ENSURE_ARG_POINTER(aParentStyleSheet); 1.1723 + 1.1724 + NS_IF_ADDREF(*aParentStyleSheet = mParent); 1.1725 + 1.1726 + return NS_OK; 1.1727 +} 1.1728 + 1.1729 +NS_IMETHODIMP 1.1730 +nsCSSStyleSheet::GetHref(nsAString& aHref) 1.1731 +{ 1.1732 + if (mInner->mOriginalSheetURI) { 1.1733 + nsAutoCString str; 1.1734 + mInner->mOriginalSheetURI->GetSpec(str); 1.1735 + CopyUTF8toUTF16(str, aHref); 1.1736 + } else { 1.1737 + SetDOMStringToNull(aHref); 1.1738 + } 1.1739 + 1.1740 + return NS_OK; 1.1741 +} 1.1742 + 1.1743 +/* virtual */ void 1.1744 +nsCSSStyleSheet::GetTitle(nsString& aTitle) const 1.1745 +{ 1.1746 + aTitle = mTitle; 1.1747 +} 1.1748 + 1.1749 +NS_IMETHODIMP 1.1750 +nsCSSStyleSheet::GetTitle(nsAString& aTitle) 1.1751 +{ 1.1752 + aTitle.Assign(mTitle); 1.1753 + return NS_OK; 1.1754 +} 1.1755 + 1.1756 +NS_IMETHODIMP 1.1757 +nsCSSStyleSheet::GetMedia(nsIDOMMediaList** aMedia) 1.1758 +{ 1.1759 + NS_ADDREF(*aMedia = Media()); 1.1760 + return NS_OK; 1.1761 +} 1.1762 + 1.1763 +nsMediaList* 1.1764 +nsCSSStyleSheet::Media() 1.1765 +{ 1.1766 + if (!mMedia) { 1.1767 + mMedia = new nsMediaList(); 1.1768 + mMedia->SetStyleSheet(this); 1.1769 + } 1.1770 + 1.1771 + return mMedia; 1.1772 +} 1.1773 + 1.1774 +NS_IMETHODIMP 1.1775 +nsCSSStyleSheet::GetOwnerRule(nsIDOMCSSRule** aOwnerRule) 1.1776 +{ 1.1777 + NS_IF_ADDREF(*aOwnerRule = GetOwnerRule()); 1.1778 + return NS_OK; 1.1779 +} 1.1780 + 1.1781 +nsIDOMCSSRule* 1.1782 +nsCSSStyleSheet::GetDOMOwnerRule() const 1.1783 +{ 1.1784 + return mOwnerRule ? mOwnerRule->GetDOMRule() : nullptr; 1.1785 +} 1.1786 + 1.1787 +NS_IMETHODIMP 1.1788 +nsCSSStyleSheet::GetCssRules(nsIDOMCSSRuleList** aCssRules) 1.1789 +{ 1.1790 + ErrorResult rv; 1.1791 + nsCOMPtr<nsIDOMCSSRuleList> rules = GetCssRules(rv); 1.1792 + rules.forget(aCssRules); 1.1793 + return rv.ErrorCode(); 1.1794 +} 1.1795 + 1.1796 +nsIDOMCSSRuleList* 1.1797 +nsCSSStyleSheet::GetCssRules(ErrorResult& aRv) 1.1798 +{ 1.1799 + // No doing this on incomplete sheets! 1.1800 + if (!mInner->mComplete) { 1.1801 + aRv.Throw(NS_ERROR_DOM_INVALID_ACCESS_ERR); 1.1802 + return nullptr; 1.1803 + } 1.1804 + 1.1805 + //-- Security check: Only scripts whose principal subsumes that of the 1.1806 + // style sheet can access rule collections. 1.1807 + nsresult rv = SubjectSubsumesInnerPrincipal(); 1.1808 + if (NS_FAILED(rv)) { 1.1809 + aRv.Throw(rv); 1.1810 + return nullptr; 1.1811 + } 1.1812 + 1.1813 + // OK, security check passed, so get the rule collection 1.1814 + if (!mRuleCollection) { 1.1815 + mRuleCollection = new CSSRuleListImpl(this); 1.1816 + } 1.1817 + 1.1818 + return mRuleCollection; 1.1819 +} 1.1820 + 1.1821 +NS_IMETHODIMP 1.1822 +nsCSSStyleSheet::InsertRule(const nsAString& aRule, 1.1823 + uint32_t aIndex, 1.1824 + uint32_t* aReturn) 1.1825 +{ 1.1826 + //-- Security check: Only scripts whose principal subsumes that of the 1.1827 + // style sheet can modify rule collections. 1.1828 + nsresult rv = SubjectSubsumesInnerPrincipal(); 1.1829 + NS_ENSURE_SUCCESS(rv, rv); 1.1830 + 1.1831 + return InsertRuleInternal(aRule, aIndex, aReturn); 1.1832 +} 1.1833 + 1.1834 +static bool 1.1835 +RuleHasPendingChildSheet(css::Rule *cssRule) 1.1836 +{ 1.1837 + nsCOMPtr<nsIDOMCSSImportRule> importRule(do_QueryInterface(cssRule)); 1.1838 + NS_ASSERTION(importRule, "Rule which has type IMPORT_RULE and does not implement nsIDOMCSSImportRule!"); 1.1839 + nsCOMPtr<nsIDOMCSSStyleSheet> childSheet; 1.1840 + importRule->GetStyleSheet(getter_AddRefs(childSheet)); 1.1841 + nsRefPtr<nsCSSStyleSheet> cssSheet = do_QueryObject(childSheet); 1.1842 + return cssSheet != nullptr && !cssSheet->IsComplete(); 1.1843 +} 1.1844 + 1.1845 +nsresult 1.1846 +nsCSSStyleSheet::InsertRuleInternal(const nsAString& aRule, 1.1847 + uint32_t aIndex, 1.1848 + uint32_t* aReturn) 1.1849 +{ 1.1850 + // No doing this if the sheet is not complete! 1.1851 + if (!mInner->mComplete) { 1.1852 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.1853 + } 1.1854 + 1.1855 + WillDirty(); 1.1856 + 1.1857 + if (aIndex > uint32_t(mInner->mOrderedRules.Count())) 1.1858 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.1859 + 1.1860 + NS_ASSERTION(uint32_t(mInner->mOrderedRules.Count()) <= INT32_MAX, 1.1861 + "Too many style rules!"); 1.1862 + 1.1863 + // Hold strong ref to the CSSLoader in case the document update 1.1864 + // kills the document 1.1865 + nsRefPtr<css::Loader> loader; 1.1866 + if (mDocument) { 1.1867 + loader = mDocument->CSSLoader(); 1.1868 + NS_ASSERTION(loader, "Document with no CSS loader!"); 1.1869 + } 1.1870 + 1.1871 + nsCSSParser css(loader, this); 1.1872 + 1.1873 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.1874 + 1.1875 + nsRefPtr<css::Rule> rule; 1.1876 + nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI, 1.1877 + mInner->mPrincipal, getter_AddRefs(rule)); 1.1878 + if (NS_FAILED(result)) 1.1879 + return result; 1.1880 + 1.1881 + // Hierarchy checking. 1.1882 + int32_t newType = rule->GetType(); 1.1883 + 1.1884 + // check that we're not inserting before a charset rule 1.1885 + css::Rule* nextRule = mInner->mOrderedRules.SafeObjectAt(aIndex); 1.1886 + if (nextRule) { 1.1887 + int32_t nextType = nextRule->GetType(); 1.1888 + if (nextType == css::Rule::CHARSET_RULE) { 1.1889 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1890 + } 1.1891 + 1.1892 + if (nextType == css::Rule::IMPORT_RULE && 1.1893 + newType != css::Rule::CHARSET_RULE && 1.1894 + newType != css::Rule::IMPORT_RULE) { 1.1895 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1896 + } 1.1897 + 1.1898 + if (nextType == css::Rule::NAMESPACE_RULE && 1.1899 + newType != css::Rule::CHARSET_RULE && 1.1900 + newType != css::Rule::IMPORT_RULE && 1.1901 + newType != css::Rule::NAMESPACE_RULE) { 1.1902 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1903 + } 1.1904 + } 1.1905 + 1.1906 + if (aIndex != 0) { 1.1907 + // no inserting charset at nonzero position 1.1908 + if (newType == css::Rule::CHARSET_RULE) { 1.1909 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1910 + } 1.1911 + 1.1912 + css::Rule* prevRule = mInner->mOrderedRules.SafeObjectAt(aIndex - 1); 1.1913 + int32_t prevType = prevRule->GetType(); 1.1914 + 1.1915 + if (newType == css::Rule::IMPORT_RULE && 1.1916 + prevType != css::Rule::CHARSET_RULE && 1.1917 + prevType != css::Rule::IMPORT_RULE) { 1.1918 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1919 + } 1.1920 + 1.1921 + if (newType == css::Rule::NAMESPACE_RULE && 1.1922 + prevType != css::Rule::CHARSET_RULE && 1.1923 + prevType != css::Rule::IMPORT_RULE && 1.1924 + prevType != css::Rule::NAMESPACE_RULE) { 1.1925 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.1926 + } 1.1927 + } 1.1928 + 1.1929 + bool insertResult = mInner->mOrderedRules.InsertObjectAt(rule, aIndex); 1.1930 + NS_ENSURE_TRUE(insertResult, NS_ERROR_OUT_OF_MEMORY); 1.1931 + DidDirty(); 1.1932 + 1.1933 + rule->SetStyleSheet(this); 1.1934 + 1.1935 + int32_t type = rule->GetType(); 1.1936 + if (type == css::Rule::NAMESPACE_RULE) { 1.1937 + // XXXbz does this screw up when inserting a namespace rule before 1.1938 + // another namespace rule that binds the same prefix to a different 1.1939 + // namespace? 1.1940 + result = RegisterNamespaceRule(rule); 1.1941 + NS_ENSURE_SUCCESS(result, result); 1.1942 + } 1.1943 + 1.1944 + // We don't notify immediately for @import rules, but rather when 1.1945 + // the sheet the rule is importing is loaded (see StyleSheetLoaded) 1.1946 + if ((type != css::Rule::IMPORT_RULE || !RuleHasPendingChildSheet(rule)) && 1.1947 + mDocument) { 1.1948 + mDocument->StyleRuleAdded(this, rule); 1.1949 + } 1.1950 + 1.1951 + *aReturn = aIndex; 1.1952 + return NS_OK; 1.1953 +} 1.1954 + 1.1955 +NS_IMETHODIMP 1.1956 +nsCSSStyleSheet::DeleteRule(uint32_t aIndex) 1.1957 +{ 1.1958 + // No doing this if the sheet is not complete! 1.1959 + if (!mInner->mComplete) { 1.1960 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.1961 + } 1.1962 + 1.1963 + //-- Security check: Only scripts whose principal subsumes that of the 1.1964 + // style sheet can modify rule collections. 1.1965 + nsresult rv = SubjectSubsumesInnerPrincipal(); 1.1966 + NS_ENSURE_SUCCESS(rv, rv); 1.1967 + 1.1968 + // XXX TBI: handle @rule types 1.1969 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.1970 + 1.1971 + WillDirty(); 1.1972 + 1.1973 + if (aIndex >= uint32_t(mInner->mOrderedRules.Count())) 1.1974 + return NS_ERROR_DOM_INDEX_SIZE_ERR; 1.1975 + 1.1976 + NS_ASSERTION(uint32_t(mInner->mOrderedRules.Count()) <= INT32_MAX, 1.1977 + "Too many style rules!"); 1.1978 + 1.1979 + // Hold a strong ref to the rule so it doesn't die when we RemoveObjectAt 1.1980 + nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(aIndex); 1.1981 + if (rule) { 1.1982 + mInner->mOrderedRules.RemoveObjectAt(aIndex); 1.1983 + if (mDocument && mDocument->StyleSheetChangeEventsEnabled()) { 1.1984 + // Force creation of the DOM rule, so that it can be put on the 1.1985 + // StyleRuleRemoved event object. 1.1986 + rule->GetDOMRule(); 1.1987 + } 1.1988 + rule->SetStyleSheet(nullptr); 1.1989 + DidDirty(); 1.1990 + 1.1991 + if (mDocument) { 1.1992 + mDocument->StyleRuleRemoved(this, rule); 1.1993 + } 1.1994 + } 1.1995 + 1.1996 + return NS_OK; 1.1997 +} 1.1998 + 1.1999 +nsresult 1.2000 +nsCSSStyleSheet::DeleteRuleFromGroup(css::GroupRule* aGroup, uint32_t aIndex) 1.2001 +{ 1.2002 + NS_ENSURE_ARG_POINTER(aGroup); 1.2003 + NS_ASSERTION(mInner->mComplete, "No deleting from an incomplete sheet!"); 1.2004 + nsRefPtr<css::Rule> rule = aGroup->GetStyleRuleAt(aIndex); 1.2005 + NS_ENSURE_TRUE(rule, NS_ERROR_ILLEGAL_VALUE); 1.2006 + 1.2007 + // check that the rule actually belongs to this sheet! 1.2008 + if (this != rule->GetStyleSheet()) { 1.2009 + return NS_ERROR_INVALID_ARG; 1.2010 + } 1.2011 + 1.2012 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.2013 + 1.2014 + WillDirty(); 1.2015 + 1.2016 + nsresult result = aGroup->DeleteStyleRuleAt(aIndex); 1.2017 + NS_ENSURE_SUCCESS(result, result); 1.2018 + 1.2019 + rule->SetStyleSheet(nullptr); 1.2020 + 1.2021 + DidDirty(); 1.2022 + 1.2023 + if (mDocument) { 1.2024 + mDocument->StyleRuleRemoved(this, rule); 1.2025 + } 1.2026 + 1.2027 + return NS_OK; 1.2028 +} 1.2029 + 1.2030 +nsresult 1.2031 +nsCSSStyleSheet::InsertRuleIntoGroup(const nsAString & aRule, 1.2032 + css::GroupRule* aGroup, 1.2033 + uint32_t aIndex, 1.2034 + uint32_t* _retval) 1.2035 +{ 1.2036 + NS_ASSERTION(mInner->mComplete, "No inserting into an incomplete sheet!"); 1.2037 + // check that the group actually belongs to this sheet! 1.2038 + if (this != aGroup->GetStyleSheet()) { 1.2039 + return NS_ERROR_INVALID_ARG; 1.2040 + } 1.2041 + 1.2042 + // Hold strong ref to the CSSLoader in case the document update 1.2043 + // kills the document 1.2044 + nsRefPtr<css::Loader> loader; 1.2045 + if (mDocument) { 1.2046 + loader = mDocument->CSSLoader(); 1.2047 + NS_ASSERTION(loader, "Document with no CSS loader!"); 1.2048 + } 1.2049 + 1.2050 + nsCSSParser css(loader, this); 1.2051 + 1.2052 + // parse and grab the rule 1.2053 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.2054 + 1.2055 + WillDirty(); 1.2056 + 1.2057 + nsRefPtr<css::Rule> rule; 1.2058 + nsresult result = css.ParseRule(aRule, mInner->mSheetURI, mInner->mBaseURI, 1.2059 + mInner->mPrincipal, getter_AddRefs(rule)); 1.2060 + if (NS_FAILED(result)) 1.2061 + return result; 1.2062 + 1.2063 + switch (rule->GetType()) { 1.2064 + case css::Rule::STYLE_RULE: 1.2065 + case css::Rule::MEDIA_RULE: 1.2066 + case css::Rule::FONT_FACE_RULE: 1.2067 + case css::Rule::PAGE_RULE: 1.2068 + case css::Rule::KEYFRAMES_RULE: 1.2069 + case css::Rule::DOCUMENT_RULE: 1.2070 + case css::Rule::SUPPORTS_RULE: 1.2071 + // these types are OK to insert into a group 1.2072 + break; 1.2073 + case css::Rule::CHARSET_RULE: 1.2074 + case css::Rule::IMPORT_RULE: 1.2075 + case css::Rule::NAMESPACE_RULE: 1.2076 + // these aren't 1.2077 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.2078 + default: 1.2079 + NS_NOTREACHED("unexpected rule type"); 1.2080 + return NS_ERROR_DOM_HIERARCHY_REQUEST_ERR; 1.2081 + } 1.2082 + 1.2083 + result = aGroup->InsertStyleRuleAt(aIndex, rule); 1.2084 + NS_ENSURE_SUCCESS(result, result); 1.2085 + DidDirty(); 1.2086 + 1.2087 + if (mDocument) { 1.2088 + mDocument->StyleRuleAdded(this, rule); 1.2089 + } 1.2090 + 1.2091 + *_retval = aIndex; 1.2092 + return NS_OK; 1.2093 +} 1.2094 + 1.2095 +nsresult 1.2096 +nsCSSStyleSheet::ReplaceRuleInGroup(css::GroupRule* aGroup, 1.2097 + css::Rule* aOld, css::Rule* aNew) 1.2098 +{ 1.2099 + NS_PRECONDITION(mInner->mComplete, "No replacing in an incomplete sheet!"); 1.2100 + NS_ASSERTION(this == aGroup->GetStyleSheet(), "group doesn't belong to this sheet"); 1.2101 + 1.2102 + WillDirty(); 1.2103 + 1.2104 + nsresult result = aGroup->ReplaceStyleRule(aOld, aNew); 1.2105 + DidDirty(); 1.2106 + return result; 1.2107 +} 1.2108 + 1.2109 +// nsICSSLoaderObserver implementation 1.2110 +NS_IMETHODIMP 1.2111 +nsCSSStyleSheet::StyleSheetLoaded(nsCSSStyleSheet* aSheet, 1.2112 + bool aWasAlternate, 1.2113 + nsresult aStatus) 1.2114 +{ 1.2115 + if (aSheet->GetParentSheet() == nullptr) { 1.2116 + return NS_OK; // ignore if sheet has been detached already (see parseSheet) 1.2117 + } 1.2118 + NS_ASSERTION(this == aSheet->GetParentSheet(), 1.2119 + "We are being notified of a sheet load for a sheet that is not our child!"); 1.2120 + 1.2121 + if (mDocument && NS_SUCCEEDED(aStatus)) { 1.2122 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.2123 + 1.2124 + // XXXldb @import rules shouldn't even implement nsIStyleRule (but 1.2125 + // they do)! 1.2126 + mDocument->StyleRuleAdded(this, aSheet->GetOwnerRule()); 1.2127 + } 1.2128 + 1.2129 + return NS_OK; 1.2130 +} 1.2131 + 1.2132 +nsresult 1.2133 +nsCSSStyleSheet::ParseSheet(const nsAString& aInput) 1.2134 +{ 1.2135 + // Not doing this if the sheet is not complete! 1.2136 + if (!mInner->mComplete) { 1.2137 + return NS_ERROR_DOM_INVALID_ACCESS_ERR; 1.2138 + } 1.2139 + 1.2140 + // Hold strong ref to the CSSLoader in case the document update 1.2141 + // kills the document 1.2142 + nsRefPtr<css::Loader> loader; 1.2143 + if (mDocument) { 1.2144 + loader = mDocument->CSSLoader(); 1.2145 + NS_ASSERTION(loader, "Document with no CSS loader!"); 1.2146 + } else { 1.2147 + loader = new css::Loader(); 1.2148 + } 1.2149 + 1.2150 + mozAutoDocUpdate updateBatch(mDocument, UPDATE_STYLE, true); 1.2151 + 1.2152 + WillDirty(); 1.2153 + 1.2154 + // detach existing rules (including child sheets via import rules) 1.2155 + int ruleCount; 1.2156 + while ((ruleCount = mInner->mOrderedRules.Count()) != 0) { 1.2157 + nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(ruleCount - 1); 1.2158 + mInner->mOrderedRules.RemoveObjectAt(ruleCount - 1); 1.2159 + rule->SetStyleSheet(nullptr); 1.2160 + if (mDocument) { 1.2161 + mDocument->StyleRuleRemoved(this, rule); 1.2162 + } 1.2163 + } 1.2164 + 1.2165 + // nuke child sheets list and current namespace map 1.2166 + for (nsCSSStyleSheet* child = mInner->mFirstChild; child; child = child->mNext) { 1.2167 + NS_ASSERTION(child->mParent == this, "Child sheet is not parented to this!"); 1.2168 + child->mParent = nullptr; 1.2169 + child->mDocument = nullptr; 1.2170 + } 1.2171 + mInner->mFirstChild = nullptr; 1.2172 + mInner->mNameSpaceMap = nullptr; 1.2173 + 1.2174 + // allow unsafe rules if the style sheet's principal is the system principal 1.2175 + bool allowUnsafeRules = nsContentUtils::IsSystemPrincipal(mInner->mPrincipal); 1.2176 + 1.2177 + nsCSSParser parser(loader, this); 1.2178 + nsresult rv = parser.ParseSheet(aInput, mInner->mSheetURI, mInner->mBaseURI, 1.2179 + mInner->mPrincipal, 1, allowUnsafeRules); 1.2180 + DidDirty(); // we are always 'dirty' here since we always remove rules first 1.2181 + NS_ENSURE_SUCCESS(rv, rv); 1.2182 + 1.2183 + // notify document of all new rules 1.2184 + if (mDocument) { 1.2185 + for (int32_t index = 0; index < mInner->mOrderedRules.Count(); ++index) { 1.2186 + nsRefPtr<css::Rule> rule = mInner->mOrderedRules.ObjectAt(index); 1.2187 + if (rule->GetType() == css::Rule::IMPORT_RULE && 1.2188 + RuleHasPendingChildSheet(rule)) { 1.2189 + continue; // notify when loaded (see StyleSheetLoaded) 1.2190 + } 1.2191 + mDocument->StyleRuleAdded(this, rule); 1.2192 + } 1.2193 + } 1.2194 + return NS_OK; 1.2195 +} 1.2196 + 1.2197 +/* virtual */ nsIURI* 1.2198 +nsCSSStyleSheet::GetOriginalURI() const 1.2199 +{ 1.2200 + return mInner->mOriginalSheetURI; 1.2201 +} 1.2202 + 1.2203 +/* virtual */ 1.2204 +JSObject* 1.2205 +nsCSSStyleSheet::WrapObject(JSContext* aCx) 1.2206 +{ 1.2207 + return CSSStyleSheetBinding::Wrap(aCx, this); 1.2208 +}