LCOV - code coverage report
Current view: directory - content/svg/content/src - SVGTransformListSMILType.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 139 2 1.4 %
Date: 2012-06-02 Functions: 14 2 14.3 %

       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 SVG project.
      16                 :  *
      17                 :  * The Initial Developer of the Original Code is Brian Birtles.
      18                 :  * Portions created by the Initial Developer are Copyright (C) 2006
      19                 :  * the Initial Developer. All Rights Reserved.
      20                 :  *
      21                 :  * Contributor(s):
      22                 :  *   Brian Birtles <birtles@gmail.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                 : #include "SVGTransformListSMILType.h"
      39                 : #include "SVGTransform.h"
      40                 : #include "SVGTransformList.h"
      41                 : #include "nsSMILValue.h"
      42                 : #include "nsCRT.h"
      43                 : #include <math.h>
      44                 : 
      45                 : using namespace mozilla;
      46                 : 
      47            1464 : /*static*/ SVGTransformListSMILType SVGTransformListSMILType::sSingleton;
      48                 : 
      49                 : typedef nsTArray<SVGTransformSMILData> TransformArray;
      50                 : 
      51                 : //----------------------------------------------------------------------
      52                 : // nsISMILType implementation
      53                 : 
      54                 : void
      55               0 : SVGTransformListSMILType::Init(nsSMILValue &aValue) const
      56                 : {
      57               0 :   NS_PRECONDITION(aValue.IsNull(), "Unexpected value type");
      58                 : 
      59               0 :   TransformArray* transforms = new TransformArray(1);
      60               0 :   aValue.mU.mPtr = transforms;
      61               0 :   aValue.mType = this;
      62               0 : }
      63                 : 
      64                 : void
      65               0 : SVGTransformListSMILType::Destroy(nsSMILValue& aValue) const
      66                 : {
      67               0 :   NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
      68               0 :   TransformArray* params = static_cast<TransformArray*>(aValue.mU.mPtr);
      69               0 :   delete params;
      70               0 :   aValue.mU.mPtr = nsnull;
      71               0 :   aValue.mType = &nsSMILNullType::sSingleton;
      72               0 : }
      73                 : 
      74                 : nsresult
      75               0 : SVGTransformListSMILType::Assign(nsSMILValue& aDest,
      76                 :                                const nsSMILValue& aSrc) const
      77                 : {
      78               0 :   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
      79               0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
      80                 : 
      81                 :   const TransformArray* srcTransforms =
      82               0 :     static_cast<const TransformArray*>(aSrc.mU.mPtr);
      83               0 :   TransformArray* dstTransforms = static_cast<TransformArray*>(aDest.mU.mPtr);
      84                 : 
      85                 :   // Before we assign, ensure we have sufficient memory
      86               0 :   bool result = dstTransforms->SetCapacity(srcTransforms->Length());
      87               0 :   NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
      88                 : 
      89               0 :   *dstTransforms = *srcTransforms;
      90                 : 
      91               0 :   return NS_OK;
      92                 : }
      93                 : 
      94                 : bool
      95               0 : SVGTransformListSMILType::IsEqual(const nsSMILValue& aLeft,
      96                 :                                   const nsSMILValue& aRight) const
      97                 : {
      98               0 :   NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
      99               0 :   NS_PRECONDITION(aLeft.mType == this, "Unexpected SMIL type");
     100                 : 
     101                 :   const TransformArray& leftArr
     102               0 :     (*static_cast<const TransformArray*>(aLeft.mU.mPtr));
     103                 :   const TransformArray& rightArr
     104               0 :     (*static_cast<const TransformArray*>(aRight.mU.mPtr));
     105                 : 
     106                 :   // If array-lengths don't match, we're trivially non-equal.
     107               0 :   if (leftArr.Length() != rightArr.Length()) {
     108               0 :     return false;
     109                 :   }
     110                 : 
     111                 :   // Array-lengths match -- check each array-entry for equality.
     112               0 :   PRUint32 length = leftArr.Length(); // == rightArr->Length(), if we get here
     113               0 :   for (PRUint32 i = 0; i < length; ++i) {
     114               0 :     if (leftArr[i] != rightArr[i]) {
     115               0 :       return false;
     116                 :     }
     117                 :   }
     118                 : 
     119                 :   // Found no differences.
     120               0 :   return true;
     121                 : }
     122                 : 
     123                 : nsresult
     124               0 : SVGTransformListSMILType::Add(nsSMILValue& aDest,
     125                 :                               const nsSMILValue& aValueToAdd,
     126                 :                               PRUint32 aCount) const
     127                 : {
     128               0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
     129               0 :   NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types");
     130                 : 
     131               0 :   TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
     132                 :   const TransformArray& srcTransforms
     133               0 :     (*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
     134                 : 
     135                 :   // We're doing a simple add here (as opposed to a sandwich add below).
     136                 :   // We only do this when we're accumulating a repeat result or calculating
     137                 :   // a by-animation value.
     138                 :   //
     139                 :   // In either case we should have 1 transform in the source array.
     140               0 :   NS_ASSERTION(srcTransforms.Length() == 1,
     141                 :     "Invalid source transform list to add");
     142                 : 
     143                 :   // And we should have 0 or 1 transforms in the dest array.
     144                 :   // (We can have 0 transforms in the case of by-animation when we are
     145                 :   // calculating the by-value as "0 + by". Zero being represented by an
     146                 :   // nsSMILValue with an empty transform array.)
     147               0 :   NS_ASSERTION(dstTransforms.Length() < 2,
     148                 :     "Invalid dest transform list to add to");
     149                 : 
     150                 :   // Get the individual transforms to add
     151               0 :   const SVGTransformSMILData& srcTransform = srcTransforms[0];
     152               0 :   if (dstTransforms.IsEmpty()) {
     153                 :     SVGTransformSMILData* result = dstTransforms.AppendElement(
     154               0 :       SVGTransformSMILData(srcTransform.mTransformType));
     155               0 :     NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
     156                 :   }
     157               0 :   SVGTransformSMILData& dstTransform = dstTransforms[0];
     158                 : 
     159                 :   // The types must be the same
     160               0 :   NS_ASSERTION(srcTransform.mTransformType == dstTransform.mTransformType,
     161                 :     "Trying to perform simple add of different transform types");
     162                 : 
     163                 :   // And it should be impossible that one of them is of matrix type
     164               0 :   NS_ASSERTION(
     165                 :     srcTransform.mTransformType != nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX,
     166                 :     "Trying to perform simple add with matrix transform");
     167                 : 
     168                 :   // Add the parameters
     169               0 :   for (int i = 0; i <= 2; ++i) {
     170               0 :     dstTransform.mParams[i] += srcTransform.mParams[i] * aCount;
     171                 :   }
     172                 : 
     173               0 :   return NS_OK;
     174                 : }
     175                 : 
     176                 : nsresult
     177               0 : SVGTransformListSMILType::SandwichAdd(nsSMILValue& aDest,
     178                 :                                       const nsSMILValue& aValueToAdd) const
     179                 : {
     180               0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
     181               0 :   NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types");
     182                 : 
     183                 :   // For <animateTransform> a sandwich add means a matrix post-multiplication
     184                 :   // which just means to put the additional transform on the end of the array
     185                 : 
     186               0 :   TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
     187                 :   const TransformArray& srcTransforms
     188               0 :     (*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
     189                 : 
     190                 :   // We should have 0 or 1 transforms in the src list.
     191               0 :   NS_ASSERTION(srcTransforms.Length() < 2,
     192                 :     "Trying to do sandwich add of more than one value");
     193                 : 
     194                 :   // The empty src transform list case only occurs in some limited circumstances
     195                 :   // where we create an empty 'from' value to interpolate from (e.g.
     196                 :   // by-animation) but then skip the interpolation step for some reason (e.g.
     197                 :   // because we have an indefinite duration which means we'll never get past the
     198                 :   // first value) and instead attempt to add that empty value to the underlying
     199                 :   // value.
     200                 :   // In any case, the expected result is that nothing is added.
     201               0 :   if (srcTransforms.IsEmpty())
     202               0 :     return NS_OK;
     203                 : 
     204                 :   // Stick the src on the end of the array
     205               0 :   const SVGTransformSMILData& srcTransform = srcTransforms[0];
     206               0 :   SVGTransformSMILData* result = dstTransforms.AppendElement(srcTransform);
     207               0 :   NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY);
     208                 : 
     209               0 :   return NS_OK;
     210                 : }
     211                 : 
     212                 : nsresult
     213               0 : SVGTransformListSMILType::ComputeDistance(const nsSMILValue& aFrom,
     214                 :                                           const nsSMILValue& aTo,
     215                 :                                           double& aDistance) const
     216                 : {
     217               0 :   NS_PRECONDITION(aFrom.mType == aTo.mType,
     218                 :       "Can't compute difference between different SMIL types");
     219               0 :   NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
     220                 : 
     221                 :   const TransformArray* fromTransforms =
     222               0 :     static_cast<const TransformArray*>(aFrom.mU.mPtr);
     223                 :   const TransformArray* toTransforms =
     224               0 :     static_cast<const TransformArray*>(aTo.mU.mPtr);
     225                 : 
     226                 :   // ComputeDistance is only used for calculating distances between single
     227                 :   // values in a values array which necessarily have the same type
     228                 :   //
     229                 :   // So we should only have one transform in each array and they should be of
     230                 :   // the same type
     231               0 :   NS_ASSERTION(fromTransforms->Length() == 1,
     232                 :     "Wrong number of elements in from value");
     233               0 :   NS_ASSERTION(toTransforms->Length() == 1,
     234                 :     "Wrong number of elements in to value");
     235                 : 
     236               0 :   const SVGTransformSMILData& fromTransform = (*fromTransforms)[0];
     237               0 :   const SVGTransformSMILData& toTransform = (*toTransforms)[0];
     238               0 :   NS_ASSERTION(fromTransform.mTransformType == toTransform.mTransformType,
     239                 :     "Incompatible transform types to calculate distance between");
     240                 : 
     241               0 :   switch (fromTransform.mTransformType)
     242                 :   {
     243                 :     // We adopt the SVGT1.2 notions of distance here
     244                 :     // See: http://www.w3.org/TR/SVGTiny12/animate.html#complexDistances
     245                 :     // (As discussed in bug #469040)
     246                 :     case nsIDOMSVGTransform::SVG_TRANSFORM_TRANSLATE:
     247                 :     case nsIDOMSVGTransform::SVG_TRANSFORM_SCALE:
     248                 :       {
     249               0 :         const float& a_tx = fromTransform.mParams[0];
     250               0 :         const float& a_ty = fromTransform.mParams[1];
     251               0 :         const float& b_tx = toTransform.mParams[0];
     252               0 :         const float& b_ty = toTransform.mParams[1];
     253               0 :         aDistance = sqrt(pow(a_tx - b_tx, 2) + (pow(a_ty - b_ty, 2)));
     254                 :       }
     255               0 :       break;
     256                 : 
     257                 :     case nsIDOMSVGTransform::SVG_TRANSFORM_ROTATE:
     258                 :     case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWX:
     259                 :     case nsIDOMSVGTransform::SVG_TRANSFORM_SKEWY:
     260                 :       {
     261               0 :         const float& a = fromTransform.mParams[0];
     262               0 :         const float& b = toTransform.mParams[0];
     263               0 :         aDistance = fabs(a-b);
     264                 :       }
     265               0 :       break;
     266                 : 
     267                 :     default:
     268               0 :       NS_ERROR("Got bad transform types for calculating distances");
     269               0 :       aDistance = 1.0;
     270               0 :       return NS_ERROR_FAILURE;
     271                 :   }
     272                 : 
     273               0 :   return NS_OK;
     274                 : }
     275                 : 
     276                 : nsresult
     277               0 : SVGTransformListSMILType::Interpolate(const nsSMILValue& aStartVal,
     278                 :                                       const nsSMILValue& aEndVal,
     279                 :                                       double aUnitDistance,
     280                 :                                       nsSMILValue& aResult) const
     281                 : {
     282               0 :   NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
     283                 :       "Can't interpolate between different SMIL types");
     284               0 :   NS_PRECONDITION(aStartVal.mType == this,
     285                 :       "Unexpected type for interpolation");
     286               0 :   NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
     287                 : 
     288                 :   const TransformArray& startTransforms =
     289               0 :     (*static_cast<const TransformArray*>(aStartVal.mU.mPtr));
     290                 :   const TransformArray& endTransforms
     291               0 :     (*static_cast<const TransformArray*>(aEndVal.mU.mPtr));
     292                 : 
     293                 :   // We may have 0..n transforms in the start transform array (the base
     294                 :   // value) but we should only have 1 transform in the end transform array
     295               0 :   NS_ASSERTION(endTransforms.Length() == 1,
     296                 :     "Invalid end-point for interpolating between transform values");
     297                 : 
     298                 :   // The end point should never be a matrix transform
     299               0 :   const SVGTransformSMILData& endTransform = endTransforms[0];
     300               0 :   NS_ASSERTION(
     301                 :     endTransform.mTransformType != nsIDOMSVGTransform::SVG_TRANSFORM_MATRIX,
     302                 :     "End point for interpolation should not be a matrix transform");
     303                 : 
     304                 :   // If we have 0 or more than 1 transform in the start transform array then we
     305                 :   // just interpolate from 0, 0, 0
     306                 :   // Likewise, even if there's only 1 transform in the start transform array
     307                 :   // then if the type of the start transform doesn't match the end then we
     308                 :   // can't interpolate and should just use 0, 0, 0
     309                 :   static float identityParams[3] = { 0.f };
     310               0 :   const float* startParams = nsnull;
     311               0 :   if (startTransforms.Length() == 1) {
     312               0 :     const SVGTransformSMILData& startTransform = startTransforms[0];
     313               0 :     if (startTransform.mTransformType == endTransform.mTransformType) {
     314               0 :       startParams = startTransform.mParams;
     315                 :     }
     316                 :   }
     317               0 :   if (!startParams) {
     318               0 :     startParams = identityParams;
     319                 :   }
     320                 : 
     321               0 :   const float* endParams = endTransform.mParams;
     322                 : 
     323                 :   // Interpolate between the params
     324                 :   float newParams[3];
     325               0 :   for (int i = 0; i <= 2; ++i) {
     326               0 :     const float& a = startParams[i];
     327               0 :     const float& b = endParams[i];
     328               0 :     newParams[i] = static_cast<float>(a + (b - a) * aUnitDistance);
     329                 :   }
     330                 : 
     331                 :   // Make the result
     332               0 :   SVGTransformSMILData resultTransform(endTransform.mTransformType, newParams);
     333                 : 
     334                 :   // Clear the way for it in the result array
     335                 :   TransformArray& dstTransforms =
     336               0 :     (*static_cast<TransformArray*>(aResult.mU.mPtr));
     337               0 :   dstTransforms.Clear();
     338                 : 
     339                 :   // Assign the result
     340                 :   SVGTransformSMILData* transform =
     341               0 :     dstTransforms.AppendElement(resultTransform);
     342               0 :   NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY);
     343                 : 
     344               0 :   return NS_OK;
     345                 : }
     346                 : 
     347                 : //----------------------------------------------------------------------
     348                 : // Transform array accessors
     349                 : 
     350                 : // static
     351                 : nsresult
     352               0 : SVGTransformListSMILType::AppendTransform(
     353                 :   const SVGTransformSMILData& aTransform,
     354                 :   nsSMILValue& aValue)
     355                 : {
     356               0 :   NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
     357                 : 
     358               0 :   TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
     359               0 :   return transforms.AppendElement(aTransform) ?
     360               0 :     NS_OK : NS_ERROR_OUT_OF_MEMORY;
     361                 : }
     362                 : 
     363                 : // static
     364                 : bool
     365               0 : SVGTransformListSMILType::AppendTransforms(const SVGTransformList& aList,
     366                 :                                            nsSMILValue& aValue)
     367                 : {
     368               0 :   NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
     369                 : 
     370               0 :   TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
     371                 : 
     372               0 :   if (!transforms.SetCapacity(transforms.Length() + aList.Length()))
     373               0 :     return false;
     374                 : 
     375               0 :   for (PRUint32 i = 0; i < aList.Length(); ++i) {
     376                 :     // No need to check the return value below since we have already allocated
     377                 :     // the necessary space
     378               0 :     transforms.AppendElement(SVGTransformSMILData(aList[i]));
     379                 :   }
     380               0 :   return true;
     381                 : }
     382                 : 
     383                 : // static
     384                 : bool
     385               0 : SVGTransformListSMILType::GetTransforms(const nsSMILValue& aValue,
     386                 :                                         nsTArray<SVGTransform>& aTransforms)
     387                 : {
     388               0 :   NS_PRECONDITION(aValue.mType == &sSingleton, "Unexpected SMIL value type");
     389                 : 
     390                 :   const TransformArray& smilTransforms =
     391               0 :     *static_cast<const TransformArray*>(aValue.mU.mPtr);
     392                 : 
     393               0 :   aTransforms.Clear();
     394               0 :   if (!aTransforms.SetCapacity(smilTransforms.Length()))
     395               0 :       return false;
     396                 : 
     397               0 :   for (PRUint32 i = 0; i < smilTransforms.Length(); ++i) {
     398                 :     // No need to check the return value below since we have already allocated
     399                 :     // the necessary space
     400               0 :     aTransforms.AppendElement(smilTransforms[i].ToSVGTransform());
     401                 :   }
     402               0 :   return true;
     403            4392 : }

Generated by: LCOV version 1.7