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 {
|
||||
public:
|
||||
SVGLengthListAndInfo()
|
||||
: mElement(nullptr), mAxis(0), mCanZeroPadList(false) {}
|
||||
SVGLengthListAndInfo() : mElement(nullptr), mAxis(0), mCanZeroPadList(true) {}
|
||||
|
||||
SVGLengthListAndInfo(dom::SVGElement* aElement, uint8_t aAxis,
|
||||
bool aCanZeroPadList)
|
||||
|
|
|
|||
|
|
@ -24,12 +24,7 @@ SVGLengthListSMILType SVGLengthListSMILType::sSingleton;
|
|||
void SVGLengthListSMILType::Init(SMILValue& aValue) const {
|
||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||
|
||||
SVGLengthListAndInfo* lengthList = new SVGLengthListAndInfo();
|
||||
|
||||
// See the comment documenting Init() in our header file:
|
||||
lengthList->SetCanZeroPadList(true);
|
||||
|
||||
aValue.mU.mPtr = lengthList;
|
||||
aValue.mU.mPtr = new SVGLengthListAndInfo();
|
||||
aValue.mType = this;
|
||||
}
|
||||
|
||||
|
|
@ -251,19 +246,28 @@ nsresult SVGLengthListSMILType::Interpolate(const SMILValue& aStartVal,
|
|||
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;
|
||||
for (; i < start.Length() && i < end.Length(); ++i) {
|
||||
float s;
|
||||
float s, e;
|
||||
uint8_t unit;
|
||||
if (start[i].GetUnit() == end[i].GetUnit()) {
|
||||
unit = start[i].GetUnit();
|
||||
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 {
|
||||
// If units differ, we use the unit of the item in 'end'.
|
||||
// We leave it to the frame code to check that values are finite.
|
||||
s = start[i].GetValueInSpecifiedUnit(end[i].GetUnit(), end.Element(),
|
||||
end.Axis());
|
||||
unit = start[i].GetUnit();
|
||||
s = start[i].GetValueInCurrentUnits();
|
||||
e = end[i].GetValueInSpecifiedUnit(unit, start.Element(), start.Axis());
|
||||
}
|
||||
float e = end[i].GetValueInCurrentUnits();
|
||||
result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, end[i].GetUnit());
|
||||
result[i].SetValueAndUnit(s + (e - s) * aUnitDistance, unit);
|
||||
}
|
||||
|
||||
// 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 {
|
||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||
|
||||
SVGNumberListAndInfo* numberList = new SVGNumberListAndInfo();
|
||||
|
||||
aValue.mU.mPtr = numberList;
|
||||
aValue.mU.mPtr = new SVGNumberListAndInfo();
|
||||
aValue.mType = this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -56,6 +56,15 @@ bool SVGOrientSMILType::IsEqual(const SMILValue& aLeft,
|
|||
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,
|
||||
uint32_t aCount) const {
|
||||
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
|
||||
// degrees for the add:
|
||||
float currentAngle =
|
||||
aDest.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aDest.mU.mOrient.mUnit);
|
||||
float angleToAdd =
|
||||
aValueToAdd.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aValueToAdd.mU.mOrient.mUnit) *
|
||||
aCount;
|
||||
float currentAngle = ValueInDegrees(aDest);
|
||||
float angleToAdd = ValueInDegrees(aValueToAdd) * aCount;
|
||||
|
||||
// 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):
|
||||
|
|
@ -100,12 +104,7 @@ nsresult SVGOrientSMILType::ComputeDistance(const SMILValue& aFrom,
|
|||
}
|
||||
|
||||
// Normalize both to degrees in case they're different angle units:
|
||||
double from = aFrom.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aFrom.mU.mOrient.mUnit);
|
||||
double to = aTo.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aTo.mU.mOrient.mUnit);
|
||||
|
||||
aDistance = fabs(to - from);
|
||||
aDistance = fabs(ValueInDegrees(aTo) - ValueInDegrees(aFrom));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
@ -125,17 +124,20 @@ nsresult SVGOrientSMILType::Interpolate(const SMILValue& aStartVal,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
float start =
|
||||
aStartVal.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aStartVal.mU.mOrient.mUnit);
|
||||
float end = aEndVal.mU.mOrient.mAngle *
|
||||
SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
|
||||
float start = ValueInDegrees(aStartVal);
|
||||
float end = ValueInDegrees(aEndVal);
|
||||
float result = (start + (end - start) * aUnitDistance);
|
||||
|
||||
// Again, we use the unit of the to/by value for the result:
|
||||
aResult.mU.mOrient.mAngle =
|
||||
result / SVGAnimatedOrient::GetDegreesPerUnit(aEndVal.mU.mOrient.mUnit);
|
||||
aResult.mU.mOrient.mUnit = aEndVal.mU.mOrient.mUnit;
|
||||
// we use the unit of the nearest value for the result:
|
||||
if (aUnitDistance > 0.5) {
|
||||
aResult.mU.mOrient.mAngle =
|
||||
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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,9 +23,7 @@ SVGPointListSMILType SVGPointListSMILType::sSingleton;
|
|||
void SVGPointListSMILType::Init(SMILValue& aValue) const {
|
||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||
|
||||
SVGPointListAndInfo* pointList = new SVGPointListAndInfo();
|
||||
|
||||
aValue.mU.mPtr = pointList;
|
||||
aValue.mU.mPtr = new SVGPointListAndInfo();
|
||||
aValue.mType = this;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ using TransformArray = FallibleTArray<SVGTransformSMILData>;
|
|||
void SVGTransformListSMILType::Init(SMILValue& aValue) const {
|
||||
MOZ_ASSERT(aValue.IsNull(), "Unexpected value type");
|
||||
|
||||
TransformArray* transforms = new TransformArray(1);
|
||||
aValue.mU.mPtr = transforms;
|
||||
aValue.mU.mPtr = new TransformArray(1);
|
||||
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