Bug 867089 - Validate the playbackRate before using it. r=ehsan
[gecko.git] / layout / style / nsStyleUtil.cpp
blob5f16aaf397f3e439e7e27023246379bafcf796fa
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsStyleUtil.h"
7 #include "nsStyleConsts.h"
9 #include "nsIContent.h"
10 #include "nsReadableUtils.h"
11 #include "nsCSSProps.h"
12 #include "nsRuleNode.h"
14 using namespace mozilla;
16 //------------------------------------------------------------------------------
17 // Font Algorithm Code
18 //------------------------------------------------------------------------------
20 // Compare two language strings
21 bool nsStyleUtil::DashMatchCompare(const nsAString& aAttributeValue,
22 const nsAString& aSelectorValue,
23 const nsStringComparator& aComparator)
25 bool result;
26 uint32_t selectorLen = aSelectorValue.Length();
27 uint32_t attributeLen = aAttributeValue.Length();
28 if (selectorLen > attributeLen) {
29 result = false;
31 else {
32 nsAString::const_iterator iter;
33 if (selectorLen != attributeLen &&
34 *aAttributeValue.BeginReading(iter).advance(selectorLen) !=
35 PRUnichar('-')) {
36 // to match, the aAttributeValue must have a dash after the end of
37 // the aSelectorValue's text (unless the aSelectorValue and the
38 // aAttributeValue have the same text)
39 result = false;
41 else {
42 result = StringBeginsWith(aAttributeValue, aSelectorValue, aComparator);
45 return result;
48 void nsStyleUtil::AppendEscapedCSSString(const nsAString& aString,
49 nsAString& aReturn,
50 PRUnichar quoteChar)
52 NS_PRECONDITION(quoteChar == '\'' || quoteChar == '"',
53 "CSS strings must be quoted with ' or \"");
54 aReturn.Append(quoteChar);
56 const PRUnichar* in = aString.BeginReading();
57 const PRUnichar* const end = aString.EndReading();
58 for (; in != end; in++) {
59 if (*in < 0x20 || (*in >= 0x7F && *in < 0xA0)) {
60 // Escape U+0000 through U+001F and U+007F through U+009F numerically.
61 aReturn.AppendPrintf("\\%hX ", *in);
62 } else {
63 if (*in == '"' || *in == '\'' || *in == '\\') {
64 // Escape backslash and quote characters symbolically.
65 // It's not technically necessary to escape the quote
66 // character that isn't being used to delimit the string,
67 // but we do it anyway because that makes testing simpler.
68 aReturn.Append(PRUnichar('\\'));
70 aReturn.Append(*in);
74 aReturn.Append(quoteChar);
77 /* static */ void
78 nsStyleUtil::AppendEscapedCSSIdent(const nsAString& aIdent, nsAString& aReturn)
80 // The relevant parts of the CSS grammar are:
81 // ident [-]?{nmstart}{nmchar}*
82 // nmstart [_a-z]|{nonascii}|{escape}
83 // nmchar [_a-z0-9-]|{nonascii}|{escape}
84 // nonascii [^\0-\177]
85 // escape {unicode}|\\[^\n\r\f0-9a-f]
86 // unicode \\[0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
87 // from http://www.w3.org/TR/CSS21/syndata.html#tokenization
89 const PRUnichar* in = aIdent.BeginReading();
90 const PRUnichar* const end = aIdent.EndReading();
92 if (in == end)
93 return;
95 // A leading dash does not need to be escaped as long as it is not the
96 // *only* character in the identifier.
97 if (in + 1 != end && *in == '-') {
98 aReturn.Append(PRUnichar('-'));
99 ++in;
102 // Escape a digit at the start (including after a dash),
103 // numerically. If we didn't escape it numerically, it would get
104 // interpreted as a numeric escape for the wrong character.
105 // A second dash immediately after a leading dash must also be
106 // escaped, but this may be done symbolically.
107 if (in != end && (*in == '-' ||
108 ('0' <= *in && *in <= '9'))) {
109 if (*in == '-') {
110 aReturn.Append(PRUnichar('\\'));
111 aReturn.Append(PRUnichar('-'));
112 } else {
113 aReturn.AppendPrintf("\\%hX ", *in);
115 ++in;
118 for (; in != end; ++in) {
119 PRUnichar ch = *in;
120 if (ch < 0x20 || (0x7F <= ch && ch < 0xA0)) {
121 // Escape U+0000 through U+001F and U+007F through U+009F numerically.
122 aReturn.AppendPrintf("\\%hX ", *in);
123 } else {
124 // Escape ASCII non-identifier printables as a backslash plus
125 // the character.
126 if (ch < 0x7F &&
127 ch != '_' && ch != '-' &&
128 (ch < '0' || '9' < ch) &&
129 (ch < 'A' || 'Z' < ch) &&
130 (ch < 'a' || 'z' < ch)) {
131 aReturn.Append(PRUnichar('\\'));
133 aReturn.Append(ch);
138 /* static */ void
139 nsStyleUtil::AppendBitmaskCSSValue(nsCSSProperty aProperty,
140 int32_t aMaskedValue,
141 int32_t aFirstMask,
142 int32_t aLastMask,
143 nsAString& aResult)
145 for (int32_t mask = aFirstMask; mask <= aLastMask; mask <<= 1) {
146 if (mask & aMaskedValue) {
147 AppendASCIItoUTF16(nsCSSProps::LookupPropertyValue(aProperty, mask),
148 aResult);
149 aMaskedValue &= ~mask;
150 if (aMaskedValue) { // more left
151 aResult.Append(PRUnichar(' '));
155 NS_ABORT_IF_FALSE(aMaskedValue == 0, "unexpected bit remaining in bitfield");
158 /* static */ void
159 nsStyleUtil::AppendPaintOrderValue(uint8_t aValue,
160 nsAString& aResult)
162 MOZ_STATIC_ASSERT
163 (NS_STYLE_PAINT_ORDER_BITWIDTH * NS_STYLE_PAINT_ORDER_LAST_VALUE <= 8,
164 "SVGStyleStruct::mPaintOrder and local variables not big enough");
166 if (aValue == NS_STYLE_PAINT_ORDER_NORMAL) {
167 aResult.AppendLiteral("normal");
168 return;
171 // Append the minimal value necessary for the given paint order.
172 MOZ_STATIC_ASSERT(NS_STYLE_PAINT_ORDER_LAST_VALUE == 3,
173 "paint-order values added; check serialization");
175 // The following relies on the default order being the order of the
176 // constant values.
178 const uint8_t MASK = (1 << NS_STYLE_PAINT_ORDER_BITWIDTH) - 1;
180 uint32_t lastPositionToSerialize = 0;
181 for (uint32_t position = NS_STYLE_PAINT_ORDER_LAST_VALUE - 1;
182 position > 0;
183 position--) {
184 uint8_t component =
185 (aValue >> (position * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
186 uint8_t earlierComponent =
187 (aValue >> ((position - 1) * NS_STYLE_PAINT_ORDER_BITWIDTH)) & MASK;
188 if (component < earlierComponent) {
189 lastPositionToSerialize = position - 1;
190 break;
194 for (uint32_t position = 0; position <= lastPositionToSerialize; position++) {
195 if (position > 0) {
196 aResult.AppendLiteral(" ");
198 uint8_t component = aValue & MASK;
199 switch (component) {
200 case NS_STYLE_PAINT_ORDER_FILL:
201 aResult.AppendLiteral("fill");
202 break;
204 case NS_STYLE_PAINT_ORDER_STROKE:
205 aResult.AppendLiteral("stroke");
206 break;
208 case NS_STYLE_PAINT_ORDER_MARKERS:
209 aResult.AppendLiteral("markers");
210 break;
212 default:
213 NS_NOTREACHED("unexpected paint-order component value");
215 aValue >>= NS_STYLE_PAINT_ORDER_BITWIDTH;
219 /* static */ void
220 nsStyleUtil::AppendFontFeatureSettings(const nsTArray<gfxFontFeature>& aFeatures,
221 nsAString& aResult)
223 for (uint32_t i = 0, numFeat = aFeatures.Length(); i < numFeat; i++) {
224 const gfxFontFeature& feat = aFeatures[i];
226 if (i != 0) {
227 aResult.AppendLiteral(", ");
230 // output tag
231 char tag[7];
232 tag[0] = '"';
233 tag[1] = (feat.mTag >> 24) & 0xff;
234 tag[2] = (feat.mTag >> 16) & 0xff;
235 tag[3] = (feat.mTag >> 8) & 0xff;
236 tag[4] = feat.mTag & 0xff;
237 tag[5] = '"';
238 tag[6] = 0;
239 aResult.AppendASCII(tag);
241 // output value, if necessary
242 if (feat.mValue == 0) {
243 // 0 ==> off
244 aResult.AppendLiteral(" off");
245 } else if (feat.mValue > 1) {
246 aResult.AppendLiteral(" ");
247 aResult.AppendInt(feat.mValue);
249 // else, omit value if 1, implied by default
253 /* static */ void
254 nsStyleUtil::AppendFontFeatureSettings(const nsCSSValue& aSrc,
255 nsAString& aResult)
257 nsCSSUnit unit = aSrc.GetUnit();
259 if (unit == eCSSUnit_Normal) {
260 aResult.AppendLiteral("normal");
261 return;
264 NS_PRECONDITION(unit == eCSSUnit_PairList || unit == eCSSUnit_PairListDep,
265 "improper value unit for font-feature-settings:");
267 nsTArray<gfxFontFeature> featureSettings;
268 nsRuleNode::ComputeFontFeatures(aSrc.GetPairListValue(), featureSettings);
269 AppendFontFeatureSettings(featureSettings, aResult);
272 /* static */ float
273 nsStyleUtil::ColorComponentToFloat(uint8_t aAlpha)
275 // Alpha values are expressed as decimals, so we should convert
276 // back, using as few decimal places as possible for
277 // round-tripping.
278 // First try two decimal places:
279 float rounded = NS_roundf(float(aAlpha) * 100.0f / 255.0f) / 100.0f;
280 if (FloatToColorComponent(rounded) != aAlpha) {
281 // Use three decimal places.
282 rounded = NS_roundf(float(aAlpha) * 1000.0f / 255.0f) / 1000.0f;
284 return rounded;
287 /* static */ bool
288 nsStyleUtil::IsSignificantChild(nsIContent* aChild, bool aTextIsSignificant,
289 bool aWhitespaceIsSignificant)
291 NS_ASSERTION(!aWhitespaceIsSignificant || aTextIsSignificant,
292 "Nonsensical arguments");
294 bool isText = aChild->IsNodeOfType(nsINode::eTEXT);
296 if (!isText && !aChild->IsNodeOfType(nsINode::eCOMMENT) &&
297 !aChild->IsNodeOfType(nsINode::ePROCESSING_INSTRUCTION)) {
298 return true;
301 return aTextIsSignificant && isText && aChild->TextLength() != 0 &&
302 (aWhitespaceIsSignificant ||
303 !aChild->TextIsOnlyWhitespace());