SVGOrientSMILType.cpp (5643B)
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 "SVGOrientSMILType.h" 8 9 #include <math.h> 10 11 #include "SVGAnimatedOrient.h" 12 #include "mozilla/SMILValue.h" 13 #include "mozilla/dom/SVGMarkerElement.h" 14 #include "nsDebug.h" 15 16 namespace mozilla { 17 18 using namespace dom::SVGAngle_Binding; 19 using namespace dom::SVGMarkerElement_Binding; 20 21 /*static*/ 22 SVGOrientSMILType SVGOrientSMILType::sSingleton; 23 24 void SVGOrientSMILType::InitValue(SMILValue& aValue) const { 25 MOZ_ASSERT(aValue.IsNull(), "Unexpected value type"); 26 27 aValue.mU.mOrient.mAngle = 0.0f; 28 aValue.mU.mOrient.mUnit = SVG_ANGLETYPE_UNSPECIFIED; 29 aValue.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_ANGLE; 30 aValue.mType = this; 31 } 32 33 void SVGOrientSMILType::DestroyValue(SMILValue& aValue) const { 34 MOZ_ASSERT(aValue.mType == this, "Unexpected SMIL value."); 35 aValue.mU.mPtr = nullptr; 36 aValue.mType = SMILNullType::Singleton(); 37 } 38 39 nsresult SVGOrientSMILType::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."); 43 44 aDest.mU.mOrient.mAngle = aSrc.mU.mOrient.mAngle; 45 aDest.mU.mOrient.mUnit = aSrc.mU.mOrient.mUnit; 46 aDest.mU.mOrient.mOrientType = aSrc.mU.mOrient.mOrientType; 47 return NS_OK; 48 } 49 50 bool SVGOrientSMILType::IsEqual(const SMILValue& aLeft, 51 const SMILValue& aRight) const { 52 MOZ_ASSERT(aLeft.mType == aRight.mType, "Incompatible SMIL types"); 53 MOZ_ASSERT(aLeft.mType == this, "Unexpected type for SMIL value"); 54 55 return aLeft.mU.mOrient.mAngle == aRight.mU.mOrient.mAngle && 56 aLeft.mU.mOrient.mUnit == aRight.mU.mOrient.mUnit && 57 aLeft.mU.mOrient.mOrientType == aRight.mU.mOrient.mOrientType; 58 } 59 60 static float ValueInDegrees(const SMILValue& aValue) { 61 MOZ_ASSERT(aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_ANGLE); 62 63 return aValue.mU.mOrient.mAngle == 0.0f 64 ? 0.0f 65 : aValue.mU.mOrient.mAngle * SVGAnimatedOrient::GetDegreesPerUnit( 66 aValue.mU.mOrient.mUnit); 67 } 68 69 nsresult SVGOrientSMILType::Add(SMILValue& aDest, const SMILValue& aValueToAdd, 70 uint32_t aCount) const { 71 MOZ_ASSERT(aValueToAdd.mType == aDest.mType, "Trying to add invalid types"); 72 MOZ_ASSERT(aValueToAdd.mType == this, "Unexpected source type"); 73 74 if (aDest.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE || 75 aValueToAdd.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) { 76 // TODO: it would be nice to be able to add to auto angles 77 return NS_ERROR_FAILURE; 78 } 79 80 // We may be dealing with two different angle units, so we normalize to 81 // degrees for the add: 82 float currentAngle = ValueInDegrees(aDest); 83 float angleToAdd = ValueInDegrees(aValueToAdd) * aCount; 84 85 // And then we give the resulting animated value the same units as the value 86 // that we're animating to/by (i.e. the same as aValueToAdd): 87 aDest.mU.mOrient.mAngle = 88 (currentAngle + angleToAdd) / 89 SVGAnimatedOrient::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit); 90 aDest.mU.mOrient.mUnit = aValueToAdd.mU.mOrient.mUnit; 91 92 return NS_OK; 93 } 94 95 nsresult SVGOrientSMILType::ComputeDistance(const SMILValue& aFrom, 96 const SMILValue& aTo, 97 double& aDistance) const { 98 MOZ_ASSERT(aFrom.mType == aTo.mType, "Trying to compare different types"); 99 MOZ_ASSERT(aFrom.mType == this, "Unexpected source type"); 100 101 if (aFrom.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE || 102 aTo.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) { 103 // TODO: it would be nice to be able to compute distance with auto angles 104 return NS_ERROR_FAILURE; 105 } 106 107 // Normalize both to degrees in case they're different angle units: 108 aDistance = fabs(ValueInDegrees(aTo) - ValueInDegrees(aFrom)); 109 110 return NS_OK; 111 } 112 113 nsresult SVGOrientSMILType::Interpolate(const SMILValue& aStartVal, 114 const SMILValue& aEndVal, 115 double aUnitDistance, 116 SMILValue& aResult) const { 117 MOZ_ASSERT(aStartVal.mType == aEndVal.mType, 118 "Trying to interpolate different types"); 119 MOZ_ASSERT(aStartVal.mType == this, "Unexpected types for interpolation."); 120 MOZ_ASSERT(aResult.mType == this, "Unexpected result type."); 121 122 if (aStartVal.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE || 123 aEndVal.mU.mOrient.mOrientType != SVG_MARKER_ORIENT_ANGLE) { 124 // TODO: it would be nice to be able to handle auto angles too. 125 return NS_ERROR_FAILURE; 126 } 127 128 float start = ValueInDegrees(aStartVal); 129 float end = ValueInDegrees(aEndVal); 130 float result = (start + (end - start) * aUnitDistance); 131 132 // we use the unit of the nearest value for the result: 133 if (aUnitDistance > 0.5) { 134 aResult.mU.mOrient.mAngle = 135 result / SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit); 136 aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit; 137 } else { 138 aResult.mU.mOrient.mAngle = result / SVGAnimatedOrient::GetDegreesPerUnit( 139 aStartVal.mU.mOrient.mUnit); 140 aResult.mU.mOrient.mUnit = aStartVal.mU.mOrient.mUnit; 141 } 142 143 return NS_OK; 144 } 145 146 } // namespace mozilla