LCOV - code coverage report
Current view: directory - content/svg/content/src - SVGAnimatedTransformList.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 126 0 0.0 %
Date: 2012-06-02 Functions: 13 0 0.0 %

       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 Mozilla SVG Project code.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is the Mozilla Foundation.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2011
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *
      23                 :  * Alternatively, the contents of this file may be used under the terms of
      24                 :  * either the GNU General Public License Version 2 or later (the "GPL"), or
      25                 :  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
      26                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
      27                 :  * of those above. If you wish to allow use of your version of this file only
      28                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
      29                 :  * use your version of this file under the terms of the MPL, indicate your
      30                 :  * decision by deleting the provisions above and replace them with the notice
      31                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
      32                 :  * the provisions above, a recipient may use your version of this file under
      33                 :  * the terms of any one of the MPL, the GPL or the LGPL.
      34                 :  *
      35                 :  * ***** END LICENSE BLOCK ***** */
      36                 : 
      37                 : #include "SVGAnimatedTransformList.h"
      38                 : #include "DOMSVGAnimatedTransformList.h"
      39                 : 
      40                 : #include "nsSMILValue.h"
      41                 : #include "SVGTransform.h"
      42                 : #include "SVGTransformListSMILType.h"
      43                 : #include "nsSVGUtils.h"
      44                 : #include "prdtoa.h"
      45                 : 
      46                 : namespace mozilla {
      47                 : 
      48                 : nsresult
      49               0 : SVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
      50                 : {
      51               0 :   SVGTransformList newBaseValue;
      52               0 :   nsresult rv = newBaseValue.SetValueFromString(aValue);
      53               0 :   if (NS_FAILED(rv)) {
      54               0 :     return rv;
      55                 :   }
      56                 : 
      57                 :   DOMSVGAnimatedTransformList *domWrapper =
      58               0 :     DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
      59               0 :   if (domWrapper) {
      60                 :     // We must send this notification *before* changing mBaseVal! If the length
      61                 :     // of our baseVal is being reduced, our baseVal's DOM wrapper list may have
      62                 :     // to remove DOM items from itself, and any removed DOM items need to copy
      63                 :     // their internal counterpart values *before* we change them.
      64                 :     //
      65               0 :     domWrapper->InternalBaseValListWillChangeLengthTo(newBaseValue.Length());
      66                 :   }
      67                 : 
      68                 :   // We don't need to call DidChange* here - we're only called by
      69                 :   // nsSVGElement::ParseAttribute under nsGenericElement::SetAttr,
      70                 :   // which takes care of notifying.
      71                 : 
      72               0 :   rv = mBaseVal.CopyFrom(newBaseValue);
      73               0 :   if (NS_FAILED(rv) && domWrapper) {
      74                 :     // Attempting to increase mBaseVal's length failed - reduce domWrapper
      75                 :     // back to the same length:
      76               0 :     domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
      77                 :   } else {
      78               0 :     mIsAttrSet = true;
      79                 :   }
      80               0 :   return rv;
      81                 : }
      82                 : 
      83                 : void
      84               0 : SVGAnimatedTransformList::ClearBaseValue()
      85                 : {
      86                 :   DOMSVGAnimatedTransformList *domWrapper =
      87               0 :     DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
      88               0 :   if (domWrapper) {
      89                 :     // We must send this notification *before* changing mBaseVal! (See above.)
      90               0 :     domWrapper->InternalBaseValListWillChangeLengthTo(0);
      91                 :   }
      92               0 :   mBaseVal.Clear();
      93               0 :   mIsAttrSet = false;
      94                 :   // Caller notifies
      95               0 : }
      96                 : 
      97                 : nsresult
      98               0 : SVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
      99                 :                                        nsSVGElement *aElement)
     100                 : {
     101                 :   DOMSVGAnimatedTransformList *domWrapper =
     102               0 :     DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
     103               0 :   if (domWrapper) {
     104                 :     // A new animation may totally change the number of items in the animVal
     105                 :     // list, replacing what was essentially a mirror of the baseVal list, or
     106                 :     // else replacing and overriding an existing animation. When this happens
     107                 :     // we must try and keep our animVal's DOM wrapper in sync (see the comment
     108                 :     // in DOMSVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
     109                 :     //
     110                 :     // It's not possible for us to reliably distinguish between calls to this
     111                 :     // method that are setting a new sample for an existing animation, and
     112                 :     // calls that are setting the first sample of an animation that will
     113                 :     // override an existing animation. Happily it's cheap to just blindly
     114                 :     // notify our animVal's DOM wrapper of its internal counterpart's new value
     115                 :     // each time this method is called, so that's what we do.
     116                 :     //
     117                 :     // Note that we must send this notification *before* setting or changing
     118                 :     // mAnimVal! (See the comment in SetBaseValueString above.)
     119                 :     //
     120               0 :     domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
     121                 :   }
     122               0 :   if (!mAnimVal) {
     123               0 :     mAnimVal = new SVGTransformList();
     124                 :   }
     125               0 :   nsresult rv = mAnimVal->CopyFrom(aValue);
     126               0 :   if (NS_FAILED(rv)) {
     127                 :     // OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
     128                 :     // that mAnimVal and its DOM wrapper (if any) will have the same length!
     129               0 :     ClearAnimValue(aElement);
     130               0 :     return rv;
     131                 :   }
     132               0 :   aElement->DidAnimateTransformList();
     133               0 :   return NS_OK;
     134                 : }
     135                 : 
     136                 : void
     137               0 : SVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
     138                 : {
     139                 :   DOMSVGAnimatedTransformList *domWrapper =
     140               0 :     DOMSVGAnimatedTransformList::GetDOMWrapperIfExists(this);
     141               0 :   if (domWrapper) {
     142                 :     // When all animation ends, animVal simply mirrors baseVal, which may have
     143                 :     // a different number of items to the last active animated value. We must
     144                 :     // keep the length of our animVal's DOM wrapper list in sync, and again we
     145                 :     // must do that before touching mAnimVal. See comments above.
     146                 :     //
     147               0 :     domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
     148                 :   }
     149               0 :   mAnimVal = nsnull;
     150               0 :   aElement->DidAnimateTransformList();
     151               0 : }
     152                 : 
     153                 : bool
     154               0 : SVGAnimatedTransformList::IsExplicitlySet() const
     155                 : {
     156                 :   // Like other methods of this name, we need to know when a transform value has
     157                 :   // been explicitly set.
     158                 :   //
     159                 :   // There are three ways an animated list can become set:
     160                 :   // 1) Markup -- we set mIsAttrSet to true on any successful call to
     161                 :   //    SetBaseValueString and clear it on ClearBaseValue (as called by
     162                 :   //    nsSVGElement::UnsetAttr or a failed nsSVGElement::ParseAttribute)
     163                 :   // 2) DOM call -- simply fetching the baseVal doesn't mean the transform value
     164                 :   //    has been set. It is set if that baseVal has one or more transforms in
     165                 :   //    the list.
     166                 :   // 3) Animation -- which will cause the mAnimVal member to be allocated
     167               0 :   return mIsAttrSet || !mBaseVal.IsEmpty() || mAnimVal;
     168                 : }
     169                 : 
     170                 : nsISMILAttr*
     171               0 : SVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
     172                 : {
     173               0 :   return new SMILAnimatedTransformList(this, aSVGElement);
     174                 : }
     175                 : 
     176                 : nsresult
     177               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
     178                 :   const nsAString& aStr,
     179                 :   const nsISMILAnimationElement* aSrcElement,
     180                 :   nsSMILValue& aValue,
     181                 :   bool& aPreventCachingOfSandwich) const
     182                 : {
     183               0 :   NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
     184               0 :   NS_ABORT_IF_FALSE(aValue.IsNull(),
     185                 :     "aValue should have been cleared before calling ValueFromString");
     186                 : 
     187               0 :   const nsAttrValue* typeAttr = aSrcElement->GetAnimAttr(nsGkAtoms::type);
     188               0 :   const nsIAtom* transformType = nsGkAtoms::translate; // default val
     189               0 :   if (typeAttr) {
     190               0 :     if (typeAttr->Type() != nsAttrValue::eAtom) {
     191                 :       // Recognized values of |type| are parsed as an atom -- so if we have
     192                 :       // something other than an atom, then we know already our |type| is
     193                 :       // invalid.
     194               0 :       return NS_ERROR_FAILURE;
     195                 :     }
     196               0 :     transformType = typeAttr->GetAtomValue();
     197                 :   }
     198                 : 
     199               0 :   ParseValue(aStr, transformType, aValue);
     200               0 :   aPreventCachingOfSandwich = false;
     201               0 :   return aValue.IsNull() ? NS_ERROR_FAILURE : NS_OK;
     202                 : }
     203                 : 
     204                 : void
     205               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
     206                 :   const nsAString& aSpec,
     207                 :   const nsIAtom* aTransformType,
     208                 :   nsSMILValue& aResult)
     209                 : {
     210               0 :   NS_ABORT_IF_FALSE(aResult.IsNull(), "Unexpected type for SMIL value");
     211                 : 
     212                 :   // nsSVGSMILTransform constructor should be expecting array with 3 params
     213                 :   PR_STATIC_ASSERT(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3);
     214                 : 
     215               0 :   float params[3] = { 0.f };
     216               0 :   PRInt32 numParsed = ParseParameterList(aSpec, params, 3);
     217                 :   PRUint16 transformType;
     218                 : 
     219               0 :   if (aTransformType == nsGkAtoms::translate) {
     220                 :     // tx [ty=0]
     221               0 :     if (numParsed != 1 && numParsed != 2)
     222               0 :       return;
     223               0 :     transformType = nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE;
     224               0 :   } else if (aTransformType == nsGkAtoms::scale) {
     225                 :     // sx [sy=sx]
     226               0 :     if (numParsed != 1 && numParsed != 2)
     227               0 :       return;
     228               0 :     if (numParsed == 1) {
     229               0 :       params[1] = params[0];
     230                 :     }
     231               0 :     transformType = nsIDOMSVGTransform::SVG_TRANSFORM_SCALE;
     232               0 :   } else if (aTransformType == nsGkAtoms::rotate) {
     233                 :     // r [cx=0 cy=0]
     234               0 :     if (numParsed != 1 && numParsed != 3)
     235               0 :       return;
     236               0 :     transformType = nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE;
     237               0 :   } else if (aTransformType == nsGkAtoms::skewX) {
     238                 :     // x-angle
     239               0 :     if (numParsed != 1)
     240               0 :       return;
     241               0 :     transformType = nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX;
     242               0 :   } else if (aTransformType == nsGkAtoms::skewY) {
     243                 :     // y-angle
     244               0 :     if (numParsed != 1)
     245               0 :       return;
     246               0 :     transformType = nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY;
     247                 :   } else {
     248               0 :     return;
     249                 :   }
     250                 : 
     251               0 :   nsSMILValue val(&SVGTransformListSMILType::sSingleton);
     252               0 :   SVGTransformSMILData transform(transformType, params);
     253               0 :   if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
     254                 :     return; // OOM
     255                 :   }
     256                 : 
     257                 :   // Success! Populate our outparam with parsed value.
     258               0 :   aResult.Swap(val);
     259                 : }
     260                 : 
     261                 : namespace
     262                 : {
     263                 :   inline void
     264               0 :   SkipWsp(nsACString::const_iterator& aIter,
     265                 :           const nsACString::const_iterator& aIterEnd)
     266                 :   {
     267               0 :     while (aIter != aIterEnd && IsSVGWhitespace(*aIter))
     268               0 :       ++aIter;
     269               0 :   }
     270                 : } // end anonymous namespace block
     271                 : 
     272                 : PRInt32
     273               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
     274                 :   const nsAString& aSpec,
     275                 :   float* aVars,
     276                 :   PRInt32 aNVars)
     277                 : {
     278               0 :   NS_ConvertUTF16toUTF8 spec(aSpec);
     279                 : 
     280               0 :   nsACString::const_iterator start, end;
     281               0 :   spec.BeginReading(start);
     282               0 :   spec.EndReading(end);
     283                 : 
     284               0 :   SkipWsp(start, end);
     285                 : 
     286               0 :   int numArgsFound = 0;
     287                 : 
     288               0 :   while (start != end) {
     289               0 :     char const *arg = start.get();
     290                 :     char *argend;
     291               0 :     float f = float(PR_strtod(arg, &argend));
     292               0 :     if (arg == argend || argend > end.get() || !NS_finite(f))
     293               0 :       return -1;
     294                 : 
     295               0 :     if (numArgsFound < aNVars) {
     296               0 :       aVars[numArgsFound] = f;
     297                 :     }
     298                 : 
     299               0 :     start.advance(argend - arg);
     300               0 :     numArgsFound++;
     301                 : 
     302               0 :     SkipWsp(start, end);
     303               0 :     if (*start == ',') {
     304               0 :       ++start;
     305               0 :       SkipWsp(start, end);
     306                 :     }
     307                 :   }
     308                 : 
     309               0 :   return numArgsFound;
     310                 : }
     311                 : 
     312                 : nsSMILValue
     313               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
     314                 : {
     315                 :   // To benefit from Return Value Optimization and avoid copy constructor calls
     316                 :   // due to our use of return-by-value, we must return the exact same object
     317                 :   // from ALL return points. This function must only return THIS variable:
     318               0 :   nsSMILValue val(&SVGTransformListSMILType::sSingleton);
     319               0 :   if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
     320               0 :     val = nsSMILValue();
     321                 :   }
     322                 : 
     323                 :   return val;
     324                 : }
     325                 : 
     326                 : nsresult
     327               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
     328                 :   const nsSMILValue& aNewAnimValue)
     329                 : {
     330               0 :   NS_ABORT_IF_FALSE(
     331                 :     aNewAnimValue.mType == &SVGTransformListSMILType::sSingleton,
     332                 :     "Unexpected type to assign animated value");
     333               0 :   SVGTransformList animVal;
     334               0 :   if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
     335               0 :                                                animVal.mItems)) {
     336               0 :     return NS_ERROR_FAILURE;
     337                 :   }
     338                 : 
     339               0 :   return mVal->SetAnimValue(animVal, mElement);
     340                 : }
     341                 : 
     342                 : void
     343               0 : SVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
     344                 : {
     345               0 :   if (mVal->mAnimVal) {
     346               0 :     mVal->ClearAnimValue(mElement);
     347                 :   }
     348               0 : }
     349                 : 
     350                 : } // namespace mozilla

Generated by: LCOV version 1.7