From 9da723b5c6603e2220dacd4c77d11c1665de608b Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Mon, 27 Oct 2025 10:06:59 +0000 Subject: [PATCH] LibWeb: Ensure layout is up to date before resolving canvas colors --- Libraries/LibWeb/DOM/Document.h | 104 +++++++++--------- .../HTML/Canvas/CanvasFillStrokeStyles.cpp | 12 +- .../LibWeb/HTML/CanvasRenderingContext2D.cpp | 4 +- .../2d.fillStyle.parse.current.basic.txt | 6 + .../2d.fillStyle.parse.current.changed.txt | 6 + ...w.attributes.shadowColor.current.basic.txt | 6 + ...attributes.shadowColor.current.changed.txt | 6 + .../2d.fillStyle.parse.current.basic.html | 31 ++++++ .../2d.fillStyle.parse.current.changed.html | 32 ++++++ ....attributes.shadowColor.current.basic.html | 29 +++++ ...ttributes.shadowColor.current.changed.html | 30 +++++ 11 files changed, 210 insertions(+), 56 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.txt create mode 100644 Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.txt create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.html create mode 100644 Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.html diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 154b1976d0..4c29ed82ed 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -71,56 +71,60 @@ enum class InvalidateLayoutTreeReason { [[nodiscard]] StringView to_string(InvalidateLayoutTreeReason); -#define ENUMERATE_UPDATE_LAYOUT_REASONS(X) \ - X(CanvasRenderingContext2DSetFilter) \ - X(CursorBlinkTimer) \ - X(Debugging) \ - X(DocumentElementFromPoint) \ - X(DocumentElementsFromPoint) \ - X(DocumentFindMatchingText) \ - X(DocumentSetDesignMode) \ - X(DumpDisplayList) \ - X(ElementCheckVisibility) \ - X(ElementClientHeight) \ - X(ElementClientLeft) \ - X(ElementClientTop) \ - X(ElementClientWidth) \ - X(ElementGetClientRects) \ - X(ElementIsPotentiallyScrollable) \ - X(ElementScroll) \ - X(ElementScrollHeight) \ - X(ElementScrollIntoView) \ - X(ElementScrollLeft) \ - X(ElementScrollTop) \ - X(ElementScrollWidth) \ - X(ElementSetScrollLeft) \ - X(ElementSetScrollTop) \ - X(EventHandlerHandleDoubleClick) \ - X(EventHandlerHandleDragAndDrop) \ - X(EventHandlerHandleMouseDown) \ - X(EventHandlerHandleMouseMove) \ - X(EventHandlerHandleMouseUp) \ - X(EventHandlerHandleMouseWheel) \ - X(HTMLElementGetTheTextSteps) \ - X(HTMLElementOffsetHeight) \ - X(HTMLElementOffsetLeft) \ - X(HTMLElementOffsetParent) \ - X(HTMLElementOffsetTop) \ - X(HTMLElementOffsetWidth) \ - X(HTMLElementScrollParent) \ - X(HTMLEventLoopRenderingUpdate) \ - X(HTMLImageElementHeight) \ - X(HTMLImageElementWidth) \ - X(HTMLInputElementHeight) \ - X(HTMLInputElementWidth) \ - X(InternalsHitTest) \ - X(MediaQueryListMatches) \ - X(NodeNameOrDescription) \ - X(RangeGetClientRects) \ - X(ResolvedCSSStyleDeclarationProperty) \ - X(SVGDecodedImageDataRender) \ - X(SVGGraphicsElementGetBBox) \ - X(SourceSetNormalizeSourceDensities) \ +#define ENUMERATE_UPDATE_LAYOUT_REASONS(X) \ + X(CanvasRenderingContext2DSetFilter) \ + X(CanvasRenderingContext2DSetFillStyle) \ + X(CanvasRenderingContext2DSetShadowColor) \ + X(CanvasRenderingContext2DSetStrokeStyle) \ + X(CanvasSetFillStyle) \ + X(CursorBlinkTimer) \ + X(Debugging) \ + X(DocumentElementFromPoint) \ + X(DocumentElementsFromPoint) \ + X(DocumentFindMatchingText) \ + X(DocumentSetDesignMode) \ + X(DumpDisplayList) \ + X(ElementCheckVisibility) \ + X(ElementClientHeight) \ + X(ElementClientLeft) \ + X(ElementClientTop) \ + X(ElementClientWidth) \ + X(ElementGetClientRects) \ + X(ElementIsPotentiallyScrollable) \ + X(ElementScroll) \ + X(ElementScrollHeight) \ + X(ElementScrollIntoView) \ + X(ElementScrollLeft) \ + X(ElementScrollTop) \ + X(ElementScrollWidth) \ + X(ElementSetScrollLeft) \ + X(ElementSetScrollTop) \ + X(EventHandlerHandleDoubleClick) \ + X(EventHandlerHandleDragAndDrop) \ + X(EventHandlerHandleMouseDown) \ + X(EventHandlerHandleMouseMove) \ + X(EventHandlerHandleMouseUp) \ + X(EventHandlerHandleMouseWheel) \ + X(HTMLElementGetTheTextSteps) \ + X(HTMLElementOffsetHeight) \ + X(HTMLElementOffsetLeft) \ + X(HTMLElementOffsetParent) \ + X(HTMLElementOffsetTop) \ + X(HTMLElementOffsetWidth) \ + X(HTMLElementScrollParent) \ + X(HTMLEventLoopRenderingUpdate) \ + X(HTMLImageElementHeight) \ + X(HTMLImageElementWidth) \ + X(HTMLInputElementHeight) \ + X(HTMLInputElementWidth) \ + X(InternalsHitTest) \ + X(MediaQueryListMatches) \ + X(NodeNameOrDescription) \ + X(RangeGetClientRects) \ + X(ResolvedCSSStyleDeclarationProperty) \ + X(SVGDecodedImageDataRender) \ + X(SVGGraphicsElementGetBBox) \ + X(SourceSetNormalizeSourceDensities) \ X(WindowScroll) enum class UpdateLayoutReason { diff --git a/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp b/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp index fdabc47e8b..6f6bc9601d 100644 --- a/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp +++ b/Libraries/LibWeb/HTML/Canvas/CanvasFillStrokeStyles.cpp @@ -43,8 +43,10 @@ void CanvasFillStrokeStyles::set_fill_style(FillOrStrokeStyleVar if (style_value && style_value->has_color()) { CSS::ColorResolutionContext color_resolution_context {}; - if (context && context->layout_node()) { - color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node()); + if (context) { + context->document().update_layout(DOM::UpdateLayoutReason::CanvasRenderingContext2DSetFillStyle); + if (context->layout_node()) + color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node()); } auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black); @@ -97,8 +99,10 @@ void CanvasFillStrokeStyles::set_stroke_style(FillOrStrokeStyleV if (style_value && style_value->has_color()) { CSS::ColorResolutionContext color_resolution_context {}; - if (context && context->layout_node()) { - color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node()); + if (context) { + context->document().update_layout(DOM::UpdateLayoutReason::CanvasRenderingContext2DSetStrokeStyle); + if (context->layout_node()) + color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context->layout_node()); } auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black); diff --git a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp index f9c401b5e5..5c3929bbea 100644 --- a/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp +++ b/Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp @@ -1053,9 +1053,9 @@ void CanvasRenderingContext2D::set_shadow_color(String color) auto style_value = parse_css_value(CSS::Parser::ParsingParams(), color, CSS::PropertyID::Color); if (style_value && style_value->has_color()) { CSS::ColorResolutionContext color_resolution_context {}; - + context.document().update_layout(DOM::UpdateLayoutReason::CanvasRenderingContext2DSetShadowColor); if (auto node = context.layout_node()) { - color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*context.layout_node()); + color_resolution_context = CSS::ColorResolutionContext::for_layout_node_with_style(*node); } auto parsedValue = style_value->to_color(color_resolution_context).value_or(Color::Black); diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.txt b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.txt new file mode 100644 index 0000000000..6d31480642 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass currentColor is computed from the canvas element \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.txt b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.txt new file mode 100644 index 0000000000..cfe1d0ed17 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass currentColor is computed when the attribute is set, not when it is painted \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.txt b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.txt new file mode 100644 index 0000000000..6d31480642 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass currentColor is computed from the canvas element \ No newline at end of file diff --git a/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.txt b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.txt new file mode 100644 index 0000000000..cfe1d0ed17 --- /dev/null +++ b/Tests/LibWeb/Text/expected/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.txt @@ -0,0 +1,6 @@ +Harness status: OK + +Found 1 tests + +1 Pass +Pass currentColor is computed when the attribute is set, not when it is painted \ No newline at end of file diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.html b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.html new file mode 100644 index 0000000000..a8178d3469 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.basic.html @@ -0,0 +1,31 @@ + + + +Canvas test: 2d.fillStyle.parse.current.basic + + + + + + +

2d.fillStyle.parse.current.basic

+

currentColor is computed from the canvas element

+ + +

Actual output:

+

FAIL (fallback content)

+

Expected output:

+

    + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.html b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.html new file mode 100644 index 0000000000..bb6ccdb68d --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/fill-and-stroke-styles/2d.fillStyle.parse.current.changed.html @@ -0,0 +1,32 @@ + + + +Canvas test: 2d.fillStyle.parse.current.changed + + + + + + +

    2d.fillStyle.parse.current.changed

    +

    currentColor is computed when the attribute is set, not when it is painted

    + + +

    Actual output:

    +

    FAIL (fallback content)

    +

    Expected output:

    +

      + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.html b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.html new file mode 100644 index 0000000000..1e2e52f53d --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.basic.html @@ -0,0 +1,29 @@ + + + +Canvas test: 2d.shadow.attributes.shadowColor.current.basic + + + + + + +

      2d.shadow.attributes.shadowColor.current.basic

      +

      currentColor is computed from the canvas element

      + + +

      Actual output:

      +

      FAIL (fallback content)

      + +
        + + diff --git a/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.html b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.html new file mode 100644 index 0000000000..a90abd4997 --- /dev/null +++ b/Tests/LibWeb/Text/input/wpt-import/html/canvas/element/shadows/2d.shadow.attributes.shadowColor.current.changed.html @@ -0,0 +1,30 @@ + + + +Canvas test: 2d.shadow.attributes.shadowColor.current.changed + + + + + + +

        2d.shadow.attributes.shadowColor.current.changed

        +

        currentColor is computed when the attribute is set, not when it is painted

        + + +

        Actual output:

        +

        FAIL (fallback content)

        + +
          + +