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 "SVGPointListSMILType.h"
9 #include "mozilla/FloatingPoint.h"
10 #include "mozilla/SMILValue.h"
11 #include "nsMathUtils.h"
12 #include "SVGPointList.h"
18 SVGPointListSMILType
SVGPointListSMILType::sSingleton
;
20 //----------------------------------------------------------------------
21 // nsISMILType implementation
23 void SVGPointListSMILType::Init(SMILValue
& aValue
) const {
24 MOZ_ASSERT(aValue
.IsNull(), "Unexpected value type");
26 aValue
.mU
.mPtr
= new SVGPointListAndInfo();
30 void SVGPointListSMILType::Destroy(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();
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");
42 const SVGPointListAndInfo
* src
=
43 static_cast<const SVGPointListAndInfo
*>(aSrc
.mU
.mPtr
);
44 SVGPointListAndInfo
* dest
= static_cast<SVGPointListAndInfo
*>(aDest
.mU
.mPtr
);
46 return dest
->CopyFrom(*src
);
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");
54 return *static_cast<const SVGPointListAndInfo
*>(aLeft
.mU
.mPtr
) ==
55 *static_cast<const SVGPointListAndInfo
*>(aRight
.mU
.mPtr
);
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");
64 SVGPointListAndInfo
& dest
= *static_cast<SVGPointListAndInfo
*>(aDest
.mU
.mPtr
);
65 const SVGPointListAndInfo
& valueToAdd
=
66 *static_cast<const SVGPointListAndInfo
*>(aValueToAdd
.mU
.mPtr
);
68 MOZ_ASSERT(dest
.Element() || valueToAdd
.Element(),
69 "Target element propagation failure");
71 if (valueToAdd
.IsIdentity()) {
74 if (dest
.IsIdentity()) {
75 if (!dest
.SetLength(valueToAdd
.Length())) {
76 return NS_ERROR_OUT_OF_MEMORY
;
78 for (uint32_t i
= 0; i
< dest
.Length(); ++i
) {
79 dest
[i
] = aCount
* valueToAdd
[i
];
81 dest
.SetInfo(valueToAdd
.Element()); // propagate target element info!
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
;
91 for (uint32_t i
= 0; i
< dest
.Length(); ++i
) {
92 dest
[i
] += aCount
* valueToAdd
[i
];
94 dest
.SetInfo(valueToAdd
.Element()); // propagate target element info!
98 nsresult
SVGPointListSMILType::ComputeDistance(const SMILValue
& aFrom
,
100 double& aDistance
) const {
101 MOZ_ASSERT(aFrom
.mType
== this, "Unexpected SMIL type");
102 MOZ_ASSERT(aTo
.mType
== this, "Incompatible SMIL type");
104 const SVGPointListAndInfo
& from
=
105 *static_cast<const SVGPointListAndInfo
*>(aFrom
.mU
.mPtr
);
106 const SVGPointListAndInfo
& to
=
107 *static_cast<const SVGPointListAndInfo
*>(aTo
.mU
.mPtr
);
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
;
115 // We return the root of the sum of the squares of the distances between the
116 // points at each corresponding index.
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
;
125 double distance
= sqrt(total
);
126 if (!std::isfinite(distance
)) {
127 return NS_ERROR_FAILURE
;
129 aDistance
= distance
;
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");
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
);
150 MOZ_ASSERT(end
.Element(), "Can't propagate target element");
151 MOZ_ASSERT(start
.Element() == end
.Element() || !start
.Element(),
152 "Different target elements");
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
;
160 if (!result
.SetLength(end
.Length())) {
161 return NS_ERROR_OUT_OF_MEMORY
;
164 result
.SetInfo(end
.Element()); // propagate target element info!
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
];
173 for (uint32_t i
= 0; i
< end
.Length(); ++i
) {
174 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * aUnitDistance
;
179 } // namespace mozilla