SVGNumberListSMILType.cpp (7565B)
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 "SVGNumberListSMILType.h" 8 9 #include <math.h> 10 11 #include "SVGNumberList.h" 12 #include "mozilla/SMILValue.h" 13 #include "nsMathUtils.h" 14 15 /* The "identity" number list for a given number list attribute (the effective 16 * number list that is used if an attribute value is not specified) varies 17 * widely for different number list attributes, and can depend on the value of 18 * other attributes on the same element: 19 * 20 * http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute 21 * 22 http://www.w3.org/TR/SVG11/filters.html#feComponentTransferTableValuesAttribute 23 * 24 http://www.w3.org/TR/SVG11/filters.html#feConvolveMatrixElementKernelMatrixAttribute 25 * http://www.w3.org/TR/SVG11/text.html#TextElementRotateAttribute 26 * 27 * Note that we don't need to worry about that variation here, however. The way 28 * that the SMIL engine creates and composites sandwich layers together allows 29 * us to treat "identity" SMILValue objects as a number list of zeros. Such 30 * identity SMILValues are identified by the fact that their 31 # SVGNumberListAndInfo has not been given an element yet. 32 */ 33 34 namespace mozilla { 35 36 /*static*/ 37 SVGNumberListSMILType SVGNumberListSMILType::sSingleton; 38 39 //---------------------------------------------------------------------- 40 // nsISMILType implementation 41 42 void SVGNumberListSMILType::InitValue(SMILValue& aValue) const { 43 MOZ_ASSERT(aValue.IsNull(), "Unexpected value type"); 44 45 aValue.mU.mPtr = new SVGNumberListAndInfo(); 46 aValue.mType = this; 47 } 48 49 void SVGNumberListSMILType::DestroyValue(SMILValue& aValue) const { 50 MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type"); 51 delete static_cast<SVGNumberListAndInfo*>(aValue.mU.mPtr); 52 aValue.mU.mPtr = nullptr; 53 aValue.mType = SMILNullType::Singleton(); 54 } 55 56 nsresult SVGNumberListSMILType::Assign(SMILValue& aDest, 57 const SMILValue& aSrc) const { 58 MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types"); 59 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value"); 60 61 const SVGNumberListAndInfo* src = 62 static_cast<const SVGNumberListAndInfo*>(aSrc.mU.mPtr); 63 SVGNumberListAndInfo* dest = 64 static_cast<SVGNumberListAndInfo*>(aDest.mU.mPtr); 65 66 return dest->CopyFrom(*src); 67 } 68 69 bool SVGNumberListSMILType::IsEqual(const SMILValue& aLeft, 70 const SMILValue& aRight) const { 71 MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types"); 72 MOZ_ASSERT(aLeft.mType == this, "Unexpected type for SMIL value"); 73 74 return *static_cast<const SVGNumberListAndInfo*>(aLeft.mU.mPtr) == 75 *static_cast<const SVGNumberListAndInfo*>(aRight.mU.mPtr); 76 } 77 78 nsresult SVGNumberListSMILType::Add(SMILValue& aDest, 79 const SMILValue& aValueToAdd, 80 uint32_t aCount) const { 81 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type"); 82 MOZ_ASSERT(aValueToAdd.mType == this, "Incompatible SMIL type"); 83 84 SVGNumberListAndInfo& dest = 85 *static_cast<SVGNumberListAndInfo*>(aDest.mU.mPtr); 86 const SVGNumberListAndInfo& valueToAdd = 87 *static_cast<const SVGNumberListAndInfo*>(aValueToAdd.mU.mPtr); 88 89 MOZ_ASSERT(dest.Element() || valueToAdd.Element(), 90 "Target element propagation failure"); 91 92 if (!valueToAdd.Element()) { 93 MOZ_ASSERT(valueToAdd.Length() == 0, 94 "Not identity value - target element propagation failure"); 95 return NS_OK; 96 } 97 if (!dest.Element()) { 98 MOZ_ASSERT(dest.Length() == 0, 99 "Not identity value - target element propagation failure"); 100 if (!dest.SetLength(valueToAdd.Length())) { 101 return NS_ERROR_OUT_OF_MEMORY; 102 } 103 for (uint32_t i = 0; i < dest.Length(); ++i) { 104 dest[i] = aCount * valueToAdd[i]; 105 } 106 dest.SetInfo(valueToAdd.Element()); // propagate target element info! 107 return NS_OK; 108 } 109 MOZ_ASSERT(dest.Element() == valueToAdd.Element(), 110 "adding values from different elements...?"); 111 if (dest.Length() != valueToAdd.Length()) { 112 // For now we only support animation between lists with the same number of 113 // items. SVGContentUtils::ReportToConsole 114 return NS_ERROR_FAILURE; 115 } 116 for (uint32_t i = 0; i < dest.Length(); ++i) { 117 dest[i] += aCount * valueToAdd[i]; 118 } 119 dest.SetInfo(valueToAdd.Element()); // propagate target element info! 120 return NS_OK; 121 } 122 123 nsresult SVGNumberListSMILType::ComputeDistance(const SMILValue& aFrom, 124 const SMILValue& aTo, 125 double& aDistance) const { 126 MOZ_ASSERT(aFrom.mType == this, "Unexpected SMIL type"); 127 MOZ_ASSERT(aTo.mType == this, "Incompatible SMIL type"); 128 129 const SVGNumberListAndInfo& from = 130 *static_cast<const SVGNumberListAndInfo*>(aFrom.mU.mPtr); 131 const SVGNumberListAndInfo& to = 132 *static_cast<const SVGNumberListAndInfo*>(aTo.mU.mPtr); 133 134 if (from.Length() != to.Length()) { 135 // Lists in the 'values' attribute must have the same length. 136 // SVGContentUtils::ReportToConsole 137 return NS_ERROR_FAILURE; 138 } 139 140 // We return the root of the sum of the squares of the delta between the 141 // numbers at each correspanding index. 142 143 double total = 0.0; 144 145 for (uint32_t i = 0; i < to.Length(); ++i) { 146 double delta = to[i] - from[i]; 147 total += delta * delta; 148 } 149 double distance = sqrt(total); 150 if (!std::isfinite(distance)) { 151 return NS_ERROR_FAILURE; 152 } 153 aDistance = distance; 154 155 return NS_OK; 156 } 157 158 nsresult SVGNumberListSMILType::Interpolate(const SMILValue& aStartVal, 159 const SMILValue& aEndVal, 160 double aUnitDistance, 161 SMILValue& aResult) const { 162 MOZ_ASSERT(aStartVal.mType == aEndVal.mType, 163 "Trying to interpolate different types"); 164 MOZ_ASSERT(aStartVal.mType == this, "Unexpected types for interpolation"); 165 MOZ_ASSERT(aResult.mType == this, "Unexpected result type"); 166 167 const SVGNumberListAndInfo& start = 168 *static_cast<const SVGNumberListAndInfo*>(aStartVal.mU.mPtr); 169 const SVGNumberListAndInfo& end = 170 *static_cast<const SVGNumberListAndInfo*>(aEndVal.mU.mPtr); 171 SVGNumberListAndInfo& result = 172 *static_cast<SVGNumberListAndInfo*>(aResult.mU.mPtr); 173 174 MOZ_ASSERT(end.Element(), "Can't propagate target element"); 175 MOZ_ASSERT(start.Element() == end.Element() || !start.Element(), 176 "Different target elements"); 177 178 if (start.Element() && // 'start' is not an "identity" value 179 start.Length() != end.Length()) { 180 // For now we only support animation between lists of the same length. 181 // SVGContentUtils::ReportToConsole 182 return NS_ERROR_FAILURE; 183 } 184 if (!result.SetLength(end.Length())) { 185 return NS_ERROR_OUT_OF_MEMORY; 186 } 187 188 result.SetInfo(end.Element()); // propagate target element info! 189 190 if (start.Length() != end.Length()) { 191 MOZ_ASSERT(start.Length() == 0, "Not an identity value"); 192 for (uint32_t i = 0; i < end.Length(); ++i) { 193 result[i] = aUnitDistance * end[i]; 194 } 195 return NS_OK; 196 } 197 for (uint32_t i = 0; i < end.Length(); ++i) { 198 result[i] = start[i] + (end[i] - start[i]) * aUnitDistance; 199 } 200 return NS_OK; 201 } 202 203 } // namespace mozilla