0

Delineate 'background-attachment: fixed' in BackgroundImageGeometry

Explicitly handle it within BackgroundImageGeometry::Calculate() now
that said function is much smaller (and thus hopefully easier to follow)
and more manageable. This allows seeing both the pre- and post-
adjustments to the computed geometry in the same function. Fold
UseFixedAttachment() and split some functions on
BoxBackgroundPaintContext in support of this.

Bug: 1500572
Change-Id: Ibe588d3b4373f07b21f1a136e55722c6d4fc8218
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5130060
Auto-Submit: Fredrik Söderquist <fs@opera.com>
Commit-Queue: Stephen Chenney <schenney@chromium.org>
Reviewed-by: Stephen Chenney <schenney@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1239137}
This commit is contained in:
Fredrik Söderquist
2023-12-19 15:10:47 +00:00
committed by Chromium LUCI CQ
parent 9704615b00
commit a79482acc0
4 changed files with 85 additions and 82 deletions

@ -204,14 +204,6 @@ void BackgroundImageGeometry::SetSpaceY(LayoutUnit space,
SetPhaseY(ComputeTilePhase(extra_offset, tile_size_.height + space));
}
void BackgroundImageGeometry::UseFixedAttachment(
const PhysicalOffset& attachment_point) {
PhysicalOffset fixed_adjustment =
attachment_point - unsnapped_dest_rect_.offset;
fixed_adjustment.ClampNegativeToZero();
phase_ += fixed_adjustment;
}
SnappedAndUnsnappedOutsets BackgroundImageGeometry::ComputeDestRectAdjustments(
const FillLayer& fill_layer,
const BoxBackgroundPaintContext& paint_context,
@ -340,76 +332,68 @@ BackgroundImageGeometry::ComputePositioningAreaAdjustments(
void BackgroundImageGeometry::AdjustPositioningArea(
const FillLayer& fill_layer,
const BoxBackgroundPaintContext& paint_context,
const PhysicalRect& paint_rect,
const PaintInfo& paint_info,
PhysicalRect& unsnapped_positioning_area,
PhysicalRect& snapped_positioning_area,
PhysicalOffset& unsnapped_box_offset,
PhysicalOffset& snapped_box_offset) {
if (paint_context.ShouldUseFixedAttachment(fill_layer)) {
unsnapped_dest_rect_ = snapped_dest_rect_ = snapped_positioning_area =
unsnapped_positioning_area;
} else {
unsnapped_dest_rect_ = paint_rect;
// Attempt to shrink the destination rect if possible while also ensuring
// that it paints to the border:
//
// * for background-clip content-box/padding-box, we can restrict to the
// respective box, but for padding-box we also try to force alignment
// with the inner border.
//
// * for border-box, we can modify individual edges iff the border fully
// obscures the background.
//
// It is unsafe to derive dest from border information when any of the
// following is true:
// * the layer is not painted as part of a regular background phase
// (e.g.paint_phase == kMask)
// * non-SrcOver compositing is active
// * painting_view_ is set, meaning we're dealing with a
// LayoutView - for which dest rect is overflowing (expanded to cover
// the whole canvas).
// * We are painting table cells using the table background, or the table
// has collapsed borders
// * We are painting a block-fragmented box.
// * There is a border image, because it may not be opaque or may be outset.
bool disallow_border_derived_adjustment =
!ShouldPaintSelfBlockBackground(paint_info.phase) ||
fill_layer.Composite() != CompositeOperator::kCompositeSourceOver ||
paint_context.DisallowBorderDerivedAdjustment();
// Attempt to shrink the destination rect if possible while also ensuring
// that it paints to the border:
//
// * for background-clip content-box/padding-box, we can restrict to the
// respective box, but for padding-box we also try to force alignment
// with the inner border.
//
// * for border-box, we can modify individual edges iff the border fully
// obscures the background.
//
// It is unsafe to derive dest from border information when any of the
// following is true:
// * the layer is not painted as part of a regular background phase
// (e.g.paint_phase == kMask)
// * non-SrcOver compositing is active
// * painting_view_ is set, meaning we're dealing with a
// LayoutView - for which dest rect is overflowing (expanded to cover
// the whole canvas).
// * We are painting table cells using the table background, or the table
// has collapsed borders
// * We are painting a block-fragmented box.
// * There is a border image, because it may not be opaque or may be outset.
bool disallow_border_derived_adjustment =
!ShouldPaintSelfBlockBackground(paint_info.phase) ||
fill_layer.Composite() != CompositeOperator::kCompositeSourceOver ||
paint_context.DisallowBorderDerivedAdjustment();
// Compute all the outsets we need to apply to the rectangles. These
// outsets also include the snapping behavior.
const SnappedAndUnsnappedOutsets dest_adjust = ComputeDestRectAdjustments(
fill_layer, paint_context, unsnapped_positioning_area,
disallow_border_derived_adjustment);
const SnappedAndUnsnappedOutsets box_outset =
ComputePositioningAreaAdjustments(fill_layer, paint_context,
unsnapped_positioning_area,
disallow_border_derived_adjustment);
// Compute all the outsets we need to apply to the rectangles. These
// outsets also include the snapping behavior.
const SnappedAndUnsnappedOutsets dest_adjust = ComputeDestRectAdjustments(
fill_layer, paint_context, unsnapped_positioning_area,
disallow_border_derived_adjustment);
const SnappedAndUnsnappedOutsets box_outset =
ComputePositioningAreaAdjustments(fill_layer, paint_context,
unsnapped_positioning_area,
disallow_border_derived_adjustment);
// Offset of the positioning area from the corner of positioning_box_.
unsnapped_box_offset =
box_outset.unsnapped.Offset() - dest_adjust.unsnapped.Offset();
snapped_box_offset =
box_outset.snapped.Offset() - dest_adjust.snapped.Offset();
// Offset of the positioning area from the corner of positioning_box_.
unsnapped_box_offset =
box_outset.unsnapped.Offset() - dest_adjust.unsnapped.Offset();
snapped_box_offset =
box_outset.snapped.Offset() - dest_adjust.snapped.Offset();
// Apply the adjustments.
snapped_dest_rect_ = unsnapped_dest_rect_;
snapped_dest_rect_.Contract(dest_adjust.snapped);
snapped_dest_rect_ = PhysicalRect(ToPixelSnappedRect(snapped_dest_rect_));
snapped_dest_rect_.size.ClampNegativeToZero();
unsnapped_dest_rect_.Contract(dest_adjust.unsnapped);
unsnapped_dest_rect_.size.ClampNegativeToZero();
snapped_positioning_area = unsnapped_positioning_area;
snapped_positioning_area.Contract(box_outset.snapped);
snapped_positioning_area =
PhysicalRect(ToPixelSnappedRect(snapped_positioning_area));
snapped_positioning_area.size.ClampNegativeToZero();
unsnapped_positioning_area.Contract(box_outset.unsnapped);
unsnapped_positioning_area.size.ClampNegativeToZero();
}
// Apply the adjustments.
snapped_dest_rect_ = unsnapped_dest_rect_;
snapped_dest_rect_.Contract(dest_adjust.snapped);
snapped_dest_rect_ = PhysicalRect(ToPixelSnappedRect(snapped_dest_rect_));
snapped_dest_rect_.size.ClampNegativeToZero();
unsnapped_dest_rect_.Contract(dest_adjust.unsnapped);
unsnapped_dest_rect_.size.ClampNegativeToZero();
snapped_positioning_area = unsnapped_positioning_area;
snapped_positioning_area.Contract(box_outset.snapped);
snapped_positioning_area =
PhysicalRect(ToPixelSnappedRect(snapped_positioning_area));
snapped_positioning_area.size.ClampNegativeToZero();
unsnapped_positioning_area.Contract(box_outset.unsnapped);
unsnapped_positioning_area.size.ClampNegativeToZero();
}
void BackgroundImageGeometry::CalculateFillTileSize(
@ -659,8 +643,7 @@ void BackgroundImageGeometry::Calculate(
// Unsnapped positioning area is used to derive quantities
// that reference source image maps and define non-integer values, such
// as phase and position.
PhysicalRect unsnapped_positioning_area =
paint_context.ComputePositioningArea(paint_info, fill_layer, paint_rect);
PhysicalRect unsnapped_positioning_area;
// Snapped positioning area is used for sizing images based on the
// background area (like cover and contain), and for setting the repeat
@ -671,10 +654,22 @@ void BackgroundImageGeometry::Calculate(
PhysicalOffset unsnapped_box_offset;
PhysicalOffset snapped_box_offset;
// This method also sets the destination rects.
AdjustPositioningArea(fill_layer, paint_context, paint_rect, paint_info,
unsnapped_positioning_area, snapped_positioning_area,
unsnapped_box_offset, snapped_box_offset);
if (paint_context.ShouldUseFixedAttachment(fill_layer)) {
unsnapped_positioning_area =
paint_context.FixedAttachmentPositioningArea(paint_info);
unsnapped_dest_rect_ = snapped_dest_rect_ = snapped_positioning_area =
unsnapped_positioning_area;
} else {
unsnapped_positioning_area =
paint_context.NormalPositioningArea(paint_rect);
unsnapped_dest_rect_ = paint_rect;
// This method adjusts `unsnapped_dest_rect_` and sets
// `snapped_dest_rect_`.
AdjustPositioningArea(fill_layer, paint_context, paint_info,
unsnapped_positioning_area, snapped_positioning_area,
unsnapped_box_offset, snapped_box_offset);
}
// Sets the tile_size_.
CalculateFillTileSize(fill_layer, paint_context.Style(),
@ -689,7 +684,10 @@ void BackgroundImageGeometry::Calculate(
snapped_positioning_area.size, unsnapped_box_offset, snapped_box_offset);
if (paint_context.ShouldUseFixedAttachment(fill_layer)) {
UseFixedAttachment(paint_rect.offset);
PhysicalOffset fixed_adjustment =
paint_rect.offset - unsnapped_dest_rect_.offset;
fixed_adjustment.ClampNegativeToZero();
phase_ += fixed_adjustment;
}
// The actual painting area can be bigger than the provided background

@ -79,8 +79,6 @@ class BackgroundImageGeometry {
void SetSpaceX(LayoutUnit space, LayoutUnit extra_offset);
void SetSpaceY(LayoutUnit space, LayoutUnit extra_offset);
void UseFixedAttachment(const PhysicalOffset& attachment_point);
// Compute adjustments for the destination rects. Adjustments
// both optimize painting when the background is obscured by a
// border, and snap the dest rect to the border. They also
@ -109,7 +107,6 @@ class BackgroundImageGeometry {
void AdjustPositioningArea(const FillLayer&,
const BoxBackgroundPaintContext&,
const PhysicalRect&,
const PaintInfo&,
PhysicalRect&,
PhysicalRect&,

@ -208,6 +208,11 @@ PhysicalRect BoxBackgroundPaintContext::ComputePositioningArea(
if (ShouldUseFixedAttachment(fill_layer)) {
return FixedAttachmentPositioningArea(paint_info);
}
return NormalPositioningArea(paint_rect);
}
PhysicalRect BoxBackgroundPaintContext::NormalPositioningArea(
const PhysicalRect& paint_rect) const {
if (painting_view_ || cell_using_container_background_ ||
box_has_multiple_fragments_) {
return {PhysicalOffset(), positioning_size_override_};

@ -50,9 +50,14 @@ class BoxBackgroundPaintContext {
// Compute the initial position area based on the geometry for the object
// this BackgroundPaintContext was created for.
PhysicalRect NormalPositioningArea(const PhysicalRect& paint_rect) const;
// As above, but also considers background-attachment: fixed.
PhysicalRect ComputePositioningArea(const PaintInfo& paint_info,
const FillLayer& fill_layer,
const PhysicalRect& paint_rect) const;
// The positioning area for a background layer with background-attachment:
// fixed.
PhysicalRect FixedAttachmentPositioningArea(const PaintInfo&) const;
PhysicalBoxStrut BorderOutsets() const;
PhysicalBoxStrut PaddingOutsets() const;
@ -89,8 +94,6 @@ class BoxBackgroundPaintContext {
BoxBackgroundPaintContext(const LayoutBoxModelObject* box,
const LayoutBoxModelObject* positioning_box);
PhysicalRect FixedAttachmentPositioningArea(const PaintInfo&) const;
// In most cases this is the same as positioning_box_. They are different
// when we are painting:
// 1. the view background (box_ is the LayoutView, and positioning_box_ is