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