diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h
index e5fa17a78e..3ed170f201 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h
@@ -2,6 +2,7 @@
* Copyright (c) 2020-2022, Andreas Kling
* Copyright (c) 2021-2022, Linus Groh
* Copyright (c) 2022, Sam Atkins
+ * Copyright (c) 2023, MacDue
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -19,27 +20,39 @@ template
class CanvasFillStrokeStyles {
public:
~CanvasFillStrokeStyles() = default;
+ using FillOrStrokeStyleVariant = Variant>;
- void set_fill_style(DeprecatedString style)
+ static CanvasState::FillOrStrokeStyle to_canvas_state_fill_or_stoke_style(auto const& style)
+ {
+ return style.visit(
+ [&](DeprecatedString const& string) -> CanvasState::FillOrStrokeStyle {
+ return Gfx::Color::from_string(string).value_or(Color::Black);
+ },
+ [&](JS::Handle gradient) -> CanvasState::FillOrStrokeStyle {
+ return gradient;
+ });
+ }
+
+ void set_fill_style(FillOrStrokeStyleVariant style)
{
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
- my_drawing_state().fill_style = Gfx::Color::from_string(style).value_or(Color::Black);
+ my_drawing_state().fill_style = to_canvas_state_fill_or_stoke_style(style);
}
- DeprecatedString fill_style() const
+ FillOrStrokeStyleVariant fill_style() const
{
- return my_drawing_state().fill_style.to_deprecated_string();
+ return my_drawing_state().fill_style.to_js_fill_or_stoke_style();
}
- void set_stroke_style(DeprecatedString style)
+ void set_stroke_style(FillOrStrokeStyleVariant style)
{
// FIXME: 2. If the given value is a CanvasPattern object that is marked as not origin-clean, then set this's origin-clean flag to false.
- my_drawing_state().stroke_style = Gfx::Color::from_string(style).value_or(Color::Black);
+ my_drawing_state().stroke_style = to_canvas_state_fill_or_stoke_style(style);
}
- DeprecatedString stroke_style() const
+ FillOrStrokeStyleVariant stroke_style() const
{
- return my_drawing_state().stroke_style.to_deprecated_string();
+ return my_drawing_state().stroke_style.to_js_fill_or_stoke_style();
}
JS::NonnullGCPtr create_radial_gradient(double x0, double y0, double r0, double x1, double y1, double r1)
diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.idl b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.idl
index 45b393c7cf..ee8e8c1134 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.idl
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.idl
@@ -3,9 +3,9 @@
// https://html.spec.whatwg.org/multipage/canvas.html#canvasfillstrokestyles
interface mixin CanvasFillStrokeStyles {
// FIXME: Should be `(DOMString or CanvasGradient or CanvasPattern)`
- attribute DOMString strokeStyle;
+ attribute (DOMString or CanvasGradient) strokeStyle;
// FIXME: Should be `(DOMString or CanvasGradient or CanvasPattern)`
- attribute DOMString fillStyle;
+ attribute (DOMString or CanvasGradient) fillStyle;
CanvasGradient createLinearGradient(double x0, double y0, double x1, double y1);
CanvasGradient createRadialGradient(double x0, double y0, double r0, double x1, double y1, double r1);
CanvasGradient createConicGradient(double startAngle, double x, double y);
diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.cpp b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.cpp
index c907fe52a2..880a28b31e 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.cpp
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2021-2022, Linus Groh
* Copyright (c) 2022, Sam Atkins
+ * Copyright (c) 2023, MacDue
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -39,4 +40,21 @@ bool CanvasState::is_context_lost()
return m_context_lost;
}
+NonnullRefPtr CanvasState::FillOrStrokeStyle::to_gfx_paint_style()
+{
+ VERIFY_NOT_REACHED();
+}
+
+Gfx::Color CanvasState::FillOrStrokeStyle::to_color_but_fixme_should_accept_any_paint_style() const
+{
+ return as_color().value_or(Gfx::Color::Black);
+}
+
+Optional CanvasState::FillOrStrokeStyle::as_color() const
+{
+ if (auto* color = m_fill_or_stoke_style.get_pointer())
+ return *color;
+ return {};
+}
+
}
diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
index 9e230c8ba7..eef073bf77 100644
--- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
+++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasState.h
@@ -1,14 +1,18 @@
/*
* Copyright (c) 2022, Sam Atkins
+ * Copyright (c) 2023, MacDue
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#pragma once
+#include
#include
#include
#include
+#include
+#include
namespace Web::HTML {
@@ -22,11 +26,41 @@ public:
void reset();
bool is_context_lost();
+ using FillOrStrokeVariant = Variant>;
+
+ struct FillOrStrokeStyle {
+ FillOrStrokeStyle(Gfx::Color color)
+ : m_fill_or_stoke_style(color)
+ {
+ }
+
+ FillOrStrokeStyle(JS::Handle gradient)
+ : m_fill_or_stoke_style(gradient)
+ {
+ }
+
+ NonnullRefPtr to_gfx_paint_style();
+
+ Optional as_color() const;
+ Gfx::Color to_color_but_fixme_should_accept_any_paint_style() const;
+
+ Variant> to_js_fill_or_stoke_style() const
+ {
+ if (auto* handle = m_fill_or_stoke_style.get_pointer>())
+ return *handle;
+ return m_fill_or_stoke_style.get().to_deprecated_string();
+ }
+
+ private:
+ FillOrStrokeVariant m_fill_or_stoke_style;
+ RefPtr m_color_fill_style { nullptr };
+ };
+
// https://html.spec.whatwg.org/multipage/canvas.html#drawing-state
struct DrawingState {
Gfx::AffineTransform transform;
- Gfx::Color fill_style { Gfx::Color::Black };
- Gfx::Color stroke_style { Gfx::Color::Black };
+ FillOrStrokeStyle fill_style { Gfx::Color::Black };
+ FillOrStrokeStyle stroke_style { Gfx::Color::Black };
float line_width { 1 };
};
DrawingState& drawing_state() { return m_drawing_state; }
diff --git a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
index 2b7a30705f..1b41e9d448 100644
--- a/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
+++ b/Userland/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp
@@ -1,6 +1,7 @@
/*
* Copyright (c) 2020-2022, Andreas Kling
* Copyright (c) 2021-2022, Linus Groh
+ * Copyright (c) 2023, MacDue
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@@ -73,7 +74,13 @@ void CanvasRenderingContext2D::fill_rect(float x, float y, float width, float he
auto& drawing_state = this->drawing_state();
auto rect = drawing_state.transform.map(Gfx::FloatRect(x, y, width, height));
- painter->fill_rect(rect, drawing_state.fill_style);
+ auto color_fill = drawing_state.fill_style.as_color();
+ if (color_fill.has_value()) {
+ painter->fill_rect(rect, *color_fill);
+ } else {
+ // FIXME: This should use AntiAliasingPainter::fill_rect() too but that does not support FillPath yet.
+ painter->underlying_painter().fill_rect(rect.to_rounded(), *drawing_state.fill_style.to_gfx_paint_style());
+ }
did_draw(rect);
}
@@ -109,7 +116,7 @@ void CanvasRenderingContext2D::stroke_rect(float x, float y, float width, float
path.line_to(bottom_right);
path.line_to(bottom_left);
path.line_to(top_left);
- painter->stroke_path(path, drawing_state.stroke_style, drawing_state.line_width);
+ painter->stroke_path(path, drawing_state.stroke_style.to_color_but_fixme_should_accept_any_paint_style(), drawing_state.line_width);
did_draw(rect);
}
@@ -211,7 +218,7 @@ void CanvasRenderingContext2D::fill_text(DeprecatedString const& text, float x,
auto text_rect = Gfx::FloatRect(x, y, max_width.has_value() ? static_cast(max_width.value()) : painter->font().width(text), painter->font().pixel_size());
auto transformed_rect = drawing_state.transform.map(text_rect);
- painter->draw_text(transformed_rect, text, Gfx::TextAlignment::TopLeft, drawing_state.fill_style);
+ painter->draw_text(transformed_rect, text, Gfx::TextAlignment::TopLeft, drawing_state.fill_style.to_color_but_fixme_should_accept_any_paint_style());
did_draw(transformed_rect);
}
@@ -234,7 +241,7 @@ void CanvasRenderingContext2D::stroke_internal(Gfx::Path const& path)
auto& drawing_state = this->drawing_state();
- painter->stroke_path(path, drawing_state.stroke_style, drawing_state.line_width);
+ painter->stroke_path(path, drawing_state.stroke_style.to_color_but_fixme_should_accept_any_paint_style(), drawing_state.line_width);
did_draw(path.bounding_box());
}
@@ -266,7 +273,7 @@ void CanvasRenderingContext2D::fill_internal(Gfx::Path& path, DeprecatedString c
else
dbgln("Unrecognized fillRule for CRC2D.fill() - this problem goes away once we pass an enum instead of a string");
- painter->fill_path(path, drawing_state().fill_style, winding);
+ painter->fill_path(path, *drawing_state().fill_style.to_gfx_paint_style(), winding);
did_draw(path.bounding_box());
}