From 9cbb3fac123d0ce12bc1d0127d22ed26417dffd7 Mon Sep 17 00:00:00 2001 From: doctortheemh Date: Mon, 22 Jul 2024 18:59:29 -0700 Subject: [PATCH] LibWeb: Parse fill and stroke values Use the CSS color data type using the CSS parser. --- .../Screenshot/canvas-fillstyle-rgb.html | 8 +- .../images/canvas-fillstyle-rgb.png | Bin 264 -> 566 bytes .../LibWeb/Text/expected/canvas/fillstyle.txt | 8 +- Tests/LibWeb/Text/input/canvas/fillstyle.html | 10 +- .../HTML/Canvas/CanvasFillStrokeStyles.h | 97 ++++++++++++++---- 5 files changed, 91 insertions(+), 32 deletions(-) diff --git a/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html b/Tests/LibWeb/Screenshot/canvas-fillstyle-rgb.html index c64d6cbf74..88b5936b27 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 543e29778cc85c922f81ccb029ee935809b6dc11..2ed1dbb35ca08cdd8d03a6a2a3d1c4bdc97c801b 100644 GIT binary patch literal 566 zcmeAS@N?(olHy`uVBq!ia0y~yVEh8YEX+U=%O8h!0x6*YpAc6DhW|jw!SNpifgBEw zy%qmCflBXtx;TbZ+?n_TUY=9 literal 264 zcmeAS@N?(olHy`uVBq!ia0y~yVEh8YOw2%$Z9B{*ffP@GPlzkSe+G{K96%li2Z!f= zS#=<5yQhm|NX4zUw*xsD40xOm&YE*_=ADohhn>bB7W_TO15^P64relp>R=oot#Bfb y35k1S)$Z9ld|#0UPQPA%^8QuQK=apEd5@TvD6Dzf5LfgT { - 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 44318b7819..2bfc893d11 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