LCOV - code coverage report
Current view: top level - dom/svg - nsSVGAnimatedTransformList.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 15 125 12.0 %
Date: 2017-07-14 16:53:18 Functions: 4 15 26.7 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsSVGAnimatedTransformList.h"
       8             : 
       9             : #include "mozilla/dom/SVGAnimatedTransformList.h"
      10             : #include "mozilla/dom/SVGAnimationElement.h"
      11             : #include "mozilla/Move.h"
      12             : #include "nsCharSeparatedTokenizer.h"
      13             : #include "nsSVGTransform.h"
      14             : #include "nsSMILValue.h"
      15             : #include "SVGContentUtils.h"
      16             : #include "SVGTransformListSMILType.h"
      17             : #include "nsIDOMMutationEvent.h"
      18             : 
      19             : namespace mozilla {
      20             : 
      21             : using namespace dom;
      22             : 
      23             : nsresult
      24           7 : nsSVGAnimatedTransformList::SetBaseValueString(const nsAString& aValue)
      25             : {
      26          14 :   SVGTransformList newBaseValue;
      27           7 :   nsresult rv = newBaseValue.SetValueFromString(aValue);
      28           7 :   if (NS_FAILED(rv)) {
      29           0 :     return rv;
      30             :   }
      31             : 
      32           7 :   return SetBaseValue(newBaseValue);
      33             : }
      34             : 
      35             : nsresult
      36           7 : nsSVGAnimatedTransformList::SetBaseValue(const SVGTransformList& aValue)
      37             : {
      38             :   SVGAnimatedTransformList *domWrapper =
      39           7 :     SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
      40           7 :   if (domWrapper) {
      41             :     // We must send this notification *before* changing mBaseVal! If the length
      42             :     // of our baseVal is being reduced, our baseVal's DOM wrapper list may have
      43             :     // to remove DOM items from itself, and any removed DOM items need to copy
      44             :     // their internal counterpart values *before* we change them.
      45             :     //
      46           0 :     domWrapper->InternalBaseValListWillChangeLengthTo(aValue.Length());
      47             :   }
      48             : 
      49             :   // (This bool will be copied to our member-var, if attr-change succeeds.)
      50           7 :   bool hadTransform = HasTransform();
      51             : 
      52             :   // We don't need to call DidChange* here - we're only called by
      53             :   // nsSVGElement::ParseAttribute under Element::SetAttr,
      54             :   // which takes care of notifying.
      55             : 
      56           7 :   nsresult rv = mBaseVal.CopyFrom(aValue);
      57           7 :   if (NS_FAILED(rv) && domWrapper) {
      58             :     // Attempting to increase mBaseVal's length failed - reduce domWrapper
      59             :     // back to the same length:
      60           0 :     domWrapper->InternalBaseValListWillChangeLengthTo(mBaseVal.Length());
      61             :   } else {
      62           7 :     mIsAttrSet = true;
      63           7 :     mHadTransformBeforeLastBaseValChange = hadTransform;
      64             :   }
      65           7 :   return rv;
      66             : }
      67             : 
      68             : void
      69           0 : nsSVGAnimatedTransformList::ClearBaseValue()
      70             : {
      71           0 :   mHadTransformBeforeLastBaseValChange = HasTransform();
      72             : 
      73             :   SVGAnimatedTransformList *domWrapper =
      74           0 :     SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
      75           0 :   if (domWrapper) {
      76             :     // We must send this notification *before* changing mBaseVal! (See above.)
      77           0 :     domWrapper->InternalBaseValListWillChangeLengthTo(0);
      78             :   }
      79           0 :   mBaseVal.Clear();
      80           0 :   mIsAttrSet = false;
      81             :   // Caller notifies
      82           0 : }
      83             : 
      84             : nsresult
      85           0 : nsSVGAnimatedTransformList::SetAnimValue(const SVGTransformList& aValue,
      86             :                                          nsSVGElement *aElement)
      87             : {
      88           0 :   bool prevSet = HasTransform() || aElement->GetAnimateMotionTransform();
      89             :   SVGAnimatedTransformList *domWrapper =
      90           0 :     SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
      91           0 :   if (domWrapper) {
      92             :     // A new animation may totally change the number of items in the animVal
      93             :     // list, replacing what was essentially a mirror of the baseVal list, or
      94             :     // else replacing and overriding an existing animation. When this happens
      95             :     // we must try and keep our animVal's DOM wrapper in sync (see the comment
      96             :     // in SVGAnimatedTransformList::InternalBaseValListWillChangeLengthTo).
      97             :     //
      98             :     // It's not possible for us to reliably distinguish between calls to this
      99             :     // method that are setting a new sample for an existing animation, and
     100             :     // calls that are setting the first sample of an animation that will
     101             :     // override an existing animation. Happily it's cheap to just blindly
     102             :     // notify our animVal's DOM wrapper of its internal counterpart's new value
     103             :     // each time this method is called, so that's what we do.
     104             :     //
     105             :     // Note that we must send this notification *before* setting or changing
     106             :     // mAnimVal! (See the comment in SetBaseValueString above.)
     107             :     //
     108           0 :     domWrapper->InternalAnimValListWillChangeLengthTo(aValue.Length());
     109             :   }
     110           0 :   if (!mAnimVal) {
     111           0 :     mAnimVal = new SVGTransformList();
     112             :   }
     113           0 :   nsresult rv = mAnimVal->CopyFrom(aValue);
     114           0 :   if (NS_FAILED(rv)) {
     115             :     // OOM. We clear the animation, and, importantly, ClearAnimValue() ensures
     116             :     // that mAnimVal and its DOM wrapper (if any) will have the same length!
     117           0 :     ClearAnimValue(aElement);
     118           0 :     return rv;
     119             :   }
     120             :   int32_t modType;
     121           0 :   if(prevSet) {
     122           0 :     modType = nsIDOMMutationEvent::MODIFICATION;
     123             :   } else {
     124           0 :     modType = nsIDOMMutationEvent::ADDITION;
     125             :   }
     126           0 :   aElement->DidAnimateTransformList(modType);
     127           0 :   return NS_OK;
     128             : }
     129             : 
     130             : void
     131           0 : nsSVGAnimatedTransformList::ClearAnimValue(nsSVGElement *aElement)
     132             : {
     133             :   SVGAnimatedTransformList *domWrapper =
     134           0 :     SVGAnimatedTransformList::GetDOMWrapperIfExists(this);
     135           0 :   if (domWrapper) {
     136             :     // When all animation ends, animVal simply mirrors baseVal, which may have
     137             :     // a different number of items to the last active animated value. We must
     138             :     // keep the length of our animVal's DOM wrapper list in sync, and again we
     139             :     // must do that before touching mAnimVal. See comments above.
     140             :     //
     141           0 :     domWrapper->InternalAnimValListWillChangeLengthTo(mBaseVal.Length());
     142             :   }
     143           0 :   mAnimVal = nullptr;
     144             :   int32_t modType;
     145           0 :   if (HasTransform() || aElement->GetAnimateMotionTransform()) {
     146           0 :     modType = nsIDOMMutationEvent::MODIFICATION;
     147             :   } else {
     148           0 :     modType = nsIDOMMutationEvent::REMOVAL;
     149             :   }
     150           0 :   aElement->DidAnimateTransformList(modType);
     151           0 : }
     152             : 
     153             : bool
     154           0 : nsSVGAnimatedTransformList::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             : UniquePtr<nsISMILAttr>
     171           0 : nsSVGAnimatedTransformList::ToSMILAttr(nsSVGElement* aSVGElement)
     172             : {
     173           0 :   return MakeUnique<SMILAnimatedTransformList>(this, aSVGElement);
     174             : }
     175             : 
     176             : nsresult
     177           0 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::ValueFromString(
     178             :   const nsAString& aStr,
     179             :   const dom::SVGAnimationElement* aSrcElement,
     180             :   nsSMILValue& aValue,
     181             :   bool& aPreventCachingOfSandwich) const
     182             : {
     183           0 :   NS_ENSURE_TRUE(aSrcElement, NS_ERROR_FAILURE);
     184           0 :   MOZ_ASSERT(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 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseValue(
     206             :   const nsAString& aSpec,
     207             :   const nsIAtom* aTransformType,
     208             :   nsSMILValue& aResult)
     209             : {
     210           0 :   MOZ_ASSERT(aResult.IsNull(), "Unexpected type for SMIL value");
     211             : 
     212             :   static_assert(SVGTransformSMILData::NUM_SIMPLE_PARAMS == 3,
     213             :                 "nsSVGSMILTransform constructor should be expecting array "
     214             :                 "with 3 params");
     215             : 
     216           0 :   float params[3] = { 0.f };
     217           0 :   int32_t numParsed = ParseParameterList(aSpec, params, 3);
     218             :   uint16_t transformType;
     219             : 
     220           0 :   if (aTransformType == nsGkAtoms::translate) {
     221             :     // tx [ty=0]
     222           0 :     if (numParsed != 1 && numParsed != 2)
     223           0 :       return;
     224           0 :     transformType = SVG_TRANSFORM_TRANSLATE;
     225           0 :   } else if (aTransformType == nsGkAtoms::scale) {
     226             :     // sx [sy=sx]
     227           0 :     if (numParsed != 1 && numParsed != 2)
     228           0 :       return;
     229           0 :     if (numParsed == 1) {
     230           0 :       params[1] = params[0];
     231             :     }
     232           0 :     transformType = SVG_TRANSFORM_SCALE;
     233           0 :   } else if (aTransformType == nsGkAtoms::rotate) {
     234             :     // r [cx=0 cy=0]
     235           0 :     if (numParsed != 1 && numParsed != 3)
     236           0 :       return;
     237           0 :     transformType = SVG_TRANSFORM_ROTATE;
     238           0 :   } else if (aTransformType == nsGkAtoms::skewX) {
     239             :     // x-angle
     240           0 :     if (numParsed != 1)
     241           0 :       return;
     242           0 :     transformType = SVG_TRANSFORM_SKEWX;
     243           0 :   } else if (aTransformType == nsGkAtoms::skewY) {
     244             :     // y-angle
     245           0 :     if (numParsed != 1)
     246           0 :       return;
     247           0 :     transformType = SVG_TRANSFORM_SKEWY;
     248             :   } else {
     249           0 :     return;
     250             :   }
     251             : 
     252           0 :   nsSMILValue val(SVGTransformListSMILType::Singleton());
     253           0 :   SVGTransformSMILData transform(transformType, params);
     254           0 :   if (NS_FAILED(SVGTransformListSMILType::AppendTransform(transform, val))) {
     255           0 :     return; // OOM
     256             :   }
     257             : 
     258             :   // Success! Populate our outparam with parsed value.
     259           0 :   aResult = Move(val);
     260             : }
     261             : 
     262             : int32_t
     263           0 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::ParseParameterList(
     264             :   const nsAString& aSpec,
     265             :   float* aVars,
     266             :   int32_t aNVars)
     267             : {
     268             :   nsCharSeparatedTokenizerTemplate<IsSVGWhitespace>
     269           0 :     tokenizer(aSpec, ',', nsCharSeparatedTokenizer::SEPARATOR_OPTIONAL);
     270             : 
     271           0 :   int numArgsFound = 0;
     272             : 
     273           0 :   while (tokenizer.hasMoreTokens()) {
     274             :     float f;
     275           0 :     if (!SVGContentUtils::ParseNumber(tokenizer.nextToken(), f)) {
     276           0 :       return -1;
     277             :     }
     278           0 :     if (numArgsFound < aNVars) {
     279           0 :       aVars[numArgsFound] = f;
     280             :     }
     281           0 :     numArgsFound++;
     282             :   }
     283           0 :   return numArgsFound;
     284             : }
     285             : 
     286             : nsSMILValue
     287           0 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::GetBaseValue() const
     288             : {
     289             :   // To benefit from Return Value Optimization and avoid copy constructor calls
     290             :   // due to our use of return-by-value, we must return the exact same object
     291             :   // from ALL return points. This function must only return THIS variable:
     292           0 :   nsSMILValue val(SVGTransformListSMILType::Singleton());
     293           0 :   if (!SVGTransformListSMILType::AppendTransforms(mVal->mBaseVal, val)) {
     294           0 :     val = nsSMILValue();
     295             :   }
     296             : 
     297           0 :   return val;
     298             : }
     299             : 
     300             : nsresult
     301           0 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::SetAnimValue(
     302             :   const nsSMILValue& aNewAnimValue)
     303             : {
     304           0 :   MOZ_ASSERT(aNewAnimValue.mType == SVGTransformListSMILType::Singleton(),
     305             :              "Unexpected type to assign animated value");
     306           0 :   SVGTransformList animVal;
     307           0 :   if (!SVGTransformListSMILType::GetTransforms(aNewAnimValue,
     308             :                                                animVal.mItems)) {
     309           0 :     return NS_ERROR_FAILURE;
     310             :   }
     311             : 
     312           0 :   return mVal->SetAnimValue(animVal, mElement);
     313             : }
     314             : 
     315             : void
     316           0 : nsSVGAnimatedTransformList::SMILAnimatedTransformList::ClearAnimValue()
     317             : {
     318           0 :   if (mVal->mAnimVal) {
     319           0 :     mVal->ClearAnimValue(mElement);
     320             :   }
     321           0 : }
     322             : 
     323           9 : } // namespace mozilla

Generated by: LCOV version 1.13