diff --git a/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html b/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html index c64d6cbf74d..88b5936b271 100644 --- a/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html +++ b/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html @@ -18,11 +18,11 @@ ctx.fillRect(0, 0, 500, 100); // Decimal numbers - ctx.fillStyle = "rgb(0.28813966673057,254.56022744510793,0.2973971574794)"; + ctx.fillStyle = "rgb(254.56022744510793,0.28813966673057,0.2973971574794)"; ctx.fillRect(0, 100, 500, 100); // Numbers below 0 and above 255 should be clamped - ctx.fillStyle = "rgba(-50,500,-50,1)"; + ctx.fillStyle = "rgba(-50,-50,500,1)"; ctx.fillRect(0, 200, 500, 100); // Percentages @@ -30,6 +30,8 @@ ctx.fillRect(0, 300, 500, 100); // Calc - ctx.fillStyle = "rgb(0, calc(infinity), 0)"; + // FIXME: The CSS parser currently chokes on calc expressions, which will + // leave the fillStyle as it was (green). + ctx.fillStyle = "rgb(calc(infinity), 0, 0)"; ctx.fillRect(0, 400, 500, 100); diff --git a/Tests/LibWeb/Screenshot/images/canvas-fillstyle-rgb.png b/Tests/LibWeb/Screenshot/images/canvas-fillstyle-rgb.png index 543e29778cc..2ed1dbb35ca 100644 Binary files a/Tests/LibWeb/Screenshot/images/canvas-fillstyle-rgb.png and b/Tests/LibWeb/Screenshot/images/canvas-fillstyle-rgb.png differ diff --git a/Tests/LibWeb/Text/expected/canvas/fillstyle.txt b/Tests/LibWeb/Text/expected/canvas/fillstyle.txt index 2e68da87ee8..b342d5b0d5b 100644 --- a/Tests/LibWeb/Text/expected/canvas/fillstyle.txt +++ b/Tests/LibWeb/Text/expected/canvas/fillstyle.txt @@ -1,5 +1,5 @@ 1. "#00ff00ff" -2. "#00ff00ff" -3. "#00ff00ff" -4. "#000000ff" -5. "#000000ff" +2. "#ff0000ff" +3. "#0000ffff" +4. "#00ff00ff" +5. "#00ff00ff" diff --git a/Tests/LibWeb/Text/input/canvas/fillstyle.html b/Tests/LibWeb/Text/input/canvas/fillstyle.html index 26124ce4222..87a3e851d45 100644 --- a/Tests/LibWeb/Text/input/canvas/fillstyle.html +++ b/Tests/LibWeb/Text/input/canvas/fillstyle.html @@ -17,25 +17,27 @@ // 2. Decimals testPart(() => { - context.fillStyle = "rgb(0.28813966673057,254.56022744510793,0.2973971574794)"; + context.fillStyle = "rgb(254.56022744510793,0.28813966673057,0.2973971574794)"; return context.fillStyle; }); // 3. Clamp numbers between 0-255 testPart(() => { - context.fillStyle = "rgba(-50,500,-50,1)"; + context.fillStyle = "rgba(-50,-50,500,1)"; return context.fillStyle; }); // 4. Percentages testPart(() => { - context.fillStyle = "rgb(0%,100%,0%)"; + context.fillStyle = "rgb(0%, 100%, 0%)"; return context.fillStyle; }); // 5. Percentages testPart(() => { - context.fillStyle = "rgb(0,calc(infinity),0)"; + // FIXME: The CSS parser currently chokes on calc expressions, which will + // leave the fillStyle as it was (green). + context.fillStyle = "rgb(calc(infinity), 0, 0)"; return context.fillStyle; }); }); diff --git a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h index 44318b78194..2bfc893d116 100644 --- a/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h +++ b/Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h @@ -10,6 +10,7 @@ #pragma once #include +#include #include #include #include @@ -23,27 +24,45 @@ public: ~CanvasFillStrokeStyles() = default; using FillOrStrokeStyleVariant = Variant, JS::Handle>; - static CanvasState::FillOrStrokeStyle to_canvas_state_fill_or_stroke_style(auto const& style) - { - return style.visit( - [&](String const& string) -> CanvasState::FillOrStrokeStyle { - // FIXME: This should parse color strings the same as CSS - auto color = Gfx::Color::from_string(string); - - if (!color.has_value()) - dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasFillStrokeStyles: Unsupported canvas fill or stroke style \"{}\". Defaulting to Color::Black.", string); - - return color.value_or(Color::Black); - }, - [&](auto fill_or_stroke_style) -> CanvasState::FillOrStrokeStyle { - return fill_or_stroke_style; - }); - } - 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 = to_canvas_state_fill_or_stroke_style(style); + auto& realm = static_cast(*this).realm(); + + // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-fillstyle + style.visit( + // 1. If the given value is a string, then: + [&](String const& string) { + // 1. Let context be this's canvas attribute's value, if that is an element; otherwise null. + auto maybe_parser = CSS::Parser::Parser::create(CSS::Parser::ParsingContext(realm), string); + if (maybe_parser.is_error()) { + dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasFillStrokeStyles: Failed to create CSS parser."); + return; + } + auto parser = maybe_parser.release_value(); + + // 2. Let parsedValue be the result of parsing the given value with context if non-null. + // FIXME: Parse a color value + // https://drafts.csswg.org/css-color/#parse-a-css-color-value + auto style_value = parser.parse_as_css_value(CSS::PropertyID::Color); + if (style_value && style_value->has_color()) { + auto parsedValue = style_value->to_color(OptionalNone()); + + // 4. Set this's fill style to parsedValue. + my_drawing_state().fill_style = parsedValue; + } else { + // 3. If parsedValue is failure, then return. + return; + } + + // 5. Return. + return; + }, + [&](auto fill_or_stroke_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. + + // 3. Set this's fill style to the given value. + my_drawing_state().fill_style = fill_or_stroke_style; + }); } FillOrStrokeStyleVariant fill_style() const @@ -53,8 +72,44 @@ public: 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 = to_canvas_state_fill_or_stroke_style(style); + auto& realm = static_cast(*this).realm(); + + // https://html.spec.whatwg.org/multipage/canvas.html#dom-context-2d-strokestyle + + style.visit( + // 1. If the given value is a string, then: + [&](String const& string) { + // 1. Let context be this's canvas attribute's value, if that is an element; otherwise null. + auto maybe_parser = CSS::Parser::Parser::create(CSS::Parser::ParsingContext(realm), string); + if (maybe_parser.is_error()) { + dbgln_if(CANVAS_RENDERING_CONTEXT_2D_DEBUG, "CanvasFillStrokeStyles: Failed to create CSS parser."); + return; + } + auto parser = maybe_parser.release_value(); + + // 2. Let parsedValue be the result of parsing the given value with context if non-null. + // FIXME: Parse a color value + // https://drafts.csswg.org/css-color/#parse-a-css-color-value + auto style_value = parser.parse_as_css_value(CSS::PropertyID::Color); + if (style_value && style_value->has_color()) { + auto parsedValue = style_value->to_color(OptionalNone()); + + // 4. Set this's stroke style to parsedValue. + my_drawing_state().stroke_style = parsedValue; + } else { + // 3. If parsedValue is failure, then return. + return; + } + + // 5. Return. + return; + }, + [&](auto fill_or_stroke_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. + + // 3. Set this's stroke style to the given value. + my_drawing_state().fill_style = fill_or_stroke_style; + }); } FillOrStrokeStyleVariant stroke_style() const