1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/layout/style/nsStyleUtil.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,577 @@ 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 +#include "nsStyleUtil.h" 1.10 +#include "nsStyleConsts.h" 1.11 + 1.12 +#include "nsIContent.h" 1.13 +#include "nsCSSProps.h" 1.14 +#include "nsRuleNode.h" 1.15 +#include "nsROCSSPrimitiveValue.h" 1.16 +#include "nsIContentPolicy.h" 1.17 +#include "nsIContentSecurityPolicy.h" 1.18 +#include "nsIURI.h" 1.19 + 1.20 +using namespace mozilla; 1.21 + 1.22 +//------------------------------------------------------------------------------ 1.23 +// Font Algorithm Code 1.24 +//------------------------------------------------------------------------------ 1.25 + 1.26 +// Compare two language strings 1.27 +bool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue, 1.28 + const nsAString& aSelectorValue, 1.29 + const nsStringComparator& aComparator) 1.30 +{ 1.31 + bool result; 1.32 + uint32_t selectorLen = aSelectorValue.Length(); 1.33 + uint32_t attributeLen = aAttributeValue.Length(); 1.34 + if (selectorLen > attributeLen) { 1.35 + result = false; 1.36 + } 1.37 + else { 1.38 + nsAString::const_iterator iter; 1.39 + if (selectorLen != attributeLen && 1.40 + *aAttributeValue.BeginReading(iter).advance(selectorLen) != 1.41 + char16_t('-')) { 1.42 + // to match, the aAttributeValue must have a dash after the end of 1.43 + // the aSelectorValue's text (unless the aSelectorValue and the 1.44 + // aAttributeValue have the same text) 1.45 + result = false; 1.46 + } 1.47 + else { 1.48 + result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator); 1.49 + } 1.50 + } 1.51 + return result; 1.52 +} 1.53 + 1.54 +void nsStyleUtil::AppendEscapedCSSString(const nsAString& aString, 1.55 + nsAString& aReturn, 1.56 + char16_t quoteChar) 1.57 +{ 1.58 + NS_PRECONDITION(quoteChar == '\'' || quoteChar == '"', 1.59 + "CSS strings must be quoted with ' or \""); 1.60 + aReturn.Append(quoteChar); 1.61 + 1.62 + const char16_t* in = aString.BeginReading(); 1.63 + const char16_t* const end = aString.EndReading(); 1.64 + for (; in != end; in++) { 1.65 + if (*in < 0x20 || (*in >= 0x7F && *in < 0xA0)) { 1.66 + // Escape U+0000 through U+001F and U+007F through U+009F numerically. 1.67 + aReturn.AppendPrintf("\\%hX ", *in); 1.68 + } else { 1.69 + if (*in == '"' || *in == '\'' || *in == '\\') { 1.70 + // Escape backslash and quote characters symbolically. 1.71 + // It's not technically necessary to escape the quote 1.72 + // character that isn't being used to delimit the string, 1.73 + // but we do it anyway because that makes testing simpler. 1.74 + aReturn.Append(char16_t('\\')); 1.75 + } 1.76 + aReturn.Append(*in); 1.77 + } 1.78 + } 1.79 + 1.80 + aReturn.Append(quoteChar); 1.81 +} 1.82 + 1.83 +/* static */ bool 1.84 +nsStyleUtil::AppendEscapedCSSIdent(const nsAString& aIdent, nsAString& aReturn) 1.85 +{ 1.86 + // The relevant parts of the CSS grammar are: 1.87 + // ident [-]?{nmstart}{nmchar}* 1.88 + // nmstart [_a-z]|{nonascii}|{escape} 1.89 + // nmchar [_a-z0-9-]|{nonascii}|{escape} 1.90 + // nonascii [^\0-\177] 1.91 + // escape {unicode}|\\[^\n\r\f0-9a-f] 1.92 + // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? 1.93 + // from http://www.w3.org/TR/CSS21/syndata.html#tokenization 1.94 + 1.95 + const char16_t* in = aIdent.BeginReading(); 1.96 + const char16_t* const end = aIdent.EndReading(); 1.97 + 1.98 + if (in == end) 1.99 + return true; 1.100 + 1.101 + // A leading dash does not need to be escaped as long as it is not the 1.102 + // *only* character in the identifier. 1.103 + if (in + 1 != end && *in == '-') { 1.104 + aReturn.Append(char16_t('-')); 1.105 + ++in; 1.106 + } 1.107 + 1.108 + // Escape a digit at the start (including after a dash), 1.109 + // numerically. If we didn't escape it numerically, it would get 1.110 + // interpreted as a numeric escape for the wrong character. 1.111 + // A second dash immediately after a leading dash must also be 1.112 + // escaped, but this may be done symbolically. 1.113 + if (in != end && (*in == '-' || 1.114 + ('0' <= *in && *in <= '9'))) { 1.115 + if (*in == '-') { 1.116 + aReturn.Append(char16_t('\\')); 1.117 + aReturn.Append(char16_t('-')); 1.118 + } else { 1.119 + aReturn.AppendPrintf("\\%hX ", *in); 1.120 + } 1.121 + ++in; 1.122 + } 1.123 + 1.124 + for (; in != end; ++in) { 1.125 + char16_t ch = *in; 1.126 + if (ch == 0x00) { 1.127 + return false; 1.128 + } 1.129 + if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) { 1.130 + // Escape U+0000 through U+001F and U+007F through U+009F numerically. 1.131 + aReturn.AppendPrintf("\\%hX ", *in); 1.132 + } else { 1.133 + // Escape ASCII non-identifier printables as a backslash plus 1.134 + // the character. 1.135 + if (ch < 0x7F && 1.136 + ch != '_' && ch != '-' && 1.137 + (ch < '0' || '9' < ch) && 1.138 + (ch < 'A' || 'Z' < ch) && 1.139 + (ch < 'a' || 'z' < ch)) { 1.140 + aReturn.Append(char16_t('\\')); 1.141 + } 1.142 + aReturn.Append(ch); 1.143 + } 1.144 + } 1.145 + return true; 1.146 +} 1.147 + 1.148 +/* static */ void 1.149 +nsStyleUtil::AppendBitmaskCSSValue(nsCSSProperty aProperty, 1.150 + int32_t aMaskedValue, 1.151 + int32_t aFirstMask, 1.152 + int32_t aLastMask, 1.153 + nsAString& aResult) 1.154 +{ 1.155 + for (int32_t mask = aFirstMask; mask <= aLastMask; mask <<= 1) { 1.156 + if (mask & aMaskedValue) { 1.157 + AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask), 1.158 + aResult); 1.159 + aMaskedValue &= ~mask; 1.160 + if (aMaskedValue) { // more left 1.161 + aResult.Append(char16_t(' ')); 1.162 + } 1.163 + } 1.164 + } 1.165 + NS_ABORT_IF_FALSE(aMaskedValue == 0, "unexpected bit remaining in bitfield"); 1.166 +} 1.167 + 1.168 +/* static */ void 1.169 +nsStyleUtil::AppendAngleValue(const nsStyleCoord& aAngle, nsAString& aResult) 1.170 +{ 1.171 + MOZ_ASSERT(aAngle.IsAngleValue(), "Should have angle value"); 1.172 + 1.173 + // Append number. 1.174 + AppendCSSNumber(aAngle.GetAngleValue(), aResult); 1.175 + 1.176 + // Append unit. 1.177 + switch (aAngle.GetUnit()) { 1.178 + case eStyleUnit_Degree: aResult.AppendLiteral("deg"); break; 1.179 + case eStyleUnit_Grad: aResult.AppendLiteral("grad"); break; 1.180 + case eStyleUnit_Radian: aResult.AppendLiteral("rad"); break; 1.181 + case eStyleUnit_Turn: aResult.AppendLiteral("turn"); break; 1.182 + default: NS_NOTREACHED("unrecognized angle unit"); 1.183 + } 1.184 +} 1.185 + 1.186 +/* static */ void 1.187 +nsStyleUtil::AppendPaintOrderValue(uint8_t aValue, 1.188 + nsAString& aResult) 1.189 +{ 1.190 + static_assert 1.191 + (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8, 1.192 + "SVGStyleStruct::mPaintOrder and local variables not big enough"); 1.193 + 1.194 + if (aValue == NS_STYLE_PAINT_ORDER_NORMAL) { 1.195 + aResult.AppendLiteral("normal"); 1.196 + return; 1.197 + } 1.198 + 1.199 + // Append the minimal value necessary for the given paint order. 1.200 + static_assert(NS_STYLE_PAINT_ORDER_LAST_VALUE == 3, 1.201 + "paint-order values added; check serialization"); 1.202 + 1.203 + // The following relies on the default order being the order of the 1.204 + // constant values. 1.205 + 1.206 + const uint8_t MASK = (1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1; 1.207 + 1.208 + uint32_t lastPositionToSerialize = 0; 1.209 + for (uint32_t position = NS_STYLE_PAINT_ORDER_LAST_VALUE - 1; 1.210 + position > 0; 1.211 + position--) { 1.212 + uint8_t component = 1.213 + (aValue >> (position * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK; 1.214 + uint8_t earlierComponent = 1.215 + (aValue >> ((position - 1) * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK; 1.216 + if (component < earlierComponent) { 1.217 + lastPositionToSerialize = position - 1; 1.218 + break; 1.219 + } 1.220 + } 1.221 + 1.222 + for (uint32_t position = 0; position <= lastPositionToSerialize; position++) { 1.223 + if (position > 0) { 1.224 + aResult.AppendLiteral(" "); 1.225 + } 1.226 + uint8_t component = aValue & MASK; 1.227 + switch (component) { 1.228 + case NS_STYLE_PAINT_ORDER_FILL: 1.229 + aResult.AppendLiteral("fill"); 1.230 + break; 1.231 + 1.232 + case NS_STYLE_PAINT_ORDER_STROKE: 1.233 + aResult.AppendLiteral("stroke"); 1.234 + break; 1.235 + 1.236 + case NS_STYLE_PAINT_ORDER_MARKERS: 1.237 + aResult.AppendLiteral("markers"); 1.238 + break; 1.239 + 1.240 + default: 1.241 + NS_NOTREACHED("unexpected paint-order component value"); 1.242 + } 1.243 + aValue >>= NS_STYLE_PAINT_ORDER_BITWIDTH; 1.244 + } 1.245 +} 1.246 + 1.247 +/* static */ void 1.248 +nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures, 1.249 + nsAString& aResult) 1.250 +{ 1.251 + for (uint32_t i = 0, numFeat = aFeatures.Length(); i < numFeat; i++) { 1.252 + const gfxFontFeature& feat = aFeatures[i]; 1.253 + 1.254 + if (i != 0) { 1.255 + aResult.AppendLiteral(", "); 1.256 + } 1.257 + 1.258 + // output tag 1.259 + char tag[7]; 1.260 + tag[0] = '"'; 1.261 + tag[1] = (feat.mTag >> 24) & 0xff; 1.262 + tag[2] = (feat.mTag >> 16) & 0xff; 1.263 + tag[3] = (feat.mTag >> 8) & 0xff; 1.264 + tag[4] = feat.mTag & 0xff; 1.265 + tag[5] = '"'; 1.266 + tag[6] = 0; 1.267 + aResult.AppendASCII(tag); 1.268 + 1.269 + // output value, if necessary 1.270 + if (feat.mValue == 0) { 1.271 + // 0 ==> off 1.272 + aResult.AppendLiteral(" off"); 1.273 + } else if (feat.mValue > 1) { 1.274 + aResult.AppendLiteral(" "); 1.275 + aResult.AppendInt(feat.mValue); 1.276 + } 1.277 + // else, omit value if 1, implied by default 1.278 + } 1.279 +} 1.280 + 1.281 +/* static */ void 1.282 +nsStyleUtil::AppendFontFeatureSettings(const nsCSSValue& aSrc, 1.283 + nsAString& aResult) 1.284 +{ 1.285 + nsCSSUnit unit = aSrc.GetUnit(); 1.286 + 1.287 + if (unit == eCSSUnit_Normal) { 1.288 + aResult.AppendLiteral("normal"); 1.289 + return; 1.290 + } 1.291 + 1.292 + NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep, 1.293 + "improper value unit for font-feature-settings:"); 1.294 + 1.295 + nsTArray<gfxFontFeature> featureSettings; 1.296 + nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings); 1.297 + AppendFontFeatureSettings(featureSettings, aResult); 1.298 +} 1.299 + 1.300 +/* static */ void 1.301 +nsStyleUtil::GetFunctionalAlternatesName(int32_t aFeature, 1.302 + nsAString& aFeatureName) 1.303 +{ 1.304 + aFeatureName.Truncate(); 1.305 + nsCSSKeyword key = 1.306 + nsCSSProps::ValueToKeywordEnum(aFeature, 1.307 + nsCSSProps::kFontVariantAlternatesFuncsKTable); 1.308 + 1.309 + NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "bad alternate feature type"); 1.310 + AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(key), aFeatureName); 1.311 +} 1.312 + 1.313 +/* static */ void 1.314 +nsStyleUtil::SerializeFunctionalAlternates( 1.315 + const nsTArray<gfxAlternateValue>& aAlternates, 1.316 + nsAString& aResult) 1.317 +{ 1.318 + nsAutoString funcName, funcParams; 1.319 + uint32_t numValues = aAlternates.Length(); 1.320 + 1.321 + uint32_t feature = 0; 1.322 + for (uint32_t i = 0; i < numValues; i++) { 1.323 + const gfxAlternateValue& v = aAlternates.ElementAt(i); 1.324 + if (feature != v.alternate) { 1.325 + feature = v.alternate; 1.326 + if (!funcName.IsEmpty() && !funcParams.IsEmpty()) { 1.327 + if (!aResult.IsEmpty()) { 1.328 + aResult.Append(char16_t(' ')); 1.329 + } 1.330 + 1.331 + // append the previous functional value 1.332 + aResult.Append(funcName); 1.333 + aResult.Append(char16_t('(')); 1.334 + aResult.Append(funcParams); 1.335 + aResult.Append(char16_t(')')); 1.336 + } 1.337 + 1.338 + // function name 1.339 + GetFunctionalAlternatesName(v.alternate, funcName); 1.340 + NS_ASSERTION(!funcName.IsEmpty(), "unknown property value name"); 1.341 + 1.342 + // function params 1.343 + funcParams.Truncate(); 1.344 + AppendEscapedCSSIdent(v.value, funcParams); 1.345 + } else { 1.346 + if (!funcParams.IsEmpty()) { 1.347 + funcParams.Append(NS_LITERAL_STRING(", ")); 1.348 + } 1.349 + AppendEscapedCSSIdent(v.value, funcParams); 1.350 + } 1.351 + } 1.352 + 1.353 + // append the previous functional value 1.354 + if (!funcName.IsEmpty() && !funcParams.IsEmpty()) { 1.355 + if (!aResult.IsEmpty()) { 1.356 + aResult.Append(char16_t(' ')); 1.357 + } 1.358 + 1.359 + aResult.Append(funcName); 1.360 + aResult.Append(char16_t('(')); 1.361 + aResult.Append(funcParams); 1.362 + aResult.Append(char16_t(')')); 1.363 + } 1.364 +} 1.365 + 1.366 +/* static */ void 1.367 +nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList, 1.368 + nsTArray<gfxAlternateValue>& aAlternateValues) 1.369 +{ 1.370 + gfxAlternateValue v; 1.371 + 1.372 + aAlternateValues.Clear(); 1.373 + for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) { 1.374 + // list contains function units 1.375 + if (curr->mValue.GetUnit() != eCSSUnit_Function) { 1.376 + continue; 1.377 + } 1.378 + 1.379 + // element 0 is the propval in ident form 1.380 + const nsCSSValue::Array *func = curr->mValue.GetArrayValue(); 1.381 + 1.382 + // lookup propval 1.383 + nsCSSKeyword key = func->Item(0).GetKeywordValue(); 1.384 + NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "unknown alternate property value"); 1.385 + 1.386 + int32_t alternate; 1.387 + if (key == eCSSKeyword_UNKNOWN || 1.388 + !nsCSSProps::FindKeyword(key, 1.389 + nsCSSProps::kFontVariantAlternatesFuncsKTable, 1.390 + alternate)) { 1.391 + NS_NOTREACHED("keyword not a font-variant-alternates value"); 1.392 + continue; 1.393 + } 1.394 + v.alternate = alternate; 1.395 + 1.396 + // other elements are the idents associated with the propval 1.397 + // append one alternate value for each one 1.398 + uint32_t numElems = func->Count(); 1.399 + for (uint32_t i = 1; i < numElems; i++) { 1.400 + const nsCSSValue& value = func->Item(i); 1.401 + NS_ASSERTION(value.GetUnit() == eCSSUnit_Ident, 1.402 + "weird unit found in variant alternate"); 1.403 + if (value.GetUnit() != eCSSUnit_Ident) { 1.404 + continue; 1.405 + } 1.406 + value.GetStringValue(v.value); 1.407 + aAlternateValues.AppendElement(v); 1.408 + } 1.409 + } 1.410 +} 1.411 + 1.412 +/* static */ float 1.413 +nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha) 1.414 +{ 1.415 + // Alpha values are expressed as decimals, so we should convert 1.416 + // back, using as few decimal places as possible for 1.417 + // round-tripping. 1.418 + // First try two decimal places: 1.419 + float rounded = NS_roundf(float(aAlpha) * 100.0f / 255.0f) / 100.0f; 1.420 + if (FloatToColorComponent(rounded) != aAlpha) { 1.421 + // Use three decimal places. 1.422 + rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f; 1.423 + } 1.424 + return rounded; 1.425 +} 1.426 + 1.427 +/* static */ bool 1.428 +nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant, 1.429 + bool aWhitespaceIsSignificant) 1.430 +{ 1.431 + NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant, 1.432 + "Nonsensical arguments"); 1.433 + 1.434 + bool isText = aChild->IsNodeOfType(nsINode::eTEXT); 1.435 + 1.436 + if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) && 1.437 + !aChild->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { 1.438 + return true; 1.439 + } 1.440 + 1.441 + return aTextIsSignificant && isText && aChild->TextLength() != 0 && 1.442 + (aWhitespaceIsSignificant || 1.443 + !aChild->TextIsOnlyWhitespace()); 1.444 +} 1.445 + 1.446 +/* static */ bool 1.447 +nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent, 1.448 + nsIPrincipal* aPrincipal, 1.449 + nsIURI* aSourceURI, 1.450 + uint32_t aLineNumber, 1.451 + const nsSubstring& aStyleText, 1.452 + nsresult* aRv) 1.453 +{ 1.454 + nsresult rv; 1.455 + 1.456 + if (aRv) { 1.457 + *aRv = NS_OK; 1.458 + } 1.459 + 1.460 + MOZ_ASSERT(!aContent || aContent->Tag() == nsGkAtoms::style, 1.461 + "aContent passed to CSPAllowsInlineStyle " 1.462 + "for an element that is not <style>"); 1.463 + 1.464 + nsCOMPtr<nsIContentSecurityPolicy> csp; 1.465 + rv = aPrincipal->GetCsp(getter_AddRefs(csp)); 1.466 + 1.467 + if (NS_FAILED(rv)) { 1.468 + if (aRv) 1.469 + *aRv = rv; 1.470 + return false; 1.471 + } 1.472 + 1.473 + if (!csp) { 1.474 + // No CSP --> the style is allowed 1.475 + return true; 1.476 + } 1.477 + 1.478 + // An inline style can be allowed because all inline styles are allowed, 1.479 + // or else because it is whitelisted by a nonce-source or hash-source. This 1.480 + // is a logical OR between whitelisting methods, so the allowInlineStyle 1.481 + // outparam can be reused for each check as long as we stop checking as soon 1.482 + // as it is set to true. This also optimizes performance by avoiding the 1.483 + // overhead of unnecessary checks. 1.484 + bool allowInlineStyle = true; 1.485 + nsAutoTArray<unsigned short, 3> violations; 1.486 + 1.487 + bool reportInlineViolation; 1.488 + rv = csp->GetAllowsInlineStyle(&reportInlineViolation, &allowInlineStyle); 1.489 + if (NS_FAILED(rv)) { 1.490 + if (aRv) 1.491 + *aRv = rv; 1.492 + return false; 1.493 + } 1.494 + if (reportInlineViolation) { 1.495 + violations.AppendElement(static_cast<unsigned short>( 1.496 + nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE)); 1.497 + } 1.498 + 1.499 + nsAutoString nonce; 1.500 + if (!allowInlineStyle) { 1.501 + // We can only find a nonce if aContent is provided 1.502 + bool foundNonce = !!aContent && 1.503 + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce); 1.504 + if (foundNonce) { 1.505 + bool reportNonceViolation; 1.506 + rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_STYLESHEET, 1.507 + &reportNonceViolation, &allowInlineStyle); 1.508 + if (NS_FAILED(rv)) { 1.509 + if (aRv) 1.510 + *aRv = rv; 1.511 + return false; 1.512 + } 1.513 + 1.514 + if (reportNonceViolation) { 1.515 + violations.AppendElement(static_cast<unsigned short>( 1.516 + nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_STYLE)); 1.517 + } 1.518 + } 1.519 + } 1.520 + 1.521 + if (!allowInlineStyle) { 1.522 + bool reportHashViolation; 1.523 + rv = csp->GetAllowsHash(aStyleText, nsIContentPolicy::TYPE_STYLESHEET, 1.524 + &reportHashViolation, &allowInlineStyle); 1.525 + if (NS_FAILED(rv)) { 1.526 + if (aRv) 1.527 + *aRv = rv; 1.528 + return false; 1.529 + } 1.530 + if (reportHashViolation) { 1.531 + violations.AppendElement(static_cast<unsigned short>( 1.532 + nsIContentSecurityPolicy::VIOLATION_TYPE_HASH_STYLE)); 1.533 + } 1.534 + } 1.535 + 1.536 + // What violation(s) should be reported? 1.537 + // 1.538 + // 1. If the style tag has a nonce attribute, and the nonce does not match 1.539 + // the policy, report VIOLATION_TYPE_NONCE_STYLE. 1.540 + // 2. If the policy has at least one hash-source, and the hashed contents of 1.541 + // the style tag did not match any of them, report VIOLATION_TYPE_HASH_STYLE 1.542 + // 3. Otherwise, report VIOLATION_TYPE_INLINE_STYLE if appropriate. 1.543 + // 1.544 + // 1 and 2 may occur together, 3 should only occur by itself. Naturally, 1.545 + // every VIOLATION_TYPE_NONCE_STYLE and VIOLATION_TYPE_HASH_STYLE are also 1.546 + // VIOLATION_TYPE_INLINE_STYLE, but reporting the 1.547 + // VIOLATION_TYPE_INLINE_STYLE is redundant and does not help the developer. 1.548 + if (!violations.IsEmpty()) { 1.549 + MOZ_ASSERT(violations[0] == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE, 1.550 + "How did we get any violations without an initial inline style violation?"); 1.551 + // This inline style is not allowed by CSP, so report the violation 1.552 + nsAutoCString asciiSpec; 1.553 + aSourceURI->GetAsciiSpec(asciiSpec); 1.554 + nsAutoString styleSample(aStyleText); 1.555 + 1.556 + // cap the length of the style sample at 40 chars. 1.557 + if (styleSample.Length() > 40) { 1.558 + styleSample.Truncate(40); 1.559 + styleSample.AppendLiteral("..."); 1.560 + } 1.561 + 1.562 + for (uint32_t i = 0; i < violations.Length(); i++) { 1.563 + // Skip reporting the redundant inline style violation if there are 1.564 + // other (nonce and/or hash violations) as well. 1.565 + if (i > 0 || violations.Length() == 1) { 1.566 + csp->LogViolationDetails(violations[i], NS_ConvertUTF8toUTF16(asciiSpec), 1.567 + styleSample, aLineNumber, nonce, aStyleText); 1.568 + } 1.569 + } 1.570 + } 1.571 + 1.572 + if (!allowInlineStyle) { 1.573 + NS_ASSERTION(!violations.IsEmpty(), 1.574 + "CSP blocked inline style but is not reporting a violation"); 1.575 + // The inline style should be blocked. 1.576 + return false; 1.577 + } 1.578 + // CSP allows inline styles. 1.579 + return true; 1.580 +}