Files
ladybird/Libraries/LibWeb/HTML/Canvas/CanvasState.h
Shannon Booth fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.

This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.

Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
2026-04-21 07:36:13 +02:00

150 lines
5.0 KiB
C++

/*
* Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
* Copyright (c) 2023, MacDue <macdue@dueutil.tech>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
#include <AK/Variant.h>
#include <AK/Vector.h>
#include <LibGfx/AffineTransform.h>
#include <LibGfx/Color.h>
#include <LibGfx/CompositingAndBlendingOperator.h>
#include <LibGfx/Filter.h>
#include <LibGfx/FontCascadeList.h>
#include <LibGfx/PaintStyle.h>
#include <LibWeb/Bindings/CanvasRenderingContext2D.h>
#include <LibWeb/CSS/Length.h>
#include <LibWeb/CSS/StyleValues/StyleValue.h>
#include <LibWeb/HTML/CanvasGradient.h>
#include <LibWeb/HTML/CanvasPattern.h>
namespace Web::HTML {
// https://html.spec.whatwg.org/multipage/canvas.html#canvasstate
class CanvasState {
public:
virtual ~CanvasState() = default;
virtual Gfx::Painter* painter_for_canvas_state() = 0;
virtual Gfx::Path& path_for_canvas_state() = 0;
void save();
void restore();
void reset();
bool is_context_lost();
using FillOrStrokeVariant = Variant<Gfx::Color, GC::Ref<CanvasGradient>, GC::Ref<CanvasPattern>>;
struct FillOrStrokeStyle {
FillOrStrokeStyle(Gfx::Color color)
: m_fill_or_stroke_style(color)
{
}
FillOrStrokeStyle(GC::Ref<CanvasGradient> gradient)
: m_fill_or_stroke_style(gradient)
{
}
FillOrStrokeStyle(GC::Ref<CanvasPattern> pattern)
: m_fill_or_stroke_style(pattern)
{
}
NonnullRefPtr<Gfx::PaintStyle> to_gfx_paint_style();
Optional<Gfx::Color> as_color() const;
Gfx::Color to_color_but_fixme_should_accept_any_paint_style() const;
using JsFillOrStrokeStyle = Variant<String, GC::Root<CanvasGradient>, GC::Root<CanvasPattern>>;
JsFillOrStrokeStyle to_js_fill_or_stroke_style() const
{
return m_fill_or_stroke_style.visit(
[&](Gfx::Color color) -> JsFillOrStrokeStyle {
return color.to_string(Gfx::Color::HTMLCompatibleSerialization::Yes);
},
[&](auto handle) -> JsFillOrStrokeStyle {
return GC::make_root(handle);
});
}
void visit_edges(GC::Cell::Visitor& visitor)
{
m_fill_or_stroke_style.visit([&](Gfx::Color) {},
[&](auto& handle) {
visitor.visit(handle);
});
}
private:
FillOrStrokeVariant m_fill_or_stroke_style;
RefPtr<Gfx::PaintStyle> m_color_paint_style { nullptr };
};
// https://html.spec.whatwg.org/multipage/canvas.html#drawing-state
struct DrawingState {
Gfx::AffineTransform transform;
FillOrStrokeStyle fill_style { Gfx::Color::Black };
FillOrStrokeStyle stroke_style { Gfx::Color::Black };
float shadow_offset_x { 0.0f };
float shadow_offset_y { 0.0f };
float shadow_blur { 0.0f };
Gfx::Color shadow_color { Gfx::Color::Transparent };
Optional<Gfx::Filter> filter;
Optional<String> filter_string;
float line_width { 1 };
Bindings::CanvasLineCap line_cap { Bindings::CanvasLineCap::Butt };
Bindings::CanvasLineJoin line_join { Bindings::CanvasLineJoin::Miter };
float miter_limit { 10 };
Vector<double> dash_list;
float line_dash_offset { 0 };
bool image_smoothing_enabled { true };
Bindings::ImageSmoothingQuality image_smoothing_quality { Bindings::ImageSmoothingQuality::Low };
float global_alpha = { 1 };
Gfx::CompositingAndBlendingOperator current_compositing_and_blending_operator = Gfx::CompositingAndBlendingOperator::SourceOver;
RefPtr<CSS::StyleValue const> font_style_value { nullptr };
RefPtr<Gfx::FontCascadeList const> current_font_cascade_list { nullptr };
Bindings::CanvasTextAlign text_align { Bindings::CanvasTextAlign::Start };
Bindings::CanvasTextBaseline text_baseline { Bindings::CanvasTextBaseline::Alphabetic };
Bindings::CanvasDirection direction { Bindings::CanvasDirection::Inherit };
CSS::Length letter_spacing { CSS::Length::make_px(0) };
void visit_edges(GC::Cell::Visitor& visitor)
{
fill_style.visit_edges(visitor);
stroke_style.visit_edges(visitor);
}
};
DrawingState& drawing_state() { return m_drawing_state; }
DrawingState const& drawing_state() const { return m_drawing_state; }
void clear_drawing_state_stack() { m_drawing_state_stack.clear(); }
void reset_drawing_state() { m_drawing_state = {}; }
virtual void reset_to_default_state() = 0;
void visit_edges(GC::Cell::Visitor& visitor)
{
m_drawing_state.visit_edges(visitor);
for (auto& state : m_drawing_state_stack) {
state.visit_edges(visitor);
}
}
protected:
CanvasState() = default;
private:
DrawingState m_drawing_state;
Vector<DrawingState> m_drawing_state_stack;
// https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-context-lost
bool m_context_lost { false };
};
}