dom/smil/nsSMILCSSValueType.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

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 }

mercurial