LibWeb: Support preserveAspectRatio=none
for SVGs
This is very easy now all transforms are computed during layout.
This commit is contained in:
parent
190a8f948e
commit
05f42efc06
Notes:
sideshowbarker
2024-07-18 05:37:06 +09:00
Author: https://github.com/MacDue Commit: https://github.com/SerenityOS/serenity/commit/05f42efc06 Pull-request: https://github.com/SerenityOS/serenity/pull/23554
2 changed files with 18 additions and 10 deletions
|
@ -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]
|
||||
|
|
|
@ -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 }));
|
||||
}();
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue