1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsDOMCSSDeclaration.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,454 @@ 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 +/* base class for DOM objects for element.style and cssStyleRule.style */ 1.10 + 1.11 +#include "nsDOMCSSDeclaration.h" 1.12 + 1.13 +#include "nsCSSParser.h" 1.14 +#include "nsCSSStyleSheet.h" 1.15 +#include "mozilla/css/Rule.h" 1.16 +#include "mozilla/css/Declaration.h" 1.17 +#include "mozilla/dom/CSS2PropertiesBinding.h" 1.18 +#include "nsCSSProps.h" 1.19 +#include "nsCOMPtr.h" 1.20 +#include "mozAutoDocUpdate.h" 1.21 +#include "nsIURI.h" 1.22 +#include "mozilla/dom/BindingUtils.h" 1.23 +#include "nsContentUtils.h" 1.24 + 1.25 +using namespace mozilla; 1.26 + 1.27 +nsDOMCSSDeclaration::~nsDOMCSSDeclaration() 1.28 +{ 1.29 +} 1.30 + 1.31 +/* virtual */ JSObject* 1.32 +nsDOMCSSDeclaration::WrapObject(JSContext* aCx) 1.33 +{ 1.34 + return dom::CSS2PropertiesBinding::Wrap(aCx, this); 1.35 +} 1.36 + 1.37 +NS_INTERFACE_TABLE_HEAD(nsDOMCSSDeclaration) 1.38 + NS_INTERFACE_TABLE(nsDOMCSSDeclaration, 1.39 + nsICSSDeclaration, 1.40 + nsIDOMCSSStyleDeclaration) 1.41 + NS_INTERFACE_TABLE_TO_MAP_SEGUE 1.42 +NS_INTERFACE_MAP_END 1.43 + 1.44 +NS_IMETHODIMP 1.45 +nsDOMCSSDeclaration::GetPropertyValue(const nsCSSProperty aPropID, 1.46 + nsAString& aValue) 1.47 +{ 1.48 + NS_PRECONDITION(aPropID != eCSSProperty_UNKNOWN, 1.49 + "Should never pass eCSSProperty_UNKNOWN around"); 1.50 + 1.51 + css::Declaration* decl = GetCSSDeclaration(false); 1.52 + 1.53 + aValue.Truncate(); 1.54 + if (decl) { 1.55 + decl->GetValue(aPropID, aValue); 1.56 + } 1.57 + return NS_OK; 1.58 +} 1.59 + 1.60 +void 1.61 +nsDOMCSSDeclaration::GetCustomPropertyValue(const nsAString& aPropertyName, 1.62 + nsAString& aValue) 1.63 +{ 1.64 + MOZ_ASSERT(Substring(aPropertyName, 0, 1.65 + CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--")); 1.66 + 1.67 + css::Declaration* decl = GetCSSDeclaration(false); 1.68 + if (!decl) { 1.69 + aValue.Truncate(); 1.70 + return; 1.71 + } 1.72 + 1.73 + decl->GetVariableDeclaration(Substring(aPropertyName, 1.74 + CSS_CUSTOM_NAME_PREFIX_LENGTH), 1.75 + aValue); 1.76 +} 1.77 + 1.78 +NS_IMETHODIMP 1.79 +nsDOMCSSDeclaration::SetPropertyValue(const nsCSSProperty aPropID, 1.80 + const nsAString& aValue) 1.81 +{ 1.82 + if (aValue.IsEmpty()) { 1.83 + // If the new value of the property is an empty string we remove the 1.84 + // property. 1.85 + return RemoveProperty(aPropID); 1.86 + } 1.87 + 1.88 + return ParsePropertyValue(aPropID, aValue, false); 1.89 +} 1.90 + 1.91 + 1.92 +NS_IMETHODIMP 1.93 +nsDOMCSSDeclaration::GetCssText(nsAString& aCssText) 1.94 +{ 1.95 + css::Declaration* decl = GetCSSDeclaration(false); 1.96 + aCssText.Truncate(); 1.97 + 1.98 + if (decl) { 1.99 + decl->ToString(aCssText); 1.100 + } 1.101 + 1.102 + return NS_OK; 1.103 +} 1.104 + 1.105 +NS_IMETHODIMP 1.106 +nsDOMCSSDeclaration::SetCssText(const nsAString& aCssText) 1.107 +{ 1.108 + // We don't need to *do* anything with the old declaration, but we need 1.109 + // to ensure that it exists, or else SetCSSDeclaration may crash. 1.110 + css::Declaration* olddecl = GetCSSDeclaration(true); 1.111 + if (!olddecl) { 1.112 + return NS_ERROR_FAILURE; 1.113 + } 1.114 + 1.115 + CSSParsingEnvironment env; 1.116 + GetCSSParsingEnvironment(env); 1.117 + if (!env.mPrincipal) { 1.118 + return NS_ERROR_NOT_AVAILABLE; 1.119 + } 1.120 + 1.121 + // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to 1.122 + // Attribute setting code, which leads in turn to BeginUpdate. We 1.123 + // need to start the update now so that the old rule doesn't get used 1.124 + // between when we mutate the declaration and when we set the new 1.125 + // rule (see stack in bug 209575). 1.126 + mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true); 1.127 + 1.128 + nsAutoPtr<css::Declaration> decl(new css::Declaration()); 1.129 + decl->InitializeEmpty(); 1.130 + nsCSSParser cssParser(env.mCSSLoader); 1.131 + bool changed; 1.132 + nsresult result = cssParser.ParseDeclarations(aCssText, env.mSheetURI, 1.133 + env.mBaseURI, 1.134 + env.mPrincipal, decl, &changed); 1.135 + if (NS_FAILED(result) || !changed) { 1.136 + return result; 1.137 + } 1.138 + 1.139 + return SetCSSDeclaration(decl.forget()); 1.140 +} 1.141 + 1.142 +NS_IMETHODIMP 1.143 +nsDOMCSSDeclaration::GetLength(uint32_t* aLength) 1.144 +{ 1.145 + css::Declaration* decl = GetCSSDeclaration(false); 1.146 + 1.147 + if (decl) { 1.148 + *aLength = decl->Count(); 1.149 + } else { 1.150 + *aLength = 0; 1.151 + } 1.152 + 1.153 + return NS_OK; 1.154 +} 1.155 + 1.156 +already_AddRefed<dom::CSSValue> 1.157 +nsDOMCSSDeclaration::GetPropertyCSSValue(const nsAString& aPropertyName, ErrorResult& aRv) 1.158 +{ 1.159 + // We don't support CSSValue yet so we'll just return null... 1.160 + 1.161 + return nullptr; 1.162 +} 1.163 + 1.164 +void 1.165 +nsDOMCSSDeclaration::IndexedGetter(uint32_t aIndex, bool& aFound, nsAString& aPropName) 1.166 +{ 1.167 + css::Declaration* decl = GetCSSDeclaration(false); 1.168 + aFound = decl && decl->GetNthProperty(aIndex, aPropName); 1.169 +} 1.170 + 1.171 +NS_IMETHODIMP 1.172 +nsDOMCSSDeclaration::GetPropertyValue(const nsAString& aPropertyName, 1.173 + nsAString& aReturn) 1.174 +{ 1.175 + const nsCSSProperty propID = 1.176 + nsCSSProps::LookupProperty(aPropertyName, 1.177 + nsCSSProps::eEnabledForAllContent); 1.178 + if (propID == eCSSProperty_UNKNOWN) { 1.179 + aReturn.Truncate(); 1.180 + return NS_OK; 1.181 + } 1.182 + 1.183 + if (propID == eCSSPropertyExtra_variable) { 1.184 + GetCustomPropertyValue(aPropertyName, aReturn); 1.185 + return NS_OK; 1.186 + } 1.187 + 1.188 + return GetPropertyValue(propID, aReturn); 1.189 +} 1.190 + 1.191 +NS_IMETHODIMP 1.192 +nsDOMCSSDeclaration::GetAuthoredPropertyValue(const nsAString& aPropertyName, 1.193 + nsAString& aReturn) 1.194 +{ 1.195 + const nsCSSProperty propID = 1.196 + nsCSSProps::LookupProperty(aPropertyName, 1.197 + nsCSSProps::eEnabledForAllContent); 1.198 + if (propID == eCSSProperty_UNKNOWN) { 1.199 + aReturn.Truncate(); 1.200 + return NS_OK; 1.201 + } 1.202 + 1.203 + if (propID == eCSSPropertyExtra_variable) { 1.204 + GetCustomPropertyValue(aPropertyName, aReturn); 1.205 + return NS_OK; 1.206 + } 1.207 + 1.208 + css::Declaration* decl = GetCSSDeclaration(false); 1.209 + if (!decl) { 1.210 + return NS_ERROR_FAILURE; 1.211 + } 1.212 + 1.213 + decl->GetAuthoredValue(propID, aReturn); 1.214 + return NS_OK; 1.215 +} 1.216 + 1.217 +NS_IMETHODIMP 1.218 +nsDOMCSSDeclaration::GetPropertyPriority(const nsAString& aPropertyName, 1.219 + nsAString& aReturn) 1.220 +{ 1.221 + css::Declaration* decl = GetCSSDeclaration(false); 1.222 + 1.223 + aReturn.Truncate(); 1.224 + if (decl && decl->GetValueIsImportant(aPropertyName)) { 1.225 + aReturn.AssignLiteral("important"); 1.226 + } 1.227 + 1.228 + return NS_OK; 1.229 +} 1.230 + 1.231 +NS_IMETHODIMP 1.232 +nsDOMCSSDeclaration::SetProperty(const nsAString& aPropertyName, 1.233 + const nsAString& aValue, 1.234 + const nsAString& aPriority) 1.235 +{ 1.236 + // In the common (and fast) cases we can use the property id 1.237 + nsCSSProperty propID = 1.238 + nsCSSProps::LookupProperty(aPropertyName, 1.239 + nsCSSProps::eEnabledForAllContent); 1.240 + if (propID == eCSSProperty_UNKNOWN) { 1.241 + return NS_OK; 1.242 + } 1.243 + 1.244 + if (aValue.IsEmpty()) { 1.245 + // If the new value of the property is an empty string we remove the 1.246 + // property. 1.247 + // XXX this ignores the priority string, should it? 1.248 + if (propID == eCSSPropertyExtra_variable) { 1.249 + return RemoveCustomProperty(aPropertyName); 1.250 + } 1.251 + return RemoveProperty(propID); 1.252 + } 1.253 + 1.254 + bool important; 1.255 + if (aPriority.IsEmpty()) { 1.256 + important = false; 1.257 + } else if (aPriority.EqualsLiteral("important")) { 1.258 + important = true; 1.259 + } else { 1.260 + // XXX silent failure? 1.261 + return NS_OK; 1.262 + } 1.263 + 1.264 + if (propID == eCSSPropertyExtra_variable) { 1.265 + return ParseCustomPropertyValue(aPropertyName, aValue, important); 1.266 + } 1.267 + return ParsePropertyValue(propID, aValue, important); 1.268 +} 1.269 + 1.270 +NS_IMETHODIMP 1.271 +nsDOMCSSDeclaration::RemoveProperty(const nsAString& aPropertyName, 1.272 + nsAString& aReturn) 1.273 +{ 1.274 + const nsCSSProperty propID = 1.275 + nsCSSProps::LookupProperty(aPropertyName, 1.276 + nsCSSProps::eEnabledForAllContent); 1.277 + if (propID == eCSSProperty_UNKNOWN) { 1.278 + aReturn.Truncate(); 1.279 + return NS_OK; 1.280 + } 1.281 + 1.282 + if (propID == eCSSPropertyExtra_variable) { 1.283 + RemoveCustomProperty(aPropertyName); 1.284 + return NS_OK; 1.285 + } 1.286 + 1.287 + nsresult rv = GetPropertyValue(propID, aReturn); 1.288 + NS_ENSURE_SUCCESS(rv, rv); 1.289 + 1.290 + return RemoveProperty(propID); 1.291 +} 1.292 + 1.293 +/* static */ void 1.294 +nsDOMCSSDeclaration::GetCSSParsingEnvironmentForRule(css::Rule* aRule, 1.295 + CSSParsingEnvironment& aCSSParseEnv) 1.296 +{ 1.297 + nsIStyleSheet* sheet = aRule ? aRule->GetStyleSheet() : nullptr; 1.298 + nsRefPtr<nsCSSStyleSheet> cssSheet(do_QueryObject(sheet)); 1.299 + if (!cssSheet) { 1.300 + aCSSParseEnv.mPrincipal = nullptr; 1.301 + return; 1.302 + } 1.303 + 1.304 + nsIDocument* document = sheet->GetOwningDocument(); 1.305 + aCSSParseEnv.mSheetURI = sheet->GetSheetURI(); 1.306 + aCSSParseEnv.mBaseURI = sheet->GetBaseURI(); 1.307 + aCSSParseEnv.mPrincipal = cssSheet->Principal(); 1.308 + aCSSParseEnv.mCSSLoader = document ? document->CSSLoader() : nullptr; 1.309 +} 1.310 + 1.311 +nsresult 1.312 +nsDOMCSSDeclaration::ParsePropertyValue(const nsCSSProperty aPropID, 1.313 + const nsAString& aPropValue, 1.314 + bool aIsImportant) 1.315 +{ 1.316 + css::Declaration* olddecl = GetCSSDeclaration(true); 1.317 + if (!olddecl) { 1.318 + return NS_ERROR_FAILURE; 1.319 + } 1.320 + 1.321 + CSSParsingEnvironment env; 1.322 + GetCSSParsingEnvironment(env); 1.323 + if (!env.mPrincipal) { 1.324 + return NS_ERROR_NOT_AVAILABLE; 1.325 + } 1.326 + 1.327 + // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to 1.328 + // Attribute setting code, which leads in turn to BeginUpdate. We 1.329 + // need to start the update now so that the old rule doesn't get used 1.330 + // between when we mutate the declaration and when we set the new 1.331 + // rule (see stack in bug 209575). 1.332 + mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true); 1.333 + css::Declaration* decl = olddecl->EnsureMutable(); 1.334 + 1.335 + nsCSSParser cssParser(env.mCSSLoader); 1.336 + bool changed; 1.337 + nsresult result = cssParser.ParseProperty(aPropID, aPropValue, env.mSheetURI, 1.338 + env.mBaseURI, env.mPrincipal, decl, 1.339 + &changed, aIsImportant); 1.340 + if (NS_FAILED(result) || !changed) { 1.341 + if (decl != olddecl) { 1.342 + delete decl; 1.343 + } 1.344 + return result; 1.345 + } 1.346 + 1.347 + return SetCSSDeclaration(decl); 1.348 +} 1.349 + 1.350 +nsresult 1.351 +nsDOMCSSDeclaration::ParseCustomPropertyValue(const nsAString& aPropertyName, 1.352 + const nsAString& aPropValue, 1.353 + bool aIsImportant) 1.354 +{ 1.355 + MOZ_ASSERT(nsCSSProps::IsCustomPropertyName(aPropertyName)); 1.356 + 1.357 + css::Declaration* olddecl = GetCSSDeclaration(true); 1.358 + if (!olddecl) { 1.359 + return NS_ERROR_FAILURE; 1.360 + } 1.361 + 1.362 + CSSParsingEnvironment env; 1.363 + GetCSSParsingEnvironment(env); 1.364 + if (!env.mPrincipal) { 1.365 + return NS_ERROR_NOT_AVAILABLE; 1.366 + } 1.367 + 1.368 + // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to 1.369 + // Attribute setting code, which leads in turn to BeginUpdate. We 1.370 + // need to start the update now so that the old rule doesn't get used 1.371 + // between when we mutate the declaration and when we set the new 1.372 + // rule (see stack in bug 209575). 1.373 + mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true); 1.374 + css::Declaration* decl = olddecl->EnsureMutable(); 1.375 + 1.376 + nsCSSParser cssParser(env.mCSSLoader); 1.377 + bool changed; 1.378 + nsresult result = 1.379 + cssParser.ParseVariable(Substring(aPropertyName, 1.380 + CSS_CUSTOM_NAME_PREFIX_LENGTH), 1.381 + aPropValue, env.mSheetURI, 1.382 + env.mBaseURI, env.mPrincipal, decl, 1.383 + &changed, aIsImportant); 1.384 + if (NS_FAILED(result) || !changed) { 1.385 + if (decl != olddecl) { 1.386 + delete decl; 1.387 + } 1.388 + return result; 1.389 + } 1.390 + 1.391 + return SetCSSDeclaration(decl); 1.392 +} 1.393 + 1.394 +nsresult 1.395 +nsDOMCSSDeclaration::RemoveProperty(const nsCSSProperty aPropID) 1.396 +{ 1.397 + css::Declaration* decl = GetCSSDeclaration(false); 1.398 + if (!decl) { 1.399 + return NS_OK; // no decl, so nothing to remove 1.400 + } 1.401 + 1.402 + // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to 1.403 + // Attribute setting code, which leads in turn to BeginUpdate. We 1.404 + // need to start the update now so that the old rule doesn't get used 1.405 + // between when we mutate the declaration and when we set the new 1.406 + // rule (see stack in bug 209575). 1.407 + mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true); 1.408 + 1.409 + decl = decl->EnsureMutable(); 1.410 + decl->RemoveProperty(aPropID); 1.411 + return SetCSSDeclaration(decl); 1.412 +} 1.413 + 1.414 +nsresult 1.415 +nsDOMCSSDeclaration::RemoveCustomProperty(const nsAString& aPropertyName) 1.416 +{ 1.417 + MOZ_ASSERT(Substring(aPropertyName, 0, 1.418 + CSS_CUSTOM_NAME_PREFIX_LENGTH).EqualsLiteral("--")); 1.419 + 1.420 + css::Declaration* decl = GetCSSDeclaration(false); 1.421 + if (!decl) { 1.422 + return NS_OK; // no decl, so nothing to remove 1.423 + } 1.424 + 1.425 + // For nsDOMCSSAttributeDeclaration, SetCSSDeclaration will lead to 1.426 + // Attribute setting code, which leads in turn to BeginUpdate. We 1.427 + // need to start the update now so that the old rule doesn't get used 1.428 + // between when we mutate the declaration and when we set the new 1.429 + // rule (see stack in bug 209575). 1.430 + mozAutoDocConditionalContentUpdateBatch autoUpdate(DocToUpdate(), true); 1.431 + 1.432 + decl = decl->EnsureMutable(); 1.433 + decl->RemoveVariableDeclaration(Substring(aPropertyName, 1.434 + CSS_CUSTOM_NAME_PREFIX_LENGTH)); 1.435 + return SetCSSDeclaration(decl); 1.436 +} 1.437 + 1.438 +bool IsCSSPropertyExposedToJS(nsCSSProperty aProperty, JSContext* cx, JSObject* obj) 1.439 +{ 1.440 + nsCSSProps::EnabledState enabledState = nsCSSProps::eEnabledForAllContent; 1.441 + 1.442 + // Optimization: we skip checking properties of the JSContext 1.443 + // in the majority case where the property does not have the 1.444 + // CSS_PROPERTY_ALWAYS_ENABLED_IN_PRIVILEGED_CONTENT flag. 1.445 + bool isEnabledInChromeOrCertifiedApp 1.446 + = nsCSSProps::PropHasFlags(aProperty, 1.447 + CSS_PROPERTY_ALWAYS_ENABLED_IN_CHROME_OR_CERTIFIED_APP); 1.448 + 1.449 + if (isEnabledInChromeOrCertifiedApp) { 1.450 + if (dom::IsInCertifiedApp(cx, obj) || 1.451 + nsContentUtils::ThreadsafeIsCallerChrome()) 1.452 + { 1.453 + enabledState |= nsCSSProps::eEnabledInChromeOrCertifiedApp; 1.454 + } 1.455 + } 1.456 + return nsCSSProps::IsEnabled(aProperty, enabledState); 1.457 +}