Bug 1867190 - Initialise the PHC allocate delay later r=glandium
[gecko.git] / dom / svg / SVGTransformListSMILType.cpp
blob957bfe3360e9a3a5c393931873acd7144ecdfaf8
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 "SVGTransformListSMILType.h"
9 #include "mozilla/SMILValue.h"
10 #include "nsCRT.h"
11 #include "SVGTransformList.h"
12 #include "SVGTransform.h"
13 #include <math.h>
15 using namespace mozilla::dom::SVGTransform_Binding;
17 namespace mozilla {
19 using TransformArray = FallibleTArray<SVGTransformSMILData>;
21 //----------------------------------------------------------------------
22 // nsISMILType implementation
24 void SVGTransformListSMILType::Init(SMILValue& aValue) const {
25 MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
27 aValue.mU.mPtr = new TransformArray(1);
28 aValue.mType = this;
31 void SVGTransformListSMILType::Destroy(SMILValue& aValue) const {
32 MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value type");
33 TransformArray* params = static_cast<TransformArray*>(aValue.mU.mPtr);
34 delete params;
35 aValue.mU.mPtr = nullptr;
36 aValue.mType = SMILNullType::Singleton();
39 nsresult SVGTransformListSMILType::Assign(SMILValue& aDest,
40 const SMILValue& aSrc) const {
41 MOZ_ASSERT(aDest.mType == aSrc.mType, "Incompatible SMIL types");
42 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL value");
44 const TransformArray* srcTransforms =
45 static_cast<const TransformArray*>(aSrc.mU.mPtr);
46 TransformArray* dstTransforms = static_cast<TransformArray*>(aDest.mU.mPtr);
47 if (!dstTransforms->Assign(*srcTransforms, fallible)) {
48 return NS_ERROR_OUT_OF_MEMORY;
51 return NS_OK;
54 bool SVGTransformListSMILType::IsEqual(const SMILValue& aLeft,
55 const SMILValue& aRight) const {
56 MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types");
57 MOZ_ASSERT(aLeft.mType == this, "Unexpected SMIL type");
59 const TransformArray& leftArr(
60 *static_cast<const TransformArray*>(aLeft.mU.mPtr));
61 const TransformArray& rightArr(
62 *static_cast<const TransformArray*>(aRight.mU.mPtr));
64 // If array-lengths don't match, we're trivially non-equal.
65 if (leftArr.Length() != rightArr.Length()) {
66 return false;
69 // Array-lengths match -- check each array-entry for equality.
70 uint32_t length = leftArr.Length(); // == rightArr->Length(), if we get here
71 for (uint32_t i = 0; i < length; ++i) {
72 if (leftArr[i] != rightArr[i]) {
73 return false;
77 // Found no differences.
78 return true;
81 nsresult SVGTransformListSMILType::Add(SMILValue& aDest,
82 const SMILValue& aValueToAdd,
83 uint32_t aCount) const {
84 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type");
85 MOZ_ASSERT(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types");
87 TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
88 const TransformArray& srcTransforms(
89 *static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
91 // We're doing a simple add here (as opposed to a sandwich add below).
92 // We only do this when we're accumulating a repeat result or calculating
93 // a by-animation value.
95 // In either case we should have 1 transform in the source array.
96 NS_ASSERTION(srcTransforms.Length() == 1,
97 "Invalid source transform list to add");
99 // And we should have 0 or 1 transforms in the dest array.
100 // (We can have 0 transforms in the case of by-animation when we are
101 // calculating the by-value as "0 + by". Zero being represented by a
102 // SMILValue with an empty transform array.)
103 NS_ASSERTION(dstTransforms.Length() < 2,
104 "Invalid dest transform list to add to");
106 // Get the individual transforms to add
107 const SVGTransformSMILData& srcTransform = srcTransforms[0];
108 if (dstTransforms.IsEmpty()) {
109 SVGTransformSMILData* result = dstTransforms.AppendElement(
110 SVGTransformSMILData(srcTransform.mTransformType), fallible);
111 NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
113 SVGTransformSMILData& dstTransform = dstTransforms[0];
115 // The types must be the same
116 NS_ASSERTION(srcTransform.mTransformType == dstTransform.mTransformType,
117 "Trying to perform simple add of different transform types");
119 // And it should be impossible that one of them is of matrix type
120 NS_ASSERTION(srcTransform.mTransformType != SVG_TRANSFORM_MATRIX,
121 "Trying to perform simple add with matrix transform");
123 // Add the parameters
124 for (int i = 0; i <= 2; ++i) {
125 dstTransform.mParams[i] += srcTransform.mParams[i] * aCount;
128 return NS_OK;
131 nsresult SVGTransformListSMILType::SandwichAdd(
132 SMILValue& aDest, const SMILValue& aValueToAdd) const {
133 MOZ_ASSERT(aDest.mType == this, "Unexpected SMIL type");
134 MOZ_ASSERT(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types");
136 // For <animateTransform> a sandwich add means a matrix post-multiplication
137 // which just means to put the additional transform on the end of the array
139 TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr));
140 const TransformArray& srcTransforms(
141 *static_cast<const TransformArray*>(aValueToAdd.mU.mPtr));
143 // We should have 0 or 1 transforms in the src list.
144 NS_ASSERTION(srcTransforms.Length() < 2,
145 "Trying to do sandwich add of more than one value");
147 // The empty src transform list case only occurs in some limited circumstances
148 // where we create an empty 'from' value to interpolate from (e.g.
149 // by-animation) but then skip the interpolation step for some reason (e.g.
150 // because we have an indefinite duration which means we'll never get past the
151 // first value) and instead attempt to add that empty value to the underlying
152 // value.
153 // In any case, the expected result is that nothing is added.
154 if (srcTransforms.IsEmpty()) return NS_OK;
156 // Stick the src on the end of the array
157 const SVGTransformSMILData& srcTransform = srcTransforms[0];
158 SVGTransformSMILData* result =
159 dstTransforms.AppendElement(srcTransform, fallible);
160 NS_ENSURE_TRUE(result, NS_ERROR_OUT_OF_MEMORY);
162 return NS_OK;
165 nsresult SVGTransformListSMILType::ComputeDistance(const SMILValue& aFrom,
166 const SMILValue& aTo,
167 double& aDistance) const {
168 MOZ_ASSERT(aFrom.mType == aTo.mType,
169 "Can't compute difference between different SMIL types");
170 MOZ_ASSERT(aFrom.mType == this, "Unexpected SMIL type");
172 const TransformArray* fromTransforms =
173 static_cast<const TransformArray*>(aFrom.mU.mPtr);
174 const TransformArray* toTransforms =
175 static_cast<const TransformArray*>(aTo.mU.mPtr);
177 // ComputeDistance is only used for calculating distances between single
178 // values in a values array which necessarily have the same type
180 // So we should only have one transform in each array and they should be of
181 // the same type
182 NS_ASSERTION(fromTransforms->Length() == 1,
183 "Wrong number of elements in from value");
184 NS_ASSERTION(toTransforms->Length() == 1,
185 "Wrong number of elements in to value");
187 const SVGTransformSMILData& fromTransform = (*fromTransforms)[0];
188 const SVGTransformSMILData& toTransform = (*toTransforms)[0];
189 NS_ASSERTION(fromTransform.mTransformType == toTransform.mTransformType,
190 "Incompatible transform types to calculate distance between");
192 switch (fromTransform.mTransformType) {
193 // We adopt the SVGT1.2 notions of distance here
194 // See: http://www.w3.org/TR/SVGTiny12/animate.html#complexDistances
195 // (As discussed in bug #469040)
196 case SVG_TRANSFORM_TRANSLATE:
197 case SVG_TRANSFORM_SCALE: {
198 const float& a_tx = fromTransform.mParams[0];
199 const float& a_ty = fromTransform.mParams[1];
200 const float& b_tx = toTransform.mParams[0];
201 const float& b_ty = toTransform.mParams[1];
202 aDistance = sqrt(pow(a_tx - b_tx, 2) + (pow(a_ty - b_ty, 2)));
203 } break;
205 case SVG_TRANSFORM_ROTATE:
206 case SVG_TRANSFORM_SKEWX:
207 case SVG_TRANSFORM_SKEWY: {
208 const float& a = fromTransform.mParams[0];
209 const float& b = toTransform.mParams[0];
210 aDistance = std::fabs(a - b);
211 } break;
213 default:
214 NS_ERROR("Got bad transform types for calculating distances");
215 aDistance = 1.0;
216 return NS_ERROR_FAILURE;
219 return NS_OK;
222 nsresult SVGTransformListSMILType::Interpolate(const SMILValue& aStartVal,
223 const SMILValue& aEndVal,
224 double aUnitDistance,
225 SMILValue& aResult) const {
226 MOZ_ASSERT(aStartVal.mType == aEndVal.mType,
227 "Can't interpolate between different SMIL types");
228 MOZ_ASSERT(aStartVal.mType == this, "Unexpected type for interpolation");
229 MOZ_ASSERT(aResult.mType == this, "Unexpected result type");
231 const TransformArray& startTransforms =
232 (*static_cast<const TransformArray*>(aStartVal.mU.mPtr));
233 const TransformArray& endTransforms(
234 *static_cast<const TransformArray*>(aEndVal.mU.mPtr));
236 // We may have 0..n transforms in the start transform array (the base
237 // value) but we should only have 1 transform in the end transform array
238 NS_ASSERTION(endTransforms.Length() == 1,
239 "Invalid end-point for interpolating between transform values");
241 // The end point should never be a matrix transform
242 const SVGTransformSMILData& endTransform = endTransforms[0];
243 NS_ASSERTION(endTransform.mTransformType != SVG_TRANSFORM_MATRIX,
244 "End point for interpolation should not be a matrix transform");
246 // If we have 0 or more than 1 transform in the start transform array then we
247 // just interpolate from 0, 0, 0
248 // Likewise, even if there's only 1 transform in the start transform array
249 // then if the type of the start transform doesn't match the end then we
250 // can't interpolate and should just use 0, 0, 0
251 static float identityParams[3] = {0.f};
252 const float* startParams = nullptr;
253 if (startTransforms.Length() == 1) {
254 const SVGTransformSMILData& startTransform = startTransforms[0];
255 if (startTransform.mTransformType == endTransform.mTransformType) {
256 startParams = startTransform.mParams;
259 if (!startParams) {
260 startParams = identityParams;
263 const float* endParams = endTransform.mParams;
265 // Interpolate between the params
266 float newParams[3];
267 for (int i = 0; i <= 2; ++i) {
268 const float& a = startParams[i];
269 const float& b = endParams[i];
270 newParams[i] = static_cast<float>(a + (b - a) * aUnitDistance);
273 // Make the result
274 SVGTransformSMILData resultTransform(endTransform.mTransformType, newParams);
276 // Clear the way for it in the result array
277 TransformArray& dstTransforms =
278 (*static_cast<TransformArray*>(aResult.mU.mPtr));
279 dstTransforms.Clear();
281 // Assign the result
282 SVGTransformSMILData* transform =
283 dstTransforms.AppendElement(resultTransform, fallible);
284 NS_ENSURE_TRUE(transform, NS_ERROR_OUT_OF_MEMORY);
286 return NS_OK;
289 //----------------------------------------------------------------------
290 // Transform array accessors
292 // static
293 nsresult SVGTransformListSMILType::AppendTransform(
294 const SVGTransformSMILData& aTransform, SMILValue& aValue) {
295 MOZ_ASSERT(aValue.mType == Singleton(), "Unexpected SMIL value type");
297 TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
298 return transforms.AppendElement(aTransform, fallible)
299 ? NS_OK
300 : NS_ERROR_OUT_OF_MEMORY;
303 // static
304 bool SVGTransformListSMILType::AppendTransforms(const SVGTransformList& aList,
305 SMILValue& aValue) {
306 MOZ_ASSERT(aValue.mType == Singleton(), "Unexpected SMIL value type");
308 TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr);
310 if (!transforms.SetCapacity(transforms.Length() + aList.Length(), fallible))
311 return false;
313 for (uint32_t i = 0; i < aList.Length(); ++i) {
314 // No need to check the return value below since we have already allocated
315 // the necessary space
316 MOZ_ALWAYS_TRUE(
317 transforms.AppendElement(SVGTransformSMILData(aList[i]), fallible));
319 return true;
322 // static
323 bool SVGTransformListSMILType::GetTransforms(
324 const SMILValue& aValue, FallibleTArray<SVGTransform>& aTransforms) {
325 MOZ_ASSERT(aValue.mType == Singleton(), "Unexpected SMIL value type");
327 const TransformArray& smilTransforms =
328 *static_cast<const TransformArray*>(aValue.mU.mPtr);
330 aTransforms.Clear();
331 if (!aTransforms.SetCapacity(smilTransforms.Length(), fallible)) return false;
333 for (const auto& smilTransform : smilTransforms) {
334 // No need to check the return value below since we have already allocated
335 // the necessary space
336 (void)aTransforms.AppendElement(smilTransform.ToSVGTransform(), fallible);
338 return true;
341 } // namespace mozilla