LibWeb: Add SVGFormattingContext to handle SVG box trees

Instead of trying to layout SVG boxes as if they are regular CSS boxes,
let's invent an "SVG formatting context" and let it manage SVG boxes.

To facilitate this, Layout::SVGBox no longer inherits from ReplacedBox,
and is instead a simple, "inline-block" style BlockBox.
This commit is contained in:
Andreas Kling 2021-09-17 23:12:16 +02:00
parent 4417f26d7c
commit 92c08ad4ac
11 changed files with 65 additions and 26 deletions

View file

@ -193,6 +193,7 @@ set(SOURCES
Layout/RadioButton.cpp
Layout/ReplacedBox.cpp
Layout/SVGBox.cpp
Layout/SVGFormattingContext.cpp
Layout/SVGGraphicsBox.cpp
Layout/SVGPathBox.cpp
Layout/SVGSVGBox.cpp

View file

@ -11,6 +11,8 @@
#include <LibWeb/Layout/FormattingContext.h>
#include <LibWeb/Layout/InlineFormattingContext.h>
#include <LibWeb/Layout/ReplacedBox.h>
#include <LibWeb/Layout/SVGFormattingContext.h>
#include <LibWeb/Layout/SVGSVGBox.h>
#include <LibWeb/Layout/TableBox.h>
#include <LibWeb/Layout/TableCellBox.h>
#include <LibWeb/Layout/TableFormattingContext.h>
@ -67,6 +69,12 @@ bool FormattingContext::creates_block_formatting_context(const Box& box)
void FormattingContext::layout_inside(Box& box, LayoutMode layout_mode)
{
if (is<SVGSVGBox>(box)) {
SVGFormattingContext context(box, this);
context.run(box, layout_mode);
return;
}
if (creates_block_formatting_context(box)) {
BlockFormattingContext context(box, this);
context.run(box, layout_mode);

View file

@ -10,8 +10,9 @@
namespace Web::Layout {
SVGBox::SVGBox(DOM::Document& document, SVG::SVGElement& element, NonnullRefPtr<CSS::StyleProperties> style)
: ReplacedBox(document, element, move(style))
: BlockBox(document, &element, move(style))
{
set_inline(true);
}
void SVGBox::before_children_paint(PaintContext& context, PaintPhase phase)

View file

@ -6,17 +6,19 @@
#pragma once
#include <LibWeb/Layout/ReplacedBox.h>
#include <LibWeb/Layout/BlockBox.h>
#include <LibWeb/SVG/SVGElement.h>
#include <LibWeb/SVG/SVGGraphicsElement.h>
namespace Web::Layout {
class SVGBox : public ReplacedBox {
class SVGBox : public BlockBox {
public:
SVGBox(DOM::Document&, SVG::SVGElement&, NonnullRefPtr<CSS::StyleProperties>);
virtual ~SVGBox() override = default;
SVG::SVGElement& dom_node() { return verify_cast<SVG::SVGElement>(*Box::dom_node()); }
virtual void before_children_paint(PaintContext& context, PaintPhase phase) override;
virtual void after_children_paint(PaintContext& context, PaintPhase phase) override;
};

View file

@ -0,0 +1,26 @@
/*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/Format.h>
#include <LibWeb/Layout/SVGFormattingContext.h>
#include <LibWeb/Layout/SVGSVGBox.h>
namespace Web::Layout {
SVGFormattingContext::SVGFormattingContext(Box& box, FormattingContext* parent)
: FormattingContext(box, parent)
{
}
SVGFormattingContext::~SVGFormattingContext()
{
}
void SVGFormattingContext::run(Box&, LayoutMode)
{
}
}

View file

@ -0,0 +1,22 @@
/*
* Copyright (c) 2021, Andreas Kling <kling@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <LibWeb/Forward.h>
#include <LibWeb/Layout/FormattingContext.h>
namespace Web::Layout {
class SVGFormattingContext : public FormattingContext {
public:
explicit SVGFormattingContext(Box&, FormattingContext* parent);
~SVGFormattingContext();
virtual void run(Box&, LayoutMode) override;
};
}

View file

@ -17,6 +17,8 @@ public:
SVGGraphicsBox(DOM::Document&, SVG::SVGGraphicsElement&, NonnullRefPtr<CSS::StyleProperties>);
virtual ~SVGGraphicsBox() override = default;
SVG::SVGGraphicsElement& dom_node() { return verify_cast<SVG::SVGGraphicsElement>(SVGBox::dom_node()); }
virtual void before_children_paint(PaintContext& context, PaintPhase phase) override;
};

View file

@ -16,18 +16,6 @@ SVGPathBox::SVGPathBox(DOM::Document& document, SVG::SVGPathElement& element, No
{
}
void SVGPathBox::prepare_for_replaced_layout()
{
auto& bounding_box = dom_node().get_path().bounding_box();
set_has_intrinsic_width(true);
set_has_intrinsic_height(true);
set_intrinsic_width(bounding_box.width());
set_intrinsic_height(bounding_box.height());
// FIXME: This does not belong here! Someone at a higher level should place this box.
set_offset(bounding_box.top_left());
}
void SVGPathBox::paint(PaintContext& context, PaintPhase phase)
{
if (!is_visible())

View file

@ -18,7 +18,6 @@ public:
SVG::SVGPathElement& dom_node() { return verify_cast<SVG::SVGPathElement>(SVGGraphicsBox::dom_node()); }
virtual void prepare_for_replaced_layout() override;
virtual void paint(PaintContext& context, PaintPhase phase) override;
};

View file

@ -13,14 +13,6 @@ SVGSVGBox::SVGSVGBox(DOM::Document& document, SVG::SVGSVGElement& element, Nonnu
{
}
void SVGSVGBox::prepare_for_replaced_layout()
{
set_has_intrinsic_width(true);
set_has_intrinsic_height(true);
set_intrinsic_width(dom_node().width());
set_intrinsic_height(dom_node().height());
}
void SVGSVGBox::before_children_paint(PaintContext& context, PaintPhase phase)
{
if (phase != PaintPhase::Foreground)

View file

@ -18,8 +18,6 @@ public:
SVG::SVGSVGElement& dom_node() { return verify_cast<SVG::SVGSVGElement>(SVGGraphicsBox::dom_node()); }
virtual void prepare_for_replaced_layout() override;
virtual void before_children_paint(PaintContext& context, PaintPhase phase) override;
virtual void after_children_paint(PaintContext& context, PaintPhase phase) override;