diff --git a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp index 2579e46bf3f..e6feb9e990c 100644 --- a/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp +++ b/Userland/Libraries/LibWeb/CSS/StyleValues/ImageStyleValue.cpp @@ -43,9 +43,13 @@ void ImageStyleValue::load_any_resources(DOM::Document& document) if (!m_document) return; - // FIXME: Do less than a full repaint if possible? - if (auto navigable = m_document->navigable()) + if (auto navigable = m_document->navigable()) { + // Once the image has loaded, we need to re-resolve CSS properties that depend on the image's dimensions. + m_document->set_needs_to_resolve_paint_only_properties(); + + // FIXME: Do less than a full repaint if possible? navigable->set_needs_display(); + } auto image_data = m_resource_request->image_data(); if (image_data->is_animated() && image_data->frame_count() > 1) { diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp index 2caa8b272b0..9bf3419ec42 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.cpp @@ -6,8 +6,6 @@ * SPDX-License-Identifier: BSD-2-Clause */ -#include -#include #include #include #include @@ -95,81 +93,52 @@ static RefPtr compute_text_clip_paths(PaintContext& context, Painta return text_clip_paths; } +static BackgroundBox get_box(CSS::BackgroundBox box_clip, BackgroundBox border_box, auto const& layout_node) +{ + auto box = border_box; + switch (box_clip) { + case CSS::BackgroundBox::ContentBox: { + auto& padding = layout_node.box_model().padding; + box.shrink(padding.top, padding.right, padding.bottom, padding.left); + [[fallthrough]]; + } + case CSS::BackgroundBox::PaddingBox: { + auto& border = layout_node.box_model().border; + box.shrink(border.top, border.right, border.bottom, border.left); + [[fallthrough]]; + } + case CSS::BackgroundBox::BorderBox: + default: + return box; + } +} + // https://www.w3.org/TR/css-backgrounds-3/#backgrounds -void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, CSSPixelRect const& border_rect, Color background_color, CSS::ImageRendering image_rendering, Vector const* background_layers, BorderRadiiData const& border_radii) +void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, CSS::ImageRendering image_rendering, ResolvedBackground resolved_background, BorderRadiiData const& border_radii) { RefPtr text_clip; - if (background_layers && !background_layers->is_empty() && background_layers->last().clip == CSS::BackgroundBox::Text) { + if (resolved_background.needs_text_clip) { text_clip = compute_text_clip_paths(context, *layout_node.paintable()); } auto& display_list_recorder = context.display_list_recorder(); - struct BackgroundBox { - CSSPixelRect rect; - BorderRadiiData radii; - - inline void shrink(CSSPixels top, CSSPixels right, CSSPixels bottom, CSSPixels left) - { - rect.shrink(top, right, bottom, left); - radii.shrink(top, right, bottom, left); - } - }; - BackgroundBox border_box { - border_rect, + resolved_background.background_rect, border_radii }; - auto get_box = [&](CSS::BackgroundBox box_clip) { - auto box = border_box; - switch (box_clip) { - case CSS::BackgroundBox::ContentBox: { - auto& padding = layout_node.box_model().padding; - box.shrink(padding.top, padding.right, padding.bottom, padding.left); - [[fallthrough]]; - } - case CSS::BackgroundBox::PaddingBox: { - auto& border = layout_node.box_model().border; - box.shrink(border.top, border.right, border.bottom, border.left); - [[fallthrough]]; - } - case CSS::BackgroundBox::BorderBox: - default: - return box; - } - }; - - auto color_box = border_box; - if (background_layers && !background_layers->is_empty()) - color_box = get_box(background_layers->last().clip); - - auto layer_is_paintable = [&](auto& layer) { - return layer.background_image && layer.background_image->is_paintable(); - }; - - bool has_paintable_layers = false; - if (background_layers) { - for (auto& layer : *background_layers) { - if (layer_is_paintable(layer)) { - has_paintable_layers = true; - break; - } - } - } + auto const& color_box = resolved_background.color_box; display_list_recorder.fill_rect_with_rounded_corners( context.rounded_device_rect(color_box.rect).to_type(), - background_color, + resolved_background.color, color_box.radii.top_left.as_corner(context), color_box.radii.top_right.as_corner(context), color_box.radii.bottom_right.as_corner(context), color_box.radii.bottom_left.as_corner(context), text_clip); - if (!has_paintable_layers) - return; - struct { DevicePixels top { 0 }; DevicePixels bottom { 0 }; @@ -191,13 +160,11 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet } // Note: Background layers are ordered front-to-back, so we paint them in reverse - for (auto& layer : background_layers->in_reverse()) { - if (!layer_is_paintable(layer)) - continue; + for (auto& layer : resolved_background.layers.in_reverse()) { DisplayListRecorderStateSaver state { display_list_recorder }; // Clip - auto clip_box = get_box(layer.clip); + auto clip_box = get_box(layer.clip, border_box, layout_node); CSSPixelRect const& css_clip_rect = clip_box.rect; auto clip_rect = context.rounded_device_rect(css_clip_rect); @@ -210,18 +177,17 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet clip_rect.shrink(clip_shrink.top, clip_shrink.right, clip_shrink.bottom, clip_shrink.left); } - auto& image = *layer.background_image; - CSSPixelRect background_positioning_area; + auto const& image = *layer.background_image; + auto image_rect = layer.image_rect; + auto background_positioning_area = layer.background_positioning_area; - // Attachment and Origin switch (layer.attachment) { case CSS::BackgroundAttachment::Fixed: - background_positioning_area = layout_node.root().navigable()->viewport_rect(); + background_positioning_area.set_location(layout_node.root().navigable()->viewport_scroll_offset()); break; case CSS::BackgroundAttachment::Local: - background_positioning_area = get_box(layer.origin).rect; if (is(layout_node)) { - auto* paintable_box = static_cast(layout_node).paintable_box(); + auto const* paintable_box = static_cast(layout_node).paintable_box(); if (paintable_box && !paintable_box->is_viewport()) { auto scroll_offset = paintable_box->scroll_offset(); background_positioning_area.translate_by(-scroll_offset.x(), -scroll_offset.y()); @@ -229,97 +195,22 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet } break; case CSS::BackgroundAttachment::Scroll: - background_positioning_area = get_box(layer.origin).rect; break; } - Optional specified_width {}; - Optional specified_height {}; - if (layer.size_type == CSS::BackgroundSize::LengthPercentage) { - if (!layer.size_x.is_auto()) - specified_width = layer.size_x.to_px(layout_node, background_positioning_area.width()); - if (!layer.size_y.is_auto()) - specified_height = layer.size_y.to_px(layout_node, background_positioning_area.height()); - } - auto concrete_image_size = run_default_sizing_algorithm( - specified_width, specified_height, - image.natural_width(), image.natural_height(), image.natural_aspect_ratio(), - background_positioning_area.size()); - - // If any of these are zero, the NaNs will pop up in the painting code. - if (background_positioning_area.is_empty() || concrete_image_size.is_empty()) + if (background_positioning_area.is_empty()) continue; - // Size - CSSPixelRect image_rect; - switch (layer.size_type) { - case CSS::BackgroundSize::Contain: { - double max_width_ratio = background_positioning_area.width().to_double() / concrete_image_size.width().to_double(); - double max_height_ratio = background_positioning_area.height().to_double() / concrete_image_size.height().to_double(); - double ratio = min(max_width_ratio, max_height_ratio); - image_rect.set_size(concrete_image_size.width().scaled(ratio), concrete_image_size.height().scaled(ratio)); - break; - } - case CSS::BackgroundSize::Cover: { - double max_width_ratio = background_positioning_area.width().to_double() / concrete_image_size.width().to_double(); - double max_height_ratio = background_positioning_area.height().to_double() / concrete_image_size.height().to_double(); - double ratio = max(max_width_ratio, max_height_ratio); - image_rect.set_size(concrete_image_size.width().scaled(ratio), concrete_image_size.height().scaled(ratio)); - break; - } - case CSS::BackgroundSize::LengthPercentage: - image_rect.set_size(concrete_image_size); - break; - } - - // If after sizing we have a 0px image, we're done. Attempting to paint this would be an infinite loop. - if (image_rect.is_empty()) - continue; - - // If background-repeat is round for one (or both) dimensions, there is a second step. - // The UA must scale the image in that dimension (or both dimensions) so that it fits a - // whole number of times in the background positioning area. - if (layer.repeat_x == CSS::Repeat::Round || layer.repeat_y == CSS::Repeat::Round) { - // If X ≠ 0 is the width of the image after step one and W is the width of the - // background positioning area, then the rounded width X' = W / round(W / X) - // where round() is a function that returns the nearest natural number - // (integer greater than zero). - if (layer.repeat_x == CSS::Repeat::Round) { - image_rect.set_width(background_positioning_area.width() / round(background_positioning_area.width() / image_rect.width())); - } - if (layer.repeat_y == CSS::Repeat::Round) { - image_rect.set_height(background_positioning_area.height() / round(background_positioning_area.height() / image_rect.height())); - } - - // If background-repeat is round for one dimension only and if background-size is auto - // for the other dimension, then there is a third step: that other dimension is scaled - // so that the original aspect ratio is restored. - if (layer.repeat_x != layer.repeat_y) { - if (layer.size_x.is_auto()) { - image_rect.set_width(image_rect.height() * (concrete_image_size.width() / concrete_image_size.height())); - } - if (layer.size_y.is_auto()) { - image_rect.set_height(image_rect.width() * (concrete_image_size.height() / concrete_image_size.width())); - } - } - } - - CSSPixels space_x = background_positioning_area.width() - image_rect.width(); - CSSPixels space_y = background_positioning_area.height() - image_rect.height(); - - // Position - CSSPixels offset_x = layer.position_offset_x.to_px(layout_node, space_x); if (layer.position_edge_x == CSS::PositionEdge::Right) { - image_rect.set_right_without_resize(background_positioning_area.right() - offset_x); + image_rect.set_right_without_resize(background_positioning_area.right() - layer.offset_x); } else { - image_rect.set_left(background_positioning_area.left() + offset_x); + image_rect.set_left(background_positioning_area.left() + layer.offset_x); } - CSSPixels offset_y = layer.position_offset_y.to_px(layout_node, space_y); if (layer.position_edge_y == CSS::PositionEdge::Bottom) { - image_rect.set_bottom_without_resize(background_positioning_area.bottom() - offset_y); + image_rect.set_bottom_without_resize(background_positioning_area.bottom() - layer.offset_y); } else { - image_rect.set_top(background_positioning_area.top() + offset_y); + image_rect.set_top(background_positioning_area.top() + layer.offset_y); } // Repetition @@ -396,7 +287,6 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet CSSPixels initial_image_x = image_rect.x(); CSSPixels image_y = image_rect.y(); - Optional last_image_device_rect; image.resolve_for_size(layout_node, image_rect.size()); @@ -449,4 +339,128 @@ void paint_background(PaintContext& context, Layout::NodeWithStyleAndBoxModelMet } } +ResolvedBackground resolve_background_layers(Vector const& layers, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, Color background_color, CSSPixelRect const& border_rect, BorderRadiiData const& border_radii) +{ + auto layer_is_paintable = [&](auto& layer) { + return layer.background_image && layer.background_image->is_paintable(); + }; + + BackgroundBox border_box { + border_rect, + border_radii + }; + + auto color_box = border_box; + if (!layers.is_empty()) + color_box = get_box(layers.last().clip, border_box, layout_node); + + Vector resolved_layers; + for (auto const& layer : layers) { + if (!layer_is_paintable(layer)) + continue; + + auto background_positioning_area = get_box(layer.origin, border_box, layout_node).rect; + auto const& image = *layer.background_image; + + Optional specified_width {}; + Optional specified_height {}; + if (layer.size_type == CSS::BackgroundSize::LengthPercentage) { + if (!layer.size_x.is_auto()) + specified_width = layer.size_x.to_px(layout_node, background_positioning_area.width()); + if (!layer.size_y.is_auto()) + specified_height = layer.size_y.to_px(layout_node, background_positioning_area.height()); + } + auto concrete_image_size = run_default_sizing_algorithm( + specified_width, specified_height, + image.natural_width(), image.natural_height(), image.natural_aspect_ratio(), + background_positioning_area.size()); + + // If any of these are zero, the NaNs will pop up in the painting code. + if (background_positioning_area.is_empty() || concrete_image_size.is_empty()) { + continue; + } + + // Size + CSSPixelRect image_rect; + switch (layer.size_type) { + case CSS::BackgroundSize::Contain: { + double max_width_ratio = background_positioning_area.width().to_double() / concrete_image_size.width().to_double(); + double max_height_ratio = background_positioning_area.height().to_double() / concrete_image_size.height().to_double(); + double ratio = min(max_width_ratio, max_height_ratio); + image_rect.set_size(concrete_image_size.width().scaled(ratio), concrete_image_size.height().scaled(ratio)); + break; + } + case CSS::BackgroundSize::Cover: { + double max_width_ratio = background_positioning_area.width().to_double() / concrete_image_size.width().to_double(); + double max_height_ratio = background_positioning_area.height().to_double() / concrete_image_size.height().to_double(); + double ratio = max(max_width_ratio, max_height_ratio); + image_rect.set_size(concrete_image_size.width().scaled(ratio), concrete_image_size.height().scaled(ratio)); + break; + } + case CSS::BackgroundSize::LengthPercentage: + image_rect.set_size(concrete_image_size); + break; + } + + // If after sizing we have a 0px image, we're done. Attempting to paint this would be an infinite loop. + if (image_rect.is_empty()) { + continue; + } + + // If background-repeat is round for one (or both) dimensions, there is a second step. + // The UA must scale the image in that dimension (or both dimensions) so that it fits a + // whole number of times in the background positioning area. + if (layer.repeat_x == CSS::Repeat::Round || layer.repeat_y == CSS::Repeat::Round) { + // If X ≠ 0 is the width of the image after step one and W is the width of the + // background positioning area, then the rounded width X' = W / round(W / X) + // where round() is a function that returns the nearest natural number + // (integer greater than zero). + if (layer.repeat_x == CSS::Repeat::Round) { + image_rect.set_width(background_positioning_area.width() / round(background_positioning_area.width() / image_rect.width())); + } + if (layer.repeat_y == CSS::Repeat::Round) { + image_rect.set_height(background_positioning_area.height() / round(background_positioning_area.height() / image_rect.height())); + } + + // If background-repeat is round for one dimension only and if background-size is auto + // for the other dimension, then there is a third step: that other dimension is scaled + // so that the original aspect ratio is restored. + if (layer.repeat_x != layer.repeat_y) { + if (layer.size_x.is_auto()) { + image_rect.set_width(image_rect.height() * (concrete_image_size.width() / concrete_image_size.height())); + } + if (layer.size_y.is_auto()) { + image_rect.set_height(image_rect.width() * (concrete_image_size.height() / concrete_image_size.width())); + } + } + } + + CSSPixels space_x = background_positioning_area.width() - image_rect.width(); + CSSPixels space_y = background_positioning_area.height() - image_rect.height(); + + CSSPixels offset_x = layer.position_offset_x.to_px(layout_node, space_x); + CSSPixels offset_y = layer.position_offset_y.to_px(layout_node, space_y); + + resolved_layers.append({ .background_image = layer.background_image, + .attachment = layer.attachment, + .clip = layer.clip, + .position_edge_x = layer.position_edge_x, + .position_edge_y = layer.position_edge_y, + .offset_x = offset_x, + .offset_y = offset_y, + .background_positioning_area = background_positioning_area, + .image_rect = image_rect, + .repeat_x = layer.repeat_x, + .repeat_y = layer.repeat_y }); + } + + return ResolvedBackground { + .color_box = color_box, + .layers = move(resolved_layers), + .needs_text_clip = !layers.is_empty() && layers.last().clip == CSS::BackgroundBox::Text, + .background_rect = border_rect, + .color = background_color + }; +} + } diff --git a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h index 32c5fbad409..349ae414a58 100644 --- a/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h +++ b/Userland/Libraries/LibWeb/Painting/BackgroundPainting.h @@ -12,6 +12,41 @@ namespace Web::Painting { -void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelRect const&, Color background_color, CSS::ImageRendering, Vector const*, BorderRadiiData const&); +struct ResolvedBackgroundLayerData { + RefPtr background_image; + CSS::BackgroundAttachment attachment; + CSS::BackgroundBox clip; + CSS::PositionEdge position_edge_x; + CSS::PositionEdge position_edge_y; + CSSPixels offset_x; + CSSPixels offset_y; + CSSPixelRect background_positioning_area; + CSSPixelRect image_rect; + CSS::Repeat repeat_x; + CSS::Repeat repeat_y; +}; + +struct BackgroundBox { + CSSPixelRect rect; + BorderRadiiData radii; + + inline void shrink(CSSPixels top, CSSPixels right, CSSPixels bottom, CSSPixels left) + { + rect.shrink(top, right, bottom, left); + radii.shrink(top, right, bottom, left); + } +}; + +struct ResolvedBackground { + BackgroundBox color_box; + Vector layers; + bool needs_text_clip { false }; + CSSPixelRect background_rect {}; + Color color {}; +}; + +ResolvedBackground resolve_background_layers(Vector const& layers, Layout::NodeWithStyleAndBoxModelMetrics const& layout_node, Color background_color, CSSPixelRect const& border_rect, BorderRadiiData const& border_radii); + +void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, CSS::ImageRendering, ResolvedBackground resolved_background, BorderRadiiData const&); } diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp index 624dceb262d..85a72d88061 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.cpp @@ -75,7 +75,7 @@ void InlinePaintable::paint(PaintContext& context, PaintPhase phase) const absolute_fragment_rect.set_height(absolute_fragment_rect.height() + box_model().padding.top + box_model().padding.bottom); auto const& border_radii_data = fragment.border_radii_data(); - paint_background(context, layout_node(), absolute_fragment_rect, computed_values().background_color(), computed_values().image_rendering(), &computed_values().background_layers(), border_radii_data); + paint_background(context, layout_node(), computed_values().image_rendering(), fragment.resolved_background(), border_radii_data); if (!box_shadow_data().is_empty()) { auto borders_data = BordersData { @@ -248,7 +248,7 @@ void InlinePaintable::resolve_paint_properties() auto const& layout_node = this->layout_node(); auto& fragments = this->fragments(); - // Border radii + // Border radii and background layers auto const& top_left_border_radius = computed_values.border_top_left_radius(); auto const& top_right_border_radius = computed_values.border_top_right_radius(); auto const& bottom_right_border_radius = computed_values.border_bottom_right_radius(); @@ -277,6 +277,9 @@ void InlinePaintable::resolve_paint_properties() bottom_right_border_radius, bottom_left_border_radius); fragment.set_border_radii_data(border_radii_data); + + auto resolved_background = resolve_background_layers(computed_values.background_layers(), layout_node, computed_values.background_color(), absolute_fragment_rect, border_radii_data); + fragment.set_resolved_background(move(resolved_background)); } auto const& box_shadow_data = computed_values.box_shadow(); diff --git a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h index b4ce01ddb06..c39731fab48 100644 --- a/Userland/Libraries/LibWeb/Painting/InlinePaintable.h +++ b/Userland/Libraries/LibWeb/Painting/InlinePaintable.h @@ -7,6 +7,7 @@ #pragma once #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp index e0c722f62fa..66452ddd564 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.cpp @@ -463,30 +463,7 @@ void PaintableBox::paint_background(PaintContext& context) const if (layout_box().is_body() && document().html_element()->should_use_body_background_properties()) return; - CSSPixelRect background_rect; - Color background_color = computed_values().background_color(); - auto* background_layers = &computed_values().background_layers(); - - if (layout_box().is_root_element()) { - // CSS 2.1 Appendix E.2: If the element is a root element, paint the background over the entire canvas. - background_rect = context.css_viewport_rect(); - - // Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent, - // user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element. - if (document().html_element()->should_use_body_background_properties()) { - background_layers = document().background_layers(); - background_color = document().background_color(); - } - } else { - background_rect = absolute_padding_box_rect(); - } - - // HACK: If the Box has a border, use the bordered_rect to paint the background. - // This way if we have a border-radius there will be no gap between the filling and actual border. - if (computed_values().border_top().width != 0 || computed_values().border_right().width != 0 || computed_values().border_bottom().width != 0 || computed_values().border_left().width != 0) - background_rect = absolute_border_box_rect(); - - Painting::paint_background(context, layout_box(), background_rect, background_color, computed_values().image_rendering(), background_layers, normalized_border_radii_data()); + Painting::paint_background(context, layout_box(), computed_values().image_rendering(), m_resolved_background, normalized_border_radii_data()); } void PaintableBox::paint_box_shadow(PaintContext& context) const @@ -1148,6 +1125,32 @@ void PaintableBox::resolve_paint_properties() auto combined_transform = compute_combined_css_transform(); set_combined_css_transform(combined_transform); + + CSSPixelRect background_rect; + Color background_color = computed_values.background_color(); + auto const* background_layers = &computed_values.background_layers(); + if (layout_box().is_root_element()) { + background_rect = navigable()->viewport_rect(); + + // Section 2.11.2: If the computed value of background-image on the root element is none and its background-color is transparent, + // user agents must instead propagate the computed values of the background properties from that element’s first HTML BODY child element. + if (document().html_element()->should_use_body_background_properties()) { + background_layers = document().background_layers(); + background_color = document().background_color(); + } + } else { + background_rect = absolute_padding_box_rect(); + } + + // HACK: If the Box has a border, use the bordered_rect to paint the background. + // This way if we have a border-radius there will be no gap between the filling and actual border. + if (computed_values.border_top().width != 0 || computed_values.border_right().width != 0 || computed_values.border_bottom().width != 0 || computed_values.border_left().width != 0) + background_rect = absolute_border_box_rect(); + + m_resolved_background.layers.clear(); + if (background_layers) { + m_resolved_background = resolve_background_layers(*background_layers, layout_box(), background_color, background_rect, normalized_border_radii_data()); + }; } void PaintableWithLines::resolve_paint_properties() diff --git a/Userland/Libraries/LibWeb/Painting/PaintableBox.h b/Userland/Libraries/LibWeb/Painting/PaintableBox.h index 1ab4ef67187..331cd77ca29 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableBox.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableBox.h @@ -6,6 +6,7 @@ #pragma once +#include #include #include #include @@ -262,6 +263,8 @@ private: Optional m_last_mouse_tracking_position; Optional m_scroll_thumb_dragging_direction; + + ResolvedBackground m_resolved_background; }; class PaintableWithLines : public PaintableBox { diff --git a/Userland/Libraries/LibWeb/Painting/PaintableFragment.h b/Userland/Libraries/LibWeb/Painting/PaintableFragment.h index f044d336ee3..22504b158e5 100644 --- a/Userland/Libraries/LibWeb/Painting/PaintableFragment.h +++ b/Userland/Libraries/LibWeb/Painting/PaintableFragment.h @@ -8,6 +8,7 @@ #include #include +#include #include #include @@ -37,6 +38,9 @@ public: Vector const& shadows() const { return m_shadows; } void set_shadows(Vector&& shadows) { m_shadows = shadows; } + ResolvedBackground const& resolved_background() const { return m_resolved_background; } + void set_resolved_background(ResolvedBackground resolved_background) { m_resolved_background = resolved_background; } + CSSPixelRect const absolute_rect() const; RefPtr glyph_run() const { return m_glyph_run; } @@ -60,6 +64,7 @@ private: Painting::BorderRadiiData m_border_radii_data; RefPtr m_glyph_run; Vector m_shadows; + ResolvedBackground m_resolved_background; }; }