Bug 879659 - Part 3: Implement <marker orient="auto-start-reverse">. r=longsonr

This commit is contained in:
Cameron McCormack 2013-07-12 16:39:38 +10:00
parent 3c1809b4b3
commit ec8519bdbb
10 changed files with 209 additions and 17 deletions

View File

@ -61,12 +61,22 @@ nsresult
nsSVGOrientType::SetBaseValue(uint16_t aValue,
nsSVGElement *aSVGElement)
{
if (aValue == SVG_MARKER_ORIENT_AUTO || aValue == SVG_MARKER_ORIENT_ANGLE) {
if (aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE &&
!SVGMarkerElement::MarkerImprovementsPrefEnabled()) {
return NS_ERROR_DOM_SYNTAX_ERR;
}
if (aValue == SVG_MARKER_ORIENT_AUTO ||
aValue == SVG_MARKER_ORIENT_ANGLE ||
aValue == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
SetBaseValue(aValue);
aSVGElement->SetAttr(
kNameSpaceID_None, nsGkAtoms::orient, nullptr,
(aValue == SVG_MARKER_ORIENT_AUTO ?
NS_LITERAL_STRING("auto") : NS_LITERAL_STRING("0")),
NS_LITERAL_STRING("auto") :
aValue == SVG_MARKER_ORIENT_ANGLE ?
NS_LITERAL_STRING("0") :
NS_LITERAL_STRING("auto-start-reverse")),
true);
return NS_OK;
}
@ -206,6 +216,12 @@ SVGMarkerElement::ParseAttribute(int32_t aNameSpaceID, nsIAtom* aName,
aResult.SetTo(aValue);
return true;
}
if (aValue.EqualsLiteral("auto-start-reverse") &&
MarkerImprovementsPrefEnabled()) {
mOrientType.SetBaseValue(SVG_MARKER_ORIENT_AUTO_START_REVERSE);
aResult.SetTo(aValue);
return true;
}
mOrientType.SetBaseValue(SVG_MARKER_ORIENT_ANGLE);
}
return SVGMarkerElementBase::ParseAttribute(aNameSpaceID, aName,
@ -282,14 +298,24 @@ SVGMarkerElement::GetPreserveAspectRatio()
gfxMatrix
SVGMarkerElement::GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAutoAngle)
float aX, float aY, float aAutoAngle,
bool aIsStart)
{
gfxFloat scale = mEnumAttributes[MARKERUNITS].GetAnimValue() ==
SVG_MARKERUNITS_STROKEWIDTH ? aStrokeWidth : 1.0;
gfxFloat angle = mOrientType.GetAnimValue() == SVG_MARKER_ORIENT_AUTO ?
aAutoAngle :
mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0;
gfxFloat angle;
switch (mOrientType.GetAnimValueInternal()) {
case SVG_MARKER_ORIENT_AUTO:
angle = aAutoAngle;
break;
case SVG_MARKER_ORIENT_AUTO_START_REVERSE:
angle = aAutoAngle + (aIsStart ? M_PI : 0.0);
break;
default: // SVG_MARKER_ORIENT_ANGLE
angle = mAngleAttributes[ORIENT].GetAnimValue() * M_PI / 180.0;
break;
}
return gfxMatrix(cos(angle) * scale, sin(angle) * scale,
-sin(angle) * scale, cos(angle) * scale,

View File

@ -30,9 +30,10 @@ static const unsigned short SVG_MARKERUNITS_USERSPACEONUSE = 1;
static const unsigned short SVG_MARKERUNITS_STROKEWIDTH = 2;
// Marker Orientation Types
static const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
static const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
static const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;
static const unsigned short SVG_MARKER_ORIENT_UNKNOWN = 0;
static const unsigned short SVG_MARKER_ORIENT_AUTO = 1;
static const unsigned short SVG_MARKER_ORIENT_ANGLE = 2;
static const unsigned short SVG_MARKER_ORIENT_AUTO_START_REVERSE = 3;
class nsSVGOrientType
{
@ -52,9 +53,15 @@ public:
void SetAnimValue(uint16_t aValue)
{ mAnimVal = uint8_t(aValue); }
// we want to avoid exposing SVG_MARKER_ORIENT_AUTO_START_REVERSE to
// Web content
uint16_t GetBaseValue() const
{ return mBaseVal; }
{ return mAnimVal == SVG_MARKER_ORIENT_AUTO_START_REVERSE ?
SVG_MARKER_ORIENT_UNKNOWN : mBaseVal; }
uint16_t GetAnimValue() const
{ return mAnimVal == SVG_MARKER_ORIENT_AUTO_START_REVERSE ?
SVG_MARKER_ORIENT_UNKNOWN : mAnimVal; }
uint16_t GetAnimValueInternal() const
{ return mAnimVal; }
already_AddRefed<SVGAnimatedEnumeration>
@ -115,7 +122,8 @@ public:
// public helpers
gfxMatrix GetMarkerTransform(float aStrokeWidth,
float aX, float aY, float aAutoAngle);
float aX, float aY, float aAutoAngle,
bool aIsStart);
nsSVGViewBoxRect GetViewBoxRect();
gfxMatrix GetViewBoxTransform();

View File

@ -15,14 +15,20 @@ class nsSMILValue;
* This nsISMILType class is a special case for the 'orient' attribute on SVG's
* 'marker' element.
*
* orient = "auto | <angle>"
* orient = "auto | auto-start-reverse | <angle>"
*
* Unusually, this attribute doesn't have just a single corresponding DOM
* property, but rather is split into two properties: 'orientType' (of type
* SVGAnimatedEnumeration) and 'orientAngle' (of type SVGAnimatedAngle). If
* 'orientType.animVal' is not SVG_MARKER_ORIENT_AUTO, then
* 'orientType.animVal' is SVG_MARKER_ORIENT_ANGLE, then
* 'orientAngle.animVal' contains the angle that is being used. The lacuna
* value is 0.
*
* The SVG 2 specification does not define a
* SVG_MARKER_ORIENT_AUTO_START_REVERSE constant value for orientType to use;
* instead, if the attribute is set to "auto-start-reverse",
* SVG_MARKER_ORIENT_UNKNOWN is used. Internally, however, we do use a
* constant with this name.
*/
namespace mozilla {

View File

@ -379,6 +379,8 @@ nsSVGAngle::SMILOrient::ValueFromString(const nsAString& aStr,
nsSMILValue val(&SVGOrientSMILType::sSingleton);
if (aStr.EqualsLiteral("auto")) {
val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO;
} else if (aStr.EqualsLiteral("auto-start-reverse")) {
val.mU.mOrient.mOrientType = SVG_MARKER_ORIENT_AUTO_START_REVERSE;
} else {
float value;
uint16_t unitType;
@ -426,7 +428,8 @@ nsSVGAngle::SMILOrient::SetAnimValue(const nsSMILValue& aValue)
if (aValue.mType == &SVGOrientSMILType::sSingleton) {
mOrientType->SetAnimValue(aValue.mU.mOrient.mOrientType);
if (aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO) {
if (aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO ||
aValue.mU.mOrient.mOrientType == SVG_MARKER_ORIENT_AUTO_START_REVERSE) {
mAngle->SetAnimValue(0.0f, SVG_ANGLETYPE_UNSPECIFIED, mSVGElement);
} else {
mAngle->SetAnimValue(aValue.mU.mOrient.mAngle, aValue.mU.mOrient.mUnit, mSVGElement);

View File

@ -169,6 +169,13 @@ function runTests()
marker.setAttribute("orient", "auto");
is(marker.getAttribute("orient"), "auto", "checking 'auto' string preserved");
is(marker.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO, "type baseVal");
is(marker.orientType.animVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO, "type animVal");
marker.setAttribute("orient", "auto-start-reverse");
is(marker.getAttribute("orient"), "auto-start-reverse", "checking 'auto-start-reverse' string preserved");
is(marker.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN, "type baseVal");
is(marker.orientType.animVal, SVGMarkerElement.SVG_MARKER_ORIENT_UNKNOWN, "type animVal");
marker.setAttribute("orient", "");
ok(marker.getAttribute("orient") === "", "empty angle attribute");
@ -296,7 +303,11 @@ function runTests()
SimpleTest.finish();
}
window.addEventListener("load", runTests, false);
function runTestsWithPref() {
SpecialPowers.pushPrefEnv({ 'set': [['svg.marker-improvements.enabled', true]] }, runTests);
}
window.addEventListener("load", runTestsWithPref, false);
</script>
</pre>
</body>

View File

@ -0,0 +1,69 @@
<!--
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-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"/>
<path d="M 25,10 35,20 25,30 z"/>
</g>
<g id="m2" transform="translate(-20,-20)" fill="red">
<rect x="5" y="15" width="22" height="10"/>
<path d="M 25,10 35,20 25,30 z"/>
</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>

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -0,0 +1,64 @@
<!--
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-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"/>
<path d="M 25,10 35,20 25,30 z"/>
</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"/>
<path d="M 25,10 35,20 25,30 z"/>
</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>

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@ -184,6 +184,7 @@ fuzzy-if(Android,9,980) == gradient-live-01d.svg gradient-live-01-ref.svg
== marker-attribute-01.svg pass.svg
== marker-viewBox-01.svg marker-viewBox-01-ref.svg
== marker-orientation-01.svg marker-orientation-01-ref.svg
pref(svg.marker-improvements.enabled,true) == marker-orientation-02.svg marker-orientation-02-ref.svg
== mask-basic-01.svg pass.svg
== mask-basic-02.svg mask-basic-02-ref.svg
== mask-basic-03.svg pass.svg

View File

@ -85,7 +85,8 @@ nsSVGMarkerFrame::GetCanvasTM(uint32_t aFor)
gfxMatrix markedTM = mMarkedFrame->GetCanvasTM(aFor);
mInUse2 = false;
gfxMatrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle);
gfxMatrix markerTM = content->GetMarkerTransform(mStrokeWidth, mX, mY,
mAutoAngle, mIsStart);
gfxMatrix viewBoxTM = content->GetViewBoxTransform();
return viewBoxTM * markerTM * markedTM;
@ -118,6 +119,7 @@ nsSVGMarkerFrame::PaintMark(nsRenderingContext *aContext,
mX = aMark->x;
mY = aMark->y;
mAutoAngle = aMark->angle;
mIsStart = aMark->type == nsSVGMark::eStart;
gfxContext *gfx = aContext->ThebesContext();
@ -175,9 +177,10 @@ nsSVGMarkerFrame::GetMarkBBoxContribution(const gfxMatrix &aToBBoxUserspace,
mX = aMark->x;
mY = aMark->y;
mAutoAngle = aMark->angle;
mIsStart = aMark->type == nsSVGMark::eStart;
gfxMatrix markerTM =
content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle);
content->GetMarkerTransform(mStrokeWidth, mX, mY, mAutoAngle, mIsStart);
gfxMatrix viewBoxTM = content->GetViewBoxTransform();
gfxMatrix tm = viewBoxTM * markerTM * aToBBoxUserspace;

View File

@ -94,6 +94,7 @@ private:
// stuff needed for callback
nsSVGPathGeometryFrame *mMarkedFrame;
float mStrokeWidth, mX, mY, mAutoAngle;
bool mIsStart; // whether the callback is for a marker-start marker
// nsSVGContainerFrame methods:
virtual gfxMatrix GetCanvasTM(uint32_t aFor) MOZ_OVERRIDE;