diff options
author | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
---|---|---|
committer | Matt A. Tobin <mattatobin@localhost.localdomain> | 2018-02-02 04:16:08 -0500 |
commit | 5f8de423f190bbb79a62f804151bc24824fa32d8 (patch) | |
tree | 10027f336435511475e392454359edea8e25895d /dom/svg/SVGTransformListSMILType.cpp | |
parent | 49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff) | |
download | UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip |
Add m-esr52 at 52.6.0
Diffstat (limited to 'dom/svg/SVGTransformListSMILType.cpp')
-rw-r--r-- | dom/svg/SVGTransformListSMILType.cpp | 369 |
1 files changed, 369 insertions, 0 deletions
diff --git a/dom/svg/SVGTransformListSMILType.cpp b/dom/svg/SVGTransformListSMILType.cpp new file mode 100644 index 000000000..40777b026 --- /dev/null +++ b/dom/svg/SVGTransformListSMILType.cpp @@ -0,0 +1,369 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "SVGTransformListSMILType.h" +#include "SVGTransformList.h" +#include "nsSVGTransform.h" +#include "nsSMILValue.h" +#include "nsCRT.h" +#include <math.h> + +using namespace mozilla; + +typedef FallibleTArray<SVGTransformSMILData> TransformArray; + +//---------------------------------------------------------------------- +// nsISMILType implementation + +void +SVGTransformListSMILType::Init(nsSMILValue &aValue) const +{ + NS_PRECONDITION(aValue.IsNull(), "Unexpected value type"); + + TransformArray* transforms = new TransformArray(1); + aValue.mU.mPtr = transforms; + aValue.mType = this; +} + +void +SVGTransformListSMILType::Destroy(nsSMILValue& aValue) const +{ + NS_PRECONDITION(aValue.mType == this, "Unexpected SMIL value type"); + TransformArray* params = static_cast<TransformArray*>(aValue.mU.mPtr); + delete params; + aValue.mU.mPtr = nullptr; + aValue.mType = nsSMILNullType::Singleton(); +} + +nsresult +SVGTransformListSMILType::Assign(nsSMILValue& aDest, + const nsSMILValue& aSrc) const +{ + NS_PRECONDITION(aDest.mType == aSrc.mType, "Incompatible SMIL types"); + NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL value"); + + const TransformArray* srcTransforms = + static_cast<const TransformArray*>(aSrc.mU.mPtr); + TransformArray* dstTransforms = static_cast<TransformArray*>(aDest.mU.mPtr); + if (!dstTransforms->Assign(*srcTransforms, fallible)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + return NS_OK; +} + +bool +SVGTransformListSMILType::IsEqual(const nsSMILValue& aLeft, + const nsSMILValue& aRight) const +{ + NS_PRECONDITION(aLeft.mType == aRight.mType, "Incompatible SMIL types"); + NS_PRECONDITION(aLeft.mType == this, "Unexpected SMIL type"); + + const TransformArray& leftArr + (*static_cast<const TransformArray*>(aLeft.mU.mPtr)); + const TransformArray& rightArr + (*static_cast<const TransformArray*>(aRight.mU.mPtr)); + + // If array-lengths don't match, we're trivially non-equal. + if (leftArr.Length() != rightArr.Length()) { + return false; + } + + // Array-lengths match -- check each array-entry for equality. + uint32_t length = leftArr.Length(); // == rightArr->Length(), if we get here + for (uint32_t i = 0; i < length; ++i) { + if (leftArr[i] != rightArr[i]) { + return false; + } + } + + // Found no differences. + return true; +} + +nsresult +SVGTransformListSMILType::Add(nsSMILValue& aDest, + const nsSMILValue& aValueToAdd, + uint32_t aCount) const +{ + NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type"); + NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types"); + + TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr)); + const TransformArray& srcTransforms + (*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr)); + + // We're doing a simple add here (as opposed to a sandwich add below). + // We only do this when we're accumulating a repeat result or calculating + // a by-animation value. + // + // In either case we should have 1 transform in the source array. + NS_ASSERTION(srcTransforms.Length() == 1, + "Invalid source transform list to add"); + + // And we should have 0 or 1 transforms in the dest array. + // (We can have 0 transforms in the case of by-animation when we are + // calculating the by-value as "0 + by". Zero being represented by an + // nsSMILValue with an empty transform array.) + NS_ASSERTION(dstTransforms.Length() < 2, + "Invalid dest transform list to add to"); + + // Get the individual transforms to add + const SVGTransformSMILData& srcTransform = srcTransforms[0]; + if (dstTransforms.IsEmpty()) { + SVGTransformSMILData* result = dstTransforms.AppendElement( + SVGTransformSMILData(srcTransform.mTransformType), fallible); + NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY); + } + SVGTransformSMILData& dstTransform = dstTransforms[0]; + + // The types must be the same + NS_ASSERTION(srcTransform.mTransformType == dstTransform.mTransformType, + "Trying to perform simple add of different transform types"); + + // And it should be impossible that one of them is of matrix type + NS_ASSERTION( + srcTransform.mTransformType != SVG_TRANSFORM_MATRIX, + "Trying to perform simple add with matrix transform"); + + // Add the parameters + for (int i = 0; i <= 2; ++i) { + dstTransform.mParams[i] += srcTransform.mParams[i] * aCount; + } + + return NS_OK; +} + +nsresult +SVGTransformListSMILType::SandwichAdd(nsSMILValue& aDest, + const nsSMILValue& aValueToAdd) const +{ + NS_PRECONDITION(aDest.mType == this, "Unexpected SMIL type"); + NS_PRECONDITION(aDest.mType == aValueToAdd.mType, "Incompatible SMIL types"); + + // For <animateTransform> a sandwich add means a matrix post-multiplication + // which just means to put the additional transform on the end of the array + + TransformArray& dstTransforms(*static_cast<TransformArray*>(aDest.mU.mPtr)); + const TransformArray& srcTransforms + (*static_cast<const TransformArray*>(aValueToAdd.mU.mPtr)); + + // We should have 0 or 1 transforms in the src list. + NS_ASSERTION(srcTransforms.Length() < 2, + "Trying to do sandwich add of more than one value"); + + // The empty src transform list case only occurs in some limited circumstances + // where we create an empty 'from' value to interpolate from (e.g. + // by-animation) but then skip the interpolation step for some reason (e.g. + // because we have an indefinite duration which means we'll never get past the + // first value) and instead attempt to add that empty value to the underlying + // value. + // In any case, the expected result is that nothing is added. + if (srcTransforms.IsEmpty()) + return NS_OK; + + // Stick the src on the end of the array + const SVGTransformSMILData& srcTransform = srcTransforms[0]; + SVGTransformSMILData* result = + dstTransforms.AppendElement(srcTransform, fallible); + NS_ENSURE_TRUE(result,NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; +} + +nsresult +SVGTransformListSMILType::ComputeDistance(const nsSMILValue& aFrom, + const nsSMILValue& aTo, + double& aDistance) const +{ + NS_PRECONDITION(aFrom.mType == aTo.mType, + "Can't compute difference between different SMIL types"); + NS_PRECONDITION(aFrom.mType == this, "Unexpected SMIL type"); + + const TransformArray* fromTransforms = + static_cast<const TransformArray*>(aFrom.mU.mPtr); + const TransformArray* toTransforms = + static_cast<const TransformArray*>(aTo.mU.mPtr); + + // ComputeDistance is only used for calculating distances between single + // values in a values array which necessarily have the same type + // + // So we should only have one transform in each array and they should be of + // the same type + NS_ASSERTION(fromTransforms->Length() == 1, + "Wrong number of elements in from value"); + NS_ASSERTION(toTransforms->Length() == 1, + "Wrong number of elements in to value"); + + const SVGTransformSMILData& fromTransform = (*fromTransforms)[0]; + const SVGTransformSMILData& toTransform = (*toTransforms)[0]; + NS_ASSERTION(fromTransform.mTransformType == toTransform.mTransformType, + "Incompatible transform types to calculate distance between"); + + switch (fromTransform.mTransformType) + { + // We adopt the SVGT1.2 notions of distance here + // See: http://www.w3.org/TR/SVGTiny12/animate.html#complexDistances + // (As discussed in bug #469040) + case SVG_TRANSFORM_TRANSLATE: + case SVG_TRANSFORM_SCALE: + { + const float& a_tx = fromTransform.mParams[0]; + const float& a_ty = fromTransform.mParams[1]; + const float& b_tx = toTransform.mParams[0]; + const float& b_ty = toTransform.mParams[1]; + aDistance = sqrt(pow(a_tx - b_tx, 2) + (pow(a_ty - b_ty, 2))); + } + break; + + case SVG_TRANSFORM_ROTATE: + case SVG_TRANSFORM_SKEWX: + case SVG_TRANSFORM_SKEWY: + { + const float& a = fromTransform.mParams[0]; + const float& b = toTransform.mParams[0]; + aDistance = fabs(a-b); + } + break; + + default: + NS_ERROR("Got bad transform types for calculating distances"); + aDistance = 1.0; + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + +nsresult +SVGTransformListSMILType::Interpolate(const nsSMILValue& aStartVal, + const nsSMILValue& aEndVal, + double aUnitDistance, + nsSMILValue& aResult) const +{ + NS_PRECONDITION(aStartVal.mType == aEndVal.mType, + "Can't interpolate between different SMIL types"); + NS_PRECONDITION(aStartVal.mType == this, + "Unexpected type for interpolation"); + NS_PRECONDITION(aResult.mType == this, "Unexpected result type"); + + const TransformArray& startTransforms = + (*static_cast<const TransformArray*>(aStartVal.mU.mPtr)); + const TransformArray& endTransforms + (*static_cast<const TransformArray*>(aEndVal.mU.mPtr)); + + // We may have 0..n transforms in the start transform array (the base + // value) but we should only have 1 transform in the end transform array + NS_ASSERTION(endTransforms.Length() == 1, + "Invalid end-point for interpolating between transform values"); + + // The end point should never be a matrix transform + const SVGTransformSMILData& endTransform = endTransforms[0]; + NS_ASSERTION( + endTransform.mTransformType != SVG_TRANSFORM_MATRIX, + "End point for interpolation should not be a matrix transform"); + + // If we have 0 or more than 1 transform in the start transform array then we + // just interpolate from 0, 0, 0 + // Likewise, even if there's only 1 transform in the start transform array + // then if the type of the start transform doesn't match the end then we + // can't interpolate and should just use 0, 0, 0 + static float identityParams[3] = { 0.f }; + const float* startParams = nullptr; + if (startTransforms.Length() == 1) { + const SVGTransformSMILData& startTransform = startTransforms[0]; + if (startTransform.mTransformType == endTransform.mTransformType) { + startParams = startTransform.mParams; + } + } + if (!startParams) { + startParams = identityParams; + } + + const float* endParams = endTransform.mParams; + + // Interpolate between the params + float newParams[3]; + for (int i = 0; i <= 2; ++i) { + const float& a = startParams[i]; + const float& b = endParams[i]; + newParams[i] = static_cast<float>(a + (b - a) * aUnitDistance); + } + + // Make the result + SVGTransformSMILData resultTransform(endTransform.mTransformType, newParams); + + // Clear the way for it in the result array + TransformArray& dstTransforms = + (*static_cast<TransformArray*>(aResult.mU.mPtr)); + dstTransforms.Clear(); + + // Assign the result + SVGTransformSMILData* transform = + dstTransforms.AppendElement(resultTransform, fallible); + NS_ENSURE_TRUE(transform,NS_ERROR_OUT_OF_MEMORY); + + return NS_OK; +} + +//---------------------------------------------------------------------- +// Transform array accessors + +// static +nsresult +SVGTransformListSMILType::AppendTransform( + const SVGTransformSMILData& aTransform, + nsSMILValue& aValue) +{ + NS_PRECONDITION(aValue.mType == Singleton(), "Unexpected SMIL value type"); + + TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr); + return transforms.AppendElement(aTransform, fallible) ? + NS_OK : NS_ERROR_OUT_OF_MEMORY; +} + +// static +bool +SVGTransformListSMILType::AppendTransforms(const SVGTransformList& aList, + nsSMILValue& aValue) +{ + NS_PRECONDITION(aValue.mType == Singleton(), "Unexpected SMIL value type"); + + TransformArray& transforms = *static_cast<TransformArray*>(aValue.mU.mPtr); + + if (!transforms.SetCapacity(transforms.Length() + aList.Length(), fallible)) + return false; + + for (uint32_t i = 0; i < aList.Length(); ++i) { + // No need to check the return value below since we have already allocated + // the necessary space + MOZ_ALWAYS_TRUE(transforms.AppendElement(SVGTransformSMILData(aList[i]), + fallible)); + } + return true; +} + +// static +bool +SVGTransformListSMILType::GetTransforms(const nsSMILValue& aValue, + FallibleTArray<nsSVGTransform>& aTransforms) +{ + NS_PRECONDITION(aValue.mType == Singleton(), "Unexpected SMIL value type"); + + const TransformArray& smilTransforms = + *static_cast<const TransformArray*>(aValue.mU.mPtr); + + aTransforms.Clear(); + if (!aTransforms.SetCapacity(smilTransforms.Length(), fallible)) + return false; + + for (uint32_t i = 0; i < smilTransforms.Length(); ++i) { + // No need to check the return value below since we have already allocated + // the necessary space + aTransforms.AppendElement(smilTransforms[i].ToSVGTransform(), fallible); + } + return true; +} |