Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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 /* representation of a value for a SMIL-animated CSS property */
8 #include "nsSMILCSSValueType.h"
9 #include "nsString.h"
10 #include "nsStyleAnimation.h"
11 #include "nsSMILParserUtils.h"
12 #include "nsSMILValue.h"
13 #include "nsCSSValue.h"
14 #include "nsColor.h"
15 #include "nsPresContext.h"
16 #include "mozilla/dom/Element.h"
17 #include "nsDebug.h"
18 #include "nsStyleUtil.h"
19 #include "nsIDocument.h"
21 using namespace mozilla::dom;
23 /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
25 struct ValueWrapper {
26 ValueWrapper(nsCSSProperty aPropID, const nsStyleAnimation::Value& aValue) :
27 mPropID(aPropID), mCSSValue(aValue) {}
29 nsCSSProperty mPropID;
30 nsStyleAnimation::Value mCSSValue;
31 };
33 // Helper Methods
34 // --------------
35 static const nsStyleAnimation::Value*
36 GetZeroValueForUnit(nsStyleAnimation::Unit aUnit)
37 {
38 static const nsStyleAnimation::Value
39 sZeroCoord(0, nsStyleAnimation::Value::CoordConstructor);
40 static const nsStyleAnimation::Value
41 sZeroPercent(0.0f, nsStyleAnimation::Value::PercentConstructor);
42 static const nsStyleAnimation::Value
43 sZeroFloat(0.0f, nsStyleAnimation::Value::FloatConstructor);
44 static const nsStyleAnimation::Value
45 sZeroColor(NS_RGB(0,0,0), nsStyleAnimation::Value::ColorConstructor);
47 NS_ABORT_IF_FALSE(aUnit != nsStyleAnimation::eUnit_Null,
48 "Need non-null unit for a zero value");
49 switch (aUnit) {
50 case nsStyleAnimation::eUnit_Coord:
51 return &sZeroCoord;
52 case nsStyleAnimation::eUnit_Percent:
53 return &sZeroPercent;
54 case nsStyleAnimation::eUnit_Float:
55 return &sZeroFloat;
56 case nsStyleAnimation::eUnit_Color:
57 return &sZeroColor;
58 default:
59 return nullptr;
60 }
61 }
63 // This method requires at least one of its arguments to be non-null.
64 //
65 // If one argument is null, this method updates it to point to "zero"
66 // for the other argument's Unit (if applicable; otherwise, we return false).
67 //
68 // If neither argument is null, this method generally does nothing, though it
69 // may apply a workaround for the special case where a 0 length-value is mixed
70 // with a eUnit_Float value. (See comment below.)
71 //
72 // Returns true on success, or false.
73 static const bool
74 FinalizeStyleAnimationValues(const nsStyleAnimation::Value*& aValue1,
75 const nsStyleAnimation::Value*& aValue2)
76 {
77 NS_ABORT_IF_FALSE(aValue1 || aValue2,
78 "expecting at least one non-null value");
80 // Are we missing either val? (If so, it's an implied 0 in other val's units)
81 if (!aValue1) {
82 aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
83 return !!aValue1; // Fail if we have no zero value for this unit.
84 }
85 if (!aValue2) {
86 aValue2 = GetZeroValueForUnit(aValue1->GetUnit());
87 return !!aValue2; // Fail if we have no zero value for this unit.
88 }
90 // Ok, both values were specified.
91 // Need to handle a special-case, though: unitless nonzero length (parsed as
92 // eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord). These
93 // won't interoperate in nsStyleAnimation, since their Units don't match.
94 // In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value.
95 const nsStyleAnimation::Value& zeroCoord =
96 *GetZeroValueForUnit(nsStyleAnimation::eUnit_Coord);
97 if (*aValue1 == zeroCoord &&
98 aValue2->GetUnit() == nsStyleAnimation::eUnit_Float) {
99 aValue1 = GetZeroValueForUnit(nsStyleAnimation::eUnit_Float);
100 } else if (*aValue2 == zeroCoord &&
101 aValue1->GetUnit() == nsStyleAnimation::eUnit_Float) {
102 aValue2 = GetZeroValueForUnit(nsStyleAnimation::eUnit_Float);
103 }
105 return true;
106 }
108 static void
109 InvertSign(nsStyleAnimation::Value& aValue)
110 {
111 switch (aValue.GetUnit()) {
112 case nsStyleAnimation::eUnit_Coord:
113 aValue.SetCoordValue(-aValue.GetCoordValue());
114 break;
115 case nsStyleAnimation::eUnit_Percent:
116 aValue.SetPercentValue(-aValue.GetPercentValue());
117 break;
118 case nsStyleAnimation::eUnit_Float:
119 aValue.SetFloatValue(-aValue.GetFloatValue());
120 break;
121 default:
122 NS_NOTREACHED("Calling InvertSign with an unsupported unit");
123 break;
124 }
125 }
127 static ValueWrapper*
128 ExtractValueWrapper(nsSMILValue& aValue)
129 {
130 return static_cast<ValueWrapper*>(aValue.mU.mPtr);
131 }
133 static const ValueWrapper*
134 ExtractValueWrapper(const nsSMILValue& aValue)
135 {
136 return static_cast<const ValueWrapper*>(aValue.mU.mPtr);
137 }
139 // Class methods
140 // -------------
141 void
142 nsSMILCSSValueType::Init(nsSMILValue& aValue) const
143 {
144 NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected SMIL value type");
146 aValue.mU.mPtr = nullptr;
147 aValue.mType = this;
148 }
150 void
151 nsSMILCSSValueType::Destroy(nsSMILValue& aValue) const
152 {
153 NS_ABORT_IF_FALSE(aValue.mType == this, "Unexpected SMIL value type");
154 delete static_cast<ValueWrapper*>(aValue.mU.mPtr);
155 aValue.mType = nsSMILNullType::Singleton();
156 }
158 nsresult
159 nsSMILCSSValueType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
160 {
161 NS_ABORT_IF_FALSE(aDest.mType == aSrc.mType, "Incompatible SMIL types");
162 NS_ABORT_IF_FALSE(aDest.mType == this, "Unexpected SMIL value type");
163 const ValueWrapper* srcWrapper = ExtractValueWrapper(aSrc);
164 ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
166 if (srcWrapper) {
167 if (!destWrapper) {
168 // barely-initialized dest -- need to alloc & copy
169 aDest.mU.mPtr = new ValueWrapper(*srcWrapper);
170 } else {
171 // both already fully-initialized -- just copy straight across
172 *destWrapper = *srcWrapper;
173 }
174 } else if (destWrapper) {
175 // fully-initialized dest, barely-initialized src -- clear dest
176 delete destWrapper;
177 aDest.mU.mPtr = destWrapper = nullptr;
178 } // else, both are barely-initialized -- nothing to do.
180 return NS_OK;
181 }
183 bool
184 nsSMILCSSValueType::IsEqual(const nsSMILValue& aLeft,
185 const nsSMILValue& aRight) const
186 {
187 NS_ABORT_IF_FALSE(aLeft.mType == aRight.mType, "Incompatible SMIL types");
188 NS_ABORT_IF_FALSE(aLeft.mType == this, "Unexpected SMIL value");
189 const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
190 const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
192 if (leftWrapper) {
193 if (rightWrapper) {
194 // Both non-null
195 NS_WARN_IF_FALSE(leftWrapper != rightWrapper,
196 "Two nsSMILValues with matching ValueWrapper ptr");
197 return (leftWrapper->mPropID == rightWrapper->mPropID &&
198 leftWrapper->mCSSValue == rightWrapper->mCSSValue);
199 }
200 // Left non-null, right null
201 return false;
202 }
203 if (rightWrapper) {
204 // Left null, right non-null
205 return false;
206 }
207 // Both null
208 return true;
209 }
211 nsresult
212 nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
213 uint32_t aCount) const
214 {
215 NS_ABORT_IF_FALSE(aValueToAdd.mType == aDest.mType,
216 "Trying to add invalid types");
217 NS_ABORT_IF_FALSE(aValueToAdd.mType == this, "Unexpected source type");
219 ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
220 const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
221 NS_ABORT_IF_FALSE(destWrapper || valueToAddWrapper,
222 "need at least one fully-initialized value");
224 nsCSSProperty property = (valueToAddWrapper ? valueToAddWrapper->mPropID :
225 destWrapper->mPropID);
226 // Special case: font-size-adjust and stroke-dasharray are explicitly
227 // non-additive (even though nsStyleAnimation *could* support adding them)
228 if (property == eCSSProperty_font_size_adjust ||
229 property == eCSSProperty_stroke_dasharray) {
230 return NS_ERROR_FAILURE;
231 }
233 const nsStyleAnimation::Value* valueToAdd = valueToAddWrapper ?
234 &valueToAddWrapper->mCSSValue : nullptr;
235 const nsStyleAnimation::Value* destValue = destWrapper ?
236 &destWrapper->mCSSValue : nullptr;
237 if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) {
238 return NS_ERROR_FAILURE;
239 }
240 // Did FinalizeStyleAnimationValues change destValue?
241 // If so, update outparam to use the new value.
242 if (destWrapper && &destWrapper->mCSSValue != destValue) {
243 destWrapper->mCSSValue = *destValue;
244 }
246 // Handle barely-initialized "zero" destination.
247 if (!destWrapper) {
248 aDest.mU.mPtr = destWrapper =
249 new ValueWrapper(property, *destValue);
250 }
252 return nsStyleAnimation::Add(property,
253 destWrapper->mCSSValue, *valueToAdd, aCount) ?
254 NS_OK : NS_ERROR_FAILURE;
255 }
257 nsresult
258 nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
259 const nsSMILValue& aTo,
260 double& aDistance) const
261 {
262 NS_ABORT_IF_FALSE(aFrom.mType == aTo.mType,
263 "Trying to compare different types");
264 NS_ABORT_IF_FALSE(aFrom.mType == this, "Unexpected source type");
266 const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom);
267 const ValueWrapper* toWrapper = ExtractValueWrapper(aTo);
268 NS_ABORT_IF_FALSE(toWrapper, "expecting non-null endpoint");
270 const nsStyleAnimation::Value* fromCSSValue = fromWrapper ?
271 &fromWrapper->mCSSValue : nullptr;
272 const nsStyleAnimation::Value* toCSSValue = &toWrapper->mCSSValue;
273 if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
274 return NS_ERROR_FAILURE;
275 }
277 return nsStyleAnimation::ComputeDistance(toWrapper->mPropID,
278 *fromCSSValue, *toCSSValue,
279 aDistance) ?
280 NS_OK : NS_ERROR_FAILURE;
281 }
283 nsresult
284 nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
285 const nsSMILValue& aEndVal,
286 double aUnitDistance,
287 nsSMILValue& aResult) const
288 {
289 NS_ABORT_IF_FALSE(aStartVal.mType == aEndVal.mType,
290 "Trying to interpolate different types");
291 NS_ABORT_IF_FALSE(aStartVal.mType == this,
292 "Unexpected types for interpolation");
293 NS_ABORT_IF_FALSE(aResult.mType == this, "Unexpected result type");
294 NS_ABORT_IF_FALSE(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
295 "unit distance value out of bounds");
296 NS_ABORT_IF_FALSE(!aResult.mU.mPtr, "expecting barely-initialized outparam");
298 const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal);
299 const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
300 NS_ABORT_IF_FALSE(endWrapper, "expecting non-null endpoint");
302 const nsStyleAnimation::Value* startCSSValue = startWrapper ?
303 &startWrapper->mCSSValue : nullptr;
304 const nsStyleAnimation::Value* endCSSValue = &endWrapper->mCSSValue;
305 if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
306 return NS_ERROR_FAILURE;
307 }
309 nsStyleAnimation::Value resultValue;
310 if (nsStyleAnimation::Interpolate(endWrapper->mPropID,
311 *startCSSValue, *endCSSValue,
312 aUnitDistance, resultValue)) {
313 aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue);
314 return NS_OK;
315 }
316 return NS_ERROR_FAILURE;
317 }
319 // Helper function to extract presContext
320 static nsPresContext*
321 GetPresContextForElement(Element* aElem)
322 {
323 nsIDocument* doc = aElem->GetCurrentDoc();
324 if (!doc) {
325 // This can happen if we process certain types of restyles mid-sample
326 // and remove anonymous animated content from the document as a result.
327 // See bug 534975.
328 return nullptr;
329 }
330 nsIPresShell* shell = doc->GetShell();
331 return shell ? shell->GetPresContext() : nullptr;
332 }
334 // Helper function to parse a string into a nsStyleAnimation::Value
335 static bool
336 ValueFromStringHelper(nsCSSProperty aPropID,
337 Element* aTargetElement,
338 nsPresContext* aPresContext,
339 const nsAString& aString,
340 nsStyleAnimation::Value& aStyleAnimValue,
341 bool* aIsContextSensitive)
342 {
343 // If value is negative, we'll strip off the "-" so the CSS parser won't
344 // barf, and then manually make the parsed value negative.
345 // (This is a partial solution to let us accept some otherwise out-of-bounds
346 // CSS values. Bug 501188 will provide a more complete fix.)
347 bool isNegative = false;
348 uint32_t subStringBegin = 0;
350 // NOTE: We need to opt-out 'stroke-dasharray' from the negative-number
351 // check. Its values might look negative (e.g. by starting with "-1"), but
352 // they're more complicated than our simple negation logic here can handle.
353 if (aPropID != eCSSProperty_stroke_dasharray) {
354 int32_t absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
355 if (absValuePos > 0) {
356 isNegative = true;
357 subStringBegin = (uint32_t)absValuePos; // Start parsing after '-' sign
358 }
359 }
360 nsDependentSubstring subString(aString, subStringBegin);
361 if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
362 true, aStyleAnimValue,
363 aIsContextSensitive)) {
364 return false;
365 }
366 if (isNegative) {
367 InvertSign(aStyleAnimValue);
368 }
370 if (aPropID == eCSSProperty_font_size) {
371 // Divide out text-zoom, since SVG is supposed to ignore it
372 NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
373 nsStyleAnimation::eUnit_Coord,
374 "'font-size' value with unexpected style unit");
375 aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
376 aPresContext->TextZoom());
377 }
378 return true;
379 }
381 // static
382 void
383 nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
384 Element* aTargetElement,
385 const nsAString& aString,
386 nsSMILValue& aValue,
387 bool* aIsContextSensitive)
388 {
389 NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
390 nsPresContext* presContext = GetPresContextForElement(aTargetElement);
391 if (!presContext) {
392 NS_WARNING("Not parsing animation value; unable to get PresContext");
393 return;
394 }
396 nsIDocument* doc = aTargetElement->GetCurrentDoc();
397 if (doc && !nsStyleUtil::CSPAllowsInlineStyle(nullptr,
398 doc->NodePrincipal(),
399 doc->GetDocumentURI(),
400 0, aString, nullptr)) {
401 return;
402 }
404 nsStyleAnimation::Value parsedValue;
405 if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
406 aString, parsedValue, aIsContextSensitive)) {
407 sSingleton.Init(aValue);
408 aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue);
409 }
410 }
412 // static
413 bool
414 nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
415 nsAString& aString)
416 {
417 NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
418 "Unexpected SMIL value type");
419 const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
420 return !wrapper ||
421 nsStyleAnimation::UncomputeValue(wrapper->mPropID,
422 wrapper->mCSSValue, aString);
423 }