layout/style/nsStyleUtil.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsStyleUtil.h"
michael@0 7 #include "nsStyleConsts.h"
michael@0 8
michael@0 9 #include "nsIContent.h"
michael@0 10 #include "nsCSSProps.h"
michael@0 11 #include "nsRuleNode.h"
michael@0 12 #include "nsROCSSPrimitiveValue.h"
michael@0 13 #include "nsIContentPolicy.h"
michael@0 14 #include "nsIContentSecurityPolicy.h"
michael@0 15 #include "nsIURI.h"
michael@0 16
michael@0 17 using namespace mozilla;
michael@0 18
michael@0 19 //------------------------------------------------------------------------------
michael@0 20 // Font Algorithm Code
michael@0 21 //------------------------------------------------------------------------------
michael@0 22
michael@0 23 // Compare two language strings
michael@0 24 bool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue,
michael@0 25 const nsAString& aSelectorValue,
michael@0 26 const nsStringComparator& aComparator)
michael@0 27 {
michael@0 28 bool result;
michael@0 29 uint32_t selectorLen = aSelectorValue.Length();
michael@0 30 uint32_t attributeLen = aAttributeValue.Length();
michael@0 31 if (selectorLen > attributeLen) {
michael@0 32 result = false;
michael@0 33 }
michael@0 34 else {
michael@0 35 nsAString::const_iterator iter;
michael@0 36 if (selectorLen != attributeLen &&
michael@0 37 *aAttributeValue.BeginReading(iter).advance(selectorLen) !=
michael@0 38 char16_t('-')) {
michael@0 39 // to match, the aAttributeValue must have a dash after the end of
michael@0 40 // the aSelectorValue's text (unless the aSelectorValue and the
michael@0 41 // aAttributeValue have the same text)
michael@0 42 result = false;
michael@0 43 }
michael@0 44 else {
michael@0 45 result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
michael@0 46 }
michael@0 47 }
michael@0 48 return result;
michael@0 49 }
michael@0 50
michael@0 51 void nsStyleUtil::AppendEscapedCSSString(const nsAString& aString,
michael@0 52 nsAString& aReturn,
michael@0 53 char16_t quoteChar)
michael@0 54 {
michael@0 55 NS_PRECONDITION(quoteChar == '\'' || quoteChar == '"',
michael@0 56 "CSS strings must be quoted with ' or \"");
michael@0 57 aReturn.Append(quoteChar);
michael@0 58
michael@0 59 const char16_t* in = aString.BeginReading();
michael@0 60 const char16_t* const end = aString.EndReading();
michael@0 61 for (; in != end; in++) {
michael@0 62 if (*in < 0x20 || (*in >= 0x7F && *in < 0xA0)) {
michael@0 63 // Escape U+0000 through U+001F and U+007F through U+009F numerically.
michael@0 64 aReturn.AppendPrintf("\\%hX ", *in);
michael@0 65 } else {
michael@0 66 if (*in == '"' || *in == '\'' || *in == '\\') {
michael@0 67 // Escape backslash and quote characters symbolically.
michael@0 68 // It's not technically necessary to escape the quote
michael@0 69 // character that isn't being used to delimit the string,
michael@0 70 // but we do it anyway because that makes testing simpler.
michael@0 71 aReturn.Append(char16_t('\\'));
michael@0 72 }
michael@0 73 aReturn.Append(*in);
michael@0 74 }
michael@0 75 }
michael@0 76
michael@0 77 aReturn.Append(quoteChar);
michael@0 78 }
michael@0 79
michael@0 80 /* static */ bool
michael@0 81 nsStyleUtil::AppendEscapedCSSIdent(const nsAString& aIdent, nsAString& aReturn)
michael@0 82 {
michael@0 83 // The relevant parts of the CSS grammar are:
michael@0 84 // ident [-]?{nmstart}{nmchar}*
michael@0 85 // nmstart [_a-z]|{nonascii}|{escape}
michael@0 86 // nmchar [_a-z0-9-]|{nonascii}|{escape}
michael@0 87 // nonascii [^\0-\177]
michael@0 88 // escape {unicode}|\\[^\n\r\f0-9a-f]
michael@0 89 // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
michael@0 90 // from http://www.w3.org/TR/CSS21/syndata.html#tokenization
michael@0 91
michael@0 92 const char16_t* in = aIdent.BeginReading();
michael@0 93 const char16_t* const end = aIdent.EndReading();
michael@0 94
michael@0 95 if (in == end)
michael@0 96 return true;
michael@0 97
michael@0 98 // A leading dash does not need to be escaped as long as it is not the
michael@0 99 // *only* character in the identifier.
michael@0 100 if (in + 1 != end && *in == '-') {
michael@0 101 aReturn.Append(char16_t('-'));
michael@0 102 ++in;
michael@0 103 }
michael@0 104
michael@0 105 // Escape a digit at the start (including after a dash),
michael@0 106 // numerically. If we didn't escape it numerically, it would get
michael@0 107 // interpreted as a numeric escape for the wrong character.
michael@0 108 // A second dash immediately after a leading dash must also be
michael@0 109 // escaped, but this may be done symbolically.
michael@0 110 if (in != end && (*in == '-' ||
michael@0 111 ('0' <= *in && *in <= '9'))) {
michael@0 112 if (*in == '-') {
michael@0 113 aReturn.Append(char16_t('\\'));
michael@0 114 aReturn.Append(char16_t('-'));
michael@0 115 } else {
michael@0 116 aReturn.AppendPrintf("\\%hX ", *in);
michael@0 117 }
michael@0 118 ++in;
michael@0 119 }
michael@0 120
michael@0 121 for (; in != end; ++in) {
michael@0 122 char16_t ch = *in;
michael@0 123 if (ch == 0x00) {
michael@0 124 return false;
michael@0 125 }
michael@0 126 if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) {
michael@0 127 // Escape U+0000 through U+001F and U+007F through U+009F numerically.
michael@0 128 aReturn.AppendPrintf("\\%hX ", *in);
michael@0 129 } else {
michael@0 130 // Escape ASCII non-identifier printables as a backslash plus
michael@0 131 // the character.
michael@0 132 if (ch < 0x7F &&
michael@0 133 ch != '_' && ch != '-' &&
michael@0 134 (ch < '0' || '9' < ch) &&
michael@0 135 (ch < 'A' || 'Z' < ch) &&
michael@0 136 (ch < 'a' || 'z' < ch)) {
michael@0 137 aReturn.Append(char16_t('\\'));
michael@0 138 }
michael@0 139 aReturn.Append(ch);
michael@0 140 }
michael@0 141 }
michael@0 142 return true;
michael@0 143 }
michael@0 144
michael@0 145 /* static */ void
michael@0 146 nsStyleUtil::AppendBitmaskCSSValue(nsCSSProperty aProperty,
michael@0 147 int32_t aMaskedValue,
michael@0 148 int32_t aFirstMask,
michael@0 149 int32_t aLastMask,
michael@0 150 nsAString& aResult)
michael@0 151 {
michael@0 152 for (int32_t mask = aFirstMask; mask <= aLastMask; mask <<= 1) {
michael@0 153 if (mask & aMaskedValue) {
michael@0 154 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask),
michael@0 155 aResult);
michael@0 156 aMaskedValue &= ~mask;
michael@0 157 if (aMaskedValue) { // more left
michael@0 158 aResult.Append(char16_t(' '));
michael@0 159 }
michael@0 160 }
michael@0 161 }
michael@0 162 NS_ABORT_IF_FALSE(aMaskedValue == 0, "unexpected bit remaining in bitfield");
michael@0 163 }
michael@0 164
michael@0 165 /* static */ void
michael@0 166 nsStyleUtil::AppendAngleValue(const nsStyleCoord& aAngle, nsAString& aResult)
michael@0 167 {
michael@0 168 MOZ_ASSERT(aAngle.IsAngleValue(), "Should have angle value");
michael@0 169
michael@0 170 // Append number.
michael@0 171 AppendCSSNumber(aAngle.GetAngleValue(), aResult);
michael@0 172
michael@0 173 // Append unit.
michael@0 174 switch (aAngle.GetUnit()) {
michael@0 175 case eStyleUnit_Degree: aResult.AppendLiteral("deg"); break;
michael@0 176 case eStyleUnit_Grad: aResult.AppendLiteral("grad"); break;
michael@0 177 case eStyleUnit_Radian: aResult.AppendLiteral("rad"); break;
michael@0 178 case eStyleUnit_Turn: aResult.AppendLiteral("turn"); break;
michael@0 179 default: NS_NOTREACHED("unrecognized angle unit");
michael@0 180 }
michael@0 181 }
michael@0 182
michael@0 183 /* static */ void
michael@0 184 nsStyleUtil::AppendPaintOrderValue(uint8_t aValue,
michael@0 185 nsAString& aResult)
michael@0 186 {
michael@0 187 static_assert
michael@0 188 (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
michael@0 189 "SVGStyleStruct::mPaintOrder and local variables not big enough");
michael@0 190
michael@0 191 if (aValue == NS_STYLE_PAINT_ORDER_NORMAL) {
michael@0 192 aResult.AppendLiteral("normal");
michael@0 193 return;
michael@0 194 }
michael@0 195
michael@0 196 // Append the minimal value necessary for the given paint order.
michael@0 197 static_assert(NS_STYLE_PAINT_ORDER_LAST_VALUE == 3,
michael@0 198 "paint-order values added; check serialization");
michael@0 199
michael@0 200 // The following relies on the default order being the order of the
michael@0 201 // constant values.
michael@0 202
michael@0 203 const uint8_t MASK = (1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1;
michael@0 204
michael@0 205 uint32_t lastPositionToSerialize = 0;
michael@0 206 for (uint32_t position = NS_STYLE_PAINT_ORDER_LAST_VALUE - 1;
michael@0 207 position > 0;
michael@0 208 position--) {
michael@0 209 uint8_t component =
michael@0 210 (aValue >> (position * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
michael@0 211 uint8_t earlierComponent =
michael@0 212 (aValue >> ((position - 1) * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
michael@0 213 if (component < earlierComponent) {
michael@0 214 lastPositionToSerialize = position - 1;
michael@0 215 break;
michael@0 216 }
michael@0 217 }
michael@0 218
michael@0 219 for (uint32_t position = 0; position <= lastPositionToSerialize; position++) {
michael@0 220 if (position > 0) {
michael@0 221 aResult.AppendLiteral(" ");
michael@0 222 }
michael@0 223 uint8_t component = aValue & MASK;
michael@0 224 switch (component) {
michael@0 225 case NS_STYLE_PAINT_ORDER_FILL:
michael@0 226 aResult.AppendLiteral("fill");
michael@0 227 break;
michael@0 228
michael@0 229 case NS_STYLE_PAINT_ORDER_STROKE:
michael@0 230 aResult.AppendLiteral("stroke");
michael@0 231 break;
michael@0 232
michael@0 233 case NS_STYLE_PAINT_ORDER_MARKERS:
michael@0 234 aResult.AppendLiteral("markers");
michael@0 235 break;
michael@0 236
michael@0 237 default:
michael@0 238 NS_NOTREACHED("unexpected paint-order component value");
michael@0 239 }
michael@0 240 aValue >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
michael@0 241 }
michael@0 242 }
michael@0 243
michael@0 244 /* static */ void
michael@0 245 nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures,
michael@0 246 nsAString& aResult)
michael@0 247 {
michael@0 248 for (uint32_t i = 0, numFeat = aFeatures.Length(); i < numFeat; i++) {
michael@0 249 const gfxFontFeature& feat = aFeatures[i];
michael@0 250
michael@0 251 if (i != 0) {
michael@0 252 aResult.AppendLiteral(", ");
michael@0 253 }
michael@0 254
michael@0 255 // output tag
michael@0 256 char tag[7];
michael@0 257 tag[0] = '"';
michael@0 258 tag[1] = (feat.mTag >> 24) & 0xff;
michael@0 259 tag[2] = (feat.mTag >> 16) & 0xff;
michael@0 260 tag[3] = (feat.mTag >> 8) & 0xff;
michael@0 261 tag[4] = feat.mTag & 0xff;
michael@0 262 tag[5] = '"';
michael@0 263 tag[6] = 0;
michael@0 264 aResult.AppendASCII(tag);
michael@0 265
michael@0 266 // output value, if necessary
michael@0 267 if (feat.mValue == 0) {
michael@0 268 // 0 ==> off
michael@0 269 aResult.AppendLiteral(" off");
michael@0 270 } else if (feat.mValue > 1) {
michael@0 271 aResult.AppendLiteral(" ");
michael@0 272 aResult.AppendInt(feat.mValue);
michael@0 273 }
michael@0 274 // else, omit value if 1, implied by default
michael@0 275 }
michael@0 276 }
michael@0 277
michael@0 278 /* static */ void
michael@0 279 nsStyleUtil::AppendFontFeatureSettings(const nsCSSValue& aSrc,
michael@0 280 nsAString& aResult)
michael@0 281 {
michael@0 282 nsCSSUnit unit = aSrc.GetUnit();
michael@0 283
michael@0 284 if (unit == eCSSUnit_Normal) {
michael@0 285 aResult.AppendLiteral("normal");
michael@0 286 return;
michael@0 287 }
michael@0 288
michael@0 289 NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep,
michael@0 290 "improper value unit for font-feature-settings:");
michael@0 291
michael@0 292 nsTArray<gfxFontFeature> featureSettings;
michael@0 293 nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings);
michael@0 294 AppendFontFeatureSettings(featureSettings, aResult);
michael@0 295 }
michael@0 296
michael@0 297 /* static */ void
michael@0 298 nsStyleUtil::GetFunctionalAlternatesName(int32_t aFeature,
michael@0 299 nsAString& aFeatureName)
michael@0 300 {
michael@0 301 aFeatureName.Truncate();
michael@0 302 nsCSSKeyword key =
michael@0 303 nsCSSProps::ValueToKeywordEnum(aFeature,
michael@0 304 nsCSSProps::kFontVariantAlternatesFuncsKTable);
michael@0 305
michael@0 306 NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "bad alternate feature type");
michael@0 307 AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(key), aFeatureName);
michael@0 308 }
michael@0 309
michael@0 310 /* static */ void
michael@0 311 nsStyleUtil::SerializeFunctionalAlternates(
michael@0 312 const nsTArray<gfxAlternateValue>& aAlternates,
michael@0 313 nsAString& aResult)
michael@0 314 {
michael@0 315 nsAutoString funcName, funcParams;
michael@0 316 uint32_t numValues = aAlternates.Length();
michael@0 317
michael@0 318 uint32_t feature = 0;
michael@0 319 for (uint32_t i = 0; i < numValues; i++) {
michael@0 320 const gfxAlternateValue& v = aAlternates.ElementAt(i);
michael@0 321 if (feature != v.alternate) {
michael@0 322 feature = v.alternate;
michael@0 323 if (!funcName.IsEmpty() && !funcParams.IsEmpty()) {
michael@0 324 if (!aResult.IsEmpty()) {
michael@0 325 aResult.Append(char16_t(' '));
michael@0 326 }
michael@0 327
michael@0 328 // append the previous functional value
michael@0 329 aResult.Append(funcName);
michael@0 330 aResult.Append(char16_t('('));
michael@0 331 aResult.Append(funcParams);
michael@0 332 aResult.Append(char16_t(')'));
michael@0 333 }
michael@0 334
michael@0 335 // function name
michael@0 336 GetFunctionalAlternatesName(v.alternate, funcName);
michael@0 337 NS_ASSERTION(!funcName.IsEmpty(), "unknown property value name");
michael@0 338
michael@0 339 // function params
michael@0 340 funcParams.Truncate();
michael@0 341 AppendEscapedCSSIdent(v.value, funcParams);
michael@0 342 } else {
michael@0 343 if (!funcParams.IsEmpty()) {
michael@0 344 funcParams.Append(NS_LITERAL_STRING(", "));
michael@0 345 }
michael@0 346 AppendEscapedCSSIdent(v.value, funcParams);
michael@0 347 }
michael@0 348 }
michael@0 349
michael@0 350 // append the previous functional value
michael@0 351 if (!funcName.IsEmpty() && !funcParams.IsEmpty()) {
michael@0 352 if (!aResult.IsEmpty()) {
michael@0 353 aResult.Append(char16_t(' '));
michael@0 354 }
michael@0 355
michael@0 356 aResult.Append(funcName);
michael@0 357 aResult.Append(char16_t('('));
michael@0 358 aResult.Append(funcParams);
michael@0 359 aResult.Append(char16_t(')'));
michael@0 360 }
michael@0 361 }
michael@0 362
michael@0 363 /* static */ void
michael@0 364 nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList,
michael@0 365 nsTArray<gfxAlternateValue>& aAlternateValues)
michael@0 366 {
michael@0 367 gfxAlternateValue v;
michael@0 368
michael@0 369 aAlternateValues.Clear();
michael@0 370 for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) {
michael@0 371 // list contains function units
michael@0 372 if (curr->mValue.GetUnit() != eCSSUnit_Function) {
michael@0 373 continue;
michael@0 374 }
michael@0 375
michael@0 376 // element 0 is the propval in ident form
michael@0 377 const nsCSSValue::Array *func = curr->mValue.GetArrayValue();
michael@0 378
michael@0 379 // lookup propval
michael@0 380 nsCSSKeyword key = func->Item(0).GetKeywordValue();
michael@0 381 NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "unknown alternate property value");
michael@0 382
michael@0 383 int32_t alternate;
michael@0 384 if (key == eCSSKeyword_UNKNOWN ||
michael@0 385 !nsCSSProps::FindKeyword(key,
michael@0 386 nsCSSProps::kFontVariantAlternatesFuncsKTable,
michael@0 387 alternate)) {
michael@0 388 NS_NOTREACHED("keyword not a font-variant-alternates value");
michael@0 389 continue;
michael@0 390 }
michael@0 391 v.alternate = alternate;
michael@0 392
michael@0 393 // other elements are the idents associated with the propval
michael@0 394 // append one alternate value for each one
michael@0 395 uint32_t numElems = func->Count();
michael@0 396 for (uint32_t i = 1; i < numElems; i++) {
michael@0 397 const nsCSSValue& value = func->Item(i);
michael@0 398 NS_ASSERTION(value.GetUnit() == eCSSUnit_Ident,
michael@0 399 "weird unit found in variant alternate");
michael@0 400 if (value.GetUnit() != eCSSUnit_Ident) {
michael@0 401 continue;
michael@0 402 }
michael@0 403 value.GetStringValue(v.value);
michael@0 404 aAlternateValues.AppendElement(v);
michael@0 405 }
michael@0 406 }
michael@0 407 }
michael@0 408
michael@0 409 /* static */ float
michael@0 410 nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
michael@0 411 {
michael@0 412 // Alpha values are expressed as decimals, so we should convert
michael@0 413 // back, using as few decimal places as possible for
michael@0 414 // round-tripping.
michael@0 415 // First try two decimal places:
michael@0 416 float rounded = NS_roundf(float(aAlpha) * 100.0f / 255.0f) / 100.0f;
michael@0 417 if (FloatToColorComponent(rounded) != aAlpha) {
michael@0 418 // Use three decimal places.
michael@0 419 rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f;
michael@0 420 }
michael@0 421 return rounded;
michael@0 422 }
michael@0 423
michael@0 424 /* static */ bool
michael@0 425 nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
michael@0 426 bool aWhitespaceIsSignificant)
michael@0 427 {
michael@0 428 NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant,
michael@0 429 "Nonsensical arguments");
michael@0 430
michael@0 431 bool isText = aChild->IsNodeOfType(nsINode::eTEXT);
michael@0 432
michael@0 433 if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) &&
michael@0 434 !aChild->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
michael@0 435 return true;
michael@0 436 }
michael@0 437
michael@0 438 return aTextIsSignificant && isText && aChild->TextLength() != 0 &&
michael@0 439 (aWhitespaceIsSignificant ||
michael@0 440 !aChild->TextIsOnlyWhitespace());
michael@0 441 }
michael@0 442
michael@0 443 /* static */ bool
michael@0 444 nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent,
michael@0 445 nsIPrincipal* aPrincipal,
michael@0 446 nsIURI* aSourceURI,
michael@0 447 uint32_t aLineNumber,
michael@0 448 const nsSubstring& aStyleText,
michael@0 449 nsresult* aRv)
michael@0 450 {
michael@0 451 nsresult rv;
michael@0 452
michael@0 453 if (aRv) {
michael@0 454 *aRv = NS_OK;
michael@0 455 }
michael@0 456
michael@0 457 MOZ_ASSERT(!aContent || aContent->Tag() == nsGkAtoms::style,
michael@0 458 "aContent passed to CSPAllowsInlineStyle "
michael@0 459 "for an element that is not <style>");
michael@0 460
michael@0 461 nsCOMPtr<nsIContentSecurityPolicy> csp;
michael@0 462 rv = aPrincipal->GetCsp(getter_AddRefs(csp));
michael@0 463
michael@0 464 if (NS_FAILED(rv)) {
michael@0 465 if (aRv)
michael@0 466 *aRv = rv;
michael@0 467 return false;
michael@0 468 }
michael@0 469
michael@0 470 if (!csp) {
michael@0 471 // No CSP --> the style is allowed
michael@0 472 return true;
michael@0 473 }
michael@0 474
michael@0 475 // An inline style can be allowed because all inline styles are allowed,
michael@0 476 // or else because it is whitelisted by a nonce-source or hash-source. This
michael@0 477 // is a logical OR between whitelisting methods, so the allowInlineStyle
michael@0 478 // outparam can be reused for each check as long as we stop checking as soon
michael@0 479 // as it is set to true. This also optimizes performance by avoiding the
michael@0 480 // overhead of unnecessary checks.
michael@0 481 bool allowInlineStyle = true;
michael@0 482 nsAutoTArray<unsigned short, 3> violations;
michael@0 483
michael@0 484 bool reportInlineViolation;
michael@0 485 rv = csp->GetAllowsInlineStyle(&reportInlineViolation, &allowInlineStyle);
michael@0 486 if (NS_FAILED(rv)) {
michael@0 487 if (aRv)
michael@0 488 *aRv = rv;
michael@0 489 return false;
michael@0 490 }
michael@0 491 if (reportInlineViolation) {
michael@0 492 violations.AppendElement(static_cast<unsigned short>(
michael@0 493 nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE));
michael@0 494 }
michael@0 495
michael@0 496 nsAutoString nonce;
michael@0 497 if (!allowInlineStyle) {
michael@0 498 // We can only find a nonce if aContent is provided
michael@0 499 bool foundNonce = !!aContent &&
michael@0 500 aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce);
michael@0 501 if (foundNonce) {
michael@0 502 bool reportNonceViolation;
michael@0 503 rv = csp->GetAllowsNonce(nonce, nsIContentPolicy::TYPE_STYLESHEET,
michael@0 504 &reportNonceViolation, &allowInlineStyle);
michael@0 505 if (NS_FAILED(rv)) {
michael@0 506 if (aRv)
michael@0 507 *aRv = rv;
michael@0 508 return false;
michael@0 509 }
michael@0 510
michael@0 511 if (reportNonceViolation) {
michael@0 512 violations.AppendElement(static_cast<unsigned short>(
michael@0 513 nsIContentSecurityPolicy::VIOLATION_TYPE_NONCE_STYLE));
michael@0 514 }
michael@0 515 }
michael@0 516 }
michael@0 517
michael@0 518 if (!allowInlineStyle) {
michael@0 519 bool reportHashViolation;
michael@0 520 rv = csp->GetAllowsHash(aStyleText, nsIContentPolicy::TYPE_STYLESHEET,
michael@0 521 &reportHashViolation, &allowInlineStyle);
michael@0 522 if (NS_FAILED(rv)) {
michael@0 523 if (aRv)
michael@0 524 *aRv = rv;
michael@0 525 return false;
michael@0 526 }
michael@0 527 if (reportHashViolation) {
michael@0 528 violations.AppendElement(static_cast<unsigned short>(
michael@0 529 nsIContentSecurityPolicy::VIOLATION_TYPE_HASH_STYLE));
michael@0 530 }
michael@0 531 }
michael@0 532
michael@0 533 // What violation(s) should be reported?
michael@0 534 //
michael@0 535 // 1. If the style tag has a nonce attribute, and the nonce does not match
michael@0 536 // the policy, report VIOLATION_TYPE_NONCE_STYLE.
michael@0 537 // 2. If the policy has at least one hash-source, and the hashed contents of
michael@0 538 // the style tag did not match any of them, report VIOLATION_TYPE_HASH_STYLE
michael@0 539 // 3. Otherwise, report VIOLATION_TYPE_INLINE_STYLE if appropriate.
michael@0 540 //
michael@0 541 // 1 and 2 may occur together, 3 should only occur by itself. Naturally,
michael@0 542 // every VIOLATION_TYPE_NONCE_STYLE and VIOLATION_TYPE_HASH_STYLE are also
michael@0 543 // VIOLATION_TYPE_INLINE_STYLE, but reporting the
michael@0 544 // VIOLATION_TYPE_INLINE_STYLE is redundant and does not help the developer.
michael@0 545 if (!violations.IsEmpty()) {
michael@0 546 MOZ_ASSERT(violations[0] == nsIContentSecurityPolicy::VIOLATION_TYPE_INLINE_STYLE,
michael@0 547 "How did we get any violations without an initial inline style violation?");
michael@0 548 // This inline style is not allowed by CSP, so report the violation
michael@0 549 nsAutoCString asciiSpec;
michael@0 550 aSourceURI->GetAsciiSpec(asciiSpec);
michael@0 551 nsAutoString styleSample(aStyleText);
michael@0 552
michael@0 553 // cap the length of the style sample at 40 chars.
michael@0 554 if (styleSample.Length() > 40) {
michael@0 555 styleSample.Truncate(40);
michael@0 556 styleSample.AppendLiteral("...");
michael@0 557 }
michael@0 558
michael@0 559 for (uint32_t i = 0; i < violations.Length(); i++) {
michael@0 560 // Skip reporting the redundant inline style violation if there are
michael@0 561 // other (nonce and/or hash violations) as well.
michael@0 562 if (i > 0 || violations.Length() == 1) {
michael@0 563 csp->LogViolationDetails(violations[i], NS_ConvertUTF8toUTF16(asciiSpec),
michael@0 564 styleSample, aLineNumber, nonce, aStyleText);
michael@0 565 }
michael@0 566 }
michael@0 567 }
michael@0 568
michael@0 569 if (!allowInlineStyle) {
michael@0 570 NS_ASSERTION(!violations.IsEmpty(),
michael@0 571 "CSP blocked inline style but is not reporting a violation");
michael@0 572 // The inline style should be blocked.
michael@0 573 return false;
michael@0 574 }
michael@0 575 // CSP allows inline styles.
michael@0 576 return true;
michael@0 577 }

mercurial