Bug 1218257 - Use rust lengths for the SVG lengths. r=boris

As it turns out we need this to avoid losing precision both during painting and
during serialization.

This patch also changes to serialize `context-value` if it's the computed value.

I could keep the previous behavior, but it makes no sense to serialize the
initial value. We're the only ones to support this value anyway, and I couldn't
find a definition or spec for this.

Also update tests and expectations for:

 * New unexpected passes.
 * Always serializing the unit in getComputedStyle.
 * Calc and interpolation support.

Chrome also always serializes the unit in getComputedStyle, so I'm pretty sure
this is compatible with them. Chrome is inconsistent and keeps numbers in
specified style, but that's inconsistent with itself and with other quirky
lengths, so I updated the tests instead.

Differential Revision: https://phabricator.services.mozilla.com/D21819
This commit is contained in:
Emilio Cobos Álvarez 2019-03-02 02:09:19 +01:00
parent 7e10c7b612
commit f02f6a3545
23 changed files with 100 additions and 235 deletions

View File

@ -287,11 +287,11 @@ var gPacedBundles =
new TestcaseBundle(gPropList.stroke_dasharray,
[].concat(_pacedTestLists.lengthPctSVG, [
new AnimTestcasePaced("7, 7, 7; 7, 10, 3; 1, 2, 3",
{ comp0: "7, 7, 7",
comp1_6: "7, 8.5, 5",
comp1_3: "7, 10, 3",
comp2_3: "4, 6, 3",
comp1: "1, 2, 3"
{ comp0: "7px, 7px, 7px",
comp1_6: "7px, 8.5px, 5px",
comp1_3: "7px, 10px, 3px",
comp2_3: "4px, 6px, 3px",
comp1: "1px, 2px, 3px"
}),
])),
new TestcaseBundle(gPropList.stroke_dashoffset,
@ -304,5 +304,4 @@ var gPacedBundles =
_pacedTestLists.lengthPx,
_pacedTestLists.lengthPctSVG,
_pacedTestLists.lengthPxPctSVG)),
// XXXdholbert TODO: test 'stroke-dasharray' once we support animating it
];

View File

@ -179,7 +179,7 @@ static DashState GetStrokeDashData(
(i % 2 ? totalLengthOfGaps : totalLengthOfDashes) += dashSrc[i];
}
} else {
const nsTArray<nsStyleCoord>& dasharray = aStyleSVG->mStrokeDasharray;
const auto& dasharray = aStyleSVG->mStrokeDasharray;
dashArrayLength = aStyleSVG->mStrokeDasharray.Length();
if (dashArrayLength <= 0) {
return eContinuousStroke;
@ -198,8 +198,7 @@ static DashState GetStrokeDashData(
}
for (uint32_t i = 0; i < dashArrayLength; i++) {
Float dashLength =
SVGContentUtils::CoordToFloat(aElement, dasharray[i], true) *
pathScale;
SVGContentUtils::CoordToFloat(aElement, dasharray[i]) * pathScale;
if (dashLength < 0.0) {
return eContinuousStroke; // invalid
}
@ -243,8 +242,7 @@ static DashState GetStrokeDashData(
aStrokeOptions->mDashOffset = Float(aContextPaint->GetStrokeDashOffset());
} else {
aStrokeOptions->mDashOffset =
SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset,
false) *
SVGContentUtils::CoordToFloat(aElement, aStyleSVG->mStrokeDashoffset) *
pathScale;
}
@ -345,7 +343,7 @@ Float SVGContentUtils::GetStrokeWidth(SVGElement* aElement,
return aContextPaint->GetStrokeWidth();
}
return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth, true);
return SVGContentUtils::CoordToFloat(aElement, styleSVG->mStrokeWidth);
}
float SVGContentUtils::GetFontSize(Element* aElement) {
@ -766,36 +764,17 @@ bool SVGContentUtils::ParseInteger(const nsAString& aString, int32_t& aValue) {
}
float SVGContentUtils::CoordToFloat(SVGElement* aContent,
const nsStyleCoord& aCoord,
bool aClampNegativeCalc) {
switch (aCoord.GetUnit()) {
case eStyleUnit_Coord:
return nsPresContext::AppUnitsToFloatCSSPixels(aCoord.GetCoordValue());
case eStyleUnit_Percent: {
SVGViewportElement* ctx = aContent->GetCtx();
if (!ctx) {
return 0.0f;
}
return aCoord.GetPercentValue() * ctx->GetLength(SVGContentUtils::XY);
}
case eStyleUnit_Calc: {
auto* calc = aCoord.GetCalcValue();
float result = nsPresContext::AppUnitsToFloatCSSPixels(calc->mLength);
if (calc->mHasPercent) {
SVGViewportElement* ctx = aContent->GetCtx();
if (!ctx) {
return 0.0f;
}
result += calc->mPercent * ctx->GetLength(SVGContentUtils::XY);
}
return aClampNegativeCalc ? std::max(result, 0.0f) : result;
}
default:
MOZ_ASSERT_UNREACHABLE("Unknown unit for SVG length");
return 0.0f;
const LengthPercentage& aLength) {
float result = aLength.ResolveToCSSPixelsWith([&] {
SVGViewportElement* ctx = aContent->GetCtx();
return CSSCoord(ctx ? ctx->GetLength(SVGContentUtils::XY) : 0.0f);
});
if (aLength.clamping_mode == StyleAllowedNumericType::NonNegative) {
result = std::max(result, 0.0f);
} else {
MOZ_ASSERT(aLength.clamping_mode == StyleAllowedNumericType::All);
}
return result;
}
already_AddRefed<gfx::Path> SVGContentUtils::GetPath(

View File

@ -13,6 +13,7 @@
#include "mozilla/gfx/2D.h" // for StrokeOptions
#include "mozilla/gfx/Matrix.h"
#include "mozilla/RangedPtr.h"
#include "nsStyleCoord.h"
#include "nsError.h"
#include "nsStringFwd.h"
#include "gfx2DGlue.h"
@ -21,7 +22,6 @@ class nsIContent;
class nsIFrame;
class nsPresContext;
class nsStyleCoord;
namespace mozilla {
class ComputedStyle;
@ -321,9 +321,7 @@ class SVGContentUtils {
* Converts an nsStyleCoord into a userspace value, resolving percentage
* values relative to aContent's SVG viewport.
*/
static float CoordToFloat(dom::SVGElement* aContent,
const nsStyleCoord& aCoord,
bool aClampNegativeCalc);
static float CoordToFloat(dom::SVGElement* aContent, const LengthPercentage&);
/**
* Parse the SVG path string
* Returns a path

View File

@ -28,30 +28,30 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=302971
// ordinary
rect.setAttribute("stroke-width", "5");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "5", "Ordinary");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "5px", "Ordinary");
// valid exponential notation
rect.setAttribute("stroke-width", "4E1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "40", "Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "40px", "Exponent");
rect.setAttribute("stroke-width", "6e1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "60", "Lower-case Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "60px", "Lower-case Exponent");
rect.setAttribute("stroke-width", "2E+1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "20", "Positive Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "20px", "Positive Exponent");
rect.setAttribute("stroke-width", "100E-1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "10", "Negative Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "10px", "Negative Exponent");
rect.setAttribute("stroke-width", "0.7E1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "7", "Floating Point with Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "7px", "Floating Point with Exponent");
rect.setAttribute("stroke-width", "50.0E-1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "5", "Floating Point with Negative Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "5px", "Floating Point with Negative Exponent");
rect.setAttribute("stroke-width", "0.8E+1");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "8", "Floating Point with Positive Exponent");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "8px", "Floating Point with Positive Exponent");
rect.setAttribute("stroke-width", "4E1px");
is(doc.defaultView.getComputedStyle(rect).getPropertyValue("stroke-width"), "40px", "Units");

View File

@ -88,7 +88,6 @@ LONGHANDS_NOT_SERIALIZED_WITH_SERVO = [
"contain",
"display",
"fill",
"fill-opacity",
"filter",
"flex-basis",
"flex-grow",
@ -129,11 +128,6 @@ LONGHANDS_NOT_SERIALIZED_WITH_SERVO = [
"scroll-snap-points-x",
"scroll-snap-points-y",
"stroke",
"stroke-dasharray",
"stroke-dashoffset",
"stroke-miterlimit",
"stroke-opacity",
"stroke-width",
"text-decoration-line",
"text-emphasis-position",
"text-emphasis-style",

View File

@ -3198,56 +3198,6 @@ already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetMarkerStart() {
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetStrokeDasharray() {
const nsStyleSVG* svg = StyleSVG();
if (svg->mStrokeDasharray.IsEmpty()) {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetIdent(eCSSKeyword_none);
return val.forget();
}
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(true);
for (uint32_t i = 0; i < svg->mStrokeDasharray.Length(); i++) {
RefPtr<nsROCSSPrimitiveValue> dash = new nsROCSSPrimitiveValue;
SetValueToCoord(dash, svg->mStrokeDasharray[i], true);
valueList->AppendCSSValue(dash.forget());
}
return valueList.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetStrokeDashoffset() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToCoord(val, StyleSVG()->mStrokeDashoffset, false);
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetStrokeWidth() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
SetValueToCoord(val, StyleSVG()->mStrokeWidth, true);
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetFillOpacity() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetNumber(StyleSVG()->mFillOpacity);
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetStrokeMiterlimit() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetNumber(StyleSVG()->mStrokeMiterlimit);
return val.forget();
}
already_AddRefed<CSSValue> nsComputedDOMStyle::DoGetStrokeOpacity() {
RefPtr<nsROCSSPrimitiveValue> val = new nsROCSSPrimitiveValue;
val->SetNumber(StyleSVG()->mStrokeOpacity);
return val.forget();
}
void nsComputedDOMStyle::BoxValuesToString(
nsAString& aString, const nsTArray<nsStyleCoord>& aBoxValues,
bool aClampNegativeCalc) {

View File

@ -378,14 +378,8 @@ class nsComputedDOMStyle final : public nsDOMCSSDeclaration,
already_AddRefed<CSSValue> DoGetMarkerEnd();
already_AddRefed<CSSValue> DoGetMarkerMid();
already_AddRefed<CSSValue> DoGetMarkerStart();
already_AddRefed<CSSValue> DoGetStrokeDasharray();
already_AddRefed<CSSValue> DoGetStrokeDashoffset();
already_AddRefed<CSSValue> DoGetStrokeWidth();
already_AddRefed<CSSValue> DoGetFillOpacity();
already_AddRefed<CSSValue> DoGetStrokeMiterlimit();
already_AddRefed<CSSValue> DoGetStrokeOpacity();
already_AddRefed<CSSValue> DoGetFilter();
already_AddRefed<CSSValue> DoGetPaintOrder();

View File

@ -642,9 +642,8 @@ nsChangeHint nsStyleColumn::CalcDifference(
nsStyleSVG::nsStyleSVG(const Document& aDocument)
: mFill(eStyleSVGPaintType_Color), // Will be initialized to NS_RGB(0,0,0)
mStroke(eStyleSVGPaintType_None),
mStrokeDashoffset(0, nsStyleCoord::CoordConstructor),
mStrokeWidth(nsPresContext::CSSPixelsToAppUnits(1),
nsStyleCoord::CoordConstructor),
mStrokeDashoffset(LengthPercentage::Zero()),
mStrokeWidth(LengthPercentage::FromPixels(1.0f)),
mFillOpacity(1.0f),
mStrokeMiterlimit(4.0f),
mStrokeOpacity(1.0f),

View File

@ -2708,11 +2708,11 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleSVG {
RefPtr<mozilla::css::URLValue> mMarkerEnd;
RefPtr<mozilla::css::URLValue> mMarkerMid;
RefPtr<mozilla::css::URLValue> mMarkerStart;
nsTArray<nsStyleCoord> mStrokeDasharray; // coord, percent, factor
nsTArray<mozilla::NonNegativeLengthPercentage> mStrokeDasharray;
nsTArray<RefPtr<nsAtom>> mContextProps;
nsStyleCoord mStrokeDashoffset; // coord, percent, factor
nsStyleCoord mStrokeWidth; // coord, percent, factor
mozilla::LengthPercentage mStrokeDashoffset;
mozilla::NonNegativeLengthPercentage mStrokeWidth;
float mFillOpacity;
float mStrokeMiterlimit;

View File

@ -5144,8 +5144,8 @@ var gCSSProperties = {
domProp: "fillOpacity",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "1", "2.8", "1.000", "context-fill-opacity", "context-stroke-opacity" ],
other_values: [ "0", "0.3", "-7.3" ],
initial_values: [ "1", "2.8", "1.000", ],
other_values: [ "0", "0.3", "-7.3", "context-fill-opacity", "context-stroke-opacity" ],
invalid_values: []
},
"fill-rule": {
@ -5559,16 +5559,16 @@ var gCSSProperties = {
domProp: "strokeDasharray",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none", "context-value" ],
other_values: [ "5px,3px,2px", "5px 3px 2px", " 5px ,3px\t, 2px ", "1px", "5%", "3em", "0.0002" ],
initial_values: [ "none" ],
other_values: [ "5px,3px,2px", "5px 3px 2px", " 5px ,3px\t, 2px ", "1px", "5%", "3em", "0.0002", "context-value"],
invalid_values: [ "-5px,3px,2px", "5px,3px,-2px" ]
},
"stroke-dashoffset": {
domProp: "strokeDashoffset",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "0", "-0px", "0em", "context-value" ],
other_values: [ "3px", "3%", "1em", "0.0002" ],
initial_values: [ "0", "-0px", "0em" ],
other_values: [ "3px", "3%", "1em", "0.0002", "context-value" ],
invalid_values: []
},
"stroke-linecap": {
@ -5599,16 +5599,16 @@ var gCSSProperties = {
domProp: "strokeOpacity",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "1", "2.8", "1.000", "context-fill-opacity", "context-stroke-opacity" ],
other_values: [ "0", "0.3", "-7.3" ],
initial_values: [ "1", "2.8", "1.000" ],
other_values: [ "0", "0.3", "-7.3", "context-fill-opacity", "context-stroke-opacity" ],
invalid_values: []
},
"stroke-width": {
domProp: "strokeWidth",
inherited: true,
type: CSS_TYPE_LONGHAND,
initial_values: [ "1px", "context-value" ],
other_values: [ "0", "0px", "-0em", "17px", "0.2em", "0.0002" ],
initial_values: [ "1px" ],
other_values: [ "0", "0px", "-0em", "17px", "0.2em", "0.0002", "context-value" ],
invalid_values: [ "-0.1px", "-3px" ]
},
"text-anchor": {

View File

@ -261,20 +261,16 @@ var supported_properties = {
"stroke": [ test_color_transition,
test_currentcolor_transition ],
"stroke-dasharray": [ test_dasharray_transition ],
// NOTE: when calc() is supported on 'stroke-dashoffset', we should
// add test_length_percent_calc_transition.
"stroke-dashoffset": [ test_length_transition_svg, test_percent_transition,
test_length_unclamped_svg, test_percent_unclamped ],
"stroke-dashoffset": [ test_length_transition, test_percent_transition,
test_length_unclamped, test_percent_unclamped, ],
"stroke-miterlimit": [ test_float_aboveOne_transition,
test_float_aboveOne_clamped ],
"stroke-opacity" : [ test_float_zeroToOne_transition,
// opacity is clamped in computed style
// (not parsing/interpolation)
test_float_zeroToOne_clamped ],
// NOTE: when calc() is supported on 'stroke-width', we should add
// test_length_percent_calc_transition.
"stroke-width": [ test_length_transition_svg, test_percent_transition,
test_length_clamped_svg, test_percent_clamped ],
"stroke-width": [ test_length_transition, test_percent_transition,
test_length_clamped, test_percent_clamped, ],
"-moz-tab-size": [ test_float_zeroToOne_transition,
test_float_aboveOne_transition, test_length_clamped ],
"text-decoration": [ test_color_shorthand_transition,
@ -1264,43 +1260,27 @@ function check_distance(prop, start, quarter, end)
ok(Math.abs((qe * 4 - se * 3) / se) < 0.0001, "property '" + prop + "': distance " + qe + " from quarter '" + quarter + "' to end '" + end + "' should be three quarters distance " + se + " from start '" + start + "' to end '" + end + "'");
}
function test_length_transition_svg_or_units(prop, numbers_are_pixels) {
function test_length_transition(prop) {
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "4px", "");
is(cs.getPropertyValue(prop), "4px",
"length-valued property " + prop + ": computed value before transition");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "12px", "");
is(cs.getPropertyValue(prop), numbers_are_pixels ? "6" : "6px",
is(cs.getPropertyValue(prop), "6px",
"length-valued property " + prop + ": interpolation of lengths");
check_distance(prop, "4px", "6px", "12px");
}
function test_length_transition(prop) {
test_length_transition_svg_or_units(prop, false);
}
function test_length_transition_svg(prop) {
test_length_transition_svg_or_units(prop, true);
}
function test_length_clamped(prop) {
test_length_clamped_or_unclamped(prop, true, false);
test_length_clamped_or_unclamped(prop, true);
}
function test_length_unclamped(prop) {
test_length_clamped_or_unclamped(prop, false, false);
test_length_clamped_or_unclamped(prop, false);
}
function test_length_clamped_svg(prop) {
test_length_clamped_or_unclamped(prop, true, true);
}
function test_length_unclamped_svg(prop) {
test_length_clamped_or_unclamped(prop, false, true);
}
function test_length_clamped_or_unclamped(prop, is_clamped, numbers_are_pixels) {
function test_length_clamped_or_unclamped(prop, is_clamped) {
div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "0px", "");
@ -1308,8 +1288,7 @@ function test_length_clamped_or_unclamped(prop, is_clamped, numbers_are_pixels)
"length-valued property " + prop + ": flush before clamping test");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "100px", "");
(is_clamped ? is : isnot)(cs.getPropertyValue(prop),
numbers_are_pixels ? "0" : "0px",
(is_clamped ? is : isnot)(cs.getPropertyValue(prop), "0px",
"length-valued property " + prop + ": clamping of negatives");
div.style.setProperty("transition-timing-function", "linear", "");
}
@ -1439,6 +1418,8 @@ function test_percent_clamped_or_unclamped(prop, is_clamped) {
div.style.setProperty("transition-timing-function", "linear", "");
}
// FIXME: This doesn't deal well with properties for which the resolved value
// is not the used value, like stroke-dashoffset or stroke-width.
function test_length_percent_calc_transition(prop) {
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "0%", "");
@ -2046,53 +2027,60 @@ function test_shadow_transition(prop) {
function test_dasharray_transition(prop) {
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "3", "");
is(cs.getPropertyValue(prop), "3",
is(cs.getPropertyValue(prop), "3px",
"dasharray-valued property " + prop +
": computed value before transition");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "15px", "");
is(cs.getPropertyValue(prop), "6",
is(cs.getPropertyValue(prop), "6px",
"dasharray-valued property " + prop + ": interpolation of dasharray");
check_distance(prop, "3", "6", "15px");
div.style.setProperty(prop, "none", "");
is(cs.getPropertyValue(prop), "none",
"dasharray-valued property " + prop + ": non-interpolability of none");
div.style.setProperty(prop, "6,8px,4,4", "");
is(cs.getPropertyValue(prop), "6, 8px, 4, 4",
is(cs.getPropertyValue(prop), "6px, 8px, 4px, 4px",
"dasharray-valued property " + prop +
": computed value before transition");
div.style.setProperty(prop, "14, 12,16,16px", "");
is(cs.getPropertyValue(prop), "8, 9, 7, 7",
is(cs.getPropertyValue(prop), "8px, 9px, 7px, 7px",
"dasharray-valued property " + prop + ": interpolation of dasharray");
check_distance(prop, "6,8px,4,4", "8,9,7,7", "14, 12,16,16px");
div.style.setProperty(prop, "none", "");
is(cs.getPropertyValue(prop), "none",
"dasharray-valued property " + prop + ": non-interpolability of none");
div.style.setProperty(prop, "8,16,4", "");
is(cs.getPropertyValue(prop), "8, 16, 4",
is(cs.getPropertyValue(prop), "8px, 16px, 4px",
"dasharray-valued property " + prop +
": computed value before transition");
div.style.setProperty(prop, "4,8,12,16", "");
is(cs.getPropertyValue(prop), "7, 14, 6, 10, 13, 5, 9, 16, 4, 8, 15, 7",
is(cs.getPropertyValue(prop), "7px, 14px, 6px, 10px, 13px, 5px, 9px, 16px, 4px, 8px, 15px, 7px",
"dasharray-valued property " + prop + ": interpolation of dasharray");
check_distance(prop, "8,16,4", "7, 14, 6, 10, 13, 5, 9, 16, 4, 8, 15, 7",
"4,8,12,16");
div.style.setProperty(prop, "2,50%,6,10", "");
is(cs.getPropertyValue(prop), "2, 50%, 6, 10",
"dasharray-valued property " + prop + ": non-interpolability of mixed units");
is(cs.getPropertyValue(prop),
"5.75px, calc(12.5% + 10.5px), 6px, 10px, 10.25px, calc(12.5% + 3.75px), 8.25px, 14.5px, 3.5px, calc(12.5% + 6px), 12.75px, 7.75px",
"dasharray-valued property " + prop + ": interpolability of mixed units");
div.style.setProperty(prop, "none", "");
is(cs.getPropertyValue(prop), "none",
"dasharray-valued property " + prop + ": non-interpolability of none");
div.style.setProperty(prop, "2,50%,6,10", "");
is(cs.getPropertyValue(prop), "2px, 50%, 6px, 10px",
"dasharray-valued property " + prop + ": non-interpolability of none");
div.style.setProperty(prop, "6,30%,2,2", "");
is(cs.getPropertyValue(prop), "3, 45%, 5, 8",
is(cs.getPropertyValue(prop), "3px, 45%, 5px, 8px",
"dasharray-valued property " + prop + ": interpolation of dasharray");
check_distance(prop, "2,50%,6,10", "3, 45%, 5, 8", "6,30%,2,2");
div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "0,0%", "");
is(cs.getPropertyValue(prop), "0, 0%",
is(cs.getPropertyValue(prop), "0px, 0%",
"dasharray-valued property " + prop + ": flush before clamping test");
div.style.setProperty("transition-property", prop, "");
div.style.setProperty(prop, "5, 25%", "");
is(cs.getPropertyValue(prop), "0, 0%",
div.style.setProperty(prop, "5px, 25%", "");
is(cs.getPropertyValue(prop), "0px, 0%",
"dasharray-valued property " + prop + ": clamping of negatives");
div.style.setProperty("transition-timing-function", "linear", "");
}

View File

@ -44,12 +44,6 @@
/** Test for computation of values in property database **/
var gBadComputed = {
// This is the only SVG-length property (i.e., length allowing
// unitless lengths) whose initial value is zero.
"stroke-dashoffset": [ "0", "-moz-objectValue" ],
};
var gBadComputedNoFrame = {
// These are probably bogus tests...
"-moz-margin-end": [ "0%", "calc(0% + 0px)" ],
@ -77,10 +71,6 @@ var gBadComputedNoFrame = {
};
function xfail_value(property, value, is_initial, has_frame) {
if ((property in gBadComputed) &&
gBadComputed[property].includes(value))
return true;
if (!has_frame && (property in gBadComputedNoFrame) &&
gBadComputedNoFrame[property].includes(value))
return true;

View File

@ -5006,7 +5006,7 @@ bool SVGTextFrame::ShouldRenderAsPath(nsTextFrame* aFrame,
// Text has a stroke.
if (style->HasStroke() &&
SVGContentUtils::CoordToFloat(static_cast<SVGElement*>(GetContent()),
style->mStrokeWidth, true) > 0) {
style->mStrokeWidth) > 0) {
return true;
}

View File

@ -1542,7 +1542,7 @@ float nsSVGUtils::GetStrokeWidth(nsIFrame* aFrame,
}
SVGElement* ctx = static_cast<SVGElement*>(content);
return SVGContentUtils::CoordToFloat(ctx, style->mStrokeWidth, true);
return SVGContentUtils::CoordToFloat(ctx, style->mStrokeWidth);
}
void nsSVGUtils::SetupStrokeGeometry(nsIFrame* aFrame, gfxContext* aContext,

View File

@ -478,12 +478,12 @@ def set_gecko_property(ffi_name, expr):
}
}
};
self.gecko.${gecko_ffi_name}.set(length)
self.gecko.${gecko_ffi_name} = length;
}
pub fn copy_${ident}_from(&mut self, other: &Self) {
use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
self.gecko.${gecko_ffi_name}.copy_from(&other.gecko.${gecko_ffi_name});
self.gecko.${gecko_ffi_name} = other.gecko.${gecko_ffi_name};
self.gecko.mContextFlags =
(self.gecko.mContextFlags & !CONTEXT_VALUE) |
(other.gecko.mContextFlags & CONTEXT_VALUE);
@ -495,15 +495,11 @@ def set_gecko_property(ffi_name, expr):
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use crate::values::generics::svg::SVGLength;
use crate::values::computed::LengthPercentage;
use crate::gecko_bindings::structs::nsStyleSVG_${ident.upper()}_CONTEXT as CONTEXT_VALUE;
if (self.gecko.mContextFlags & CONTEXT_VALUE) != 0 {
return SVGLength::ContextValue;
}
// TODO(emilio): Use the Rust representation instead.
let length =
LengthPercentage::from_gecko_style_coord(&self.gecko.${gecko_ffi_name}).unwrap();
SVGLength::LengthPercentage(length.into())
SVGLength::LengthPercentage(self.gecko.${gecko_ffi_name})
}
</%def>
@ -4707,7 +4703,7 @@ clip-path
bindings::Gecko_nsStyleSVG_SetDashArrayLength(&mut self.gecko, v.len() as u32);
}
for (gecko, servo) in self.gecko.mStrokeDasharray.iter_mut().zip(v) {
gecko.set(servo)
*gecko = servo;
}
}
SVGStrokeDashArray::ContextValue => {
@ -4735,19 +4731,13 @@ clip-path
pub fn clone_stroke_dasharray(&self) -> longhands::stroke_dasharray::computed_value::T {
use crate::gecko_bindings::structs::nsStyleSVG_STROKE_DASHARRAY_CONTEXT as CONTEXT_VALUE;
use crate::values::computed::NonNegativeLengthPercentage;
use crate::values::generics::svg::SVGStrokeDashArray;
if self.gecko.mContextFlags & CONTEXT_VALUE != 0 {
debug_assert_eq!(self.gecko.mStrokeDasharray.len(), 0);
return SVGStrokeDashArray::ContextValue;
}
// TODO(emilio): Use the rust representation instead.
let mut vec = vec![];
for gecko in self.gecko.mStrokeDasharray.iter() {
vec.push(NonNegativeLengthPercentage::from_gecko_style_coord(gecko).unwrap());
}
SVGStrokeDashArray::Values(vec)
SVGStrokeDashArray::Values(self.gecko.mStrokeDasharray.iter().cloned().collect())
}
#[allow(non_snake_case)]

View File

@ -84,7 +84,8 @@ ${helpers.predefined_type(
)}
${helpers.predefined_type(
"stroke-width", "SVGWidth",
"stroke-width",
"SVGWidth",
"computed::SVGWidth::one()",
products="gecko",
animation_value_type="crate::values::computed::SVGWidth",

View File

@ -1,10 +0,0 @@
[stroke-dasharray-computed.svg]
[Property stroke-dasharray value '0, 5' computes to '0px, 5px']
expected: FAIL
[Property stroke-dasharray value '10' computes to '10px']
expected: FAIL
[Property stroke-dasharray value 'calc(50% + 60px)' computes to 'calc(50% + 60px)']
expected: FAIL

View File

@ -1,7 +0,0 @@
[stroke-dashoffset-computed.svg]
[Property stroke-dashoffset value 'calc(50% + 60px)' computes to 'calc(50% + 60px)']
expected: FAIL
[Property stroke-dashoffset value '10' computes to '10px']
expected: FAIL

View File

@ -1,7 +1,7 @@
[stroke-width-computed.svg]
[Property stroke-width value 'calc(50% + 60px)' computes to 'calc(50% + 60px)']
[stroke-width computes mm lengths]
expected: FAIL
[Property stroke-width value '10' computes to '10px']
bug: Precision difference with non-Servo serialization.
[stroke-width computes Q lengths]
expected: FAIL
bug: Precision difference with non-Servo serialization.

View File

@ -13,10 +13,10 @@
<h:script src="/css/support/parsing-testcommon.js"/>
<script><![CDATA[
test_valid_value("stroke-dashoffset", "0");
test_valid_value("stroke-dashoffset", "0", "0px");
test_valid_value("stroke-dashoffset", "10px");
test_valid_value("stroke-dashoffset", "-20%");
test_valid_value("stroke-dashoffset", "30");
test_valid_value("stroke-dashoffset", "30", "30px");
test_valid_value("stroke-dashoffset", "40Q", "40q");
test_valid_value("stroke-dashoffset", "calc(2em + 3ex)");

Before

Width:  |  Height:  |  Size: 975 B

After

Width:  |  Height:  |  Size: 990 B

View File

@ -13,8 +13,8 @@
<h:script src="/css/support/parsing-testcommon.js"/>
<script><![CDATA[
test_valid_value("stroke-width", "0");
test_valid_value("stroke-width", "10");
test_valid_value("stroke-width", "0", "0px");
test_valid_value("stroke-width", "10", "10px");
test_valid_value("stroke-width", "1px");
test_valid_value("stroke-width", "calc(2em + 3ex)");
test_valid_value("stroke-width", "4%");

Before

Width:  |  Height:  |  Size: 990 B

After

Width:  |  Height:  |  Size: 1005 B

View File

@ -1218,7 +1218,7 @@ const gCSSProperties = {
// https://svgwg.org/svg2-draft/painting.html#StrokeDasharrayProperty
types: [
'dasharray',
{ type: 'discrete', options: [ [ 'none', '10, 20' ] ] }
{ type: 'discrete', options: [ [ 'none', '10px, 20px' ] ] }
]
},
'stroke-dashoffset': {

View File

@ -473,14 +473,14 @@ const lengthPercentageOrCalcType = {
};
const positiveNumberType = {
testInterpolation: (property, setup) => {
testInterpolation: (property, setup, expectedUnit='') => {
test(t => {
const idlName = propertyToIDL(property);
const target = createTestElement(t, setup);
const animation = target.animate({ [idlName]: [1.1, 1.5] },
{ duration: 1000, fill: 'both' });
testAnimationSamples(animation, idlName,
[{ time: 500, expected: '1.3' }]);
[{ time: 500, expected: '1.3' + expectedUnit }]);
}, `${property} supports animating as a positive number`);
},
@ -2622,7 +2622,7 @@ const rectType = {
const dasharrayType = {
testInterpolation: (property, setup) => {
percentageType.testInterpolation(property, setup);
positiveNumberType.testInterpolation(property, setup);
positiveNumberType.testInterpolation(property, setup, 'px');
test(t => {
const idlName = propertyToIDL(property);
@ -2633,7 +2633,7 @@ const dasharrayType = {
{ duration: 1000, fill: 'both' });
testAnimationSamples(
animation, idlName,
[{ time: 500, expected: '6, 12, 8, 12, 10, 6, 10, 16, 4, 8, 14, 10' }]);
[{ time: 500, expected: '6px, 12px, 8px, 12px, 10px, 6px, 10px, 16px, 4px, 8px, 14px, 10px' }]);
}, `${property} supports animating as a dasharray (mismatched length)`);
test(t => {
@ -2645,8 +2645,8 @@ const dasharrayType = {
{ duration: 1000, fill: 'both' });
testAnimationSamples(
animation, idlName,
[{ time: 500, expected: '4, 40%, 4, 6' }]);
}, `${property} supports animating as a dasharray (mixed number and percentage)`);
[{ time: 500, expected: '4px, 40%, 4px, 6px' }]);
}, `${property} supports animating as a dasharray (mixed lengths and percentages)`);
},
@ -2665,7 +2665,7 @@ const dasharrayType = {
{ duration: 1000, composite });
testAnimationSamples(
animation, idlName,
[{ time: 0, expected: '1, 2, 3, 4, 5' }]);
[{ time: 0, expected: '1px, 2px, 3px, 4px, 5px' }]);
}, `${property}: dasharray`);
},