Commit 0b3e5ace authored by ed@opera.com's avatar ed@opera.com

[SVG2] Add support for marker orient="auto-start-reverse".

Spec: https://svgwg.org/svg2-draft/painting.html#OrientAttribute

BUG=367748

Review URL: https://codereview.chromium.org/539833004

git-svn-id: svn://svn.chromium.org/blink/trunk@181732 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent e1d6de7f
SVG 1.1 dynamic animation tests
Animate SVGMarkerElement orientAttr from auto to auto-start-reverse
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_AUTO
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_AUTO
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS marker.orientAngle.animVal.value is 0
PASS marker.orientAngle.baseVal.value is 0
PASS marker.orientType.animVal is SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN
PASS marker.orientType.baseVal is SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE
PASS successfullyParsed is true
TEST COMPLETE
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<script src="../../resources/js-test.js"></script>
<script src="resources/SVGTestCase.js"></script>
<script src="resources/SVGAnimationTestCase.js"></script>
</head>
<body onload="runSMILTest()">
<h1>SVG 1.1 dynamic animation tests</h1>
<p id="description"></p>
<div id="console"></div>
<script src="script-tests/animate-marker-orient-from-auto-to-auto-start-reverse.js"></script>
</body>
</html>
description("Animate SVGMarkerElement orientAttr from auto to auto-start-reverse");
createSVGTestCase();
// Setup test document
var marker = createSVGElement("marker");
marker.setAttribute("id", "marker");
marker.setAttribute("viewBox", "0 0 10 10");
marker.setAttribute("markerWidth", "2");
marker.setAttribute("markerHeight", "2");
marker.setAttribute("refX", "5");
marker.setAttribute("refY", "5");
marker.setAttribute("markerUnits", "strokeWidth");
var markerPath = createSVGElement("path");
markerPath.setAttribute("fill", "blue");
markerPath.setAttribute("d", "M 5 0 L 10 10 L 0 10 Z");
marker.appendChild(markerPath);
var defsElement = createSVGElement("defs");
defsElement.appendChild(marker);
rootSVGElement.appendChild(defsElement);
var path = createSVGElement("path");
path.setAttribute("id", "path");
path.setAttribute("onclick", "executeTest()");
path.setAttribute("fill", "none");
path.setAttribute("stroke", "green");
path.setAttribute("stroke-width", "10");
path.setAttribute("marker-start", "url(#marker)");
path.setAttribute("marker-end", "url(#marker)");
path.setAttribute("d", "M 130 135 L 180 135 L 180 185");
path.setAttribute("transform", "translate(-130, -120)");
rootSVGElement.appendChild(path);
var animate1 = createSVGElement("animate");
animate1.setAttribute("id", "animation");
animate1.setAttribute("attributeName", "orient");
animate1.setAttribute("begin", "path.click");
animate1.setAttribute("dur", "4s");
animate1.setAttribute("from", "auto");
animate1.setAttribute("to", "auto-start-reverse");
animate1.setAttribute("fill", "freeze");
marker.appendChild(animate1);
// Setup animation test
function sample1() {
shouldBeCloseEnough("marker.orientAngle.animVal.value", "0");
shouldBe("marker.orientAngle.baseVal.value", "0");
shouldBe("marker.orientType.animVal", "SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE");
shouldBe("marker.orientType.baseVal", "SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE");
}
function sample2() {
shouldBeCloseEnough("marker.orientAngle.animVal.value", "0");
shouldBe("marker.orientAngle.baseVal.value", "0");
shouldBe("marker.orientType.animVal", "SVGMarkerElement.SVG_MARKER_ORIENT_AUTO");
shouldBe("marker.orientType.baseVal", "SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE");
}
function sample3() {
shouldBeCloseEnough("marker.orientAngle.animVal.value", "0");
shouldBe("marker.orientAngle.baseVal.value", "0");
shouldBe("marker.orientType.animVal", "SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN");
shouldBe("marker.orientType.baseVal", "SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE");
}
function executeTest() {
const expectedValues = [
// [animationId, time, sampleCallback]
["animation", 0.0, sample1],
["animation", 0.001, sample2],
["animation", 1.999, sample2],
["animation", 2.001, sample3],
["animation", 3.999, sample3],
["animation", 4.001, sample3]
];
runAnimationTest(expectedValues);
}
var successfullyParsed = true;
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg"
xmlns:xlink="http://www.w3.org/1999/xlink">
<title>Reference for test that marker orientation is correct at the end of
arcs when orient="auto-start-reverse" is used</title>
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=769115 -->
<defs>
<g id="m1" transform="translate(-20,-20)" fill="blue">
<rect x="5" y="15" width="22" height="10"/>
<rect x="25" y="10" height="20" width="10"/>
<rect x="35" y="18" height="4" width="5"/>
</g>
<g id="m2" transform="translate(-20,-20)" fill="red">
<rect x="5" y="15" width="22" height="10"/>
<rect x="25" y="10" height="20" width="10"/>
<rect x="35" y="18" height="4" width="5"/>
</g>
</defs>
<g fill="none">
<!-- arcs that go from the left of the circle to... -->
<g>
<!-- ...90 degrees anti-clockwise -->
<use xlink:href="#m1" transform="translate(100,100)rotate(270)"/>
<use xlink:href="#m2" transform="rotate(-90,150,100)translate(100,100)rotate(90)"/>
<!-- ...180 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(-180,150,100)translate(100,100)rotate(90)"/>
<!-- ...270 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(-270,150,100)translate(100,100)rotate(90)"/>
</g>
<!-- arcs that go from the left of the circle to... -->
<g transform="translate(250,0)">
<!-- ...90 degrees anti-clockwise -->
<use xlink:href="#m1" transform="translate(100,100)rotate(90)"/>
<use xlink:href="#m2" transform="rotate(90,150,100)translate(100,100)rotate(-90)"/>
<!-- ...180 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(180,150,100)translate(100,100)rotate(-90)"/>
<!-- ...270 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(270,150,100)translate(100,100)rotate(-90)"/>
</g>
<!-- arcs that go from the right of the circle to... -->
<g transform="translate(0,250)">
<!-- ...90 degrees anti-clockwise -->
<use xlink:href="#m1" transform="translate(200,100)rotate(270)"/>
<use xlink:href="#m2" transform="rotate(90,150,100)translate(200,100)rotate(90)"/>
<!-- ...180 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(180,150,100)translate(200,100)rotate(90)"/>
<!-- ...270 degrees anti-clockwise -->
<use xlink:href="#m2" transform="rotate(270,150,100)translate(200,100)rotate(90)"/>
</g>
<!-- arcs that go from the right of the circle to... -->
<g transform="translate(250,250)">
<!-- ...90 degrees clockwise -->
<use xlink:href="#m1" transform="translate(200,100)rotate(90)"/>
<use xlink:href="#m2" transform="rotate(-90,150,100)translate(200,100)rotate(-90)"/>
<!-- ...180 degrees clockwise -->
<use xlink:href="#m2" transform="rotate(-180,150,100)translate(200,100)rotate(-90)"/>
<!-- ...270 degrees clockwise -->
<use xlink:href="#m2" transform="rotate(-270,150,100)translate(200,100)rotate(-90)"/>
</g>
</g>
</svg>
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<svg xmlns="http://www.w3.org/2000/svg">
<title>Test that marker orientation is correct at the end of arcs when
orient="auto-start-reverse" is used</title>
<!-- https://bugzilla.mozilla.org/show_bug.cgi?id=769115 -->
<marker id="m1" markerWidth="40" markerHeight="40" refX="20" refY="20"
markerUnits="userSpaceOnUse" orient="auto-start-reverse" fill="blue">
<rect x="5" y="15" width="22" height="10"/>
<rect x="25" y="10" height="20" width="10"/>
<rect x="35" y="18" height="4" width="5"/>
</marker>
<marker id="m2" markerWidth="40" markerHeight="40" refX="20" refY="20"
markerUnits="userSpaceOnUse" orient="auto-start-reverse" fill="red">
<rect x="5" y="15" width="22" height="10"/>
<rect x="25" y="10" height="20" width="10"/>
<rect x="35" y="18" height="4" width="5"/>
</marker>
<g fill="none">
<!-- arcs that go from the left of the circle to... -->
<g marker-end="url(#m2)">
<!-- ...90 degrees anti-clockwise -->
<path d="M100,100 A 50,50 0 1 0 150,50" marker-start="url(#m1)"/>
<!-- ...180 degrees anti-clockwise -->
<path d="M100,100 A 50,50 0 0 0 200,100"/>
<!-- ...270 degrees anti-clockwise -->
<path d="M100,100 A 50,50 0 0 0 150,150"/>
</g>
<!-- arcs that go from the left of the circle to... -->
<g marker-end="url(#m2)" transform="translate(250,0)">
<!-- ...90 degrees clockwise -->
<path d="M100,100 A 50,50 0 0 1 150,50" marker-start="url(#m1)"/>
<!-- ...180 degrees clockwise -->
<path d="M100,100 A 50,50 0 1 1 200,100"/>
<!-- ...270 degrees clockwise -->
<path d="M100,100 A 50,50 0 1 1 150,150"/>
</g>
<!-- arcs that go from the right of the circle to... -->
<g marker-end="url(#m2)" transform="translate(0,250)">
<!-- ...90 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 0 1 150,150" marker-start="url(#m1)"/>
<!-- ...180 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 0 1 100,100"/>
<!-- ...270 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 1 1 150,50"/>
</g>
<!-- arcs that go from the right of the circle to... -->
<g marker-end="url(#m2)" transform="translate(250,250)">
<!-- ...90 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 0 0 150,50" marker-start="url(#m1)"/>
<!-- ...180 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 1 0 100,100"/>
<!-- ...270 degrees anti-clockwise -->
<path d="M200,100 A 50,50 0 1 0 150,150"/>
</g>
</g>
</svg>
......@@ -57,6 +57,7 @@ public:
FloatPoint referencePoint() const;
float angle() const;
SVGMarkerUnitsType markerUnits() const { return toSVGMarkerElement(element())->markerUnits()->currentValue()->enumValue(); }
SVGMarkerOrientType orientType() const { return toSVGMarkerElement(element())->orientType()->currentValue()->enumValue(); }
virtual RenderSVGResourceType resourceType() const OVERRIDE { return s_resourceType; }
static const RenderSVGResourceType s_resourceType;
......
......@@ -452,7 +452,12 @@ void RenderSVGShape::processMarkerPositions()
ASSERT(m_path);
SVGMarkerData markerData(m_markerPositions);
SVGResources* resources = SVGResourcesCache::cachedResourcesForRenderObject(this);
ASSERT(resources);
RenderSVGResourceMarker* markerStart = resources->markerStart();
SVGMarkerData markerData(m_markerPositions, markerStart ? markerStart->orientType() == SVGMarkerOrientAutoStartReverse : false);
m_path->apply(&markerData, SVGMarkerData::updateFromPathElement);
markerData.pathIsDone();
}
......
......@@ -47,9 +47,10 @@ struct MarkerPosition {
class SVGMarkerData {
public:
SVGMarkerData(Vector<MarkerPosition>& positions)
SVGMarkerData(Vector<MarkerPosition>& positions, bool autoStartReverse)
: m_positions(positions)
, m_elementIndex(0)
, m_autoStartReverse(autoStartReverse)
{
}
......@@ -88,6 +89,8 @@ private:
switch (type) {
case StartMarker:
if (m_autoStartReverse)
outAngle += 180;
return narrowPrecisionToFloat(outAngle);
case MidMarker:
// WK193015: Prevent bugs due to angles being non-continuous.
......@@ -147,6 +150,7 @@ private:
FloatPoint m_subpathStart;
FloatPoint m_inslopePoints[2];
FloatPoint m_outslopePoints[2];
bool m_autoStartReverse;
};
}
......
......@@ -186,6 +186,12 @@ static TextStream& operator<<(TextStream& ts, const SVGMarkerUnitsType& markerUn
return ts;
}
static TextStream& operator<<(TextStream& ts, const SVGMarkerOrientType& orientType)
{
ts << SVGEnumerationToString<SVGMarkerOrientType>(orientType);
return ts;
}
TextStream& operator<<(TextStream& ts, const Color& c)
{
return ts << c.nameForRenderTreeAsText();
......@@ -526,7 +532,7 @@ void writeSVGResourceContainer(TextStream& ts, const RenderObject& object, int i
ts << " [ref at " << marker->referencePoint() << "]";
ts << " [angle=";
if (marker->angle() == -1)
ts << "auto" << "]\n";
ts << marker->orientType() << "]\n";
else
ts << marker->angle() << "]\n";
} else if (resource->resourceType() == PatternResourceType) {
......
......@@ -38,10 +38,16 @@ template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGMarkerOr
if (entries.isEmpty()) {
entries.append(std::make_pair(SVGMarkerOrientAuto, "auto"));
entries.append(std::make_pair(SVGMarkerOrientAngle, "angle"));
entries.append(std::make_pair(SVGMarkerOrientAutoStartReverse, "auto-start-reverse"));
}
return entries;
}
template<> unsigned short getMaxExposedEnumValue<SVGMarkerOrientType>()
{
return SVGMarkerOrientAngle;
}
SVGMarkerOrientEnumeration::SVGMarkerOrientEnumeration(SVGAngle* angle)
: SVGEnumeration<SVGMarkerOrientType>(SVGMarkerOrientAngle)
, m_angle(angle)
......@@ -231,6 +237,11 @@ void SVGAngle::setValueAsString(const String& value, ExceptionState& exceptionSt
m_orientType->setEnumValue(SVGMarkerOrientAuto);
return;
}
if (value == "auto-start-reverse") {
newValueSpecifiedUnits(SVG_ANGLETYPE_UNSPECIFIED, 0);
m_orientType->setEnumValue(SVGMarkerOrientAutoStartReverse);
return;
}
float valueInSpecifiedUnits = 0;
SVGAngleType unitType = SVG_ANGLETYPE_UNKNOWN;
......@@ -373,27 +384,34 @@ void SVGAngle::calculateAnimatedValue(SVGAnimationElement* animationElement, flo
SVGMarkerOrientType toOrientType = toAngle->orientType()->enumValue();
if (fromOrientType != toOrientType) {
// Animating from eg. auto to 90deg, or auto to 90deg.
// Animating from eg. 90deg to auto.
if (fromOrientType == SVGMarkerOrientAngle) {
// Animating from an angle value to eg. 'auto' - this disabled additive as 'auto' is a keyword..
if (toOrientType == SVGMarkerOrientAuto) {
if (toOrientType == SVGMarkerOrientAuto || toOrientType == SVGMarkerOrientAutoStartReverse) {
if (percentage < 0.5f) {
newValueSpecifiedUnits(fromAngle->unitType(), fromAngle->valueInSpecifiedUnits());
return;
}
orientType()->setEnumValue(SVGMarkerOrientAuto);
orientType()->setEnumValue(toOrientType);
return;
}
m_valueInSpecifiedUnits = 0;
orientType()->setEnumValue(SVGMarkerOrientUnknown);
return;
} else if (toOrientType == SVGMarkerOrientAuto || toOrientType == SVGMarkerOrientAutoStartReverse) {
// Animating from e.g 'auto' to 'auto-start-reverse'
if (percentage >= 0.5f) {
m_valueInSpecifiedUnits = 0;
orientType()->setEnumValue(toOrientType);
return;
}
}
}
// From 'auto' to 'auto'.
if (fromOrientType == SVGMarkerOrientAuto) {
// From 'auto' to 'auto', or 'auto-start-reverse' to 'auto-start-reverse'
if (fromOrientType == SVGMarkerOrientAuto || fromOrientType == SVGMarkerOrientAutoStartReverse) {
m_valueInSpecifiedUnits = 0;
orientType()->setEnumValue(SVGMarkerOrientAuto);
orientType()->setEnumValue(fromOrientType);
return;
}
......@@ -418,7 +436,7 @@ float SVGAngle::calculateDistance(PassRefPtr<SVGPropertyBase> other, SVGElement*
void SVGAngle::orientTypeChanged()
{
if (orientType()->enumValue() == SVGMarkerOrientAuto) {
if (orientType()->enumValue() == SVGMarkerOrientAuto || orientType()->enumValue() == SVGMarkerOrientAutoStartReverse) {
m_unitType = SVG_ANGLETYPE_UNSPECIFIED;
m_valueInSpecifiedUnits = 0;
}
......
......@@ -33,9 +33,11 @@ class SVGAngleTearOff;
enum SVGMarkerOrientType {
SVGMarkerOrientUnknown = 0,
SVGMarkerOrientAuto,
SVGMarkerOrientAngle
SVGMarkerOrientAngle,
SVGMarkerOrientAutoStartReverse
};
template<> const SVGEnumerationStringEntries& getStaticStringEntries<SVGMarkerOrientType>();
template<> unsigned short getMaxExposedEnumValue<SVGMarkerOrientType>();
class SVGMarkerOrientEnumeration : public SVGEnumeration<SVGMarkerOrientType> {
public:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment