1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is the Mozilla SVG project.
16 : *
17 : * The Initial Developer of the Original Code is the Mozilla Foundation.
18 : * Portions created by the Initial Developer are Copyright (C) 2010
19 : * the Initial Developer. All Rights Reserved.
20 : *
21 : * Contributor(s):
22 : *
23 : * Alternatively, the contents of this file may be used under the terms of
24 : * either of the GNU General Public License Version 2 or later (the "GPL"),
25 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 : * in which case the provisions of the GPL or the LGPL are applicable instead
27 : * of those above. If you wish to allow use of your version of this file only
28 : * under the terms of either the GPL or the LGPL, and not to allow others to
29 : * use your version of this file under the terms of the MPL, indicate your
30 : * decision by deleting the provisions above and replace them with the notice
31 : * and other provisions required by the GPL or the LGPL. If you do not delete
32 : * the provisions above, a recipient may use your version of this file under
33 : * the terms of any one of the MPL, the GPL or the LGPL.
34 : *
35 : * ***** END LICENSE BLOCK ***** */
36 :
37 : #include "SVGNumberListSMILType.h"
38 : #include "nsSMILValue.h"
39 : #include "SVGNumberList.h"
40 : #include "nsMathUtils.h"
41 : #include <math.h>
42 :
43 : /* The "identity" number list for a given number list attribute (the effective
44 : * number list that is used if an attribute value is not specified) varies
45 : * widely for different number list attributes, and can depend on the value of
46 : * other attributes on the same element:
47 : *
48 : * http://www.w3.org/TR/SVG11/filters.html#feColorMatrixValuesAttribute
49 : * http://www.w3.org/TR/SVG11/filters.html#feComponentTransferTableValuesAttribute
50 : * http://www.w3.org/TR/SVG11/filters.html#feConvolveMatrixElementKernelMatrixAttribute
51 : * http://www.w3.org/TR/SVG11/text.html#TextElementRotateAttribute
52 : *
53 : * Note that we don't need to worry about that variation here, however. The way
54 : * that the SMIL engine creates and composites sandwich layers together allows
55 : * us to treat "identity" nsSMILValue objects as a number list of zeros. Such
56 : * identity nsSMILValues are identified by the fact that their
57 : # SVGNumberListAndInfo has not been given an element yet.
58 : */
59 :
60 : namespace mozilla {
61 :
62 1464 : /*static*/ SVGNumberListSMILType SVGNumberListSMILType::sSingleton;
63 :
64 : //----------------------------------------------------------------------
65 : // nsISMILType implementation
66 :
67 : void
68 0 : SVGNumberListSMILType::Init(nsSMILValue &aValue) const
69 : {
70 0 : NS_ABORT_IF_FALSE(aValue.IsNull(), "Unexpected value type");
71 :
72 0 : SVGNumberListAndInfo* numberList = new SVGNumberListAndInfo();
73 :
74 0 : aValue.mU.mPtr = numberList;
75 0 : aValue.mType = this;
76 0 : }
77 :
78 : void
79 0 : SVGNumberListSMILType::Destroy(nsSMILValue& aValue) const
80 : {
81 0 : NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type");
82 0 : delete static_cast<SVGNumberListAndInfo*>(aValue.mU.mPtr);
83 0 : aValue.mU.mPtr = nsnull;
84 0 : aValue.mType = &nsSMILNullType::sSingleton;
85 0 : }
86 :
87 : nsresult
88 0 : SVGNumberListSMILType::Assign(nsSMILValue& aDest,
89 : const nsSMILValue& aSrc) const
90 : {
91 0 : NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types");
92 0 : NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value");
93 :
94 : const SVGNumberListAndInfo* src =
95 0 : static_cast<const SVGNumberListAndInfo*>(aSrc.mU.mPtr);
96 : SVGNumberListAndInfo* dest =
97 0 : static_cast<SVGNumberListAndInfo*>(aDest.mU.mPtr);
98 :
99 0 : return dest->CopyFrom(*src);
100 : }
101 :
102 : bool
103 0 : SVGNumberListSMILType::IsEqual(const nsSMILValue& aLeft,
104 : const nsSMILValue& aRight) const
105 : {
106 0 : NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types");
107 0 : NS_PRECONDITION(aLeft.mType == this, "Unexpected type for SMIL value");
108 :
109 : return *static_cast<const SVGNumberListAndInfo*>(aLeft.mU.mPtr) ==
110 0 : *static_cast<const SVGNumberListAndInfo*>(aRight.mU.mPtr);
111 : }
112 :
113 : nsresult
114 0 : SVGNumberListSMILType::Add(nsSMILValue& aDest,
115 : const nsSMILValue& aValueToAdd,
116 : PRUint32 aCount) const
117 : {
118 0 : NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type");
119 0 : NS_PRECONDITION(aValueToAdd.mType == this, "Incompatible SMIL type");
120 :
121 : SVGNumberListAndInfo& dest =
122 0 : *static_cast<SVGNumberListAndInfo*>(aDest.mU.mPtr);
123 : const SVGNumberListAndInfo& valueToAdd =
124 0 : *static_cast<const SVGNumberListAndInfo*>(aValueToAdd.mU.mPtr);
125 :
126 0 : NS_ABORT_IF_FALSE(dest.Element() || valueToAdd.Element(),
127 : "Target element propagation failure");
128 :
129 0 : if (!valueToAdd.Element()) {
130 0 : NS_ABORT_IF_FALSE(valueToAdd.Length() == 0,
131 : "Not identity value - target element propagation failure");
132 0 : return NS_OK;
133 : }
134 0 : if (!dest.Element()) {
135 0 : NS_ABORT_IF_FALSE(dest.Length() == 0,
136 : "Not identity value - target element propagation failure");
137 0 : if (!dest.SetLength(valueToAdd.Length())) {
138 0 : return NS_ERROR_OUT_OF_MEMORY;
139 : }
140 0 : for (PRUint32 i = 0; i < dest.Length(); ++i) {
141 0 : dest[i] = aCount * valueToAdd[i];
142 : }
143 0 : dest.SetInfo(valueToAdd.Element()); // propagate target element info!
144 0 : return NS_OK;
145 : }
146 0 : NS_ABORT_IF_FALSE(dest.Element() == valueToAdd.Element(),
147 : "adding values from different elements...?");
148 0 : if (dest.Length() != valueToAdd.Length()) {
149 : // For now we only support animation between lists with the same number of
150 : // items. nsSVGUtils::ReportToConsole
151 0 : return NS_ERROR_FAILURE;
152 : }
153 0 : for (PRUint32 i = 0; i < dest.Length(); ++i) {
154 0 : dest[i] += aCount * valueToAdd[i];
155 : }
156 0 : dest.SetInfo(valueToAdd.Element()); // propagate target element info!
157 0 : return NS_OK;
158 : }
159 :
160 : nsresult
161 0 : SVGNumberListSMILType::ComputeDistance(const nsSMILValue& aFrom,
162 : const nsSMILValue& aTo,
163 : double& aDistance) const
164 : {
165 0 : NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type");
166 0 : NS_PRECONDITION(aTo.mType == this, "Incompatible SMIL type");
167 :
168 : const SVGNumberListAndInfo& from =
169 0 : *static_cast<const SVGNumberListAndInfo*>(aFrom.mU.mPtr);
170 : const SVGNumberListAndInfo& to =
171 0 : *static_cast<const SVGNumberListAndInfo*>(aTo.mU.mPtr);
172 :
173 0 : if (from.Length() != to.Length()) {
174 : // Lists in the 'values' attribute must have the same length.
175 : // nsSVGUtils::ReportToConsole
176 0 : return NS_ERROR_FAILURE;
177 : }
178 :
179 : // We return the root of the sum of the squares of the delta between the
180 : // numbers at each correspanding index.
181 :
182 0 : double total = 0.0;
183 :
184 0 : for (PRUint32 i = 0; i < to.Length(); ++i) {
185 0 : double delta = to[i] - from[i];
186 0 : total += delta * delta;
187 : }
188 0 : double distance = sqrt(total);
189 0 : if (!NS_finite(distance)) {
190 0 : return NS_ERROR_FAILURE;
191 : }
192 0 : aDistance = distance;
193 :
194 0 : return NS_OK;
195 : }
196 :
197 : nsresult
198 0 : SVGNumberListSMILType::Interpolate(const nsSMILValue& aStartVal,
199 : const nsSMILValue& aEndVal,
200 : double aUnitDistance,
201 : nsSMILValue& aResult) const
202 : {
203 0 : NS_PRECONDITION(aStartVal.mType == aEndVal.mType,
204 : "Trying to interpolate different types");
205 0 : NS_PRECONDITION(aStartVal.mType == this,
206 : "Unexpected types for interpolation");
207 0 : NS_PRECONDITION(aResult.mType == this, "Unexpected result type");
208 :
209 : const SVGNumberListAndInfo& start =
210 0 : *static_cast<const SVGNumberListAndInfo*>(aStartVal.mU.mPtr);
211 : const SVGNumberListAndInfo& end =
212 0 : *static_cast<const SVGNumberListAndInfo*>(aEndVal.mU.mPtr);
213 : SVGNumberListAndInfo& result =
214 0 : *static_cast<SVGNumberListAndInfo*>(aResult.mU.mPtr);
215 :
216 0 : NS_ABORT_IF_FALSE(end.Element(), "Can't propagate target element");
217 0 : NS_ABORT_IF_FALSE(start.Element() == end.Element() || !start.Element(),
218 : "Different target elements");
219 :
220 0 : if (start.Element() && // 'start' is not an "identity" value
221 0 : start.Length() != end.Length()) {
222 : // For now we only support animation between lists of the same length.
223 : // nsSVGUtils::ReportToConsole
224 0 : return NS_ERROR_FAILURE;
225 : }
226 0 : if (!result.SetLength(end.Length())) {
227 0 : return NS_ERROR_OUT_OF_MEMORY;
228 : }
229 :
230 0 : result.SetInfo(end.Element()); // propagate target element info!
231 :
232 0 : if (start.Length() != end.Length()) {
233 0 : NS_ABORT_IF_FALSE(start.Length() == 0, "Not an identity value");
234 0 : for (PRUint32 i = 0; i < end.Length(); ++i) {
235 0 : result[i] = aUnitDistance * end[i];
236 : }
237 0 : return NS_OK;
238 : }
239 0 : for (PRUint32 i = 0; i < end.Length(); ++i) {
240 0 : result[i] = start[i] + (end[i] - start[i]) * aUnitDistance;
241 : }
242 0 : return NS_OK;
243 : }
244 :
245 4392 : } // namespace mozilla
|