mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-07-31 13:19:05 +00:00
LibWeb: Move presentation attrs from SVGGraphicsElement to SVGElement
This matches how other browser behave and fixes a bunch of WPT tests.
This commit is contained in:
parent
fe6d8131ae
commit
10cff06a95
Notes:
github-actions[bot]
2025-04-25 08:19:32 +00:00
Author: https://github.com/awesomekling
Commit: 10cff06a95
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/4465
Reviewed-by: https://github.com/gmta ✅
11 changed files with 700 additions and 69 deletions
|
@ -30,6 +30,91 @@ void SVGElement::initialize(JS::Realm& realm)
|
|||
Base::initialize(realm);
|
||||
}
|
||||
|
||||
struct NamedPropertyID {
|
||||
NamedPropertyID(CSS::PropertyID property_id)
|
||||
: id(property_id)
|
||||
, name(CSS::string_from_property_id(property_id))
|
||||
{
|
||||
}
|
||||
|
||||
CSS::PropertyID id;
|
||||
StringView name;
|
||||
};
|
||||
|
||||
static Array const attribute_style_properties {
|
||||
// FIXME: The `fill` attribute and CSS `fill` property are not the same! But our support is limited enough that they are equivalent for now.
|
||||
NamedPropertyID(CSS::PropertyID::Fill),
|
||||
// FIXME: The `stroke` attribute and CSS `stroke` property are not the same! But our support is limited enough that they are equivalent for now.
|
||||
NamedPropertyID(CSS::PropertyID::ClipPath),
|
||||
NamedPropertyID(CSS::PropertyID::ClipRule),
|
||||
NamedPropertyID(CSS::PropertyID::Color),
|
||||
NamedPropertyID(CSS::PropertyID::Cursor),
|
||||
NamedPropertyID(CSS::PropertyID::Direction),
|
||||
NamedPropertyID(CSS::PropertyID::Display),
|
||||
NamedPropertyID(CSS::PropertyID::FillOpacity),
|
||||
NamedPropertyID(CSS::PropertyID::FillRule),
|
||||
NamedPropertyID(CSS::PropertyID::FontFamily),
|
||||
NamedPropertyID(CSS::PropertyID::FontSize),
|
||||
NamedPropertyID(CSS::PropertyID::FontStyle),
|
||||
NamedPropertyID(CSS::PropertyID::FontWeight),
|
||||
NamedPropertyID(CSS::PropertyID::ImageRendering),
|
||||
NamedPropertyID(CSS::PropertyID::LetterSpacing),
|
||||
NamedPropertyID(CSS::PropertyID::Mask),
|
||||
NamedPropertyID(CSS::PropertyID::MaskType),
|
||||
NamedPropertyID(CSS::PropertyID::Opacity),
|
||||
NamedPropertyID(CSS::PropertyID::Overflow),
|
||||
NamedPropertyID(CSS::PropertyID::PointerEvents),
|
||||
NamedPropertyID(CSS::PropertyID::StopColor),
|
||||
NamedPropertyID(CSS::PropertyID::StopOpacity),
|
||||
NamedPropertyID(CSS::PropertyID::Stroke),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeDasharray),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeDashoffset),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeLinecap),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeLinejoin),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeMiterlimit),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeOpacity),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeWidth),
|
||||
NamedPropertyID(CSS::PropertyID::TextAnchor),
|
||||
NamedPropertyID(CSS::PropertyID::TextOverflow),
|
||||
NamedPropertyID(CSS::PropertyID::TransformOrigin),
|
||||
NamedPropertyID(CSS::PropertyID::UnicodeBidi),
|
||||
NamedPropertyID(CSS::PropertyID::Visibility),
|
||||
NamedPropertyID(CSS::PropertyID::WhiteSpace),
|
||||
NamedPropertyID(CSS::PropertyID::WordSpacing),
|
||||
NamedPropertyID(CSS::PropertyID::WritingMode),
|
||||
};
|
||||
|
||||
bool SVGElement::is_presentational_hint(FlyString const& name) const
|
||||
{
|
||||
if (Base::is_presentational_hint(name))
|
||||
return true;
|
||||
|
||||
return any_of(attribute_style_properties, [&](auto& property) { return name.equals_ignoring_ascii_case(property.name); });
|
||||
}
|
||||
|
||||
void SVGElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties> cascaded_properties) const
|
||||
{
|
||||
CSS::Parser::ParsingParams parsing_context { document(), CSS::Parser::ParsingMode::SVGPresentationAttribute };
|
||||
for_each_attribute([&](auto& name, auto& value) {
|
||||
for (auto property : attribute_style_properties) {
|
||||
if (!name.equals_ignoring_ascii_case(property.name))
|
||||
continue;
|
||||
if (property.id == CSS::PropertyID::Mask) {
|
||||
// Mask is a shorthand property in CSS, but parse_css_value does not take that into account. For now,
|
||||
// just parse as 'mask-image' as anything else is currently not supported.
|
||||
// FIXME: properly parse longhand 'mask' property
|
||||
if (auto style_value = parse_css_value(parsing_context, value, CSS::PropertyID::MaskImage)) {
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::MaskImage, style_value.release_nonnull());
|
||||
}
|
||||
} else {
|
||||
if (auto style_value = parse_css_value(parsing_context, value, property.id))
|
||||
cascaded_properties->set_property_from_presentational_hint(property.id, style_value.release_nonnull());
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool SVGElement::should_include_in_accessibility_tree() const
|
||||
{
|
||||
bool has_title_or_desc = false;
|
||||
|
|
|
@ -28,6 +28,9 @@ public:
|
|||
bool should_include_in_accessibility_tree() const;
|
||||
virtual Optional<ARIA::Role> default_role() const override;
|
||||
|
||||
virtual bool is_presentational_hint(FlyString const&) const override;
|
||||
virtual void apply_presentational_hints(GC::Ref<CSS::CascadedProperties>) const override;
|
||||
|
||||
protected:
|
||||
SVGElement(DOM::Document&, DOM::QualifiedName);
|
||||
|
||||
|
|
|
@ -131,72 +131,6 @@ Gfx::AffineTransform SVGGraphicsElement::get_transform() const
|
|||
return transform;
|
||||
}
|
||||
|
||||
struct NamedPropertyID {
|
||||
NamedPropertyID(CSS::PropertyID property_id)
|
||||
: id(property_id)
|
||||
, name(CSS::string_from_property_id(property_id))
|
||||
{
|
||||
}
|
||||
|
||||
CSS::PropertyID id;
|
||||
StringView name;
|
||||
};
|
||||
|
||||
static Array const attribute_style_properties {
|
||||
// FIXME: The `fill` attribute and CSS `fill` property are not the same! But our support is limited enough that they are equivalent for now.
|
||||
NamedPropertyID(CSS::PropertyID::Fill),
|
||||
// FIXME: The `stroke` attribute and CSS `stroke` property are not the same! But our support is limited enough that they are equivalent for now.
|
||||
NamedPropertyID(CSS::PropertyID::Stroke),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeDasharray),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeDashoffset),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeLinecap),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeLinejoin),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeMiterlimit),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeWidth),
|
||||
NamedPropertyID(CSS::PropertyID::FillRule),
|
||||
NamedPropertyID(CSS::PropertyID::FillOpacity),
|
||||
NamedPropertyID(CSS::PropertyID::StrokeOpacity),
|
||||
NamedPropertyID(CSS::PropertyID::Opacity),
|
||||
NamedPropertyID(CSS::PropertyID::TextAnchor),
|
||||
NamedPropertyID(CSS::PropertyID::FontSize),
|
||||
NamedPropertyID(CSS::PropertyID::Mask),
|
||||
NamedPropertyID(CSS::PropertyID::MaskType),
|
||||
NamedPropertyID(CSS::PropertyID::ClipPath),
|
||||
NamedPropertyID(CSS::PropertyID::ClipRule),
|
||||
NamedPropertyID(CSS::PropertyID::Display),
|
||||
};
|
||||
|
||||
bool SVGGraphicsElement::is_presentational_hint(FlyString const& name) const
|
||||
{
|
||||
if (Base::is_presentational_hint(name))
|
||||
return true;
|
||||
|
||||
return any_of(attribute_style_properties, [&](auto& property) { return name.equals_ignoring_ascii_case(property.name); });
|
||||
}
|
||||
|
||||
void SVGGraphicsElement::apply_presentational_hints(GC::Ref<CSS::CascadedProperties> cascaded_properties) const
|
||||
{
|
||||
CSS::Parser::ParsingParams parsing_context { document(), CSS::Parser::ParsingMode::SVGPresentationAttribute };
|
||||
for_each_attribute([&](auto& name, auto& value) {
|
||||
for (auto property : attribute_style_properties) {
|
||||
if (!name.equals_ignoring_ascii_case(property.name))
|
||||
continue;
|
||||
if (property.id == CSS::PropertyID::Mask) {
|
||||
// Mask is a shorthand property in CSS, but parse_css_value does not take that into account. For now,
|
||||
// just parse as 'mask-image' as anything else is currently not supported.
|
||||
// FIXME: properly parse longhand 'mask' property
|
||||
if (auto style_value = parse_css_value(parsing_context, value, CSS::PropertyID::MaskImage)) {
|
||||
cascaded_properties->set_property_from_presentational_hint(CSS::PropertyID::MaskImage, style_value.release_nonnull());
|
||||
}
|
||||
} else {
|
||||
if (auto style_value = parse_css_value(parsing_context, value, property.id))
|
||||
cascaded_properties->set_property_from_presentational_hint(property.id, style_value.release_nonnull());
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static FillRule to_svg_fill_rule(CSS::FillRule fill_rule)
|
||||
{
|
||||
switch (fill_rule) {
|
||||
|
|
|
@ -29,9 +29,6 @@ class SVGGraphicsElement : public SVGElement {
|
|||
WEB_PLATFORM_OBJECT(SVGGraphicsElement, SVGElement);
|
||||
|
||||
public:
|
||||
virtual bool is_presentational_hint(FlyString const&) const override;
|
||||
virtual void apply_presentational_hints(GC::Ref<CSS::CascadedProperties>) const override;
|
||||
|
||||
virtual void attribute_changed(FlyString const& name, Optional<String> const& old_value, Optional<String> const& value, Optional<FlyString> const& namespace_) override;
|
||||
|
||||
Optional<Gfx::Color> fill_color() const;
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 42 tests
|
||||
|
||||
37 Pass
|
||||
5 Fail
|
||||
Pass clip-path presentation attribute supported on an irrelevant element
|
||||
Pass clip-rule presentation attribute supported on an irrelevant element
|
||||
Pass color presentation attribute supported on an irrelevant element
|
||||
Pass cursor presentation attribute supported on an irrelevant element
|
||||
Pass direction presentation attribute supported on an irrelevant element
|
||||
Pass display presentation attribute supported on an irrelevant element
|
||||
Pass fill presentation attribute supported on an irrelevant element
|
||||
Pass fill-opacity presentation attribute supported on an irrelevant element
|
||||
Pass fill-rule presentation attribute supported on an irrelevant element
|
||||
Fail filter presentation attribute supported on an irrelevant element
|
||||
Pass font-family presentation attribute supported on an irrelevant element
|
||||
Pass font-size presentation attribute supported on an irrelevant element
|
||||
Fail font-stretch presentation attribute supported on an irrelevant element
|
||||
Pass font-style presentation attribute supported on an irrelevant element
|
||||
Fail font-variant presentation attribute supported on an irrelevant element
|
||||
Pass font-weight presentation attribute supported on an irrelevant element
|
||||
Pass image-rendering presentation attribute supported on an irrelevant element
|
||||
Pass letter-spacing presentation attribute supported on an irrelevant element
|
||||
Pass mask-type presentation attribute supported on an irrelevant element
|
||||
Pass mask presentation attribute supported on an irrelevant element
|
||||
Pass opacity presentation attribute supported on an irrelevant element
|
||||
Fail overflow presentation attribute supported on an irrelevant element
|
||||
Pass pointer-events presentation attribute supported on an irrelevant element
|
||||
Pass stop-color presentation attribute supported on an irrelevant element
|
||||
Pass stop-opacity presentation attribute supported on an irrelevant element
|
||||
Pass stroke presentation attribute supported on an irrelevant element
|
||||
Pass stroke-dasharray presentation attribute supported on an irrelevant element
|
||||
Pass stroke-dashoffset presentation attribute supported on an irrelevant element
|
||||
Pass stroke-linecap presentation attribute supported on an irrelevant element
|
||||
Pass stroke-linejoin presentation attribute supported on an irrelevant element
|
||||
Pass stroke-miterlimit presentation attribute supported on an irrelevant element
|
||||
Pass stroke-opacity presentation attribute supported on an irrelevant element
|
||||
Pass stroke-width presentation attribute supported on an irrelevant element
|
||||
Pass text-anchor presentation attribute supported on an irrelevant element
|
||||
Fail text-decoration presentation attribute supported on an irrelevant element
|
||||
Pass text-overflow presentation attribute supported on an irrelevant element
|
||||
Pass transform-origin presentation attribute supported on an irrelevant element
|
||||
Pass unicode-bidi presentation attribute supported on an irrelevant element
|
||||
Pass visibility presentation attribute supported on an irrelevant element
|
||||
Pass white-space presentation attribute supported on an irrelevant element
|
||||
Pass word-spacing presentation attribute supported on an irrelevant element
|
||||
Pass writing-mode presentation attribute supported on an irrelevant element
|
|
@ -0,0 +1,58 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 52 tests
|
||||
|
||||
40 Pass
|
||||
12 Fail
|
||||
Pass clip-path presentation attribute supported on a relevant element
|
||||
Pass clip-rule presentation attribute supported on a relevant element
|
||||
Pass color presentation attribute supported on a relevant element
|
||||
Pass cursor presentation attribute supported on a relevant element
|
||||
Pass cx presentation attribute supported on a relevant element
|
||||
Pass cy presentation attribute supported on a relevant element
|
||||
Pass direction presentation attribute supported on a relevant element
|
||||
Pass display presentation attribute supported on a relevant element
|
||||
Pass fill presentation attribute supported on a relevant element
|
||||
Pass fill-opacity presentation attribute supported on a relevant element
|
||||
Pass fill-rule presentation attribute supported on a relevant element
|
||||
Fail filter presentation attribute supported on a relevant element
|
||||
Pass font-family presentation attribute supported on a relevant element
|
||||
Pass font-size presentation attribute supported on a relevant element
|
||||
Fail font-stretch presentation attribute supported on a relevant element
|
||||
Pass font-style presentation attribute supported on a relevant element
|
||||
Fail font-variant presentation attribute supported on a relevant element
|
||||
Pass font-weight presentation attribute supported on a relevant element
|
||||
Fail height presentation attribute supported on a relevant element
|
||||
Pass image-rendering presentation attribute supported on a relevant element
|
||||
Pass letter-spacing presentation attribute supported on a relevant element
|
||||
Pass mask-type presentation attribute supported on a relevant element
|
||||
Pass mask presentation attribute supported on a relevant element
|
||||
Pass opacity presentation attribute supported on a relevant element
|
||||
Fail overflow presentation attribute supported on a relevant element
|
||||
Pass pointer-events presentation attribute supported on a relevant element
|
||||
Pass r presentation attribute supported on a relevant element
|
||||
Fail rx presentation attribute supported on a relevant element
|
||||
Fail ry presentation attribute supported on a relevant element
|
||||
Pass stop-color presentation attribute supported on a relevant element
|
||||
Pass stop-opacity presentation attribute supported on a relevant element
|
||||
Pass stroke presentation attribute supported on a relevant element
|
||||
Pass stroke-dasharray presentation attribute supported on a relevant element
|
||||
Pass stroke-dashoffset presentation attribute supported on a relevant element
|
||||
Pass stroke-linecap presentation attribute supported on a relevant element
|
||||
Pass stroke-linejoin presentation attribute supported on a relevant element
|
||||
Pass stroke-miterlimit presentation attribute supported on a relevant element
|
||||
Pass stroke-opacity presentation attribute supported on a relevant element
|
||||
Pass stroke-width presentation attribute supported on a relevant element
|
||||
Pass text-anchor presentation attribute supported on a relevant element
|
||||
Fail text-decoration presentation attribute supported on a relevant element
|
||||
Pass text-overflow presentation attribute supported on a relevant element
|
||||
Pass transform-origin presentation attribute supported on a relevant element
|
||||
Fail transform presentation attribute supported on a relevant element
|
||||
Pass unicode-bidi presentation attribute supported on a relevant element
|
||||
Pass visibility presentation attribute supported on a relevant element
|
||||
Pass white-space presentation attribute supported on a relevant element
|
||||
Fail width presentation attribute supported on a relevant element
|
||||
Pass word-spacing presentation attribute supported on a relevant element
|
||||
Pass writing-mode presentation attribute supported on a relevant element
|
||||
Fail x presentation attribute supported on a relevant element
|
||||
Fail y presentation attribute supported on a relevant element
|
|
@ -0,0 +1,48 @@
|
|||
Harness status: OK
|
||||
|
||||
Found 42 tests
|
||||
|
||||
37 Pass
|
||||
5 Fail
|
||||
Pass clip-path presentation attribute supported on an unknown SVG element
|
||||
Pass clip-rule presentation attribute supported on an unknown SVG element
|
||||
Pass color presentation attribute supported on an unknown SVG element
|
||||
Pass cursor presentation attribute supported on an unknown SVG element
|
||||
Pass direction presentation attribute supported on an unknown SVG element
|
||||
Pass display presentation attribute supported on an unknown SVG element
|
||||
Pass fill presentation attribute supported on an unknown SVG element
|
||||
Pass fill-opacity presentation attribute supported on an unknown SVG element
|
||||
Pass fill-rule presentation attribute supported on an unknown SVG element
|
||||
Fail filter presentation attribute supported on an unknown SVG element
|
||||
Pass font-family presentation attribute supported on an unknown SVG element
|
||||
Pass font-size presentation attribute supported on an unknown SVG element
|
||||
Fail font-stretch presentation attribute supported on an unknown SVG element
|
||||
Pass font-style presentation attribute supported on an unknown SVG element
|
||||
Fail font-variant presentation attribute supported on an unknown SVG element
|
||||
Pass font-weight presentation attribute supported on an unknown SVG element
|
||||
Pass image-rendering presentation attribute supported on an unknown SVG element
|
||||
Pass letter-spacing presentation attribute supported on an unknown SVG element
|
||||
Pass mask-type presentation attribute supported on an unknown SVG element
|
||||
Pass mask presentation attribute supported on an unknown SVG element
|
||||
Pass opacity presentation attribute supported on an unknown SVG element
|
||||
Fail overflow presentation attribute supported on an unknown SVG element
|
||||
Pass pointer-events presentation attribute supported on an unknown SVG element
|
||||
Pass stop-color presentation attribute supported on an unknown SVG element
|
||||
Pass stop-opacity presentation attribute supported on an unknown SVG element
|
||||
Pass stroke presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-dasharray presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-dashoffset presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-linecap presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-linejoin presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-miterlimit presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-opacity presentation attribute supported on an unknown SVG element
|
||||
Pass stroke-width presentation attribute supported on an unknown SVG element
|
||||
Pass text-anchor presentation attribute supported on an unknown SVG element
|
||||
Fail text-decoration presentation attribute supported on an unknown SVG element
|
||||
Pass text-overflow presentation attribute supported on an unknown SVG element
|
||||
Pass transform-origin presentation attribute supported on an unknown SVG element
|
||||
Pass unicode-bidi presentation attribute supported on an unknown SVG element
|
||||
Pass visibility presentation attribute supported on an unknown SVG element
|
||||
Pass white-space presentation attribute supported on an unknown SVG element
|
||||
Pass word-spacing presentation attribute supported on an unknown SVG element
|
||||
Pass writing-mode presentation attribute supported on an unknown SVG element
|
|
@ -0,0 +1,21 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>SVG presentation attributes - on irrelevant elements</title>
|
||||
<link rel="help" href="https://svgwg.org/svg2-draft/styling.html#PresentationAttributes">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script src="presentation-attributes.js"></script>
|
||||
<svg id="svg"></svg>
|
||||
<script>
|
||||
// Test that all of the presentation attributes with no special rules are
|
||||
// also supported on elements that the corresponding property does not
|
||||
// apply to.
|
||||
|
||||
for (let p in PROPERTIES) {
|
||||
if (CSS.supports(p, "initial") && PROPERTIES[p].irrelevantElement) {
|
||||
test(function() {
|
||||
assertPresentationAttributeIsSupported(PROPERTIES[p].irrelevantElement, p, PROPERTIES[p].value, p);
|
||||
}, `${p} presentation attribute supported on an irrelevant element`);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>SVG presentation attributes - on relevant elements</title>
|
||||
<link rel="help" href="https://svgwg.org/svg2-draft/styling.html#PresentationAttributes">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script src="presentation-attributes.js"></script>
|
||||
<svg id="svg"></svg>
|
||||
<script>
|
||||
// Test that all of the presentation attributes with no special rules are
|
||||
// supported on elements that the corresponding properties apply to.
|
||||
|
||||
for (let p in PROPERTIES) {
|
||||
if (CSS.supports(p, "initial")) {
|
||||
test(function() {
|
||||
assertPresentationAttributeIsSupported(PROPERTIES[p].relevantElement, p, PROPERTIES[p].value, p);
|
||||
}, `${p} presentation attribute supported on a relevant element`);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
<!DOCTYPE html>
|
||||
<meta charset="utf-8">
|
||||
<title>SVG presentation attributes - on unknown SVG elements</title>
|
||||
<link rel="help" href="https://svgwg.org/svg2-draft/styling.html#PresentationAttributes">
|
||||
<script src="../../resources/testharness.js"></script>
|
||||
<script src="../../resources/testharnessreport.js"></script>
|
||||
<script src="presentation-attributes.js"></script>
|
||||
<svg id="svg"></svg>
|
||||
<script>
|
||||
// Test that all of the presentation attributes with no special
|
||||
// rules are supported on unknown SVG elements.
|
||||
|
||||
for (let p in PROPERTIES) {
|
||||
if (CSS.supports(p, "initial") && PROPERTIES[p].irrelevantElement) {
|
||||
test(function() {
|
||||
assertPresentationAttributeIsSupported("unknown", p, PROPERTIES[p].value, p);
|
||||
}, `${p} presentation attribute supported on an unknown SVG element`);
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,397 @@
|
|||
const PROPERTIES = {
|
||||
"alignment-baseline": {
|
||||
value: "middle",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"baseline-shift": {
|
||||
value: "1",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"clip-path": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"clip-rule": {
|
||||
value: "evenodd",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"color": {
|
||||
value: "blue",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"color-interpolation-filters": {
|
||||
value: "sRGB",
|
||||
relevantElement: "filter",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"color-interpolation": {
|
||||
value: "linearRGB",
|
||||
relevantElement: "linearGradient",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"cursor": {
|
||||
value: "pointer",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "defs",
|
||||
},
|
||||
"cx": {
|
||||
value: "1",
|
||||
relevantElement: "circle",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"cy": {
|
||||
value: "1",
|
||||
relevantElement: "circle",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"direction": {
|
||||
value: "rtl",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"display": {
|
||||
value: "block",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"d": {
|
||||
value: "M0,0 L1,1",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"dominant-baseline": {
|
||||
value: "middle",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"fill": {
|
||||
value: "blue",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"fill-opacity": {
|
||||
value: "0.5",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"fill-rule": {
|
||||
value: "evenodd",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"filter": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"flood-color": {
|
||||
value: "blue",
|
||||
relevantElement: "feFlood",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"flood-opacity": {
|
||||
value: "0.5",
|
||||
relevantElement: "feFlood",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-family": {
|
||||
value: "Test Family",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-size": {
|
||||
value: "50",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-size-adjust": {
|
||||
value: "0.5",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-stretch": {
|
||||
value: "expanded",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-style": {
|
||||
value: "italic",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-variant": {
|
||||
value: "small-caps",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"font-weight": {
|
||||
value: "900",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"glyph-orientation-vertical": {
|
||||
value: "90",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"height": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"image-rendering": {
|
||||
value: ["optimizeSpeed", "pixelated"],
|
||||
relevantElement: "image",
|
||||
irrelevantElement: "path",
|
||||
},
|
||||
"letter-spacing": {
|
||||
value: "1px",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"lighting-color": {
|
||||
value: "blue",
|
||||
relevantElement: "feDiffuseLighting",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"marker-end": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"marker-mid": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"marker-start": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"mask-type": {
|
||||
value: "alpha",
|
||||
relevantElement: "mask",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"mask": {
|
||||
value: "url(#e)",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"opacity": {
|
||||
value: "0.5",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"overflow": {
|
||||
value: "scroll",
|
||||
relevantElement: "svg",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"paint-order": {
|
||||
value: "fill stroke",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"pointer-events": {
|
||||
value: "none",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"r": {
|
||||
value: "1",
|
||||
relevantElement: "circle",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"rx": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"ry": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"shape-rendering": {
|
||||
value: "geometricPrecision",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stop-color": {
|
||||
value: "blue",
|
||||
relevantElement: "stop",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"stop-opacity": {
|
||||
value: "0.5",
|
||||
relevantElement: "stop",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"stroke": {
|
||||
value: "blue",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-dasharray": {
|
||||
value: "1 1",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-dashoffset": {
|
||||
value: "1",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-linecap": {
|
||||
value: "round",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-linejoin": {
|
||||
value: "round",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-miterlimit": {
|
||||
value: "1",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-opacity": {
|
||||
value: "0.5",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"stroke-width": {
|
||||
value: "2",
|
||||
relevantElement: "path",
|
||||
irrelevantElement: "image",
|
||||
},
|
||||
"text-anchor": {
|
||||
value: "middle",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"text-decoration": {
|
||||
value: "underline",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"text-overflow": {
|
||||
value: "ellipsis",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"text-rendering": {
|
||||
value: "geometricPrecision",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"transform-origin": {
|
||||
value: "1px 1px",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"transform": {
|
||||
value: "scale(2)",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"unicode-bidi": {
|
||||
value: "embed",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"vector-effect": {
|
||||
value: "non-scaling-stroke",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"visibility": {
|
||||
value: "hidden",
|
||||
relevantElement: "g",
|
||||
irrelevantElement: "linearGradient",
|
||||
},
|
||||
"white-space": {
|
||||
value: "pre",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"width": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"word-spacing": {
|
||||
value: "1",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"writing-mode": {
|
||||
value: "vertical-rl",
|
||||
relevantElement: "text",
|
||||
irrelevantElement: "rect",
|
||||
},
|
||||
"x": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
"y": {
|
||||
value: "1",
|
||||
relevantElement: "rect",
|
||||
irrelevantElement: null,
|
||||
},
|
||||
};
|
||||
|
||||
function presentationAttributeIsSupported(element, attribute, value, property) {
|
||||
let e = document.createElementNS("http://www.w3.org/2000/svg", element);
|
||||
svg.append(e);
|
||||
let propertyValueBefore = getComputedStyle(e).getPropertyValue(property);
|
||||
e.setAttribute(attribute, value);
|
||||
// Also set another attribute that is likely to be a presentation attribute,
|
||||
// in order to provoke bugs.
|
||||
const otherAttribute = attribute === 'stroke' ? 'fill' : 'stroke';
|
||||
e.setAttribute(otherAttribute, 'red');
|
||||
let propertyValueAfter = getComputedStyle(e).getPropertyValue(property);
|
||||
e.remove();
|
||||
return propertyValueBefore != propertyValueAfter;
|
||||
}
|
||||
|
||||
function assertPresentationAttributeIsSupported(element, attribute, values, property) {
|
||||
if (typeof values === 'string')
|
||||
values = [values];
|
||||
let supported = values.some(
|
||||
value => presentationAttributeIsSupported(element, attribute, value, property));
|
||||
assert_true(
|
||||
supported,
|
||||
`Presentation attribute ${attribute}="${values.join(" | ")}" should be supported on ${element} element`
|
||||
);
|
||||
}
|
||||
|
||||
function assertPresentationAttributeIsNotSupported(element, attribute, values, property) {
|
||||
if (typeof values === 'string')
|
||||
values = [values];
|
||||
let supported = values.some(
|
||||
value => presentationAttributeIsSupported(element, attribute, value, property));
|
||||
assert_false(
|
||||
supported,
|
||||
`Presentation attribute ${attribute}="${values.join(" | ")}" should not be supported on ${element} element`
|
||||
);
|
||||
}
|
||||
|
||||
function propertiesAreSupported(properties) {
|
||||
for (let p of properties) {
|
||||
if (!CSS.supports(p, "initial")) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue