ソースを参照

LibWeb: Parse fill and stroke values

Use the CSS color data type using the CSS parser.
doctortheemh 1 年間 前
コミット
9cbb3fac12

+ 5 - 3
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);
 </script>

BIN
Tests/LibWeb/Screenshot/images/canvas-fillstyle-rgb.png


+ 4 - 4
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"

+ 6 - 4
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;
         });
     });

+ 74 - 19
Userland/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.h

@@ -10,6 +10,7 @@
 #pragma once
 
 #include <AK/String.h>
+#include <LibWeb/CSS/Parser/Parser.h>
 #include <LibWeb/HTML/Canvas/CanvasState.h>
 #include <LibWeb/HTML/CanvasGradient.h>
 #include <LibWeb/HTML/CanvasPattern.h>
@@ -23,27 +24,45 @@ public:
     ~CanvasFillStrokeStyles() = default;
     using FillOrStrokeStyleVariant = Variant<String, JS::Handle<CanvasGradient>, JS::Handle<CanvasPattern>>;
 
-    static CanvasState::FillOrStrokeStyle to_canvas_state_fill_or_stroke_style(auto const& style)
+    void set_fill_style(FillOrStrokeStyleVariant 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);
+        auto& realm = static_cast<IncludingClass&>(*this).realm();
 
-                return color.value_or(Color::Black);
+        // 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) -> CanvasState::FillOrStrokeStyle {
-                return fill_or_stroke_style;
-            });
-    }
+            [&](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.
 
-    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);
+                // 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<IncludingClass&>(*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