LibWeb: Resolve background size and offset only after style invalidation

This change fixes layering violation by moving to_px() calls to happen
before display list recording. Also it should make display list
recording a bit faster by resolving background properties beforehand.
This commit is contained in:
Aliaksandr Kalenik 2024-08-02 16:58:26 +03:00 committed by Andreas Kling
commit f574e2b03a
Notes: github-actions[bot] 2024-08-06 07:41:22 +00:00
8 changed files with 244 additions and 176 deletions

View file

@ -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) {

View file

@ -6,8 +6,6 @@
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <LibGfx/AntiAliasingPainter.h>
#include <LibGfx/Font/ScaledFont.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Layout/Viewport.h>
#include <LibWeb/Painting/BackgroundPainting.h>
@ -95,81 +93,52 @@ static RefPtr<DisplayList> 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<CSS::BackgroundLayerData> 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<DisplayList> 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<int>(),
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::Box>(layout_node)) {
auto* paintable_box = static_cast<Layout::Box const&>(layout_node).paintable_box();
auto const* paintable_box = static_cast<Layout::Box const&>(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<CSSPixels> specified_width {};
Optional<CSSPixels> 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<DevicePixelRect> 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<CSS::BackgroundLayerData> 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<ResolvedBackgroundLayerData> 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<CSSPixels> specified_width {};
Optional<CSSPixels> 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
};
}
}

View file

@ -12,6 +12,41 @@
namespace Web::Painting {
void paint_background(PaintContext&, Layout::NodeWithStyleAndBoxModelMetrics const&, CSSPixelRect const&, Color background_color, CSS::ImageRendering, Vector<CSS::BackgroundLayerData> const*, BorderRadiiData const&);
struct ResolvedBackgroundLayerData {
RefPtr<CSS::AbstractImageStyleValue const> 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<ResolvedBackgroundLayerData> layers;
bool needs_text_clip { false };
CSSPixelRect background_rect {};
Color color {};
};
ResolvedBackground resolve_background_layers(Vector<CSS::BackgroundLayerData> 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&);
}

View file

@ -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();

View file

@ -7,6 +7,7 @@
#pragma once
#include <LibWeb/Layout/InlineNode.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/ClippableAndScrollable.h>
#include <LibWeb/Painting/Paintable.h>
#include <LibWeb/Painting/PaintableFragment.h>

View file

@ -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 elements 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 elements 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()

View file

@ -6,6 +6,7 @@
#pragma once
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/BorderPainting.h>
#include <LibWeb/Painting/BorderRadiusCornerClipper.h>
#include <LibWeb/Painting/ClipFrame.h>
@ -262,6 +263,8 @@ private:
Optional<CSSPixelPoint> m_last_mouse_tracking_position;
Optional<ScrollDirection> m_scroll_thumb_dragging_direction;
ResolvedBackground m_resolved_background;
};
class PaintableWithLines : public PaintableBox {

View file

@ -8,6 +8,7 @@
#include <LibWeb/Layout/LineBoxFragment.h>
#include <LibWeb/Layout/Node.h>
#include <LibWeb/Painting/BackgroundPainting.h>
#include <LibWeb/Painting/BorderRadiiData.h>
#include <LibWeb/PixelUnits.h>
@ -37,6 +38,9 @@ public:
Vector<ShadowData> const& shadows() const { return m_shadows; }
void set_shadows(Vector<ShadowData>&& 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<Gfx::GlyphRun> glyph_run() const { return m_glyph_run; }
@ -60,6 +64,7 @@ private:
Painting::BorderRadiiData m_border_radii_data;
RefPtr<Gfx::GlyphRun> m_glyph_run;
Vector<ShadowData> m_shadows;
ResolvedBackground m_resolved_background;
};
}