LCOV - app.info - content/smil/nsSMILCSSValueType.cpp

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