Coverage Report

Created: 2026-05-16 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/serenity/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h
Line
Count
Source
1
/*
2
 * Copyright (c) 2020-2022, Andreas Kling <kling@serenityos.org>
3
 * Copyright (c) 2021-2022, Linus Groh <linusg@serenityos.org>
4
 * Copyright (c) 2022, Sam Atkins <atkinssj@serenityos.org>
5
 * Copyright (c) 2023, MacDue <macdue@dueutil.tech>
6
 *
7
 * SPDX-License-Identifier: BSD-2-Clause
8
 */
9
10
#pragma once
11
12
#include <AK/String.h>
13
#include <LibWeb/CSS/Parser/Parser.h>
14
#include <LibWeb/HTML/Canvas/CanvasState.h>
15
#include <LibWeb/HTML/CanvasGradient.h>
16
#include <LibWeb/HTML/CanvasPattern.h>
17
18
namespace Web::HTML {
19
20
// https://html.spec.whatwg.org/multipage/canvas.html#canvasfillstrokestyles
21
template<typename IncludingClass>
22
class CanvasFillStrokeStyles {
23
public:
24
    ~CanvasFillStrokeStyles() = default;
25
    using FillOrStrokeStyleVariant = Variant<String, JS::Handle<CanvasGradient>, JS::Handle<CanvasPattern>>;
26
27
    void set_fill_style(FillOrStrokeStyleVariant style)
28
0
    {
29
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
30
31
        // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fillstyle
32
0
        style.visit(
33
            // 1. If the given value is a string, then:
34
0
            [&](String const& string) {
35
                // 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
36
0
                auto parser = CSS::Parser::Parser::create(CSS::Parser::ParsingContext(realm), string);
37
38
                // 2. Let parsedValue be the result of parsing the given value with context if non-null.
39
                // FIXME: Parse a color value
40
                // https://drafts.csswg.org/css-color/#parse-a-css-color-value
41
0
                auto style_value = parser.parse_as_css_value(CSS::PropertyID::Color);
42
0
                if (style_value && style_value->has_color()) {
43
0
                    auto parsedValue = style_value->to_color(OptionalNone());
44
45
                    // 4. Set this's fill style to parsedValue.
46
0
                    my_drawing_state().fill_style = parsedValue;
47
0
                } else {
48
                    // 3. If parsedValue is failure, then return.
49
0
                    return;
50
0
                }
51
52
                // 5. Return.
53
0
                return;
54
0
            },
55
0
            [&](auto fill_or_stroke_style) {
56
                // 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.
57
58
                // 3. Set this's fill style to the given value.
59
0
                my_drawing_state().fill_style = fill_or_stroke_style;
60
0
            });
Unexecuted instantiation: auto Web::HTML::CanvasFillStrokeStyles<Web::HTML::CanvasRenderingContext2D>::set_fill_style(AK::Variant<AK::String, JS::Handle<Web::HTML::CanvasGradient>, JS::Handle<Web::HTML::CanvasPattern> >)::{lambda(auto:1)#1}::operator()<JS::Handle<Web::HTML::CanvasGradient> >(JS::Handle<Web::HTML::CanvasGradient>) const
Unexecuted instantiation: auto Web::HTML::CanvasFillStrokeStyles<Web::HTML::CanvasRenderingContext2D>::set_fill_style(AK::Variant<AK::String, JS::Handle<Web::HTML::CanvasGradient>, JS::Handle<Web::HTML::CanvasPattern> >)::{lambda(auto:1)#1}::operator()<JS::Handle<Web::HTML::CanvasPattern> >(JS::Handle<Web::HTML::CanvasPattern>) const
61
0
    }
62
63
    FillOrStrokeStyleVariant fill_style() const
64
0
    {
65
0
        return my_drawing_state().fill_style.to_js_fill_or_stroke_style();
66
0
    }
67
68
    void set_stroke_style(FillOrStrokeStyleVariant style)
69
0
    {
70
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
71
72
        // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-strokestyle
73
74
0
        style.visit(
75
            // 1. If the given value is a string, then:
76
0
            [&](String const& string) {
77
                // 1. Let context be this's canvas attribute's value, if that is an element; otherwise null.
78
0
                auto parser = CSS::Parser::Parser::create(CSS::Parser::ParsingContext(realm), string);
79
80
                // 2. Let parsedValue be the result of parsing the given value with context if non-null.
81
                // FIXME: Parse a color value
82
                // https://drafts.csswg.org/css-color/#parse-a-css-color-value
83
0
                auto style_value = parser.parse_as_css_value(CSS::PropertyID::Color);
84
0
                if (style_value && style_value->has_color()) {
85
0
                    auto parsedValue = style_value->to_color(OptionalNone());
86
87
                    // 4. Set this's stroke style to parsedValue.
88
0
                    my_drawing_state().stroke_style = parsedValue;
89
0
                } else {
90
                    // 3. If parsedValue is failure, then return.
91
0
                    return;
92
0
                }
93
94
                // 5. Return.
95
0
                return;
96
0
            },
97
0
            [&](auto fill_or_stroke_style) {
98
                // 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.
99
100
                // 3. Set this's stroke style to the given value.
101
0
                my_drawing_state().fill_style = fill_or_stroke_style;
102
0
            });
Unexecuted instantiation: auto Web::HTML::CanvasFillStrokeStyles<Web::HTML::CanvasRenderingContext2D>::set_stroke_style(AK::Variant<AK::String, JS::Handle<Web::HTML::CanvasGradient>, JS::Handle<Web::HTML::CanvasPattern> >)::{lambda(auto:1)#1}::operator()<JS::Handle<Web::HTML::CanvasGradient> >(JS::Handle<Web::HTML::CanvasGradient>) const
Unexecuted instantiation: auto Web::HTML::CanvasFillStrokeStyles<Web::HTML::CanvasRenderingContext2D>::set_stroke_style(AK::Variant<AK::String, JS::Handle<Web::HTML::CanvasGradient>, JS::Handle<Web::HTML::CanvasPattern> >)::{lambda(auto:1)#1}::operator()<JS::Handle<Web::HTML::CanvasPattern> >(JS::Handle<Web::HTML::CanvasPattern>) const
103
0
    }
104
105
    FillOrStrokeStyleVariant stroke_style() const
106
0
    {
107
0
        return my_drawing_state().stroke_style.to_js_fill_or_stroke_style();
108
0
    }
109
110
    WebIDL::ExceptionOr<JS::NonnullGCPtr<CanvasGradient>> create_radial_gradient(double x0, double y0, double r0, double x1, double y1, double r1)
111
0
    {
112
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
113
0
        return CanvasGradient::create_radial(realm, x0, y0, r0, x1, y1, r1);
114
0
    }
115
116
    JS::NonnullGCPtr<CanvasGradient> create_linear_gradient(double x0, double y0, double x1, double y1)
117
0
    {
118
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
119
0
        return CanvasGradient::create_linear(realm, x0, y0, x1, y1).release_value_but_fixme_should_propagate_errors();
120
0
    }
121
122
    JS::NonnullGCPtr<CanvasGradient> create_conic_gradient(double start_angle, double x, double y)
123
0
    {
124
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
125
0
        return CanvasGradient::create_conic(realm, start_angle, x, y).release_value_but_fixme_should_propagate_errors();
126
0
    }
127
128
    WebIDL::ExceptionOr<JS::GCPtr<CanvasPattern>> create_pattern(CanvasImageSource const& image, StringView repetition)
129
0
    {
130
0
        auto& realm = static_cast<IncludingClass&>(*this).realm();
131
0
        return CanvasPattern::create(realm, image, repetition);
132
0
    }
133
134
protected:
135
    CanvasFillStrokeStyles() = default;
136
137
private:
138
0
    CanvasState::DrawingState& my_drawing_state() { return reinterpret_cast<IncludingClass&>(*this).drawing_state(); }
139
0
    CanvasState::DrawingState const& my_drawing_state() const { return reinterpret_cast<IncludingClass const&>(*this).drawing_state(); }
140
};
141
142
}