mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-09-21 08:48:57 +00:00
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:
parent
2995a57f63
commit
f574e2b03a
Notes:
github-actions[bot]
2024-08-06 07:41:22 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: f574e2b03a
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/969
8 changed files with 244 additions and 176 deletions
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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&);
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue