mirror of
https://github.com/RGBCube/serenity
synced 2025-07-26 06:47:34 +00:00
LibWeb: Remove SVGContext
The SVGContext is a leftover from when SVG properties were more ad-hoc. All properties are now (for better or worse) treated as CSS properties (or handled elsewhere). This makes the SVGContext's fill/stroke inheritance handling unnecessary.
This commit is contained in:
parent
23a7ccf607
commit
7d26383426
11 changed files with 18 additions and 150 deletions
|
@ -17,24 +17,6 @@ PaintContext::PaintContext(Gfx::Painter& painter, Palette const& palette, double
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
SVGContext& PaintContext::svg_context()
|
|
||||||
{
|
|
||||||
// FIXME: This is a total hack to avoid crashing on content that has SVG elements embedded directly in HTML without an <svg> element.
|
|
||||||
if (!m_svg_context.has_value())
|
|
||||||
m_svg_context = SVGContext { {} };
|
|
||||||
return m_svg_context.value();
|
|
||||||
}
|
|
||||||
|
|
||||||
void PaintContext::set_svg_context(SVGContext context)
|
|
||||||
{
|
|
||||||
m_svg_context = move(context);
|
|
||||||
}
|
|
||||||
|
|
||||||
void PaintContext::clear_svg_context()
|
|
||||||
{
|
|
||||||
m_svg_context.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
CSSPixelRect PaintContext::css_viewport_rect() const
|
CSSPixelRect PaintContext::css_viewport_rect() const
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
#include <LibGfx/Palette.h>
|
#include <LibGfx/Palette.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
#include <LibWeb/PixelUnits.h>
|
#include <LibWeb/PixelUnits.h>
|
||||||
#include <LibWeb/SVG/SVGContext.h>
|
|
||||||
|
|
||||||
namespace Web {
|
namespace Web {
|
||||||
|
|
||||||
|
@ -23,11 +22,6 @@ public:
|
||||||
Gfx::Painter& painter() const { return m_painter; }
|
Gfx::Painter& painter() const { return m_painter; }
|
||||||
Palette const& palette() const { return m_palette; }
|
Palette const& palette() const { return m_palette; }
|
||||||
|
|
||||||
bool has_svg_context() const { return m_svg_context.has_value(); }
|
|
||||||
SVGContext& svg_context();
|
|
||||||
void set_svg_context(SVGContext);
|
|
||||||
void clear_svg_context();
|
|
||||||
|
|
||||||
bool should_show_line_box_borders() const { return m_should_show_line_box_borders; }
|
bool should_show_line_box_borders() const { return m_should_show_line_box_borders; }
|
||||||
void set_should_show_line_box_borders(bool value) { m_should_show_line_box_borders = value; }
|
void set_should_show_line_box_borders(bool value) { m_should_show_line_box_borders = value; }
|
||||||
|
|
||||||
|
@ -60,7 +54,6 @@ public:
|
||||||
clone.m_device_viewport_rect = m_device_viewport_rect;
|
clone.m_device_viewport_rect = m_device_viewport_rect;
|
||||||
clone.m_should_show_line_box_borders = m_should_show_line_box_borders;
|
clone.m_should_show_line_box_borders = m_should_show_line_box_borders;
|
||||||
clone.m_focus = m_focus;
|
clone.m_focus = m_focus;
|
||||||
clone.m_svg_context = m_svg_context;
|
|
||||||
return clone;
|
return clone;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,7 +62,6 @@ public:
|
||||||
private:
|
private:
|
||||||
Gfx::Painter& m_painter;
|
Gfx::Painter& m_painter;
|
||||||
Palette m_palette;
|
Palette m_palette;
|
||||||
Optional<SVGContext> m_svg_context;
|
|
||||||
double m_device_pixels_per_css_pixel { 0 };
|
double m_device_pixels_per_css_pixel { 0 };
|
||||||
DevicePixelRect m_device_viewport_rect;
|
DevicePixelRect m_device_viewport_rect;
|
||||||
bool m_should_show_line_box_borders { false };
|
bool m_should_show_line_box_borders { false };
|
||||||
|
|
|
@ -66,15 +66,16 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
|
|
||||||
auto& geometry_element = layout_box().dom_node();
|
auto& geometry_element = layout_box().dom_node();
|
||||||
|
|
||||||
|
auto const* svg_element = geometry_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
|
||||||
|
auto svg_element_rect = svg_element->paintable_box()->absolute_rect();
|
||||||
|
|
||||||
Gfx::AntiAliasingPainter painter { context.painter() };
|
Gfx::AntiAliasingPainter painter { context.painter() };
|
||||||
auto& svg_context = context.svg_context();
|
|
||||||
|
|
||||||
// FIXME: This should not be trucated to an int.
|
// FIXME: This should not be trucated to an int.
|
||||||
Gfx::PainterStateSaver save_painter { context.painter() };
|
Gfx::PainterStateSaver save_painter { context.painter() };
|
||||||
auto offset = context.floored_device_point(svg_context.svg_element_position()).to_type<int>().to_type<float>();
|
auto offset = context.floored_device_point(svg_element_rect.location()).to_type<int>().to_type<float>();
|
||||||
painter.translate(offset);
|
painter.translate(offset);
|
||||||
|
|
||||||
auto const* svg_element = geometry_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
|
|
||||||
auto maybe_view_box = svg_element->view_box();
|
auto maybe_view_box = svg_element->view_box();
|
||||||
|
|
||||||
auto transform = layout_box().layout_transform();
|
auto transform = layout_box().layout_transform();
|
||||||
|
@ -102,7 +103,7 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
auto svg_viewport = [&] {
|
auto svg_viewport = [&] {
|
||||||
if (maybe_view_box.has_value())
|
if (maybe_view_box.has_value())
|
||||||
return Gfx::FloatRect { maybe_view_box->min_x, maybe_view_box->min_y, maybe_view_box->width, maybe_view_box->height };
|
return Gfx::FloatRect { maybe_view_box->min_x, maybe_view_box->min_y, maybe_view_box->width, maybe_view_box->height };
|
||||||
return Gfx::FloatRect { { 0, 0 }, svg_context.svg_element_size().to_type<double>().to_type<float>() };
|
return Gfx::FloatRect { { 0, 0 }, svg_element_rect.size().to_type<double>().to_type<float>() };
|
||||||
}();
|
}();
|
||||||
|
|
||||||
SVG::SVGPaintContext paint_context {
|
SVG::SVGPaintContext paint_context {
|
||||||
|
@ -111,26 +112,25 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
.transform = paint_transform
|
.transform = paint_transform
|
||||||
};
|
};
|
||||||
|
|
||||||
auto fill_opacity = geometry_element.fill_opacity().value_or(svg_context.fill_opacity());
|
auto fill_opacity = geometry_element.fill_opacity().value_or(1);
|
||||||
auto winding_rule = to_gfx_winding_rule(geometry_element.fill_rule().value_or(svg_context.fill_rule()));
|
auto winding_rule = to_gfx_winding_rule(geometry_element.fill_rule().value_or(SVG::FillRule::Nonzero));
|
||||||
|
|
||||||
if (auto paint_style = geometry_element.fill_paint_style(paint_context); paint_style.has_value()) {
|
if (auto paint_style = geometry_element.fill_paint_style(paint_context); paint_style.has_value()) {
|
||||||
painter.fill_path(
|
painter.fill_path(
|
||||||
closed_path(),
|
closed_path(),
|
||||||
*paint_style,
|
*paint_style,
|
||||||
fill_opacity,
|
fill_opacity,
|
||||||
winding_rule);
|
winding_rule);
|
||||||
} else if (auto fill_color = geometry_element.fill_color().value_or(svg_context.fill_color()).with_opacity(fill_opacity); fill_color.alpha() > 0) {
|
} else if (auto fill_color = geometry_element.fill_color(); fill_color.has_value()) {
|
||||||
painter.fill_path(
|
painter.fill_path(
|
||||||
closed_path(),
|
closed_path(),
|
||||||
fill_color,
|
fill_color->with_opacity(fill_opacity),
|
||||||
winding_rule);
|
winding_rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto stroke_opacity = geometry_element.stroke_opacity().value_or(svg_context.stroke_opacity());
|
auto stroke_opacity = geometry_element.stroke_opacity().value_or(1);
|
||||||
|
|
||||||
// Note: This is assuming .x_scale() == .y_scale() (which it does currently).
|
// Note: This is assuming .x_scale() == .y_scale() (which it does currently).
|
||||||
float stroke_thickness = geometry_element.stroke_width().value_or(svg_context.stroke_width()) * viewbox_scale;
|
float stroke_thickness = geometry_element.stroke_width().value_or(1) * viewbox_scale;
|
||||||
|
|
||||||
if (auto paint_style = geometry_element.stroke_paint_style(paint_context); paint_style.has_value()) {
|
if (auto paint_style = geometry_element.stroke_paint_style(paint_context); paint_style.has_value()) {
|
||||||
painter.stroke_path(
|
painter.stroke_path(
|
||||||
|
@ -138,10 +138,10 @@ void SVGGeometryPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
*paint_style,
|
*paint_style,
|
||||||
stroke_thickness,
|
stroke_thickness,
|
||||||
stroke_opacity);
|
stroke_opacity);
|
||||||
} else if (auto stroke_color = geometry_element.stroke_color().value_or(svg_context.stroke_color()).with_opacity(stroke_opacity); stroke_color.alpha() > 0) {
|
} else if (auto stroke_color = geometry_element.stroke_color(); stroke_color.has_value()) {
|
||||||
painter.stroke_path(
|
painter.stroke_path(
|
||||||
path,
|
path,
|
||||||
stroke_color,
|
stroke_color->with_opacity(stroke_opacity),
|
||||||
stroke_thickness);
|
stroke_thickness);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,26 +24,4 @@ Layout::SVGGraphicsBox const& SVGGraphicsPaintable::layout_box() const
|
||||||
return static_cast<Layout::SVGGraphicsBox const&>(layout_node());
|
return static_cast<Layout::SVGGraphicsBox const&>(layout_node());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SVGGraphicsPaintable::before_children_paint(PaintContext& context, PaintPhase phase) const
|
|
||||||
{
|
|
||||||
SVGPaintable::before_children_paint(context, phase);
|
|
||||||
if (phase != PaintPhase::Foreground)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto& graphics_element = layout_box().dom_node();
|
|
||||||
|
|
||||||
if (auto fill_rule = graphics_element.fill_rule(); fill_rule.has_value())
|
|
||||||
context.svg_context().set_fill_rule(*fill_rule);
|
|
||||||
if (auto fill_color = graphics_element.fill_color(); fill_color.has_value())
|
|
||||||
context.svg_context().set_fill_color(*fill_color);
|
|
||||||
if (auto stroke_color = graphics_element.stroke_color(); stroke_color.has_value())
|
|
||||||
context.svg_context().set_stroke_color(*stroke_color);
|
|
||||||
if (auto stroke_width = graphics_element.stroke_width(); stroke_width.has_value())
|
|
||||||
context.svg_context().set_stroke_width(*stroke_width);
|
|
||||||
if (auto fill_opacity = graphics_element.fill_opacity(); fill_opacity.has_value())
|
|
||||||
context.svg_context().set_fill_opacity(*fill_opacity);
|
|
||||||
if (auto stroke_opacity = graphics_element.stroke_opacity(); stroke_opacity.has_value())
|
|
||||||
context.svg_context().set_stroke_opacity(*stroke_opacity);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,8 +17,6 @@ class SVGGraphicsPaintable : public SVGPaintable {
|
||||||
public:
|
public:
|
||||||
static JS::NonnullGCPtr<SVGGraphicsPaintable> create(Layout::SVGGraphicsBox const&);
|
static JS::NonnullGCPtr<SVGGraphicsPaintable> create(Layout::SVGGraphicsBox const&);
|
||||||
|
|
||||||
virtual void before_children_paint(PaintContext&, PaintPhase) const override;
|
|
||||||
|
|
||||||
Layout::SVGGraphicsBox const& layout_box() const;
|
Layout::SVGGraphicsBox const& layout_box() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -20,22 +20,6 @@ Layout::SVGBox const& SVGPaintable::layout_box() const
|
||||||
return static_cast<Layout::SVGBox const&>(layout_node());
|
return static_cast<Layout::SVGBox const&>(layout_node());
|
||||||
}
|
}
|
||||||
|
|
||||||
void SVGPaintable::before_children_paint(PaintContext& context, PaintPhase phase) const
|
|
||||||
{
|
|
||||||
PaintableBox::before_children_paint(context, phase);
|
|
||||||
if (phase != PaintPhase::Foreground)
|
|
||||||
return;
|
|
||||||
context.svg_context().save();
|
|
||||||
}
|
|
||||||
|
|
||||||
void SVGPaintable::after_children_paint(PaintContext& context, PaintPhase phase) const
|
|
||||||
{
|
|
||||||
PaintableBox::after_children_paint(context, phase);
|
|
||||||
if (phase != PaintPhase::Foreground)
|
|
||||||
return;
|
|
||||||
context.svg_context().restore();
|
|
||||||
}
|
|
||||||
|
|
||||||
CSSPixelRect SVGPaintable::compute_absolute_rect() const
|
CSSPixelRect SVGPaintable::compute_absolute_rect() const
|
||||||
{
|
{
|
||||||
if (auto* svg_svg_box = layout_box().first_ancestor_of_type<Layout::SVGSVGBox>()) {
|
if (auto* svg_svg_box = layout_box().first_ancestor_of_type<Layout::SVGSVGBox>()) {
|
||||||
|
|
|
@ -15,9 +15,6 @@ class SVGPaintable : public PaintableBox {
|
||||||
JS_CELL(SVGPaintable, PaintableBox);
|
JS_CELL(SVGPaintable, PaintableBox);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
virtual void before_children_paint(PaintContext&, PaintPhase) const override;
|
|
||||||
virtual void after_children_paint(PaintContext&, PaintPhase) const override;
|
|
||||||
|
|
||||||
Layout::SVGBox const& layout_box() const;
|
Layout::SVGBox const& layout_box() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
|
@ -30,9 +30,6 @@ void SVGSVGPaintable::before_children_paint(PaintContext& context, PaintPhase ph
|
||||||
if (phase != PaintPhase::Foreground)
|
if (phase != PaintPhase::Foreground)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!context.has_svg_context())
|
|
||||||
context.set_svg_context(SVGContext(absolute_rect()));
|
|
||||||
|
|
||||||
context.painter().save();
|
context.painter().save();
|
||||||
context.painter().add_clip_rect(context.enclosing_device_rect(absolute_rect()).to_type<int>());
|
context.painter().add_clip_rect(context.enclosing_device_rect(absolute_rect()).to_type<int>());
|
||||||
}
|
}
|
||||||
|
@ -44,7 +41,6 @@ void SVGSVGPaintable::after_children_paint(PaintContext& context, PaintPhase pha
|
||||||
return;
|
return;
|
||||||
|
|
||||||
context.painter().restore();
|
context.painter().restore();
|
||||||
context.clear_svg_context();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,9 +38,12 @@ void SVGTextPaintable::paint(PaintContext& context, PaintPhase phase) const
|
||||||
|
|
||||||
auto& painter = context.painter();
|
auto& painter = context.painter();
|
||||||
|
|
||||||
|
auto& text_element = layout_box().dom_node();
|
||||||
|
auto const* svg_element = text_element.shadow_including_first_ancestor_of_type<SVG::SVGSVGElement>();
|
||||||
|
auto svg_element_rect = svg_element->paintable_box()->absolute_rect();
|
||||||
|
|
||||||
Gfx::PainterStateSaver save_painter { painter };
|
Gfx::PainterStateSaver save_painter { painter };
|
||||||
auto& svg_context = context.svg_context();
|
auto svg_context_offset = context.floored_device_point(svg_element_rect.location()).to_type<int>();
|
||||||
auto svg_context_offset = context.floored_device_point(svg_context.svg_element_position()).to_type<int>();
|
|
||||||
painter.translate(svg_context_offset);
|
painter.translate(svg_context_offset);
|
||||||
|
|
||||||
auto const& dom_node = layout_box().dom_node();
|
auto const& dom_node = layout_box().dom_node();
|
||||||
|
|
|
@ -1,61 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020, Matthew Olsson <mattco@serenityos.org>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: BSD-2-Clause
|
|
||||||
*/
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <AK/Vector.h>
|
|
||||||
#include <LibGfx/Color.h>
|
|
||||||
#include <LibGfx/Rect.h>
|
|
||||||
#include <LibWeb/SVG/AttributeParser.h>
|
|
||||||
|
|
||||||
namespace Web {
|
|
||||||
|
|
||||||
class SVGContext {
|
|
||||||
public:
|
|
||||||
SVGContext(CSSPixelRect svg_element_bounds)
|
|
||||||
: m_svg_element_bounds(svg_element_bounds)
|
|
||||||
{
|
|
||||||
m_states.append(State());
|
|
||||||
}
|
|
||||||
|
|
||||||
SVG::FillRule fill_rule() const { return state().fill_rule; }
|
|
||||||
Gfx::Color fill_color() const { return state().fill_color; }
|
|
||||||
Gfx::Color stroke_color() const { return state().stroke_color; }
|
|
||||||
float stroke_width() const { return state().stroke_width; }
|
|
||||||
float fill_opacity() const { return state().fill_opacity; }
|
|
||||||
float stroke_opacity() const { return state().stroke_opacity; }
|
|
||||||
|
|
||||||
void set_fill_rule(SVG::FillRule fill_rule) { state().fill_rule = fill_rule; }
|
|
||||||
void set_fill_color(Gfx::Color color) { state().fill_color = color; }
|
|
||||||
void set_stroke_color(Gfx::Color color) { state().stroke_color = color; }
|
|
||||||
void set_stroke_width(float width) { state().stroke_width = width; }
|
|
||||||
void set_fill_opacity(float opacity) { state().fill_opacity = opacity; }
|
|
||||||
void set_stroke_opacity(float opacity) { state().stroke_opacity = opacity; }
|
|
||||||
|
|
||||||
CSSPixelPoint svg_element_position() const { return m_svg_element_bounds.top_left(); }
|
|
||||||
CSSPixelSize svg_element_size() const { return m_svg_element_bounds.size(); }
|
|
||||||
|
|
||||||
void save() { m_states.append(m_states.last()); }
|
|
||||||
void restore() { m_states.take_last(); }
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct State {
|
|
||||||
SVG::FillRule fill_rule { SVG::FillRule::Nonzero };
|
|
||||||
Gfx::Color fill_color { Gfx::Color::Transparent };
|
|
||||||
Gfx::Color stroke_color { Gfx::Color::Transparent };
|
|
||||||
float stroke_width { 1.0f };
|
|
||||||
float fill_opacity { 1.0f };
|
|
||||||
float stroke_opacity { 1.0f };
|
|
||||||
};
|
|
||||||
|
|
||||||
State const& state() const { return m_states.last(); }
|
|
||||||
State& state() { return m_states.last(); }
|
|
||||||
|
|
||||||
CSSPixelRect m_svg_element_bounds;
|
|
||||||
Vector<State> m_states;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -108,7 +108,6 @@ Gfx::AffineTransform transform_from_transform_list(ReadonlySpan<Transform> trans
|
||||||
|
|
||||||
Gfx::AffineTransform SVGGraphicsElement::get_transform() const
|
Gfx::AffineTransform SVGGraphicsElement::get_transform() const
|
||||||
{
|
{
|
||||||
// FIXME: It would be nice to do this using the SVGContext, however, then layout/hit testing knows nothing about the transform.
|
|
||||||
Gfx::AffineTransform transform = m_transform;
|
Gfx::AffineTransform transform = m_transform;
|
||||||
for (auto* svg_ancestor = shadow_including_first_ancestor_of_type<SVGGraphicsElement>(); svg_ancestor; svg_ancestor = svg_ancestor->shadow_including_first_ancestor_of_type<SVGGraphicsElement>()) {
|
for (auto* svg_ancestor = shadow_including_first_ancestor_of_type<SVGGraphicsElement>(); svg_ancestor; svg_ancestor = svg_ancestor->shadow_including_first_ancestor_of_type<SVGGraphicsElement>()) {
|
||||||
transform = Gfx::AffineTransform { svg_ancestor->m_transform }.multiply(transform);
|
transform = Gfx::AffineTransform { svg_ancestor->m_transform }.multiply(transform);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue