layout/style/nsStyleUtil.cpp

changeset 0
6474c204b198
     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 +}

mercurial