diff options
Diffstat (limited to 'layout/style/nsStyleUtil.cpp')
-rw-r--r-- | layout/style/nsStyleUtil.cpp | 783 |
1 files changed, 783 insertions, 0 deletions
diff --git a/layout/style/nsStyleUtil.cpp b/layout/style/nsStyleUtil.cpp new file mode 100644 index 000000000..840cd03c3 --- /dev/null +++ b/layout/style/nsStyleUtil.cpp @@ -0,0 +1,783 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsStyleUtil.h" +#include "nsStyleConsts.h" + +#include "nsIContent.h" +#include "nsCSSProps.h" +#include "nsRuleNode.h" +#include "nsROCSSPrimitiveValue.h" +#include "nsStyleStruct.h" +#include "nsIContentPolicy.h" +#include "nsIContentSecurityPolicy.h" +#include "nsIURI.h" +#include "nsPrintfCString.h" + +using namespace mozilla; + +//------------------------------------------------------------------------------ +// Font Algorithm Code +//------------------------------------------------------------------------------ + +// Compare two language strings +bool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue, + const nsAString& aSelectorValue, + const nsStringComparator& aComparator) +{ + bool result; + uint32_t selectorLen = aSelectorValue.Length(); + uint32_t attributeLen = aAttributeValue.Length(); + if (selectorLen > attributeLen) { + result = false; + } + else { + nsAString::const_iterator iter; + if (selectorLen != attributeLen && + *aAttributeValue.BeginReading(iter).advance(selectorLen) != + char16_t('-')) { + // to match, the aAttributeValue must have a dash after the end of + // the aSelectorValue's text (unless the aSelectorValue and the + // aAttributeValue have the same text) + result = false; + } + else { + result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator); + } + } + return result; +} + +bool +nsStyleUtil::ValueIncludes(const nsSubstring& aValueList, + const nsSubstring& aValue, + const nsStringComparator& aComparator) +{ + const char16_t *p = aValueList.BeginReading(), + *p_end = aValueList.EndReading(); + + while (p < p_end) { + // skip leading space + while (p != p_end && nsContentUtils::IsHTMLWhitespace(*p)) + ++p; + + const char16_t *val_start = p; + + // look for space or end + while (p != p_end && !nsContentUtils::IsHTMLWhitespace(*p)) + ++p; + + const char16_t *val_end = p; + + if (val_start < val_end && + aValue.Equals(Substring(val_start, val_end), aComparator)) + return true; + + ++p; // we know the next character is not whitespace + } + return false; +} + +void nsStyleUtil::AppendEscapedCSSString(const nsAString& aString, + nsAString& aReturn, + char16_t quoteChar) +{ + NS_PRECONDITION(quoteChar == '\'' || quoteChar == '"', + "CSS strings must be quoted with ' or \""); + aReturn.Append(quoteChar); + + const char16_t* in = aString.BeginReading(); + const char16_t* const end = aString.EndReading(); + for (; in != end; in++) { + if (*in < 0x20 || (*in >= 0x7F && *in < 0xA0)) { + // Escape U+0000 through U+001F and U+007F through U+009F numerically. + aReturn.AppendPrintf("\\%hx ", *in); + } else { + if (*in == '"' || *in == '\'' || *in == '\\') { + // Escape backslash and quote characters symbolically. + // It's not technically necessary to escape the quote + // character that isn't being used to delimit the string, + // but we do it anyway because that makes testing simpler. + aReturn.Append(char16_t('\\')); + } + aReturn.Append(*in); + } + } + + aReturn.Append(quoteChar); +} + +/* static */ void +nsStyleUtil::AppendEscapedCSSIdent(const nsAString& aIdent, nsAString& aReturn) +{ + // The relevant parts of the CSS grammar are: + // ident ([-]?{nmstart}|[-][-]){nmchar}* + // nmstart [_a-z]|{nonascii}|{escape} + // nmchar [_a-z0-9-]|{nonascii}|{escape} + // nonascii [^\0-\177] + // escape {unicode}|\\[^\n\r\f0-9a-f] + // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])? + // from http://www.w3.org/TR/CSS21/syndata.html#tokenization but + // modified for idents by + // http://dev.w3.org/csswg/cssom/#serialize-an-identifier and + // http://dev.w3.org/csswg/css-syntax/#would-start-an-identifier + + const char16_t* in = aIdent.BeginReading(); + const char16_t* const end = aIdent.EndReading(); + + if (in == end) + return; + + // A leading dash does not need to be escaped as long as it is not the + // *only* character in the identifier. + if (*in == '-') { + if (in + 1 == end) { + aReturn.Append(char16_t('\\')); + aReturn.Append(char16_t('-')); + return; + } + + aReturn.Append(char16_t('-')); + ++in; + } + + // Escape a digit at the start (including after a dash), + // numerically. If we didn't escape it numerically, it would get + // interpreted as a numeric escape for the wrong character. + if (in != end && ('0' <= *in && *in <= '9')) { + aReturn.AppendPrintf("\\%hx ", *in); + ++in; + } + + for (; in != end; ++in) { + char16_t ch = *in; + if (ch == 0x00) { + aReturn.Append(char16_t(0xFFFD)); + } else if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) { + // Escape U+0000 through U+001F and U+007F through U+009F numerically. + aReturn.AppendPrintf("\\%hx ", *in); + } else { + // Escape ASCII non-identifier printables as a backslash plus + // the character. + if (ch < 0x7F && + ch != '_' && ch != '-' && + (ch < '0' || '9' < ch) && + (ch < 'A' || 'Z' < ch) && + (ch < 'a' || 'z' < ch)) { + aReturn.Append(char16_t('\\')); + } + aReturn.Append(ch); + } + } +} + +// unquoted family names must be a sequence of idents +// so escape any parts that require escaping +static void +AppendUnquotedFamilyName(const nsAString& aFamilyName, nsAString& aResult) +{ + const char16_t *p, *p_end; + aFamilyName.BeginReading(p); + aFamilyName.EndReading(p_end); + + bool moreThanOne = false; + while (p < p_end) { + const char16_t* identStart = p; + while (++p != p_end && *p != ' ') + /* nothing */ ; + + nsDependentSubstring ident(identStart, p); + if (!ident.IsEmpty()) { + if (moreThanOne) { + aResult.Append(' '); + } + nsStyleUtil::AppendEscapedCSSIdent(ident, aResult); + moreThanOne = true; + } + + ++p; + } +} + +/* static */ void +nsStyleUtil::AppendEscapedCSSFontFamilyList( + const mozilla::FontFamilyList& aFamilyList, + nsAString& aResult) +{ + const nsTArray<FontFamilyName>& fontlist = aFamilyList.GetFontlist(); + size_t i, len = fontlist.Length(); + for (i = 0; i < len; i++) { + if (i != 0) { + aResult.Append(','); + } + const FontFamilyName& name = fontlist[i]; + switch (name.mType) { + case eFamily_named: + AppendUnquotedFamilyName(name.mName, aResult); + break; + case eFamily_named_quoted: + AppendEscapedCSSString(name.mName, aResult); + break; + default: + name.AppendToString(aResult); + } + } +} + + +/* static */ void +nsStyleUtil::AppendBitmaskCSSValue(nsCSSPropertyID aProperty, + int32_t aMaskedValue, + int32_t aFirstMask, + int32_t aLastMask, + nsAString& aResult) +{ + for (int32_t mask = aFirstMask; mask <= aLastMask; mask <<= 1) { + if (mask & aMaskedValue) { + AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask), + aResult); + aMaskedValue &= ~mask; + if (aMaskedValue) { // more left + aResult.Append(char16_t(' ')); + } + } + } + MOZ_ASSERT(aMaskedValue == 0, "unexpected bit remaining in bitfield"); +} + +/* static */ void +nsStyleUtil::AppendAngleValue(const nsStyleCoord& aAngle, nsAString& aResult) +{ + MOZ_ASSERT(aAngle.IsAngleValue(), "Should have angle value"); + + // Append number. + AppendCSSNumber(aAngle.GetAngleValue(), aResult); + + // Append unit. + switch (aAngle.GetUnit()) { + case eStyleUnit_Degree: aResult.AppendLiteral("deg"); break; + case eStyleUnit_Grad: aResult.AppendLiteral("grad"); break; + case eStyleUnit_Radian: aResult.AppendLiteral("rad"); break; + case eStyleUnit_Turn: aResult.AppendLiteral("turn"); break; + default: NS_NOTREACHED("unrecognized angle unit"); + } +} + +/* static */ void +nsStyleUtil::AppendPaintOrderValue(uint8_t aValue, + nsAString& aResult) +{ + static_assert + (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8, + "SVGStyleStruct::mPaintOrder and local variables not big enough"); + + if (aValue == NS_STYLE_PAINT_ORDER_NORMAL) { + aResult.AppendLiteral("normal"); + return; + } + + // Append the minimal value necessary for the given paint order. + static_assert(NS_STYLE_PAINT_ORDER_LAST_VALUE == 3, + "paint-order values added; check serialization"); + + // The following relies on the default order being the order of the + // constant values. + + const uint8_t MASK = (1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1; + + uint32_t lastPositionToSerialize = 0; + for (uint32_t position = NS_STYLE_PAINT_ORDER_LAST_VALUE - 1; + position > 0; + position--) { + uint8_t component = + (aValue >> (position * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK; + uint8_t earlierComponent = + (aValue >> ((position - 1) * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK; + if (component < earlierComponent) { + lastPositionToSerialize = position - 1; + break; + } + } + + for (uint32_t position = 0; position <= lastPositionToSerialize; position++) { + if (position > 0) { + aResult.Append(' '); + } + uint8_t component = aValue & MASK; + switch (component) { + case NS_STYLE_PAINT_ORDER_FILL: + aResult.AppendLiteral("fill"); + break; + + case NS_STYLE_PAINT_ORDER_STROKE: + aResult.AppendLiteral("stroke"); + break; + + case NS_STYLE_PAINT_ORDER_MARKERS: + aResult.AppendLiteral("markers"); + break; + + default: + NS_NOTREACHED("unexpected paint-order component value"); + } + aValue >>= NS_STYLE_PAINT_ORDER_BITWIDTH; + } +} + +/* static */ void +nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures, + nsAString& aResult) +{ + for (uint32_t i = 0, numFeat = aFeatures.Length(); i < numFeat; i++) { + const gfxFontFeature& feat = aFeatures[i]; + + if (i != 0) { + aResult.AppendLiteral(", "); + } + + // output tag + char tag[7]; + tag[0] = '"'; + tag[1] = (feat.mTag >> 24) & 0xff; + tag[2] = (feat.mTag >> 16) & 0xff; + tag[3] = (feat.mTag >> 8) & 0xff; + tag[4] = feat.mTag & 0xff; + tag[5] = '"'; + tag[6] = 0; + aResult.AppendASCII(tag); + + // output value, if necessary + if (feat.mValue == 0) { + // 0 ==> off + aResult.AppendLiteral(" off"); + } else if (feat.mValue > 1) { + aResult.Append(' '); + aResult.AppendInt(feat.mValue); + } + // else, omit value if 1, implied by default + } +} + +/* static */ void +nsStyleUtil::AppendFontFeatureSettings(const nsCSSValue& aSrc, + nsAString& aResult) +{ + nsCSSUnit unit = aSrc.GetUnit(); + + if (unit == eCSSUnit_Normal) { + aResult.AppendLiteral("normal"); + return; + } + + NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep, + "improper value unit for font-feature-settings:"); + + nsTArray<gfxFontFeature> featureSettings; + nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings); + AppendFontFeatureSettings(featureSettings, aResult); +} + +/* static */ void +nsStyleUtil::GetFunctionalAlternatesName(int32_t aFeature, + nsAString& aFeatureName) +{ + aFeatureName.Truncate(); + nsCSSKeyword key = + nsCSSProps::ValueToKeywordEnum(aFeature, + nsCSSProps::kFontVariantAlternatesFuncsKTable); + + NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "bad alternate feature type"); + AppendUTF8toUTF16(nsCSSKeywords::GetStringValue(key), aFeatureName); +} + +/* static */ void +nsStyleUtil::SerializeFunctionalAlternates( + const nsTArray<gfxAlternateValue>& aAlternates, + nsAString& aResult) +{ + nsAutoString funcName, funcParams; + uint32_t numValues = aAlternates.Length(); + + uint32_t feature = 0; + for (uint32_t i = 0; i < numValues; i++) { + const gfxAlternateValue& v = aAlternates.ElementAt(i); + if (feature != v.alternate) { + feature = v.alternate; + if (!funcName.IsEmpty() && !funcParams.IsEmpty()) { + if (!aResult.IsEmpty()) { + aResult.Append(char16_t(' ')); + } + + // append the previous functional value + aResult.Append(funcName); + aResult.Append(char16_t('(')); + aResult.Append(funcParams); + aResult.Append(char16_t(')')); + } + + // function name + GetFunctionalAlternatesName(v.alternate, funcName); + NS_ASSERTION(!funcName.IsEmpty(), "unknown property value name"); + + // function params + funcParams.Truncate(); + AppendEscapedCSSIdent(v.value, funcParams); + } else { + if (!funcParams.IsEmpty()) { + funcParams.AppendLiteral(", "); + } + AppendEscapedCSSIdent(v.value, funcParams); + } + } + + // append the previous functional value + if (!funcName.IsEmpty() && !funcParams.IsEmpty()) { + if (!aResult.IsEmpty()) { + aResult.Append(char16_t(' ')); + } + + aResult.Append(funcName); + aResult.Append(char16_t('(')); + aResult.Append(funcParams); + aResult.Append(char16_t(')')); + } +} + +/* static */ void +nsStyleUtil::ComputeFunctionalAlternates(const nsCSSValueList* aList, + nsTArray<gfxAlternateValue>& aAlternateValues) +{ + gfxAlternateValue v; + + aAlternateValues.Clear(); + for (const nsCSSValueList* curr = aList; curr != nullptr; curr = curr->mNext) { + // list contains function units + if (curr->mValue.GetUnit() != eCSSUnit_Function) { + continue; + } + + // element 0 is the propval in ident form + const nsCSSValue::Array *func = curr->mValue.GetArrayValue(); + + // lookup propval + nsCSSKeyword key = func->Item(0).GetKeywordValue(); + NS_ASSERTION(key != eCSSKeyword_UNKNOWN, "unknown alternate property value"); + + int32_t alternate; + if (key == eCSSKeyword_UNKNOWN || + !nsCSSProps::FindKeyword(key, + nsCSSProps::kFontVariantAlternatesFuncsKTable, + alternate)) { + NS_NOTREACHED("keyword not a font-variant-alternates value"); + continue; + } + v.alternate = alternate; + + // other elements are the idents associated with the propval + // append one alternate value for each one + uint32_t numElems = func->Count(); + for (uint32_t i = 1; i < numElems; i++) { + const nsCSSValue& value = func->Item(i); + NS_ASSERTION(value.GetUnit() == eCSSUnit_Ident, + "weird unit found in variant alternate"); + if (value.GetUnit() != eCSSUnit_Ident) { + continue; + } + value.GetStringValue(v.value); + aAlternateValues.AppendElement(v); + } + } +} + +static void +AppendSerializedUnicodePoint(uint32_t aCode, nsACString& aBuf) +{ + aBuf.Append(nsPrintfCString("%0X", aCode)); +} + +// A unicode-range: descriptor is represented as an array of integers, +// to be interpreted as a sequence of pairs: min max min max ... +// It is in source order. (Possibly it should be sorted and overlaps +// consolidated, but right now we don't do that.) +/* static */ void +nsStyleUtil::AppendUnicodeRange(const nsCSSValue& aValue, nsAString& aResult) +{ + NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Null || + aValue.GetUnit() == eCSSUnit_Array, + "improper value unit for unicode-range:"); + aResult.Truncate(); + if (aValue.GetUnit() != eCSSUnit_Array) + return; + + nsCSSValue::Array const & sources = *aValue.GetArrayValue(); + nsAutoCString buf; + + MOZ_ASSERT(sources.Count() % 2 == 0, + "odd number of entries in a unicode-range: array"); + + for (uint32_t i = 0; i < sources.Count(); i += 2) { + uint32_t min = sources[i].GetIntValue(); + uint32_t max = sources[i+1].GetIntValue(); + + // We don't try to replicate the U+XX?? notation. + buf.AppendLiteral("U+"); + AppendSerializedUnicodePoint(min, buf); + + if (min != max) { + buf.Append('-'); + AppendSerializedUnicodePoint(max, buf); + } + buf.AppendLiteral(", "); + } + buf.Truncate(buf.Length() - 2); // remove the last comma-space + CopyASCIItoUTF16(buf, aResult); +} + +/* static */ void +nsStyleUtil::AppendSerializedFontSrc(const nsCSSValue& aValue, + nsAString& aResult) +{ + // A src: descriptor is represented as an array value; each entry in + // the array can be eCSSUnit_URL, eCSSUnit_Local_Font, or + // eCSSUnit_Font_Format. Blocks of eCSSUnit_Font_Format may appear + // only after one of the first two. (css3-fonts only contemplates + // annotating URLs with formats, but we handle the general case.) + + NS_PRECONDITION(aValue.GetUnit() == eCSSUnit_Array, + "improper value unit for src:"); + + const nsCSSValue::Array& sources = *aValue.GetArrayValue(); + size_t i = 0; + + while (i < sources.Count()) { + nsAutoString formats; + + if (sources[i].GetUnit() == eCSSUnit_URL) { + aResult.AppendLiteral("url("); + nsDependentString url(sources[i].GetOriginalURLValue()); + nsStyleUtil::AppendEscapedCSSString(url, aResult); + aResult.Append(')'); + } else if (sources[i].GetUnit() == eCSSUnit_Local_Font) { + aResult.AppendLiteral("local("); + nsDependentString local(sources[i].GetStringBufferValue()); + nsStyleUtil::AppendEscapedCSSString(local, aResult); + aResult.Append(')'); + } else { + NS_NOTREACHED("entry in src: descriptor with improper unit"); + i++; + continue; + } + + i++; + formats.Truncate(); + while (i < sources.Count() && + sources[i].GetUnit() == eCSSUnit_Font_Format) { + formats.Append('"'); + formats.Append(sources[i].GetStringBufferValue()); + formats.AppendLiteral("\", "); + i++; + } + if (formats.Length() > 0) { + formats.Truncate(formats.Length() - 2); // remove the last comma + aResult.AppendLiteral(" format("); + aResult.Append(formats); + aResult.Append(')'); + } + aResult.AppendLiteral(", "); + } + aResult.Truncate(aResult.Length() - 2); // remove the last comma-space +} + +/* static */ void +nsStyleUtil::AppendStepsTimingFunction(nsTimingFunction::Type aType, + uint32_t aSteps, + nsAString& aResult) +{ + MOZ_ASSERT(aType == nsTimingFunction::Type::StepStart || + aType == nsTimingFunction::Type::StepEnd); + + aResult.AppendLiteral("steps("); + aResult.AppendInt(aSteps); + if (aType == nsTimingFunction::Type::StepStart) { + aResult.AppendLiteral(", start)"); + } else { + aResult.AppendLiteral(")"); + } +} + +/* static */ void +nsStyleUtil::AppendCubicBezierTimingFunction(float aX1, float aY1, + float aX2, float aY2, + nsAString& aResult) +{ + // set the value from the cubic-bezier control points + // (We could try to regenerate the keywords if we want.) + aResult.AppendLiteral("cubic-bezier("); + aResult.AppendFloat(aX1); + aResult.AppendLiteral(", "); + aResult.AppendFloat(aY1); + aResult.AppendLiteral(", "); + aResult.AppendFloat(aX2); + aResult.AppendLiteral(", "); + aResult.AppendFloat(aY2); + aResult.Append(')'); +} + +/* static */ void +nsStyleUtil::AppendCubicBezierKeywordTimingFunction( + nsTimingFunction::Type aType, + nsAString& aResult) +{ + switch (aType) { + case nsTimingFunction::Type::Ease: + case nsTimingFunction::Type::Linear: + case nsTimingFunction::Type::EaseIn: + case nsTimingFunction::Type::EaseOut: + case nsTimingFunction::Type::EaseInOut: { + nsCSSKeyword keyword = nsCSSProps::ValueToKeywordEnum( + static_cast<int32_t>(aType), + nsCSSProps::kTransitionTimingFunctionKTable); + AppendASCIItoUTF16(nsCSSKeywords::GetStringValue(keyword), + aResult); + break; + } + default: + MOZ_ASSERT_UNREACHABLE("unexpected aType"); + break; + } +} + +/* static */ float +nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha) +{ + // Alpha values are expressed as decimals, so we should convert + // back, using as few decimal places as possible for + // round-tripping. + // First try two decimal places: + float rounded = NS_roundf(float(aAlpha) * 100.0f / 255.0f) / 100.0f; + if (FloatToColorComponent(rounded) != aAlpha) { + // Use three decimal places. + rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f; + } + return rounded; +} + +/* static */ bool +nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant, + bool aWhitespaceIsSignificant) +{ + NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant, + "Nonsensical arguments"); + + bool isText = aChild->IsNodeOfType(nsINode::eTEXT); + + if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) && + !aChild->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) { + return true; + } + + return aTextIsSignificant && isText && aChild->TextLength() != 0 && + (aWhitespaceIsSignificant || + !aChild->TextIsOnlyWhitespace()); +} + +// For a replaced element whose concrete object size is no larger than the +// element's content-box, this method checks whether the given +// "object-position" coordinate might cause overflow in its dimension. +static bool +ObjectPositionCoordMightCauseOverflow(const Position::Coord& aCoord) +{ + // Any nonzero length in "object-position" can push us to overflow + // (particularly if our concrete object size is exactly the same size as the + // replaced element's content-box). + if (aCoord.mLength != 0) { + return true; + } + + // Percentages are interpreted as a fraction of the extra space. So, + // percentages in the 0-100% range are safe, but values outside of that + // range could cause overflow. + if (aCoord.mHasPercent && + (aCoord.mPercent < 0.0f || aCoord.mPercent > 1.0f)) { + return true; + } + return false; +} + + +/* static */ bool +nsStyleUtil::ObjectPropsMightCauseOverflow(const nsStylePosition* aStylePos) +{ + auto objectFit = aStylePos->mObjectFit; + + // "object-fit: cover" & "object-fit: none" can give us a render rect that's + // larger than our container element's content-box. + if (objectFit == NS_STYLE_OBJECT_FIT_COVER || + objectFit == NS_STYLE_OBJECT_FIT_NONE) { + return true; + } + // (All other object-fit values produce a concrete object size that's no larger + // than the constraint region.) + + // Check each of our "object-position" coords to see if it could cause + // overflow in its dimension: + const Position& objectPosistion = aStylePos->mObjectPosition; + if (ObjectPositionCoordMightCauseOverflow(objectPosistion.mXPosition) || + ObjectPositionCoordMightCauseOverflow(objectPosistion.mYPosition)) { + return true; + } + + return false; +} + + +/* static */ bool +nsStyleUtil::CSPAllowsInlineStyle(nsIContent* aContent, + nsIPrincipal* aPrincipal, + nsIURI* aSourceURI, + uint32_t aLineNumber, + const nsSubstring& aStyleText, + nsresult* aRv) +{ + nsresult rv; + + if (aRv) { + *aRv = NS_OK; + } + + MOZ_ASSERT(!aContent || aContent->NodeInfo()->NameAtom() == nsGkAtoms::style, + "aContent passed to CSPAllowsInlineStyle " + "for an element that is not <style>"); + + nsCOMPtr<nsIContentSecurityPolicy> csp; + rv = aPrincipal->GetCsp(getter_AddRefs(csp)); + + if (NS_FAILED(rv)) { + if (aRv) + *aRv = rv; + return false; + } + + if (!csp) { + // No CSP --> the style is allowed + return true; + } + + // query the nonce + nsAutoString nonce; + if (aContent) { + aContent->GetAttr(kNameSpaceID_None, nsGkAtoms::nonce, nonce); + } + + bool allowInlineStyle = true; + rv = csp->GetAllowsInline(nsIContentPolicy::TYPE_STYLESHEET, + nonce, + false, // aParserCreated only applies to scripts + aStyleText, aLineNumber, + &allowInlineStyle); + NS_ENSURE_SUCCESS(rv, false); + + return allowInlineStyle; +} |