LibWeb: Support preserveAspectRatio=none for SVGs

This is very easy now all transforms are computed during layout.
This commit is contained in:
MacDue 2024-03-09 12:31:00 +01:00 committed by Andreas Kling
parent 190a8f948e
commit 05f42efc06
Notes: sideshowbarker 2024-07-18 05:37:06 +09:00
2 changed files with 18 additions and 10 deletions

View file

@ -98,7 +98,7 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
TextNode <#text>
SVGSVGBox <svg> at (249,201) content-size 160x60 [SVG] children: inline
TextNode <#text>
SVGGeometryBox <circle> at (299,201) content-size 60x60 children: not-inline
SVGGeometryBox <circle> at (249,201) content-size 160x60 children: not-inline
TextNode <#text>
TextNode <#text>
@ -141,4 +141,4 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
SVGPathPaintable (SVGGeometryBox<circle>) [114,136 125x125]
TextPaintable (TextNode<#text>)
SVGSVGPaintable (SVGSVGBox<svg>) [248,200 162x62]
SVGPathPaintable (SVGGeometryBox<circle>) [299,201 60x60]
SVGPathPaintable (SVGGeometryBox<circle>) [249,201 160x60]

View file

@ -46,7 +46,8 @@ CSSPixels SVGFormattingContext::automatic_content_height() const
struct ViewBoxTransform {
CSSPixelPoint offset;
double scale_factor;
double scale_factor_x;
double scale_factor_y;
};
// https://svgwg.org/svg2-draft/coords.html#PreserveAspectRatioAttribute
@ -55,20 +56,27 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
{
ViewBoxTransform viewbox_transform {};
if (preserve_aspect_ratio.align == SVG::PreserveAspectRatio::Align::None) {
viewbox_transform.scale_factor_x = viewbox_scale.width();
viewbox_transform.scale_factor_y = viewbox_scale.height();
viewbox_transform.offset = {};
return viewbox_transform;
}
switch (preserve_aspect_ratio.meet_or_slice) {
case SVG::PreserveAspectRatio::MeetOrSlice::Meet:
// meet (the default) - Scale the graphic such that:
// - aspect ratio is preserved
// - the entire viewBox is visible within the SVG viewport
// - the viewBox is scaled up as much as possible, while still meeting the other criteria
viewbox_transform.scale_factor = min(viewbox_scale.width(), viewbox_scale.height());
viewbox_transform.scale_factor_x = viewbox_transform.scale_factor_y = min(viewbox_scale.width(), viewbox_scale.height());
break;
case SVG::PreserveAspectRatio::MeetOrSlice::Slice:
// slice - Scale the graphic such that:
// aspect ratio is preserved
// the entire SVG viewport is covered by the viewBox
// the viewBox is scaled down as much as possible, while still meeting the other criteria
viewbox_transform.scale_factor = max(viewbox_scale.width(), viewbox_scale.height());
viewbox_transform.scale_factor_x = viewbox_transform.scale_factor_y = max(viewbox_scale.width(), viewbox_scale.height());
break;
default:
VERIFY_NOT_REACHED();
@ -93,13 +101,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMidYMax:
// Align the midpoint X value of the element's viewBox with the midpoint X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels::nearest_value_for(view_box.width * viewbox_transform.scale_factor)) / 2, 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels::nearest_value_for(view_box.width * viewbox_transform.scale_factor_x)) / 2, 0);
break;
case SVG::PreserveAspectRatio::Align::xMaxYMin:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-x>+<width> of the element's viewBox with the maximum X value of the SVG viewport.
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels::nearest_value_for(view_box.width * viewbox_transform.scale_factor)), 0);
viewbox_transform.offset.translate_by((svg_box_state.content_width() - CSSPixels::nearest_value_for(view_box.width * viewbox_transform.scale_factor_x)), 0);
break;
default:
VERIFY_NOT_REACHED();
@ -124,13 +132,13 @@ static ViewBoxTransform scale_and_align_viewbox_content(SVG::PreserveAspectRatio
case SVG::PreserveAspectRatio::Align::xMidYMid:
case SVG::PreserveAspectRatio::Align::xMaxYMid:
// Align the midpoint Y value of the element's viewBox with the midpoint Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels::nearest_value_for(view_box.height * viewbox_transform.scale_factor)) / 2);
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels::nearest_value_for(view_box.height * viewbox_transform.scale_factor_y)) / 2);
break;
case SVG::PreserveAspectRatio::Align::xMinYMax:
case SVG::PreserveAspectRatio::Align::xMidYMax:
case SVG::PreserveAspectRatio::Align::xMaxYMax:
// Align the <min-y>+<height> of the element's viewBox with the maximum Y value of the SVG viewport.
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels::nearest_value_for(view_box.height * viewbox_transform.scale_factor)));
viewbox_transform.offset.translate_by(0, (svg_box_state.content_height() - CSSPixels::nearest_value_for(view_box.height * viewbox_transform.scale_factor_y)));
break;
default:
VERIFY_NOT_REACHED();
@ -232,7 +240,7 @@ void SVGFormattingContext::run(Box const& box, LayoutMode layout_mode, Available
CSSPixelPoint offset = viewbox_offset_and_scale.offset;
return Gfx::AffineTransform { m_parent_viewbox_transform }.multiply(Gfx::AffineTransform {}
.translate(offset.to_type<float>())
.scale(viewbox_offset_and_scale.scale_factor, viewbox_offset_and_scale.scale_factor)
.scale(viewbox_offset_and_scale.scale_factor_x, viewbox_offset_and_scale.scale_factor_y)
.translate({ -viewbox->min_x, -viewbox->min_y }));
}();