Bug 1835348 - Support turn units for angles in markers r=emilio

per https://www.w3.org/TR/css-values-3/#angles it should be possible to specify angles in turn units

Note that per https://www.w3.org/TR/SVG2/types.html#InterfaceSVGAngle

    The use of numeric angle unit type constants is an anti-pattern and new constant values will not be introduced for any other units or angle types supported by SVGAngle. If other types of angles are supported and used, the SVGAngle uses the SVG_ANGLETYPE_UNKNOWN unit type.

Differential Revision: https://phabricator.services.mozilla.com/D179242
This commit is contained in:
Robert Longson 2023-05-26 20:42:23 +00:00
Родитель 7c76c7be7e
Коммит 7df52fba81
6 изменённых файлов: 79 добавлений и 27 удалений

Просмотреть файл

@ -25,11 +25,16 @@ JSObject* DOMSVGAngle::WrapObject(JSContext* aCx,
}
uint16_t DOMSVGAngle::UnitType() const {
uint16_t unitType;
if (mType == AngleType::AnimValue) {
mSVGElement->FlushAnimations();
return mVal->mAnimValUnit;
unitType = mVal->mAnimValUnit;
} else {
unitType = mVal->mBaseValUnit;
}
return mVal->mBaseValUnit;
return SVGAnimatedOrient::IsValidUnitType(unitType)
? unitType
: SVGAngle_Binding::SVG_ANGLETYPE_UNKNOWN;
}
float DOMSVGAngle::Value() const {

Просмотреть файл

@ -93,7 +93,7 @@ static bool GetValueFromString(const nsAString& aString, float& aValue,
}
const nsAString& units = Substring(iter.get(), end.get());
*aUnitType = SVGLength::GetUnitTypeForString(units);
return SVGLength::IsValidUnitType(*aUnitType);
return *aUnitType != SVGLength_Binding::SVG_LENGTHTYPE_UNKNOWN;
}
static float FixAxisLength(float aLength) {

Просмотреть файл

@ -73,9 +73,7 @@ class MOZ_RAII AutoChangeOrientNotifier {
bool mDoSetAttr;
};
static bool IsValidAngleUnitType(uint16_t aUnitType) {
return aUnitType > SVG_ANGLETYPE_UNKNOWN && aUnitType <= SVG_ANGLETYPE_GRAD;
}
const unsigned short SVG_ANGLETYPE_TURN = 5;
static void GetAngleUnitString(nsAString& aUnit, uint16_t aUnitType) {
switch (aUnitType) {
@ -91,6 +89,9 @@ static void GetAngleUnitString(nsAString& aUnit, uint16_t aUnitType) {
case SVG_ANGLETYPE_GRAD:
aUnit.AssignLiteral("grad");
return;
case SVG_ANGLETYPE_TURN:
aUnit.AssignLiteral("turn");
return;
}
MOZ_ASSERT_UNREACHABLE("Unknown unit type");
@ -109,6 +110,9 @@ static uint16_t GetAngleUnitTypeForString(const nsAString& aUnit) {
if (aUnit.LowerCaseEqualsLiteral("grad")) {
return SVG_ANGLETYPE_GRAD;
}
if (aUnit.LowerCaseEqualsLiteral("turn")) {
return SVG_ANGLETYPE_TURN;
}
return SVG_ANGLETYPE_UNKNOWN;
}
@ -121,6 +125,11 @@ static void GetAngleValueString(nsAString& aValueAsString, float aValue,
aValueAsString.Append(unitString);
}
/*static*/
bool SVGAnimatedOrient::IsValidUnitType(uint16_t aUnitType) {
return aUnitType > SVG_ANGLETYPE_UNKNOWN && aUnitType <= SVG_ANGLETYPE_GRAD;
}
/* static */
bool SVGAnimatedOrient::GetValueFromString(const nsAString& aString,
float& aValue, uint16_t* aUnitType) {
@ -140,7 +149,7 @@ bool SVGAnimatedOrient::GetValueFromString(const nsAString& aString,
const nsAString& units = Substring(iter.get(), end.get());
*aUnitType = GetAngleUnitTypeForString(units);
return IsValidAngleUnitType(*aUnitType);
return *aUnitType != SVG_ANGLETYPE_UNKNOWN;
}
/* static */
@ -153,6 +162,8 @@ float SVGAnimatedOrient::GetDegreesPerUnit(uint8_t aUnit) {
return static_cast<float>(180.0 / M_PI);
case SVG_ANGLETYPE_GRAD:
return 90.0f / 100.0f;
case SVG_ANGLETYPE_TURN:
return 360.0f;
default:
MOZ_ASSERT_UNREACHABLE("Unknown unit type");
return 0;
@ -177,7 +188,9 @@ void SVGAnimatedOrient::SetBaseValueInSpecifiedUnits(float aValue,
nsresult SVGAnimatedOrient::ConvertToSpecifiedUnits(uint16_t unitType,
SVGElement* aSVGElement) {
if (!IsValidAngleUnitType(unitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
if (!IsValidUnitType(unitType)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (mBaseValUnit == uint8_t(unitType) &&
mBaseType == SVG_MARKER_ORIENT_ANGLE) {
@ -195,7 +208,9 @@ nsresult SVGAnimatedOrient::NewValueSpecifiedUnits(uint16_t aUnitType,
SVGElement* aSVGElement) {
NS_ENSURE_FINITE(aValueInSpecifiedUnits, NS_ERROR_ILLEGAL_VALUE);
if (!IsValidAngleUnitType(aUnitType)) return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
if (!IsValidUnitType(aUnitType)) {
return NS_ERROR_DOM_NOT_SUPPORTED_ERR;
}
if (mBaseVal == aValueInSpecifiedUnits &&
mBaseValUnit == uint8_t(aUnitType) &&

Просмотреть файл

@ -79,6 +79,8 @@ class SVGAnimatedOrient {
SVGElement* aSVGElement);
UniquePtr<SMILAttr> ToSMILAttr(SVGElement* aSVGElement);
static bool IsValidUnitType(uint16_t aUnitType);
static bool GetValueFromString(const nsAString& aString, float& aValue,
uint16_t* aUnitType);
static float GetDegreesPerUnit(uint8_t aUnit);

Просмотреть файл

@ -46,7 +46,7 @@ bool SVGLength::SetValueFromString(const nsAString& aString) {
const nsAString& units = Substring(iter.get(), end.get());
uint16_t unitType = GetUnitTypeForString(units);
if (!IsValidUnitType(unitType)) {
if (unitType == SVG_LENGTHTYPE_UNKNOWN) {
return false;
}
mValue = value;

Просмотреть файл

@ -3,14 +3,22 @@
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
function createMarker() {
let markerElement = document.createElementNS("http://www.w3.org/2000/svg", "marker");
markerElement.setAttribute("markerUnits", "userSpaceOnUse");
markerElement.setAttribute("orient", "auto");
return markerElement;
}
function createSVGAngle() {
let svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
return svgElement.createSVGAngle();
}
test(function() {
// This test checks the use of SVGAnimatedEnumeration within SVGMarkerElement.
var markerElement = document.createElementNS("http://www.w3.org/2000/svg", "marker");
markerElement.setAttribute("markerUnits", "userSpaceOnUse");
markerElement.setAttribute("orient", "auto");
var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg");
let markerElement = createMarker();
// markerUnits
// Check initial 'markerUnits' value.
@ -40,6 +48,10 @@ test(function() {
markerElement.markerUnits.baseVal = SVGMarkerElement.SVG_MARKERUNITS_USERSPACEONUSE;
assert_equals(markerElement.markerUnits.baseVal, SVGMarkerElement.SVG_MARKERUNITS_USERSPACEONUSE);
assert_equals(markerElement.getAttribute('markerUnits'), "userSpaceOnUse");
}, "Test SVGAnimatedEnumeration");
test(function() {
let markerElement = createMarker();
// orientType
// Check initial 'orient' value.
@ -50,7 +62,7 @@ test(function() {
assert_equals(markerElement.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO);
// Switch to 'Pi/2 rad' value - via setOrientToAngle().
anglePiHalfRad = svgElement.createSVGAngle();
anglePiHalfRad = createSVGAngle();
anglePiHalfRad.newValueSpecifiedUnits(SVGAngle.SVG_ANGLETYPE_RAD, (Math.PI / 2).toFixed(2));
markerElement.setOrientToAngle(anglePiHalfRad);
assert_equals(markerElement.orientAngle.baseVal.value.toFixed(1), "90.0");
@ -66,7 +78,7 @@ test(function() {
assert_equals(markerElement.getAttribute('orient'), "auto");
// Switch to '20deg' value - via setOrientToAngle().
angle20deg = svgElement.createSVGAngle();
angle20deg = createSVGAngle();
angle20deg.newValueSpecifiedUnits(SVGAngle.SVG_ANGLETYPE_DEG, 20);
markerElement.setOrientToAngle(angle20deg);
assert_equals(markerElement.orientAngle.baseVal.value, 20);
@ -90,15 +102,6 @@ test(function() {
markerElement.setAttribute('orient', '10deg');
// Switch to 'auto-start-reverse' value - by modifying orientType.
markerElement.orientType.baseVal = SVGMarkerElement.SVG_MARKER_ORIENT_AUTO_START_REVERSE;
assert_equals(markerElement.orientAngle.baseVal.value, 0);
assert_equals(markerElement.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_UNSPECIFIED);
assert_equals(markerElement.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO_START_REVERSE);
assert_equals(markerElement.getAttribute('orient'), "auto-start-reverse");
markerElement.setAttribute('orient', '10deg');
// Try setting invalid values.
assert_throws_js(TypeError, function() { markerElement.orientType.baseVal = 4; });
assert_equals(markerElement.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_ANGLE);
@ -118,5 +121,32 @@ test(function() {
assert_equals(markerElement.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_UNSPECIFIED);
assert_equals(markerElement.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO);
assert_equals(markerElement.getAttribute('orient'), "auto");
});
}, "Test SVGOrient");
test(function() {
let markerElement = createMarker();
markerElement.setAttribute('orient', '400grad');
assert_equals(markerElement.orientAngle.baseVal.value, 360);
assert_equals(markerElement.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_GRAD);
}, "Test grad units");
test(function() {
let markerElement = createMarker();
markerElement.setAttribute('orient', '1turn');
assert_equals(markerElement.orientAngle.baseVal.value, 360);
assert_equals(markerElement.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_UNKNOWN);
}, "Test turn units");
test(function() {
let markerElement = createMarker();
// Switch to 'auto-start-reverse' value - by modifying orientType.
markerElement.orientType.baseVal = SVGMarkerElement.SVG_MARKER_ORIENT_AUTO_START_REVERSE;
assert_equals(markerElement.orientAngle.baseVal.value, 0);
assert_equals(markerElement.orientAngle.baseVal.unitType, SVGAngle.SVG_ANGLETYPE_UNSPECIFIED);
assert_equals(markerElement.orientType.baseVal, SVGMarkerElement.SVG_MARKER_ORIENT_AUTO_START_REVERSE);
assert_equals(markerElement.getAttribute('orient'), "auto-start-reverse");
}, "Test auto-start-reverse");
</script>