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/. */
7 #include "SVGNumberListSMILType.h"
9 #include "mozilla/FloatingPoint.h"
10 #include "mozilla/SMILValue.h"
11 #include "nsMathUtils.h"
12 #include "SVGNumberList.h"
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:
20 * http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute
22 http://www.w3.org/TR/SVG11/filters.html#feComponentTransferTableValuesAttribute
24 http://www.w3.org/TR/SVG11/filters.html#feConvolveMatrixElementKernelMatrixAttribute
25 * http://www.w3.org/TR/SVG11/text.html#TextElementRotateAttribute
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.
37 SVGNumberListSMILType
SVGNumberListSMILType::sSingleton
;
39 //----------------------------------------------------------------------
40 // nsISMILType implementation
42 void SVGNumberListSMILType::Init(SMILValue
& aValue
) const {
43 MOZ_ASSERT(aValue
.IsNull(), "Unexpected value type");
45 aValue
.mU
.mPtr
= new SVGNumberListAndInfo();
49 void SVGNumberListSMILType::Destroy(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();
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");
61 const SVGNumberListAndInfo
* src
=
62 static_cast<const SVGNumberListAndInfo
*>(aSrc
.mU
.mPtr
);
63 SVGNumberListAndInfo
* dest
=
64 static_cast<SVGNumberListAndInfo
*>(aDest
.mU
.mPtr
);
66 return dest
->CopyFrom(*src
);
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");
74 return *static_cast<const SVGNumberListAndInfo
*>(aLeft
.mU
.mPtr
) ==
75 *static_cast<const SVGNumberListAndInfo
*>(aRight
.mU
.mPtr
);
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");
84 SVGNumberListAndInfo
& dest
=
85 *static_cast<SVGNumberListAndInfo
*>(aDest
.mU
.mPtr
);
86 const SVGNumberListAndInfo
& valueToAdd
=
87 *static_cast<const SVGNumberListAndInfo
*>(aValueToAdd
.mU
.mPtr
);
89 MOZ_ASSERT(dest
.Element() || valueToAdd
.Element(),
90 "Target element propagation failure");
92 if (!valueToAdd
.Element()) {
93 MOZ_ASSERT(valueToAdd
.Length() == 0,
94 "Not identity value - target element propagation failure");
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
;
103 for (uint32_t i
= 0; i
< dest
.Length(); ++i
) {
104 dest
[i
] = aCount
* valueToAdd
[i
];
106 dest
.SetInfo(valueToAdd
.Element()); // propagate target element info!
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
;
116 for (uint32_t i
= 0; i
< dest
.Length(); ++i
) {
117 dest
[i
] += aCount
* valueToAdd
[i
];
119 dest
.SetInfo(valueToAdd
.Element()); // propagate target element info!
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");
129 const SVGNumberListAndInfo
& from
=
130 *static_cast<const SVGNumberListAndInfo
*>(aFrom
.mU
.mPtr
);
131 const SVGNumberListAndInfo
& to
=
132 *static_cast<const SVGNumberListAndInfo
*>(aTo
.mU
.mPtr
);
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
;
140 // We return the root of the sum of the squares of the delta between the
141 // numbers at each correspanding index.
145 for (uint32_t i
= 0; i
< to
.Length(); ++i
) {
146 double delta
= to
[i
] - from
[i
];
147 total
+= delta
* delta
;
149 double distance
= sqrt(total
);
150 if (!std::isfinite(distance
)) {
151 return NS_ERROR_FAILURE
;
153 aDistance
= distance
;
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");
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
);
174 MOZ_ASSERT(end
.Element(), "Can't propagate target element");
175 MOZ_ASSERT(start
.Element() == end
.Element() || !start
.Element(),
176 "Different target elements");
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
;
184 if (!result
.SetLength(end
.Length())) {
185 return NS_ERROR_OUT_OF_MEMORY
;
188 result
.SetInfo(end
.Element()); // propagate target element info!
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
];
197 for (uint32_t i
= 0; i
< end
.Length(); ++i
) {
198 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * aUnitDistance
;
203 } // namespace mozilla