LCOV - code coverage report
Current view: directory - content/smil - nsSMILCSSValueType.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 172 6 3.5 %
Date: 2012-06-02 Functions: 23 2 8.7 %

       1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2                 : /* ***** BEGIN LICENSE BLOCK *****
       3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
       4                 :  *
       5                 :  * The contents of this file are subject to the Mozilla Public License Version
       6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
       7                 :  * the License. You may obtain a copy of the License at
       8                 :  * http://www.mozilla.org/MPL/
       9                 :  *
      10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
      11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
      12                 :  * for the specific language governing rights and limitations under the
      13                 :  * License.
      14                 :  *
      15                 :  * The Original Code is the Mozilla SMIL module.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is the Mozilla Corporation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2009
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Daniel Holbert <dholbert@mozilla.com>
      23                 :  *
      24                 :  * Alternatively, the contents of this file may be used under the terms of
      25                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
      26                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      27                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      28                 :  * of those above. If you wish to allow use of your version of this file only
      29                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      30                 :  * use your version of this file under the terms of the MPL, indicate your
      31                 :  * decision by deleting the provisions above and replace them with the notice
      32                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      33                 :  * the provisions above, a recipient may use your version of this file under
      34                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      35                 :  *
      36                 :  * ***** END LICENSE BLOCK ***** */
      37                 : 
      38                 : /* representation of a value for a SMIL-animated CSS property */
      39                 : 
      40                 : #include "nsSMILCSSValueType.h"
      41                 : #include "nsString.h"
      42                 : #include "nsStyleAnimation.h"
      43                 : #include "nsSMILParserUtils.h"
      44                 : #include "nsSMILValue.h"
      45                 : #include "nsCSSValue.h"
      46                 : #include "nsColor.h"
      47                 : #include "nsPresContext.h"
      48                 : #include "mozilla/dom/Element.h"
      49                 : #include "nsDebug.h"
      50                 : 
      51                 : using namespace mozilla::dom;
      52                 : 
      53            1464 : /*static*/ nsSMILCSSValueType nsSMILCSSValueType::sSingleton;
      54                 : 
      55               0 : struct ValueWrapper {
      56               0 :   ValueWrapper(nsCSSProperty aPropID, const nsStyleAnimation::Value& aValue,
      57                 :                nsPresContext* aPresContext) :
      58               0 :     mPropID(aPropID), mCSSValue(aValue), mPresContext(aPresContext) {}
      59                 : 
      60                 :   nsCSSProperty mPropID;
      61                 :   nsStyleAnimation::Value mCSSValue;
      62                 :   nsPresContext* mPresContext;
      63                 : };
      64                 : 
      65                 : // Helper "zero" values of various types
      66                 : // -------------------------------------
      67                 : static const nsStyleAnimation::Value
      68            1464 :   sZeroCoord(0, nsStyleAnimation::Value::CoordConstructor);
      69                 : static const nsStyleAnimation::Value
      70            1464 :   sZeroPercent(0.0f, nsStyleAnimation::Value::PercentConstructor);
      71                 : static const nsStyleAnimation::Value
      72            1464 :   sZeroFloat(0.0f,  nsStyleAnimation::Value::FloatConstructor);
      73                 : static const nsStyleAnimation::Value
      74            1464 :   sZeroColor(NS_RGB(0,0,0), nsStyleAnimation::Value::ColorConstructor);
      75                 : 
      76                 : // Helper Methods
      77                 : // --------------
      78                 : static const nsStyleAnimation::Value*
      79               0 : GetZeroValueForUnit(nsStyleAnimation::Unit aUnit)
      80                 : {
      81               0 :   NS_ABORT_IF_FALSE(aUnit != nsStyleAnimation::eUnit_Null,
      82                 :                     "Need non-null unit for a zero value");
      83               0 :   switch (aUnit) {
      84                 :     case nsStyleAnimation::eUnit_Coord:
      85               0 :       return &sZeroCoord;
      86                 :     case nsStyleAnimation::eUnit_Percent:
      87               0 :       return &sZeroPercent;
      88                 :     case nsStyleAnimation::eUnit_Float:
      89               0 :       return &sZeroFloat;
      90                 :     case nsStyleAnimation::eUnit_Color:
      91               0 :       return &sZeroColor;
      92                 :     default:
      93               0 :       return nsnull;
      94                 :   }
      95                 : }
      96                 : 
      97                 : // This method requires at least one of its arguments to be non-null.
      98                 : //
      99                 : // If one argument is null, this method updates it to point to "zero"
     100                 : // for the other argument's Unit (if applicable; otherwise, we return false).
     101                 : //
     102                 : // If neither argument is null, this method generally does nothing, though it
     103                 : // may apply a workaround for the special case where a 0 length-value is mixed
     104                 : // with a eUnit_Float value.  (See comment below.)
     105                 : //
     106                 : // Returns true on success, or false.
     107                 : static const bool
     108               0 : FinalizeStyleAnimationValues(const nsStyleAnimation::Value*& aValue1,
     109                 :                              const nsStyleAnimation::Value*& aValue2)
     110                 : {
     111               0 :   NS_ABORT_IF_FALSE(aValue1 || aValue2,
     112                 :                     "expecting at least one non-null value");
     113                 : 
     114                 :   // Are we missing either val? (If so, it's an implied 0 in other val's units)
     115               0 :   if (!aValue1) {
     116               0 :     aValue1 = GetZeroValueForUnit(aValue2->GetUnit());
     117               0 :     return !!aValue1; // Fail if we have no zero value for this unit.
     118                 :   }
     119               0 :   if (!aValue2) {
     120               0 :     aValue2 = GetZeroValueForUnit(aValue1->GetUnit());
     121               0 :     return !!aValue2; // Fail if we have no zero value for this unit.
     122                 :   }
     123                 : 
     124                 :   // Ok, both values were specified.
     125                 :   // Need to handle a special-case, though: unitless nonzero length (parsed as
     126                 :   // eUnit_Float) mixed with unitless 0 length (parsed as eUnit_Coord).  These
     127                 :   // won't interoperate in nsStyleAnimation, since their Units don't match.
     128                 :   // In this case, we replace the eUnit_Coord 0 value with eUnit_Float 0 value.
     129               0 :   if (*aValue1 == sZeroCoord &&
     130               0 :       aValue2->GetUnit() == nsStyleAnimation::eUnit_Float) {
     131               0 :     aValue1 = &sZeroFloat;
     132               0 :   } else if (*aValue2 == sZeroCoord &&
     133               0 :              aValue1->GetUnit() == nsStyleAnimation::eUnit_Float) {
     134               0 :     aValue2 = &sZeroFloat;
     135                 :   }
     136                 : 
     137               0 :   return true;
     138                 : }
     139                 : 
     140                 : static void
     141               0 : InvertSign(nsStyleAnimation::Value& aValue)
     142                 : {
     143               0 :   switch (aValue.GetUnit()) {
     144                 :     case nsStyleAnimation::eUnit_Coord:
     145               0 :       aValue.SetCoordValue(-aValue.GetCoordValue());
     146               0 :       break;
     147                 :     case nsStyleAnimation::eUnit_Percent:
     148               0 :       aValue.SetPercentValue(-aValue.GetPercentValue());
     149               0 :       break;
     150                 :     case nsStyleAnimation::eUnit_Float:
     151               0 :       aValue.SetFloatValue(-aValue.GetFloatValue());
     152               0 :       break;
     153                 :     default:
     154               0 :       NS_NOTREACHED("Calling InvertSign with an unsupported unit");
     155               0 :       break;
     156                 :   }
     157               0 : }
     158                 : 
     159                 : static ValueWrapper*
     160               0 : ExtractValueWrapper(nsSMILValue& aValue)
     161                 : {
     162               0 :   return static_cast<ValueWrapper*>(aValue.mU.mPtr);
     163                 : }
     164                 : 
     165                 : static const ValueWrapper*
     166               0 : ExtractValueWrapper(const nsSMILValue& aValue)
     167                 : {
     168               0 :   return static_cast<const ValueWrapper*>(aValue.mU.mPtr);
     169                 : }
     170                 : 
     171                 : // Class methods
     172                 : // -------------
     173                 : void
     174               0 : nsSMILCSSValueType::Init(nsSMILValue& aValue) const
     175                 : {
     176               0 :   NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected SMIL value type");
     177                 : 
     178               0 :   aValue.mU.mPtr = nsnull;
     179               0 :   aValue.mType = this;
     180               0 : }
     181                 : 
     182                 : void
     183               0 : nsSMILCSSValueType::Destroy(nsSMILValue& aValue) const
     184                 : {
     185               0 :   NS_ABORT_IF_FALSE(aValue.mType == this, "Unexpected SMIL value type");
     186               0 :   delete static_cast<ValueWrapper*>(aValue.mU.mPtr);
     187               0 :   aValue.mType = &nsSMILNullType::sSingleton;
     188               0 : }
     189                 : 
     190                 : nsresult
     191               0 : nsSMILCSSValueType::Assign(nsSMILValue& aDest, const nsSMILValue& aSrc) const
     192                 : {
     193               0 :   NS_ABORT_IF_FALSE(aDest.mType == aSrc.mType, "Incompatible SMIL types");
     194               0 :   NS_ABORT_IF_FALSE(aDest.mType == this, "Unexpected SMIL value type");
     195               0 :   const ValueWrapper* srcWrapper = ExtractValueWrapper(aSrc);
     196               0 :   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
     197                 : 
     198               0 :   if (srcWrapper) {
     199               0 :     if (!destWrapper) {
     200                 :       // barely-initialized dest -- need to alloc & copy
     201               0 :       aDest.mU.mPtr = new ValueWrapper(*srcWrapper);
     202                 :     } else {
     203                 :       // both already fully-initialized -- just copy straight across
     204               0 :       *destWrapper = *srcWrapper;
     205                 :     }
     206               0 :   } else if (destWrapper) {
     207                 :     // fully-initialized dest, barely-initialized src -- clear dest
     208               0 :     delete destWrapper;
     209               0 :     aDest.mU.mPtr = destWrapper = nsnull;
     210                 :   } // else, both are barely-initialized -- nothing to do.
     211                 : 
     212               0 :   return NS_OK;
     213                 : }
     214                 : 
     215                 : bool
     216               0 : nsSMILCSSValueType::IsEqual(const nsSMILValue& aLeft,
     217                 :                             const nsSMILValue& aRight) const
     218                 : {
     219               0 :   NS_ABORT_IF_FALSE(aLeft.mType == aRight.mType, "Incompatible SMIL types");
     220               0 :   NS_ABORT_IF_FALSE(aLeft.mType == this, "Unexpected SMIL value");
     221               0 :   const ValueWrapper* leftWrapper = ExtractValueWrapper(aLeft);
     222               0 :   const ValueWrapper* rightWrapper = ExtractValueWrapper(aRight);
     223                 : 
     224               0 :   if (leftWrapper) {
     225               0 :     if (rightWrapper) {
     226                 :       // Both non-null
     227               0 :       NS_WARN_IF_FALSE(leftWrapper != rightWrapper,
     228                 :                        "Two nsSMILValues with matching ValueWrapper ptr");
     229                 :       // mPresContext doesn't really matter for equality comparison
     230                 :       return (leftWrapper->mPropID == rightWrapper->mPropID &&
     231               0 :               leftWrapper->mCSSValue == rightWrapper->mCSSValue);
     232                 :     }
     233                 :     // Left non-null, right null
     234               0 :     return false;
     235                 :   }
     236               0 :   if (rightWrapper) {
     237                 :     // Left null, right non-null
     238               0 :     return false;
     239                 :   }
     240                 :   // Both null
     241               0 :   return true;
     242                 : }
     243                 : 
     244                 : nsresult
     245               0 : nsSMILCSSValueType::Add(nsSMILValue& aDest, const nsSMILValue& aValueToAdd,
     246                 :                         PRUint32 aCount) const
     247                 : {
     248               0 :   NS_ABORT_IF_FALSE(aValueToAdd.mType == aDest.mType,
     249                 :                     "Trying to add invalid types");
     250               0 :   NS_ABORT_IF_FALSE(aValueToAdd.mType == this, "Unexpected source type");
     251                 : 
     252               0 :   ValueWrapper* destWrapper = ExtractValueWrapper(aDest);
     253               0 :   const ValueWrapper* valueToAddWrapper = ExtractValueWrapper(aValueToAdd);
     254               0 :   NS_ABORT_IF_FALSE(destWrapper || valueToAddWrapper,
     255                 :                     "need at least one fully-initialized value");
     256                 : 
     257                 :   nsCSSProperty property = (valueToAddWrapper ? valueToAddWrapper->mPropID :
     258               0 :                             destWrapper->mPropID);
     259                 :   // Special case: font-size-adjust and stroke-dasharray are explicitly
     260                 :   // non-additive (even though nsStyleAnimation *could* support adding them)
     261               0 :   if (property == eCSSProperty_font_size_adjust ||
     262                 :       property == eCSSProperty_stroke_dasharray) {
     263               0 :     return NS_ERROR_FAILURE;
     264                 :   }
     265                 : 
     266                 :   const nsStyleAnimation::Value* valueToAdd = valueToAddWrapper ?
     267               0 :     &valueToAddWrapper->mCSSValue : nsnull;
     268                 :   const nsStyleAnimation::Value* destValue = destWrapper ?
     269               0 :     &destWrapper->mCSSValue : nsnull;
     270               0 :   if (!FinalizeStyleAnimationValues(valueToAdd, destValue)) {
     271               0 :     return NS_ERROR_FAILURE;
     272                 :   }
     273                 :   // Did FinalizeStyleAnimationValues change destValue?
     274                 :   // If so, update outparam to use the new value.
     275               0 :   if (destWrapper && &destWrapper->mCSSValue != destValue) {
     276               0 :     destWrapper->mCSSValue = *destValue;
     277                 :   }
     278                 : 
     279                 :   // Handle barely-initialized "zero" destination.
     280               0 :   if (!destWrapper) {
     281                 :     aDest.mU.mPtr = destWrapper =
     282               0 :       new ValueWrapper(property, *destValue, valueToAddWrapper->mPresContext);
     283                 :   }
     284                 : 
     285                 :   return nsStyleAnimation::Add(property,
     286               0 :                                destWrapper->mCSSValue, *valueToAdd, aCount) ?
     287               0 :     NS_OK : NS_ERROR_FAILURE;
     288                 : }
     289                 : 
     290                 : nsresult
     291               0 : nsSMILCSSValueType::ComputeDistance(const nsSMILValue& aFrom,
     292                 :                                     const nsSMILValue& aTo,
     293                 :                                     double& aDistance) const
     294                 : {
     295               0 :   NS_ABORT_IF_FALSE(aFrom.mType == aTo.mType,
     296                 :                     "Trying to compare different types");
     297               0 :   NS_ABORT_IF_FALSE(aFrom.mType == this, "Unexpected source type");
     298                 : 
     299               0 :   const ValueWrapper* fromWrapper = ExtractValueWrapper(aFrom);
     300               0 :   const ValueWrapper* toWrapper = ExtractValueWrapper(aTo);
     301               0 :   NS_ABORT_IF_FALSE(toWrapper, "expecting non-null endpoint");
     302                 : 
     303                 :   const nsStyleAnimation::Value* fromCSSValue = fromWrapper ?
     304               0 :     &fromWrapper->mCSSValue : nsnull;
     305               0 :   const nsStyleAnimation::Value* toCSSValue = &toWrapper->mCSSValue;
     306               0 :   if (!FinalizeStyleAnimationValues(fromCSSValue, toCSSValue)) {
     307               0 :     return NS_ERROR_FAILURE;
     308                 :   }
     309                 : 
     310                 :   return nsStyleAnimation::ComputeDistance(toWrapper->mPropID,
     311                 :                                            *fromCSSValue, *toCSSValue,
     312               0 :                                            aDistance) ?
     313               0 :     NS_OK : NS_ERROR_FAILURE;
     314                 : }
     315                 : 
     316                 : nsresult
     317               0 : nsSMILCSSValueType::Interpolate(const nsSMILValue& aStartVal,
     318                 :                                 const nsSMILValue& aEndVal,
     319                 :                                 double aUnitDistance,
     320                 :                                 nsSMILValue& aResult) const
     321                 : {
     322               0 :   NS_ABORT_IF_FALSE(aStartVal.mType == aEndVal.mType,
     323                 :                     "Trying to interpolate different types");
     324               0 :   NS_ABORT_IF_FALSE(aStartVal.mType == this,
     325                 :                     "Unexpected types for interpolation");
     326               0 :   NS_ABORT_IF_FALSE(aResult.mType == this, "Unexpected result type");
     327               0 :   NS_ABORT_IF_FALSE(aUnitDistance >= 0.0 && aUnitDistance <= 1.0,
     328                 :                     "unit distance value out of bounds");
     329               0 :   NS_ABORT_IF_FALSE(!aResult.mU.mPtr, "expecting barely-initialized outparam");
     330                 : 
     331               0 :   const ValueWrapper* startWrapper = ExtractValueWrapper(aStartVal);
     332               0 :   const ValueWrapper* endWrapper = ExtractValueWrapper(aEndVal);
     333               0 :   NS_ABORT_IF_FALSE(endWrapper, "expecting non-null endpoint");
     334                 : 
     335                 :   const nsStyleAnimation::Value* startCSSValue = startWrapper ?
     336               0 :     &startWrapper->mCSSValue : nsnull;
     337               0 :   const nsStyleAnimation::Value* endCSSValue = &endWrapper->mCSSValue;
     338               0 :   if (!FinalizeStyleAnimationValues(startCSSValue, endCSSValue)) {
     339               0 :     return NS_ERROR_FAILURE;
     340                 :   }
     341                 : 
     342               0 :   nsStyleAnimation::Value resultValue;
     343               0 :   if (nsStyleAnimation::Interpolate(endWrapper->mPropID,
     344                 :                                     *startCSSValue, *endCSSValue,
     345               0 :                                     aUnitDistance, resultValue)) {
     346                 :     aResult.mU.mPtr = new ValueWrapper(endWrapper->mPropID, resultValue,
     347               0 :                                        endWrapper->mPresContext);
     348               0 :     return NS_OK;
     349                 :   }
     350               0 :   return NS_ERROR_FAILURE;
     351                 : }
     352                 : 
     353                 : // Helper function to extract presContext
     354                 : static nsPresContext*
     355               0 : GetPresContextForElement(Element* aElem)
     356                 : {
     357               0 :   nsIDocument* doc = aElem->GetCurrentDoc();
     358               0 :   if (!doc) {
     359                 :     // This can happen if we process certain types of restyles mid-sample
     360                 :     // and remove anonymous animated content from the document as a result.
     361                 :     // See bug 534975.
     362               0 :     return nsnull;
     363                 :   }
     364               0 :   nsIPresShell* shell = doc->GetShell();
     365               0 :   return shell ? shell->GetPresContext() : nsnull;
     366                 : }
     367                 : 
     368                 : // Helper function to parse a string into a nsStyleAnimation::Value
     369                 : static bool
     370               0 : ValueFromStringHelper(nsCSSProperty aPropID,
     371                 :                       Element* aTargetElement,
     372                 :                       nsPresContext* aPresContext,
     373                 :                       const nsAString& aString,
     374                 :                       nsStyleAnimation::Value& aStyleAnimValue,
     375                 :                       bool* aIsContextSensitive)
     376                 : {
     377                 :   // If value is negative, we'll strip off the "-" so the CSS parser won't
     378                 :   // barf, and then manually make the parsed value negative.
     379                 :   // (This is a partial solution to let us accept some otherwise out-of-bounds
     380                 :   // CSS values. Bug 501188 will provide a more complete fix.)
     381               0 :   bool isNegative = false;
     382               0 :   PRUint32 subStringBegin = 0;
     383                 : 
     384                 :   // NOTE: We need to opt-out 'stroke-dasharray' from the negative-number
     385                 :   // check.  Its values might look negative (e.g. by starting with "-1"), but
     386                 :   // they're more complicated than our simple negation logic here can handle.
     387               0 :   if (aPropID != eCSSProperty_stroke_dasharray) {
     388               0 :     PRInt32 absValuePos = nsSMILParserUtils::CheckForNegativeNumber(aString);
     389               0 :     if (absValuePos > 0) {
     390               0 :       isNegative = true;
     391               0 :       subStringBegin = (PRUint32)absValuePos; // Start parsing after '-' sign
     392                 :     }
     393                 :   }
     394               0 :   nsDependentSubstring subString(aString, subStringBegin);
     395               0 :   if (!nsStyleAnimation::ComputeValue(aPropID, aTargetElement, subString,
     396                 :                                       true, aStyleAnimValue,
     397               0 :                                       aIsContextSensitive)) {
     398               0 :     return false;
     399                 :   }
     400               0 :   if (isNegative) {
     401               0 :     InvertSign(aStyleAnimValue);
     402                 :   }
     403                 :   
     404               0 :   if (aPropID == eCSSProperty_font_size) {
     405                 :     // Divide out text-zoom, since SVG is supposed to ignore it
     406               0 :     NS_ABORT_IF_FALSE(aStyleAnimValue.GetUnit() ==
     407                 :                         nsStyleAnimation::eUnit_Coord,
     408                 :                       "'font-size' value with unexpected style unit");
     409               0 :     aStyleAnimValue.SetCoordValue(aStyleAnimValue.GetCoordValue() /
     410               0 :                                   aPresContext->TextZoom());
     411                 :   }
     412               0 :   return true;
     413                 : }
     414                 : 
     415                 : // static
     416                 : void
     417               0 : nsSMILCSSValueType::ValueFromString(nsCSSProperty aPropID,
     418                 :                                     Element* aTargetElement,
     419                 :                                     const nsAString& aString,
     420                 :                                     nsSMILValue& aValue,
     421                 :                                     bool* aIsContextSensitive)
     422                 : {
     423               0 :   NS_ABORT_IF_FALSE(aValue.IsNull(), "Outparam should be null-typed");
     424               0 :   nsPresContext* presContext = GetPresContextForElement(aTargetElement);
     425               0 :   if (!presContext) {
     426               0 :     NS_WARNING("Not parsing animation value; unable to get PresContext");
     427               0 :     return;
     428                 :   }
     429                 : 
     430               0 :   nsStyleAnimation::Value parsedValue;
     431               0 :   if (ValueFromStringHelper(aPropID, aTargetElement, presContext,
     432                 :                             aString, parsedValue, aIsContextSensitive)) {
     433               0 :     sSingleton.Init(aValue);
     434               0 :     aValue.mU.mPtr = new ValueWrapper(aPropID, parsedValue, presContext);
     435                 :   }
     436                 : }
     437                 : 
     438                 : // static
     439                 : bool
     440               0 : nsSMILCSSValueType::ValueToString(const nsSMILValue& aValue,
     441                 :                                   nsAString& aString)
     442                 : {
     443               0 :   NS_ABORT_IF_FALSE(aValue.mType == &nsSMILCSSValueType::sSingleton,
     444                 :                     "Unexpected SMIL value type");
     445               0 :   const ValueWrapper* wrapper = ExtractValueWrapper(aValue);
     446                 :   return !wrapper ||
     447                 :     nsStyleAnimation::UncomputeValue(wrapper->mPropID, wrapper->mPresContext,
     448               0 :                                      wrapper->mCSSValue, aString);
     449            4392 : }

Generated by: LCOV version 1.7