LCOV - code coverage report
Current view: top level - dom/svg - SVGLengthListSMILType.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 119 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 7 0.0 %
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 "SVGLengthListSMILType.h"
       8             : #include "nsSMILValue.h"
       9             : #include "SVGLengthList.h"
      10             : #include "nsMathUtils.h"
      11             : #include "mozilla/FloatingPoint.h"
      12             : #include <math.h>
      13             : #include <algorithm>
      14             : 
      15             : namespace mozilla {
      16             : 
      17             : /*static*/ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
      18             : 
      19             : //----------------------------------------------------------------------
      20             : // nsISMILType implementation
      21             : 
      22             : void
      23           0 : SVGLengthListSMILType::Init(nsSMILValue &aValue) const
      24             : {
      25           0 :   MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
      26             : 
      27           0 :   SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();
      28             : 
      29             :   // See the comment documenting Init() in our header file:
      30           0 :   lengthList->SetCanZeroPadList(true);
      31             : 
      32           0 :   aValue.mU.mPtr = lengthList;
      33           0 :   aValue.mType = this;
      34           0 : }
      35             : 
      36             : void
      37           0 : SVGLengthListSMILType::Destroy(nsSMILValue& aValue) const
      38             : {
      39           0 :   NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
      40           0 :   delete static_cast<SVGLengthListAndInfo*>(aValue.mU.mPtr);
      41           0 :   aValue.mU.mPtr = nullptr;
      42           0 :   aValue.mType = nsSMILNullType::Singleton();
      43           0 : }
      44             : 
      45             : nsresult
      46           0 : SVGLengthListSMILType::Assign(nsSMILValue& aDest,
      47             :                               const nsSMILValue& aSrc) const
      48             : {
      49           0 :   NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
      50           0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
      51             : 
      52             :   const SVGLengthListAndInfo* src =
      53           0 :     static_cast<const SVGLengthListAndInfo*>(aSrc.mU.mPtr);
      54             :   SVGLengthListAndInfo* dest =
      55           0 :     static_cast<SVGLengthListAndInfo*>(aDest.mU.mPtr);
      56             : 
      57           0 :   return dest->CopyFrom(*src);
      58             : }
      59             : 
      60             : bool
      61           0 : SVGLengthListSMILType::IsEqual(const nsSMILValue& aLeft,
      62             :                                const nsSMILValue& aRight) const
      63             : {
      64           0 :   NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
      65           0 :   NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
      66             : 
      67           0 :   return *static_cast<const SVGLengthListAndInfo*>(aLeft.mU.mPtr) ==
      68           0 :          *static_cast<const SVGLengthListAndInfo*>(aRight.mU.mPtr);
      69             : }
      70             : 
      71             : nsresult
      72           0 : SVGLengthListSMILType::Add(nsSMILValue& aDest,
      73             :                            const nsSMILValue& aValueToAdd,
      74             :                            uint32_t aCount) const
      75             : {
      76           0 :   NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
      77           0 :   NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
      78             : 
      79             :   SVGLengthListAndInfo& dest =
      80           0 :     *static_cast<SVGLengthListAndInfo*>(aDest.mU.mPtr);
      81             :   const SVGLengthListAndInfo& valueToAdd =
      82           0 :     *static_cast<const SVGLengthListAndInfo*>(aValueToAdd.mU.mPtr);
      83             : 
      84             :   // To understand this code, see the comments documenting our Init() method,
      85             :   // and documenting SVGLengthListAndInfo::CanZeroPadList().
      86             : 
      87             :   // Note that *this* method actually may safely zero pad a shorter list
      88             :   // regardless of the value returned by CanZeroPadList() for that list,
      89             :   // just so long as the shorter list is being added *to* the longer list
      90             :   // and *not* vice versa! It's okay in the case of adding a shorter list to a
      91             :   // longer list because during the add operation we'll end up adding the
      92             :   // zeros to actual specified values. It's *not* okay in the case of adding a
      93             :   // longer list to a shorter list because then we end up adding to implicit
      94             :   // zeros when we'd actually need to add to whatever the underlying values
      95             :   // should be, not zeros, and those values are not explicit or otherwise
      96             :   // available.
      97             : 
      98           0 :   if (valueToAdd.IsIdentity()) { // Adding identity value - no-op
      99           0 :     return NS_OK;
     100             :   }
     101             : 
     102           0 :   if (dest.IsIdentity()) { // Adding *to* an identity value
     103           0 :     if (!dest.SetLength(valueToAdd.Length())) {
     104           0 :       return NS_ERROR_OUT_OF_MEMORY;
     105             :     }
     106           0 :     for (uint32_t i = 0; i < dest.Length(); ++i) {
     107           0 :       dest[i].SetValueAndUnit(valueToAdd[i].GetValueInCurrentUnits() * aCount,
     108           0 :                               valueToAdd[i].GetUnit());
     109             :     }
     110           0 :     dest.SetInfo(valueToAdd.Element(), valueToAdd.Axis(),
     111           0 :                  valueToAdd.CanZeroPadList()); // propagate target element info!
     112           0 :     return NS_OK;
     113             :   }
     114           0 :   MOZ_ASSERT(dest.Element() == valueToAdd.Element(),
     115             :              "adding values from different elements...?");
     116             : 
     117             :   // Zero-pad our |dest| list, if necessary.
     118           0 :   if (dest.Length() < valueToAdd.Length()) {
     119           0 :     if (!dest.CanZeroPadList()) {
     120             :       // SVGContentUtils::ReportToConsole
     121           0 :       return NS_ERROR_FAILURE;
     122             :     }
     123             : 
     124           0 :     MOZ_ASSERT(valueToAdd.CanZeroPadList(),
     125             :                "values disagree about attribute's zero-paddibility");
     126             : 
     127           0 :     uint32_t i = dest.Length();
     128           0 :     if (!dest.SetLength(valueToAdd.Length())) {
     129           0 :       return NS_ERROR_OUT_OF_MEMORY;
     130             :     }
     131           0 :     for (; i < valueToAdd.Length(); ++i) {
     132           0 :       dest[i].SetValueAndUnit(0.0f, valueToAdd[i].GetUnit());
     133             :     }
     134             :   }
     135             : 
     136           0 :   for (uint32_t i = 0; i < valueToAdd.Length(); ++i) {
     137             :     float valToAdd;
     138           0 :     if (dest[i].GetUnit() == valueToAdd[i].GetUnit()) {
     139           0 :       valToAdd = valueToAdd[i].GetValueInCurrentUnits();
     140             :     } else {
     141             :       // If units differ, we use the unit of the item in 'dest'.
     142             :       // We leave it to the frame code to check that values are finite.
     143           0 :       valToAdd = valueToAdd[i].GetValueInSpecifiedUnit(dest[i].GetUnit(),
     144           0 :                                                        dest.Element(),
     145           0 :                                                        dest.Axis());
     146             :     }
     147           0 :     dest[i].SetValueAndUnit(
     148           0 :       dest[i].GetValueInCurrentUnits() + valToAdd * aCount,
     149           0 :       dest[i].GetUnit());
     150             :   }
     151             : 
     152             :   // propagate target element info!
     153           0 :   dest.SetInfo(valueToAdd.Element(), valueToAdd.Axis(),
     154           0 :                dest.CanZeroPadList() && valueToAdd.CanZeroPadList());
     155             : 
     156           0 :   return NS_OK;
     157             : }
     158             : 
     159             : nsresult
     160           0 : SVGLengthListSMILType::ComputeDistance(const nsSMILValue& aFrom,
     161             :                                        const nsSMILValue& aTo,
     162             :                                        double& aDistance) const
     163             : {
     164           0 :   NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
     165           0 :   NS_PRECONDITION(aTo.mType == this, "Incompatible SMIL type");
     166             : 
     167             :   const SVGLengthListAndInfo& from =
     168           0 :     *static_cast<const SVGLengthListAndInfo*>(aFrom.mU.mPtr);
     169             :   const SVGLengthListAndInfo& to =
     170           0 :     *static_cast<const SVGLengthListAndInfo*>(aTo.mU.mPtr);
     171             : 
     172             :   // To understand this code, see the comments documenting our Init() method,
     173             :   // and documenting SVGLengthListAndInfo::CanZeroPadList().
     174             : 
     175           0 :   NS_ASSERTION((from.CanZeroPadList() == to.CanZeroPadList()) ||
     176             :                (from.CanZeroPadList() && from.IsEmpty()) ||
     177             :                (to.CanZeroPadList() && to.IsEmpty()),
     178             :                "Only \"zero\" nsSMILValues from the SMIL engine should "
     179             :                "return true for CanZeroPadList() when the attribute "
     180             :                "being animated can't be zero padded");
     181             : 
     182           0 :   if ((from.Length() < to.Length() && !from.CanZeroPadList()) ||
     183           0 :       (to.Length() < from.Length() && !to.CanZeroPadList())) {
     184             :     // SVGContentUtils::ReportToConsole
     185           0 :     return NS_ERROR_FAILURE;
     186             :   }
     187             : 
     188             :   // We return the root of the sum of the squares of the deltas between the
     189             :   // user unit values of the lengths at each correspanding index. In the
     190             :   // general case, paced animation is probably not useful, but this strategy at
     191             :   // least does the right thing for paced animation in the face of simple
     192             :   // 'values' lists such as:
     193             :   //
     194             :   //   values="100 200 300; 101 201 301; 110 210 310"
     195             :   //
     196             :   // I.e. half way through the simple duration we'll get "105 205 305".
     197             : 
     198           0 :   double total = 0.0;
     199             : 
     200           0 :   uint32_t i = 0;
     201           0 :   for (; i < from.Length() && i < to.Length(); ++i) {
     202           0 :     double f = from[i].GetValueInUserUnits(from.Element(), from.Axis());
     203           0 :     double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
     204           0 :     double delta = t - f;
     205           0 :     total += delta * delta;
     206             :   }
     207             : 
     208             :   // In the case that from.Length() != to.Length(), one of the following loops
     209             :   // will run. (OK since CanZeroPadList()==true for the other list.)
     210             : 
     211           0 :   for (; i < from.Length(); ++i) {
     212           0 :     double f = from[i].GetValueInUserUnits(from.Element(), from.Axis());
     213           0 :     total += f * f;
     214             :   }
     215           0 :   for (; i < to.Length(); ++i) {
     216           0 :     double t = to[i].GetValueInUserUnits(to.Element(), to.Axis());
     217           0 :     total += t * t;
     218             :   }
     219             : 
     220           0 :   float distance = sqrt(total);
     221           0 :   if (!IsFinite(distance)) {
     222           0 :     return NS_ERROR_FAILURE;
     223             :   }
     224           0 :   aDistance = distance;
     225           0 :   return NS_OK;
     226             : }
     227             : 
     228             : nsresult
     229           0 : SVGLengthListSMILType::Interpolate(const nsSMILValue& aStartVal,
     230             :                                    const nsSMILValue& aEndVal,
     231             :                                    double aUnitDistance,
     232             :                                    nsSMILValue& aResult) const
     233             : {
     234           0 :   NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
     235             :                   "Trying to interpolate different types");
     236           0 :   NS_PRECONDITION(aStartVal.mType == this,
     237             :                   "Unexpected types for interpolation");
     238           0 :   NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
     239             : 
     240             :   const SVGLengthListAndInfo& start =
     241           0 :     *static_cast<const SVGLengthListAndInfo*>(aStartVal.mU.mPtr);
     242             :   const SVGLengthListAndInfo& end =
     243           0 :     *static_cast<const SVGLengthListAndInfo*>(aEndVal.mU.mPtr);
     244             :   SVGLengthListAndInfo& result =
     245           0 :     *static_cast<SVGLengthListAndInfo*>(aResult.mU.mPtr);
     246             : 
     247             :   // To understand this code, see the comments documenting our Init() method,
     248             :   // and documenting SVGLengthListAndInfo::CanZeroPadList().
     249             : 
     250           0 :   NS_ASSERTION((start.CanZeroPadList() == end.CanZeroPadList()) ||
     251             :                (start.CanZeroPadList() && start.IsEmpty()) ||
     252             :                (end.CanZeroPadList() && end.IsEmpty()),
     253             :                "Only \"zero\" nsSMILValues from the SMIL engine should "
     254             :                "return true for CanZeroPadList() when the attribute "
     255             :                "being animated can't be zero padded");
     256             : 
     257           0 :   if ((start.Length() < end.Length() && !start.CanZeroPadList()) ||
     258           0 :       (end.Length() < start.Length() && !end.CanZeroPadList())) {
     259             :     // SVGContentUtils::ReportToConsole
     260           0 :     return NS_ERROR_FAILURE;
     261             :   }
     262             : 
     263           0 :   if (!result.SetLength(std::max(start.Length(), end.Length()))) {
     264           0 :     return NS_ERROR_OUT_OF_MEMORY;
     265             :   }
     266             : 
     267           0 :   uint32_t i = 0;
     268           0 :   for (; i < start.Length() && i < end.Length(); ++i) {
     269             :     float s;
     270           0 :     if (start[i].GetUnit() == end[i].GetUnit()) {
     271           0 :       s = start[i].GetValueInCurrentUnits();
     272             :     } else {
     273             :       // If units differ, we use the unit of the item in 'end'.
     274             :       // We leave it to the frame code to check that values are finite.
     275           0 :       s = start[i].GetValueInSpecifiedUnit(end[i].GetUnit(), end.Element(), end.Axis());
     276             :     }
     277           0 :     float e = end[i].GetValueInCurrentUnits();
     278           0 :     result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, end[i].GetUnit());
     279             :   }
     280             : 
     281             :   // In the case that start.Length() != end.Length(), one of the following
     282             :   // loops will run. (Okay, since CanZeroPadList()==true for the other list.)
     283             : 
     284           0 :   for (; i < start.Length(); ++i) {
     285           0 :     result[i].SetValueAndUnit(start[i].GetValueInCurrentUnits() -
     286           0 :                               start[i].GetValueInCurrentUnits() * aUnitDistance,
     287           0 :                               start[i].GetUnit());
     288             :   }
     289           0 :   for (; i < end.Length(); ++i) {
     290           0 :     result[i].SetValueAndUnit(end[i].GetValueInCurrentUnits() * aUnitDistance,
     291           0 :                               end[i].GetUnit());
     292             :   }
     293             : 
     294             :   // propagate target element info!
     295           0 :   result.SetInfo(end.Element(), end.Axis(),
     296           0 :                  start.CanZeroPadList() && end.CanZeroPadList());
     297             : 
     298           0 :   return NS_OK;
     299             : }
     300             : 
     301             : } // namespace mozilla

Generated by: LCOV version 1.13