forked from mirrors/gecko-dev
Bug 631436 part 1 - use the nearest orient or length value for the result unit when interpolating r=emilio
Differential Revision: https://phabricator.services.mozilla.com/D191514
This commit is contained in:
parent
b3d1d40819
commit
5ec06e8577
8 changed files with 216 additions and 45 deletions
|
|
@ -174,8 +174,7 @@ class SVGLengthList {
|
||||||
*/
|
*/
|
||||||
class SVGLengthListAndInfo : public SVGLengthList {
|
class SVGLengthListAndInfo : public SVGLengthList {
|
||||||
public:
|
public:
|
||||||
SVGLengthListAndInfo()
|
SVGLengthListAndInfo() : mElement(nullptr), mAxis(0), mCanZeroPadList(true) {}
|
||||||
: mElement(nullptr), mAxis(0), mCanZeroPadList(false) {}
|
|
||||||
|
|
||||||
SVGLengthListAndInfo(dom::SVGElement* aElement, uint8_t aAxis,
|
SVGLengthListAndInfo(dom::SVGElement* aElement, uint8_t aAxis,
|
||||||
bool aCanZeroPadList)
|
bool aCanZeroPadList)
|
||||||
|
|
|
||||||
|
|
@ -24,12 +24,7 @@ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
|
||||||
void SVGLengthListSMILType::Init(SMILValue& aValue) const {
|
void SVGLengthListSMILType::Init(SMILValue& aValue) const {
|
||||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||||
|
|
||||||
SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();
|
aValue.mU.mPtr = new SVGLengthListAndInfo();
|
||||||
|
|
||||||
// See the comment documenting Init() in our header file:
|
|
||||||
lengthList->SetCanZeroPadList(true);
|
|
||||||
|
|
||||||
aValue.mU.mPtr = lengthList;
|
|
||||||
aValue.mType = this;
|
aValue.mType = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -251,19 +246,28 @@ nsresult SVGLengthListSMILType::Interpolate(const SMILValue& aStartVal,
|
||||||
return NS_ERROR_OUT_OF_MEMORY;
|
return NS_ERROR_OUT_OF_MEMORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If units differ, we use the unit of the nearest item.
|
||||||
|
// We leave it to the frame code to check that values are finite.
|
||||||
|
bool useEndUnits = (aUnitDistance > 0.5);
|
||||||
|
|
||||||
uint32_t i = 0;
|
uint32_t i = 0;
|
||||||
for (; i < start.Length() && i < end.Length(); ++i) {
|
for (; i < start.Length() && i < end.Length(); ++i) {
|
||||||
float s;
|
float s, e;
|
||||||
|
uint8_t unit;
|
||||||
if (start[i].GetUnit() == end[i].GetUnit()) {
|
if (start[i].GetUnit() == end[i].GetUnit()) {
|
||||||
|
unit = start[i].GetUnit();
|
||||||
s = start[i].GetValueInCurrentUnits();
|
s = start[i].GetValueInCurrentUnits();
|
||||||
|
e = end[i].GetValueInCurrentUnits();
|
||||||
|
} else if (useEndUnits) {
|
||||||
|
unit = end[i].GetUnit();
|
||||||
|
s = start[i].GetValueInSpecifiedUnit(unit, end.Element(), end.Axis());
|
||||||
|
e = end[i].GetValueInCurrentUnits();
|
||||||
} else {
|
} else {
|
||||||
// If units differ, we use the unit of the item in 'end'.
|
unit = start[i].GetUnit();
|
||||||
// We leave it to the frame code to check that values are finite.
|
s = start[i].GetValueInCurrentUnits();
|
||||||
s = start[i].GetValueInSpecifiedUnit(end[i].GetUnit(), end.Element(),
|
e = end[i].GetValueInSpecifiedUnit(unit, start.Element(), start.Axis());
|
||||||
end.Axis());
|
|
||||||
}
|
}
|
||||||
float e = end[i].GetValueInCurrentUnits();
|
result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, unit);
|
||||||
result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, end[i].GetUnit());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// In the case that start.Length() != end.Length(), one of the following
|
// In the case that start.Length() != end.Length(), one of the following
|
||||||
|
|
|
||||||
|
|
@ -42,9 +42,7 @@ SVGNumberListSMILType SVGNumberListSMILType::sSingleton;
|
||||||
void SVGNumberListSMILType::Init(SMILValue& aValue) const {
|
void SVGNumberListSMILType::Init(SMILValue& aValue) const {
|
||||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||||
|
|
||||||
SVGNumberListAndInfo* numberList = new SVGNumberListAndInfo();
|
aValue.mU.mPtr = new SVGNumberListAndInfo();
|
||||||
|
|
||||||
aValue.mU.mPtr = numberList;
|
|
||||||
aValue.mType = this;
|
aValue.mType = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -56,6 +56,15 @@ bool SVGOrientSMILType::IsEqual(const SMILValue& aLeft,
|
||||||
aLeft.mU.mOrient.mOrientType == aRight.mU.mOrient.mOrientType;
|
aLeft.mU.mOrient.mOrientType == aRight.mU.mOrient.mOrientType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float ValueInDegrees(const SMILValue& aValue) {
|
||||||
|
MOZ_ASSERT(aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_ANGLE);
|
||||||
|
|
||||||
|
return aValue.mU.mOrient.mAngle == 0.0f
|
||||||
|
? 0.0f
|
||||||
|
: aValue.mU.mOrient.mAngle * SVGAnimatedOrient::GetDegreesPerUnit(
|
||||||
|
aValue.mU.mOrient.mUnit);
|
||||||
|
}
|
||||||
|
|
||||||
nsresult SVGOrientSMILType::Add(SMILValue& aDest, const SMILValue& aValueToAdd,
|
nsresult SVGOrientSMILType::Add(SMILValue& aDest, const SMILValue& aValueToAdd,
|
||||||
uint32_t aCount) const {
|
uint32_t aCount) const {
|
||||||
MOZ_ASSERT(aValueToAdd.mType == aDest.mType, "Trying to add invalid types");
|
MOZ_ASSERT(aValueToAdd.mType == aDest.mType, "Trying to add invalid types");
|
||||||
|
|
@ -69,13 +78,8 @@ nsresult SVGOrientSMILType::Add(SMILValue& aDest, const SMILValue& aValueToAdd,
|
||||||
|
|
||||||
// We may be dealing with two different angle units, so we normalize to
|
// We may be dealing with two different angle units, so we normalize to
|
||||||
// degrees for the add:
|
// degrees for the add:
|
||||||
float currentAngle =
|
float currentAngle = ValueInDegrees(aDest);
|
||||||
aDest.mU.mOrient.mAngle *
|
float angleToAdd = ValueInDegrees(aValueToAdd) * aCount;
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aDest.mU.mOrient.mUnit);
|
|
||||||
float angleToAdd =
|
|
||||||
aValueToAdd.mU.mOrient.mAngle *
|
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit) *
|
|
||||||
aCount;
|
|
||||||
|
|
||||||
// And then we give the resulting animated value the same units as the value
|
// And then we give the resulting animated value the same units as the value
|
||||||
// that we're animating to/by (i.e. the same as aValueToAdd):
|
// that we're animating to/by (i.e. the same as aValueToAdd):
|
||||||
|
|
@ -100,12 +104,7 @@ nsresult SVGOrientSMILType::ComputeDistance(const SMILValue& aFrom,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Normalize both to degrees in case they're different angle units:
|
// Normalize both to degrees in case they're different angle units:
|
||||||
double from = aFrom.mU.mOrient.mAngle *
|
aDistance = fabs(ValueInDegrees(aTo) - ValueInDegrees(aFrom));
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aFrom.mU.mOrient.mUnit);
|
|
||||||
double to = aTo.mU.mOrient.mAngle *
|
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aTo.mU.mOrient.mUnit);
|
|
||||||
|
|
||||||
aDistance = fabs(to - from);
|
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
@ -125,17 +124,20 @@ nsresult SVGOrientSMILType::Interpolate(const SMILValue& aStartVal,
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
float start =
|
float start = ValueInDegrees(aStartVal);
|
||||||
aStartVal.mU.mOrient.mAngle *
|
float end = ValueInDegrees(aEndVal);
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aStartVal.mU.mOrient.mUnit);
|
|
||||||
float end = aEndVal.mU.mOrient.mAngle *
|
|
||||||
SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
|
|
||||||
float result = (start + (end - start) * aUnitDistance);
|
float result = (start + (end - start) * aUnitDistance);
|
||||||
|
|
||||||
// Again, we use the unit of the to/by value for the result:
|
// we use the unit of the nearest value for the result:
|
||||||
aResult.mU.mOrient.mAngle =
|
if (aUnitDistance > 0.5) {
|
||||||
result / SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
|
aResult.mU.mOrient.mAngle =
|
||||||
aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit;
|
result / SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
|
||||||
|
aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit;
|
||||||
|
} else {
|
||||||
|
aResult.mU.mOrient.mAngle = result / SVGAnimatedOrient::GetDegreesPerUnit(
|
||||||
|
aStartVal.mU.mOrient.mUnit);
|
||||||
|
aResult.mU.mOrient.mUnit = aStartVal.mU.mOrient.mUnit;
|
||||||
|
}
|
||||||
|
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,7 @@ SVGPointListSMILType SVGPointListSMILType::sSingleton;
|
||||||
void SVGPointListSMILType::Init(SMILValue& aValue) const {
|
void SVGPointListSMILType::Init(SMILValue& aValue) const {
|
||||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||||
|
|
||||||
SVGPointListAndInfo* pointList = new SVGPointListAndInfo();
|
aValue.mU.mPtr = new SVGPointListAndInfo();
|
||||||
|
|
||||||
aValue.mU.mPtr = pointList;
|
|
||||||
aValue.mType = this;
|
aValue.mType = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,7 @@ using TransformArray = FallibleTArray<SVGTransformSMILData>;
|
||||||
void SVGTransformListSMILType::Init(SMILValue& aValue) const {
|
void SVGTransformListSMILType::Init(SMILValue& aValue) const {
|
||||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||||
|
|
||||||
TransformArray* transforms = new TransformArray(1);
|
aValue.mU.mPtr = new TransformArray(1);
|
||||||
aValue.mU.mPtr = transforms;
|
|
||||||
aValue.mType = this;
|
aValue.mType = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,83 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test change of unit type for SVGAngle animation.</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
|
||||||
|
|
||||||
|
<svg>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var rootSVGElement = document.querySelector("svg");
|
||||||
|
|
||||||
|
// Setup test document
|
||||||
|
var defs = createSVGElement("defs");
|
||||||
|
|
||||||
|
var marker = createSVGElement("marker");
|
||||||
|
marker.setAttribute("id", "marker");
|
||||||
|
marker.setAttribute("viewBox", "0 0 10 10");
|
||||||
|
marker.setAttribute("markerWidth", "4");
|
||||||
|
marker.setAttribute("markerHeight", "3");
|
||||||
|
marker.setAttribute("markerUnits", "strokeWidth");
|
||||||
|
marker.setAttribute("refX", "1");
|
||||||
|
marker.setAttribute("refY", "5");
|
||||||
|
marker.setAttribute("orient", "0deg");
|
||||||
|
defs.appendChild(marker);
|
||||||
|
|
||||||
|
var polyline = createSVGElement("polyline");
|
||||||
|
polyline.setAttribute("id", "polyline");
|
||||||
|
polyline.setAttribute("points", "0,0 10,5 0,10 1,5");
|
||||||
|
polyline.setAttribute("fill", "green");
|
||||||
|
marker.appendChild(polyline);
|
||||||
|
|
||||||
|
var path = createSVGElement("path");
|
||||||
|
path.setAttribute("id", "path");
|
||||||
|
path.setAttribute("d", "M45,50 L55,50");
|
||||||
|
path.setAttribute("stroke-width","10");
|
||||||
|
path.setAttribute("stroke", "green");
|
||||||
|
path.setAttribute("marker-end", "url(#marker)");
|
||||||
|
path.setAttribute("onclick", "executeTest()");
|
||||||
|
|
||||||
|
var animate = createSVGElement("animate");
|
||||||
|
animate.setAttribute("id", "animation");
|
||||||
|
animate.setAttribute("attributeName", "orient");
|
||||||
|
animate.setAttribute("begin", "0s");
|
||||||
|
animate.setAttribute("dur", "4s");
|
||||||
|
animate.setAttribute("from", "0deg");
|
||||||
|
animate.setAttribute("to", "200grad");
|
||||||
|
marker.appendChild(animate);
|
||||||
|
rootSVGElement.appendChild(defs);
|
||||||
|
rootSVGElement.appendChild(path);
|
||||||
|
|
||||||
|
// Setup animation test
|
||||||
|
function sample1() {
|
||||||
|
// Check initial/end conditions
|
||||||
|
assert_equals(marker.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_DEG);
|
||||||
|
assert_equals(marker.orientAngle.animVal.unitType, SVGAngle.SVG_ANGLETYPE_DEG);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample2() {
|
||||||
|
assert_equals(marker.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_DEG);
|
||||||
|
assert_equals(marker.orientAngle.animVal.unitType, SVGAngle.SVG_ANGLETYPE_DEG);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample3() {
|
||||||
|
assert_equals(marker.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_DEG);
|
||||||
|
assert_equals(marker.orientAngle.animVal.unitType, SVGAngle.SVG_ANGLETYPE_GRAD);
|
||||||
|
}
|
||||||
|
|
||||||
|
smil_async_test((t) => {
|
||||||
|
const expectedValues = [
|
||||||
|
// [animationId, time, sampleCallback]
|
||||||
|
["animation", 0.0, sample1],
|
||||||
|
["animation", 2.0, sample2],
|
||||||
|
["animation", 3.999, sample3],
|
||||||
|
["animation", 4.001, sample1]
|
||||||
|
];
|
||||||
|
|
||||||
|
runAnimationTest(t, expectedValues);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
@ -0,0 +1,88 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Test change of unit type for SVGLengthList animation.</title>
|
||||||
|
<script src="/resources/testharness.js"></script>
|
||||||
|
<script src="/resources/testharnessreport.js"></script>
|
||||||
|
<script src="/resources/SVGAnimationTestCase-testharness.js"></script>
|
||||||
|
|
||||||
|
<svg>
|
||||||
|
</svg>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
var rootSVGElement = document.querySelector("svg");
|
||||||
|
|
||||||
|
// Setup test document
|
||||||
|
var text = createSVGElement("text");
|
||||||
|
text.setAttribute("id", "text");
|
||||||
|
text.textContent = "ABCD";
|
||||||
|
text.setAttribute("dx", "50 70 90 110");
|
||||||
|
text.setAttribute("y", "50");
|
||||||
|
text.setAttribute("onclick", "executeTest()");
|
||||||
|
rootSVGElement.appendChild(text);
|
||||||
|
|
||||||
|
var animate = createSVGElement("animate");
|
||||||
|
animate.setAttribute("id", "animation");
|
||||||
|
animate.setAttribute("attributeName", "dx");
|
||||||
|
animate.setAttribute("begin", "0s");
|
||||||
|
animate.setAttribute("dur", "4s");
|
||||||
|
animate.setAttribute("from", "50px 70px 90px 100px");
|
||||||
|
animate.setAttribute("to", "60% 90% 120% 150%");
|
||||||
|
text.appendChild(animate);
|
||||||
|
|
||||||
|
// Setup animation test
|
||||||
|
function sample1() {
|
||||||
|
assert_equals(text.dx.animVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.animVal[0].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.animVal[1].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.animVal[2].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.animVal[3].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
|
||||||
|
assert_equals(text.dx.baseVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.baseVal[0].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[1].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[2].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[3].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample2() {
|
||||||
|
assert_equals(text.dx.animVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.animVal[0].unitType, SVGLength.SVG_LENGTHTYPE_PX);
|
||||||
|
assert_equals(text.dx.animVal[1].unitType, SVGLength.SVG_LENGTHTYPE_PX);
|
||||||
|
assert_equals(text.dx.animVal[2].unitType, SVGLength.SVG_LENGTHTYPE_PX);
|
||||||
|
assert_equals(text.dx.animVal[3].unitType, SVGLength.SVG_LENGTHTYPE_PX);
|
||||||
|
|
||||||
|
assert_equals(text.dx.baseVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.baseVal[0].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[1].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[2].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[3].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sample3() {
|
||||||
|
assert_equals(text.dx.animVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.animVal[0].unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
|
||||||
|
assert_equals(text.dx.animVal[1].unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
|
||||||
|
assert_equals(text.dx.animVal[2].unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
|
||||||
|
assert_equals(text.dx.animVal[3].unitType, SVGLength.SVG_LENGTHTYPE_PERCENTAGE);
|
||||||
|
|
||||||
|
assert_equals(text.dx.baseVal.numberOfItems, 4);
|
||||||
|
assert_equals(text.dx.baseVal[0].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[1].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[2].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
assert_equals(text.dx.baseVal[3].unitType, SVGLength.SVG_LENGTHTYPE_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
smil_async_test((t) => {
|
||||||
|
const expectedValues = [
|
||||||
|
// [animationId, time, sampleCallback]
|
||||||
|
["animation", 0.0, sample1],
|
||||||
|
["animation", 2.0, sample2],
|
||||||
|
["animation", 3.999, sample3],
|
||||||
|
["animation", 4.001, sample1]
|
||||||
|
];
|
||||||
|
|
||||||
|
runAnimationTest(t, expectedValues);
|
||||||
|
});
|
||||||
|
|
||||||
|
</script>
|
||||||
Loading…
Reference in a new issue