SVGPointListSMILType.cpp (6386B)
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 "SVGPointListSMILType.h" 8 9 #include <math.h> 10 11 #include "SVGPointList.h" 12 #include "mozilla/SMILValue.h" 13 #include "nsMathUtils.h" 14 15 namespace mozilla { 16 17 /*static*/ 18 SVGPointListSMILType SVGPointListSMILType::sSingleton; 19 20 //---------------------------------------------------------------------- 21 // nsISMILType implementation 22 23 void SVGPointListSMILType::InitValue(SMILValue& aValue) const { 24 MOZ_ASSERT(aValue.IsNull(), "Unexpected value type"); 25 26 aValue.mU.mPtr = new SVGPointListAndInfo(); 27 aValue.mType = this; 28 } 29 30 void SVGPointListSMILType::DestroyValue(SMILValue& aValue) const { 31 MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type"); 32 delete static_cast<SVGPointListAndInfo*>(aValue.mU.mPtr); 33 aValue.mU.mPtr = nullptr; 34 aValue.mType = SMILNullType::Singleton(); 35 } 36 37 nsresult SVGPointListSMILType::Assign(SMILValue& aDest, 38 const SMILValue& aSrc) const { 39 MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types"); 40 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value"); 41 42 const SVGPointListAndInfo* src = 43 static_cast<const SVGPointListAndInfo*>(aSrc.mU.mPtr); 44 SVGPointListAndInfo* dest = static_cast<SVGPointListAndInfo*>(aDest.mU.mPtr); 45 46 return dest->CopyFrom(*src); 47 } 48 49 bool SVGPointListSMILType::IsEqual(const SMILValue& aLeft, 50 const SMILValue& aRight) const { 51 MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types"); 52 MOZ_ASSERT(aLeft.mType == this, "Unexpected type for SMIL value"); 53 54 return *static_cast<const SVGPointListAndInfo*>(aLeft.mU.mPtr) == 55 *static_cast<const SVGPointListAndInfo*>(aRight.mU.mPtr); 56 } 57 58 nsresult SVGPointListSMILType::Add(SMILValue& aDest, 59 const SMILValue& aValueToAdd, 60 uint32_t aCount) const { 61 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type"); 62 MOZ_ASSERT(aValueToAdd.mType == this, "Incompatible SMIL type"); 63 64 SVGPointListAndInfo& dest = *static_cast<SVGPointListAndInfo*>(aDest.mU.mPtr); 65 const SVGPointListAndInfo& valueToAdd = 66 *static_cast<const SVGPointListAndInfo*>(aValueToAdd.mU.mPtr); 67 68 MOZ_ASSERT(dest.Element() || valueToAdd.Element(), 69 "Target element propagation failure"); 70 71 if (valueToAdd.IsIdentity()) { 72 return NS_OK; 73 } 74 if (dest.IsIdentity()) { 75 if (!dest.SetLength(valueToAdd.Length())) { 76 return NS_ERROR_OUT_OF_MEMORY; 77 } 78 for (uint32_t i = 0; i < dest.Length(); ++i) { 79 dest[i] = aCount * valueToAdd[i]; 80 } 81 dest.SetInfo(valueToAdd.Element()); // propagate target element info! 82 return NS_OK; 83 } 84 MOZ_ASSERT(dest.Element() == valueToAdd.Element(), 85 "adding values from different elements...?"); 86 if (dest.Length() != valueToAdd.Length()) { 87 // For now we only support animation between lists with the same number of 88 // items. SVGContentUtils::ReportToConsole 89 return NS_ERROR_FAILURE; 90 } 91 for (uint32_t i = 0; i < dest.Length(); ++i) { 92 dest[i] += aCount * valueToAdd[i]; 93 } 94 dest.SetInfo(valueToAdd.Element()); // propagate target element info! 95 return NS_OK; 96 } 97 98 nsresult SVGPointListSMILType::ComputeDistance(const SMILValue& aFrom, 99 const SMILValue& aTo, 100 double& aDistance) const { 101 MOZ_ASSERT(aFrom.mType == this, "Unexpected SMIL type"); 102 MOZ_ASSERT(aTo.mType == this, "Incompatible SMIL type"); 103 104 const SVGPointListAndInfo& from = 105 *static_cast<const SVGPointListAndInfo*>(aFrom.mU.mPtr); 106 const SVGPointListAndInfo& to = 107 *static_cast<const SVGPointListAndInfo*>(aTo.mU.mPtr); 108 109 if (from.Length() != to.Length()) { 110 // Lists in the 'values' attribute must have the same length. 111 // SVGContentUtils::ReportToConsole 112 return NS_ERROR_FAILURE; 113 } 114 115 // We return the root of the sum of the squares of the distances between the 116 // points at each corresponding index. 117 118 double total = 0.0; 119 120 for (uint32_t i = 0; i < to.Length(); ++i) { 121 double dx = to[i].mX - from[i].mX; 122 double dy = to[i].mY - from[i].mY; 123 total += dx * dx + dy * dy; 124 } 125 double distance = sqrt(total); 126 if (!std::isfinite(distance)) { 127 return NS_ERROR_FAILURE; 128 } 129 aDistance = distance; 130 131 return NS_OK; 132 } 133 134 nsresult SVGPointListSMILType::Interpolate(const SMILValue& aStartVal, 135 const SMILValue& aEndVal, 136 double aUnitDistance, 137 SMILValue& aResult) const { 138 MOZ_ASSERT(aStartVal.mType == aEndVal.mType, 139 "Trying to interpolate different types"); 140 MOZ_ASSERT(aStartVal.mType == this, "Unexpected types for interpolation"); 141 MOZ_ASSERT(aResult.mType == this, "Unexpected result type"); 142 143 const SVGPointListAndInfo& start = 144 *static_cast<const SVGPointListAndInfo*>(aStartVal.mU.mPtr); 145 const SVGPointListAndInfo& end = 146 *static_cast<const SVGPointListAndInfo*>(aEndVal.mU.mPtr); 147 SVGPointListAndInfo& result = 148 *static_cast<SVGPointListAndInfo*>(aResult.mU.mPtr); 149 150 MOZ_ASSERT(end.Element(), "Can't propagate target element"); 151 MOZ_ASSERT(start.Element() == end.Element() || !start.Element(), 152 "Different target elements"); 153 154 if (start.Element() && // 'start' is not an "identity" value 155 start.Length() != end.Length()) { 156 // For now we only support animation between lists of the same length. 157 // SVGContentUtils::ReportToConsole 158 return NS_ERROR_FAILURE; 159 } 160 if (!result.SetLength(end.Length())) { 161 return NS_ERROR_OUT_OF_MEMORY; 162 } 163 164 result.SetInfo(end.Element()); // propagate target element info! 165 166 if (start.Length() != end.Length()) { 167 MOZ_ASSERT(start.Length() == 0, "Not an identity value"); 168 for (uint32_t i = 0; i < end.Length(); ++i) { 169 result[i] = aUnitDistance * end[i]; 170 } 171 return NS_OK; 172 } 173 for (uint32_t i = 0; i < end.Length(); ++i) { 174 result[i] = start[i] + (end[i] - start[i]) * aUnitDistance; 175 } 176 return NS_OK; 177 } 178 179 } // namespace mozilla