mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 05:48:12 +00:00
LibWeb: Handle reference cycles in SVG gradient linking
Since SVG gradients can reference each other, we have to keep track of visited gradients when traversing the link chain, or we will recurse infinitely when there's a reference cycle.
This commit is contained in:
parent
1b8d8c7bbc
commit
2e0297d703
8 changed files with 155 additions and 36 deletions
|
@ -0,0 +1 @@
|
||||||
|
PASS (didn't hang or crash)
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!doctype html>
|
||||||
|
<script src="../include.js"></script>
|
||||||
|
<svg>
|
||||||
|
<linearGradient id="lol" href="#lmao"/>
|
||||||
|
<linearGradient id="lmao" href="#even"/>
|
||||||
|
<linearGradient id="even" href="#lol"/>
|
||||||
|
<rect fill="url(#lol)" />
|
||||||
|
</svg>
|
||||||
|
<script>
|
||||||
|
test(() => {
|
||||||
|
println("PASS (didn't hang or crash)");
|
||||||
|
});
|
||||||
|
</script>
|
|
@ -34,29 +34,47 @@ void SVGGradientElement::attribute_changed(FlyString const& name, Optional<Strin
|
||||||
}
|
}
|
||||||
|
|
||||||
GradientUnits SVGGradientElement::gradient_units() const
|
GradientUnits SVGGradientElement::gradient_units() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return gradient_units_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
GradientUnits SVGGradientElement::gradient_units_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_gradient_units.has_value())
|
if (m_gradient_units.has_value())
|
||||||
return *m_gradient_units;
|
return *m_gradient_units;
|
||||||
if (auto gradient = linked_gradient())
|
if (auto gradient = linked_gradient(seen_gradients))
|
||||||
return gradient->gradient_units();
|
return gradient->gradient_units_impl(seen_gradients);
|
||||||
return GradientUnits::ObjectBoundingBox;
|
return GradientUnits::ObjectBoundingBox;
|
||||||
}
|
}
|
||||||
|
|
||||||
SpreadMethod SVGGradientElement::spread_method() const
|
SpreadMethod SVGGradientElement::spread_method() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return spread_method_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
SpreadMethod SVGGradientElement::spread_method_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_spread_method.has_value())
|
if (m_spread_method.has_value())
|
||||||
return *m_spread_method;
|
return *m_spread_method;
|
||||||
if (auto gradient = linked_gradient())
|
if (auto gradient = linked_gradient(seen_gradients))
|
||||||
return gradient->spread_method();
|
return gradient->spread_method_impl(seen_gradients);
|
||||||
return SpreadMethod::Pad;
|
return SpreadMethod::Pad;
|
||||||
}
|
}
|
||||||
|
|
||||||
Optional<Gfx::AffineTransform> SVGGradientElement::gradient_transform() const
|
Optional<Gfx::AffineTransform> SVGGradientElement::gradient_transform() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return gradient_transform_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
Optional<Gfx::AffineTransform> SVGGradientElement::gradient_transform_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_gradient_transform.has_value())
|
if (m_gradient_transform.has_value())
|
||||||
return m_gradient_transform;
|
return m_gradient_transform;
|
||||||
if (auto gradient = linked_gradient())
|
if (auto gradient = linked_gradient(seen_gradients))
|
||||||
return gradient->gradient_transform();
|
return gradient->gradient_transform_impl(seen_gradients);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +107,7 @@ void SVGGradientElement::add_color_stops(Gfx::SVGGradientPaintStyle& paint_style
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
JS::GCPtr<SVGGradientElement const> SVGGradientElement::linked_gradient() const
|
JS::GCPtr<SVGGradientElement const> SVGGradientElement::linked_gradient(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
// FIXME: This entire function is an ad-hoc hack!
|
// FIXME: This entire function is an ad-hoc hack!
|
||||||
// It can only resolve #<ids> in the same document.
|
// It can only resolve #<ids> in the same document.
|
||||||
|
@ -103,8 +121,12 @@ JS::GCPtr<SVGGradientElement const> SVGGradientElement::linked_gradient() const
|
||||||
auto element = document().get_element_by_id(id.value());
|
auto element = document().get_element_by_id(id.value());
|
||||||
if (!element)
|
if (!element)
|
||||||
return {};
|
return {};
|
||||||
|
if (element == this)
|
||||||
|
return {};
|
||||||
if (!is<SVGGradientElement>(*element))
|
if (!is<SVGGradientElement>(*element))
|
||||||
return {};
|
return {};
|
||||||
|
if (seen_gradients.set(&verify_cast<SVGGradientElement>(*element)) != AK::HashSetResult::InsertedNewEntry)
|
||||||
|
return {};
|
||||||
return &verify_cast<SVGGradientElement>(*element);
|
return &verify_cast<SVGGradientElement>(*element);
|
||||||
}
|
}
|
||||||
return {};
|
return {};
|
||||||
|
|
|
@ -55,12 +55,22 @@ protected:
|
||||||
|
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
|
||||||
JS::GCPtr<SVGGradientElement const> linked_gradient() const;
|
JS::GCPtr<SVGGradientElement const> linked_gradient(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
|
||||||
Gfx::AffineTransform gradient_paint_transform(SVGPaintContext const&) const;
|
Gfx::AffineTransform gradient_paint_transform(SVGPaintContext const&) const;
|
||||||
|
|
||||||
template<VoidFunction<SVGStopElement> Callback>
|
template<VoidFunction<SVGStopElement> Callback>
|
||||||
void for_each_color_stop(Callback const& callback) const
|
void for_each_color_stop(Callback const& callback) const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return for_each_color_stop_impl(callback, seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
void add_color_stops(Gfx::SVGGradientPaintStyle&) const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template<VoidFunction<SVGStopElement> Callback>
|
||||||
|
void for_each_color_stop_impl(Callback const& callback, HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
bool color_stops_found = false;
|
bool color_stops_found = false;
|
||||||
for_each_child_of_type<SVG::SVGStopElement>([&](auto& stop) {
|
for_each_child_of_type<SVG::SVGStopElement>([&](auto& stop) {
|
||||||
|
@ -68,14 +78,15 @@ protected:
|
||||||
callback(stop);
|
callback(stop);
|
||||||
});
|
});
|
||||||
if (!color_stops_found) {
|
if (!color_stops_found) {
|
||||||
if (auto gradient = linked_gradient())
|
if (auto gradient = linked_gradient(seen_gradients))
|
||||||
gradient->for_each_color_stop(callback);
|
gradient->for_each_color_stop_impl(callback, seen_gradients);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_color_stops(Gfx::SVGGradientPaintStyle&) const;
|
GradientUnits gradient_units_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
SpreadMethod spread_method_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
Optional<Gfx::AffineTransform> gradient_transform_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
|
||||||
private:
|
|
||||||
Optional<GradientUnits> m_gradient_units = {};
|
Optional<GradientUnits> m_gradient_units = {};
|
||||||
Optional<SpreadMethod> m_spread_method = {};
|
Optional<SpreadMethod> m_spread_method = {};
|
||||||
Optional<Gfx::AffineTransform> m_gradient_transform = {};
|
Optional<Gfx::AffineTransform> m_gradient_transform = {};
|
||||||
|
|
|
@ -48,44 +48,68 @@ void SVGLinearGradientElement::attribute_changed(FlyString const& name, Optional
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX1Attribute
|
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX1Attribute
|
||||||
NumberPercentage SVGLinearGradientElement::start_x() const
|
NumberPercentage SVGLinearGradientElement::start_x() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return start_x_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGLinearGradientElement::start_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_x1.has_value())
|
if (m_x1.has_value())
|
||||||
return *m_x1;
|
return *m_x1;
|
||||||
if (auto gradient = linked_linear_gradient())
|
if (auto gradient = linked_linear_gradient(seen_gradients))
|
||||||
return gradient->start_x();
|
return gradient->start_x_impl(seen_gradients);
|
||||||
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
||||||
return NumberPercentage::create_percentage(0);
|
return NumberPercentage::create_percentage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY1Attribute
|
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY1Attribute
|
||||||
NumberPercentage SVGLinearGradientElement::start_y() const
|
NumberPercentage SVGLinearGradientElement::start_y() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return start_y_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGLinearGradientElement::start_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_y1.has_value())
|
if (m_y1.has_value())
|
||||||
return *m_y1;
|
return *m_y1;
|
||||||
if (auto gradient = linked_linear_gradient())
|
if (auto gradient = linked_linear_gradient(seen_gradients))
|
||||||
return gradient->start_x();
|
return gradient->start_y_impl(seen_gradients);
|
||||||
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
||||||
return NumberPercentage::create_percentage(0);
|
return NumberPercentage::create_percentage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX2Attribute
|
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementX2Attribute
|
||||||
NumberPercentage SVGLinearGradientElement::end_x() const
|
NumberPercentage SVGLinearGradientElement::end_x() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return end_x_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGLinearGradientElement::end_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_x2.has_value())
|
if (m_x2.has_value())
|
||||||
return *m_x2;
|
return *m_x2;
|
||||||
if (auto gradient = linked_linear_gradient())
|
if (auto gradient = linked_linear_gradient(seen_gradients))
|
||||||
return gradient->start_x();
|
return gradient->end_x_impl(seen_gradients);
|
||||||
// If the attribute is not specified, the effect is as if a value of '100%' were specified.
|
// If the attribute is not specified, the effect is as if a value of '100%' were specified.
|
||||||
return NumberPercentage::create_percentage(100);
|
return NumberPercentage::create_percentage(100);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY2Attribute
|
// https://www.w3.org/TR/SVG11/pservers.html#LinearGradientElementY2Attribute
|
||||||
NumberPercentage SVGLinearGradientElement::end_y() const
|
NumberPercentage SVGLinearGradientElement::end_y() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return end_y_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGLinearGradientElement::end_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_y2.has_value())
|
if (m_y2.has_value())
|
||||||
return *m_y2;
|
return *m_y2;
|
||||||
if (auto gradient = linked_linear_gradient())
|
if (auto gradient = linked_linear_gradient(seen_gradients))
|
||||||
return gradient->start_x();
|
return gradient->end_y_impl(seen_gradients);
|
||||||
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
||||||
return NumberPercentage::create_percentage(0);
|
return NumberPercentage::create_percentage(0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,9 +34,9 @@ protected:
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JS::GCPtr<SVGLinearGradientElement const> linked_linear_gradient() const
|
JS::GCPtr<SVGLinearGradientElement const> linked_linear_gradient(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (auto gradient = linked_gradient(); gradient && is<SVGLinearGradientElement>(*gradient))
|
if (auto gradient = linked_gradient(seen_gradients); gradient && is<SVGLinearGradientElement>(*gradient))
|
||||||
return &verify_cast<SVGLinearGradientElement>(*gradient);
|
return &verify_cast<SVGLinearGradientElement>(*gradient);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,11 @@ private:
|
||||||
NumberPercentage end_x() const;
|
NumberPercentage end_x() const;
|
||||||
NumberPercentage end_y() const;
|
NumberPercentage end_y() const;
|
||||||
|
|
||||||
|
NumberPercentage start_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage start_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage end_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage end_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
|
||||||
Optional<NumberPercentage> m_x1;
|
Optional<NumberPercentage> m_x1;
|
||||||
Optional<NumberPercentage> m_y1;
|
Optional<NumberPercentage> m_y1;
|
||||||
Optional<NumberPercentage> m_x2;
|
Optional<NumberPercentage> m_x2;
|
||||||
|
|
|
@ -52,13 +52,19 @@ void SVGRadialGradientElement::attribute_changed(FlyString const& name, Optional
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFXAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFXAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::start_circle_x() const
|
NumberPercentage SVGRadialGradientElement::start_circle_x() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return start_circle_x_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::start_circle_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_fx.has_value())
|
if (m_fx.has_value())
|
||||||
return *m_fx;
|
return *m_fx;
|
||||||
// If the element references an element that specifies a value for 'fx', then the value of 'fx' is
|
// If the element references an element that specifies a value for 'fx', then the value of 'fx' is
|
||||||
// inherited from the referenced element.
|
// inherited from the referenced element.
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->start_circle_x();
|
return gradient->start_circle_x_impl(seen_gradients);
|
||||||
// If attribute ‘fx’ is not specified, ‘fx’ will coincide with the presentational value of ‘cx’ for
|
// If attribute ‘fx’ is not specified, ‘fx’ will coincide with the presentational value of ‘cx’ for
|
||||||
// the element whether the value for 'cx' was inherited or not.
|
// the element whether the value for 'cx' was inherited or not.
|
||||||
return end_circle_x();
|
return end_circle_x();
|
||||||
|
@ -66,13 +72,19 @@ NumberPercentage SVGRadialGradientElement::start_circle_x() const
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFYAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFYAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::start_circle_y() const
|
NumberPercentage SVGRadialGradientElement::start_circle_y() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return start_circle_y_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::start_circle_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_fy.has_value())
|
if (m_fy.has_value())
|
||||||
return *m_fy;
|
return *m_fy;
|
||||||
// If the element references an element that specifies a value for 'fy', then the value of 'fy' is
|
// If the element references an element that specifies a value for 'fy', then the value of 'fy' is
|
||||||
// inherited from the referenced element.
|
// inherited from the referenced element.
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->start_circle_y();
|
return gradient->start_circle_y_impl(seen_gradients);
|
||||||
// If attribute ‘fy’ is not specified, ‘fy’ will coincide with the presentational value of ‘cy’ for
|
// If attribute ‘fy’ is not specified, ‘fy’ will coincide with the presentational value of ‘cy’ for
|
||||||
// the element whether the value for 'cy' was inherited or not.
|
// the element whether the value for 'cy' was inherited or not.
|
||||||
return end_circle_y();
|
return end_circle_y();
|
||||||
|
@ -80,46 +92,70 @@ NumberPercentage SVGRadialGradientElement::start_circle_y() const
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFRAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementFRAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::start_circle_radius() const
|
NumberPercentage SVGRadialGradientElement::start_circle_radius() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return start_circle_radius_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::start_circle_radius_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
// Note: A negative value is an error.
|
// Note: A negative value is an error.
|
||||||
if (m_fr.has_value() && m_fr->value() >= 0)
|
if (m_fr.has_value() && m_fr->value() >= 0)
|
||||||
return *m_fr;
|
return *m_fr;
|
||||||
// if the element references an element that specifies a value for 'fr', then the value of
|
// if the element references an element that specifies a value for 'fr', then the value of
|
||||||
// 'fr' is inherited from the referenced element.
|
// 'fr' is inherited from the referenced element.
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->start_circle_radius();
|
return gradient->start_circle_radius_impl(seen_gradients);
|
||||||
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
// If the attribute is not specified, the effect is as if a value of '0%' were specified.
|
||||||
return NumberPercentage::create_percentage(0);
|
return NumberPercentage::create_percentage(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementCXAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementCXAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::end_circle_x() const
|
NumberPercentage SVGRadialGradientElement::end_circle_x() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return end_circle_x_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::end_circle_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_cx.has_value())
|
if (m_cx.has_value())
|
||||||
return *m_cx;
|
return *m_cx;
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->end_circle_x();
|
return gradient->end_circle_x_impl(seen_gradients);
|
||||||
return NumberPercentage::create_percentage(50);
|
return NumberPercentage::create_percentage(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementCYAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementCYAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::end_circle_y() const
|
NumberPercentage SVGRadialGradientElement::end_circle_y() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return end_circle_y_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::end_circle_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (m_cy.has_value())
|
if (m_cy.has_value())
|
||||||
return *m_cy;
|
return *m_cy;
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->end_circle_y();
|
return gradient->end_circle_y_impl(seen_gradients);
|
||||||
return NumberPercentage::create_percentage(50);
|
return NumberPercentage::create_percentage(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementRAttribute
|
// https://svgwg.org/svg2-draft/pservers.html#RadialGradientElementRAttribute
|
||||||
NumberPercentage SVGRadialGradientElement::end_circle_radius() const
|
NumberPercentage SVGRadialGradientElement::end_circle_radius() const
|
||||||
|
{
|
||||||
|
HashTable<SVGGradientElement const*> seen_gradients;
|
||||||
|
return end_circle_radius_impl(seen_gradients);
|
||||||
|
}
|
||||||
|
|
||||||
|
NumberPercentage SVGRadialGradientElement::end_circle_radius_impl(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
// Note: A negative value is an error.
|
// Note: A negative value is an error.
|
||||||
if (m_r.has_value() && m_r->value() >= 0)
|
if (m_r.has_value() && m_r->value() >= 0)
|
||||||
return *m_r;
|
return *m_r;
|
||||||
if (auto gradient = linked_radial_gradient())
|
if (auto gradient = linked_radial_gradient(seen_gradients))
|
||||||
return gradient->end_circle_radius();
|
return gradient->end_circle_radius_impl(seen_gradients);
|
||||||
return NumberPercentage::create_percentage(50);
|
return NumberPercentage::create_percentage(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,9 +36,9 @@ protected:
|
||||||
virtual void initialize(JS::Realm&) override;
|
virtual void initialize(JS::Realm&) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
JS::GCPtr<SVGRadialGradientElement const> linked_radial_gradient() const
|
JS::GCPtr<SVGRadialGradientElement const> linked_radial_gradient(HashTable<SVGGradientElement const*>& seen_gradients) const
|
||||||
{
|
{
|
||||||
if (auto gradient = linked_gradient(); gradient && is<SVGRadialGradientElement>(*gradient))
|
if (auto gradient = linked_gradient(seen_gradients); gradient && is<SVGRadialGradientElement>(*gradient))
|
||||||
return &verify_cast<SVGRadialGradientElement>(*gradient);
|
return &verify_cast<SVGRadialGradientElement>(*gradient);
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,13 @@ private:
|
||||||
NumberPercentage end_circle_y() const;
|
NumberPercentage end_circle_y() const;
|
||||||
NumberPercentage end_circle_radius() const;
|
NumberPercentage end_circle_radius() const;
|
||||||
|
|
||||||
|
NumberPercentage start_circle_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage start_circle_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage start_circle_radius_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage end_circle_x_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage end_circle_y_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
NumberPercentage end_circle_radius_impl(HashTable<SVGGradientElement const*>& seen_gradients) const;
|
||||||
|
|
||||||
Optional<NumberPercentage> m_cx;
|
Optional<NumberPercentage> m_cx;
|
||||||
Optional<NumberPercentage> m_cy;
|
Optional<NumberPercentage> m_cy;
|
||||||
Optional<NumberPercentage> m_fx;
|
Optional<NumberPercentage> m_fx;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue