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