mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 18:17:44 +00:00
LibWeb: Move some common SVG gradient functions into SVGGradientElement
These functions will also be used by SVG radial gradients.
This commit is contained in:
parent
eda429111e
commit
2826bd2b45
3 changed files with 38 additions and 19 deletions
|
@ -49,6 +49,35 @@ Optional<Gfx::AffineTransform> SVGGradientElement::gradient_transform() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The gradient transform, appropriately scaled and combined with the paint transform.
|
||||||
|
Gfx::AffineTransform SVGGradientElement::gradient_paint_transform(SVGPaintContext const& paint_context) const
|
||||||
|
{
|
||||||
|
auto transform = gradient_transform().value_or(Gfx::AffineTransform {});
|
||||||
|
if (gradient_units() == GradientUnits::ObjectBoundingBox) {
|
||||||
|
// Adjust transform to take place in the coordinate system defined by the bounding box:
|
||||||
|
return Gfx::AffineTransform { paint_context.transform }
|
||||||
|
.translate(paint_context.path_bounding_box.location())
|
||||||
|
.scale(paint_context.path_bounding_box.width(), paint_context.path_bounding_box.height())
|
||||||
|
.multiply(transform);
|
||||||
|
}
|
||||||
|
return Gfx::AffineTransform { paint_context.transform }.multiply(transform);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SVGGradientElement::add_color_stops(Gfx::SVGGradientPaintStyle& paint_style) const
|
||||||
|
{
|
||||||
|
for_each_color_stop([&](auto& stop) {
|
||||||
|
// https://svgwg.org/svg2-draft/pservers.html#StopNotes
|
||||||
|
// Gradient offset values less than 0 (or less than 0%) are rounded up to 0%.
|
||||||
|
// Gradient offset values greater than 1 (or greater than 100%) are rounded down to 100%.
|
||||||
|
float stop_offset = AK::clamp(stop.stop_offset().value(), 0.0f, 1.0f);
|
||||||
|
// FIXME: Each gradient offset value is required to be equal to or greater than the previous gradient
|
||||||
|
// stop's offset value. If a given gradient stop's offset value is not equal to or greater than all
|
||||||
|
// previous offset values, then the offset value is adjusted to be equal to the largest of all previous
|
||||||
|
// offset values.
|
||||||
|
paint_style.add_color_stop(stop_offset, stop.stop_color()).release_value_but_fixme_should_propagate_errors();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
JS::GCPtr<SVGGradientElement const> SVGGradientElement::xlink_href() const
|
JS::GCPtr<SVGGradientElement const> SVGGradientElement::xlink_href() const
|
||||||
{
|
{
|
||||||
// FIXME: This entire function is an ad-hoc hack!
|
// FIXME: This entire function is an ad-hoc hack!
|
||||||
|
|
|
@ -41,6 +41,8 @@ protected:
|
||||||
|
|
||||||
JS::GCPtr<SVGGradientElement const> xlink_href() const;
|
JS::GCPtr<SVGGradientElement const> xlink_href() 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
|
||||||
{
|
{
|
||||||
|
@ -55,6 +57,8 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void add_color_stops(Gfx::SVGGradientPaintStyle&) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Optional<GradientUnits> m_gradient_units = {};
|
Optional<GradientUnits> m_gradient_units = {};
|
||||||
Optional<Gfx::AffineTransform> m_gradient_transform = {};
|
Optional<Gfx::AffineTransform> m_gradient_transform = {};
|
||||||
|
|
|
@ -103,8 +103,8 @@ Optional<Gfx::PaintStyle const&> SVGLinearGradientElement::to_gfx_paint_style(SV
|
||||||
// box units) and then applying the transform specified by attribute ‘gradientTransform’. Percentages represent
|
// box units) and then applying the transform specified by attribute ‘gradientTransform’. Percentages represent
|
||||||
// values relative to the bounding box for the object.
|
// values relative to the bounding box for the object.
|
||||||
// Note: For gradientUnits="objectBoundingBox" both "100%" and "1" are treated the same.
|
// Note: For gradientUnits="objectBoundingBox" both "100%" and "1" are treated the same.
|
||||||
start_point = paint_context.path_bounding_box.location() + Gfx::FloatPoint { start_x().value() * paint_context.path_bounding_box.width(), start_y().value() * paint_context.path_bounding_box.height() };
|
start_point = { start_x().value(), start_y().value() };
|
||||||
end_point = paint_context.path_bounding_box.location() + Gfx::FloatPoint { end_x().value() * paint_context.path_bounding_box.width(), end_y().value() * paint_context.path_bounding_box.height() };
|
end_point = { end_x().value(), end_y().value() };
|
||||||
} else {
|
} else {
|
||||||
// GradientUnits::UserSpaceOnUse
|
// GradientUnits::UserSpaceOnUse
|
||||||
// If gradientUnits="userSpaceOnUse", ‘x1’, ‘y1’, ‘x2’, and ‘y2’ represent values in the coordinate system
|
// If gradientUnits="userSpaceOnUse", ‘x1’, ‘y1’, ‘x2’, and ‘y2’ represent values in the coordinate system
|
||||||
|
@ -125,28 +125,14 @@ Optional<Gfx::PaintStyle const&> SVGLinearGradientElement::to_gfx_paint_style(SV
|
||||||
if (!m_paint_style) {
|
if (!m_paint_style) {
|
||||||
m_paint_style = Gfx::SVGLinearGradientPaintStyle::create(start_point, end_point)
|
m_paint_style = Gfx::SVGLinearGradientPaintStyle::create(start_point, end_point)
|
||||||
.release_value_but_fixme_should_propagate_errors();
|
.release_value_but_fixme_should_propagate_errors();
|
||||||
// FIXME: Update this if DOM changes?
|
// FIXME: Update stops in DOM changes:
|
||||||
for_each_color_stop([&](auto& stop) {
|
add_color_stops(*m_paint_style);
|
||||||
m_paint_style->add_color_stop(stop.stop_offset().value(), stop.stop_color()).release_value_but_fixme_should_propagate_errors();
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
m_paint_style->set_start_point(start_point);
|
m_paint_style->set_start_point(start_point);
|
||||||
m_paint_style->set_end_point(end_point);
|
m_paint_style->set_end_point(end_point);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto gradient_affine_transform = gradient_transform().value_or(Gfx::AffineTransform {});
|
m_paint_style->set_gradient_transform(gradient_paint_transform(paint_context));
|
||||||
|
|
||||||
if (units == GradientUnits::ObjectBoundingBox) {
|
|
||||||
// Adjust transform to take place in the coordinate system defined by the bounding box:
|
|
||||||
gradient_affine_transform = Gfx::AffineTransform {}
|
|
||||||
.translate(paint_context.path_bounding_box.location())
|
|
||||||
.scale(paint_context.path_bounding_box.width(), paint_context.path_bounding_box.height())
|
|
||||||
.multiply(gradient_affine_transform)
|
|
||||||
.scale(1 / paint_context.path_bounding_box.width(), 1 / paint_context.path_bounding_box.height())
|
|
||||||
.translate(-paint_context.path_bounding_box.location());
|
|
||||||
}
|
|
||||||
|
|
||||||
m_paint_style->set_gradient_transform(Gfx::AffineTransform { paint_context.transform }.multiply(gradient_affine_transform));
|
|
||||||
return *m_paint_style;
|
return *m_paint_style;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue