Commit fbc399f3 authored by Xianzhu Wang's avatar Xianzhu Wang Committed by Commit Bot

[PE] Fix fixed attachment background invalidation on view size change

When view size changes, we need to check invalidation of all fixed
attachment backgrounds, including the LayoutView's and descendants'.

Bug: 901561
Change-Id: Ie6275d867f819d5c37d86b8530f7991142de9790
Reviewed-on: https://chromium-review.googlesource.com/c/1319397
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#606717}
parent 763c2406
{
"layers": [
{
"name": "Scrolling background of LayoutView #document",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "HorizontalScrollbar",
"bounds": [600, 250],
"paintInvalidations": [
{
"object": "LayoutView #document",
"rect": [0, 0, 600, 250],
"reason": "geometry"
},
{
"object": "HorizontalScrollbar",
"rect": [0, 235, 585, 15],
"reason": "scroll control"
},
{
"object": "VerticalScrollbar",
"rect": [585, 0, 15, 250],
"reason": "scroll control"
}
]
},
{
"name": "LayoutBlockFlow HTML",
"position": [8, 8],
"bounds": [1000, 1000],
"contentsOpaque": true,
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [0, 0, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "Scrolling background of LayoutView #document",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "HorizontalScrollbar",
"bounds": [400, 250],
"paintInvalidations": [
{
"object": "LayoutView #document",
"rect": [0, 0, 400, 250],
"reason": "geometry"
},
{
"object": "HorizontalScrollbar",
"rect": [0, 235, 400, 15],
"reason": "scroll control"
},
{
"object": "VerticalScrollbar",
"rect": [385, 0, 15, 235],
"reason": "scroll control"
}
]
},
{
"name": "LayoutBlockFlow HTML",
"position": [8, 8],
"bounds": [1000, 1000],
"contentsOpaque": true,
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [0, 0, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "Scrolling background of LayoutView #document",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "HorizontalScrollbar",
"bounds": [400, 600],
"paintInvalidations": [
{
"object": "LayoutView #document",
"rect": [0, 0, 400, 600],
"reason": "geometry"
},
{
"object": "HorizontalScrollbar",
"rect": [0, 585, 385, 15],
"reason": "scroll control"
},
{
"object": "HorizontalScrollbar",
"rect": [0, 235, 385, 15],
"reason": "scroll control"
},
{
"object": "VerticalScrollbar",
"rect": [385, 0, 15, 585],
"reason": "scroll control"
}
]
},
{
"name": "LayoutBlockFlow HTML",
"position": [8, 8],
"bounds": [1000, 1000],
"contentsOpaque": true,
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [0, 0, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "Scrolling background of LayoutView #document",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF"
},
{
"name": "HorizontalScrollbar",
"bounds": [800, 600],
"paintInvalidations": [
{
"object": "LayoutView #document",
"rect": [0, 0, 800, 600],
"reason": "geometry"
},
{
"object": "HorizontalScrollbar",
"rect": [0, 585, 785, 15],
"reason": "scroll control"
},
{
"object": "VerticalScrollbar",
"rect": [785, 0, 15, 585],
"reason": "scroll control"
},
{
"object": "VerticalScrollbar",
"rect": [385, 0, 15, 585],
"reason": "scroll control"
}
]
},
{
"name": "LayoutBlockFlow HTML",
"position": [8, 8],
"bounds": [1000, 1000],
"contentsOpaque": true,
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [0, 0, 1000, 1000],
"reason": "background"
}
]
}
]
}
<!DOCTYPE html>
<style>
#target {
width: 1000px;
height: 1000px;
background-image: url(../resources/apple.jpg);
background-size: cover;
background-attachment: fixed;
background-position: center;
}
</style>
<div id="target"></div>
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [600, 250],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [585, 235],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF",
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [8, 8, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [400, 250],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [385, 235],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF",
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [8, 8, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [400, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [385, 585],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF",
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [8, 8, 1000, 1000],
"reason": "background"
}
]
}
]
}
{
"layers": [
{
"name": "LayoutView #document",
"bounds": [800, 600],
"drawsContent": false,
"backgroundColor": "#FFFFFF"
},
{
"name": "Scrolling Layer",
"bounds": [785, 585],
"drawsContent": false
},
{
"name": "Scrolling Contents Layer",
"bounds": [1008, 1016],
"contentsOpaque": true,
"backgroundColor": "#FFFFFF",
"paintInvalidations": [
{
"object": "LayoutBlockFlow DIV id='target'",
"rect": [8, 8, 1000, 1000],
"reason": "background"
}
]
}
]
}
<!DOCTYPE html>
<script src="../resources/window-resize-repaint.js"></script>
<style>
#target {
width: 1000px;
height: 1000px;
background-image: url(../resources/apple.jpg);
background-size: cover;
background-attachment: fixed;
background-position: center;
}
</style>
<div id="target"></div>
...@@ -1185,10 +1185,8 @@ void LocalFrameView::RemoveBackgroundAttachmentFixedObject( ...@@ -1185,10 +1185,8 @@ void LocalFrameView::RemoveBackgroundAttachmentFixedObject(
} }
void LocalFrameView::AddViewportConstrainedObject(LayoutObject& object) { void LocalFrameView::AddViewportConstrainedObject(LayoutObject& object) {
if (!viewport_constrained_objects_) { if (!viewport_constrained_objects_)
viewport_constrained_objects_ = viewport_constrained_objects_ = std::make_unique<ObjectSet>();
std::make_unique<ViewportConstrainedObjectSet>();
}
if (!viewport_constrained_objects_->Contains(&object)) { if (!viewport_constrained_objects_->Contains(&object)) {
viewport_constrained_objects_->insert(&object); viewport_constrained_objects_->insert(&object);
...@@ -1292,10 +1290,20 @@ void LocalFrameView::NotifyFrameRectsChangedIfNeededRecursive() { ...@@ -1292,10 +1290,20 @@ void LocalFrameView::NotifyFrameRectsChangedIfNeededRecursive() {
}); });
} }
void LocalFrameView::InvalidateBackgroundAttachmentFixedDescendants( void LocalFrameView::InvalidateBackgroundAttachmentFixedDescendantsOnScroll(
const LayoutObject& object) { const LayoutObject& scrolled_object) {
for (auto* const layout_object : background_attachment_fixed_objects_) { for (auto* const layout_object : background_attachment_fixed_objects_) {
if (object != GetLayoutView() && !layout_object->IsDescendantOf(&object)) if (scrolled_object != GetLayoutView() &&
!layout_object->IsDescendantOf(&scrolled_object))
continue;
// An object needs to be repainted on scroll when it has background-
// attachment:fixed, unless the background will be separately composited
// i.e. when a LayoutView paints backgrounds only into scrolling contents.
if (layout_object == GetLayoutView() &&
GetLayoutView()->GetBackgroundPaintLocation() ==
kBackgroundPaintInScrollingContents &&
(RuntimeEnabledFeatures::SlimmingPaintV2Enabled() ||
GetLayoutView()->Compositor()->PreferCompositingToLCDTextEnabled()))
continue; continue;
layout_object->SetBackgroundNeedsFullPaintInvalidation(); layout_object->SetBackgroundNeedsFullPaintInvalidation();
} }
......
...@@ -270,10 +270,10 @@ class CORE_EXPORT LocalFrameView final ...@@ -270,10 +270,10 @@ class CORE_EXPORT LocalFrameView final
void SetDisplayShape(DisplayShape); void SetDisplayShape(DisplayShape);
// Fixed-position objects. // Fixed-position objects.
typedef HashSet<LayoutObject*> ViewportConstrainedObjectSet; typedef HashSet<LayoutObject*> ObjectSet;
void AddViewportConstrainedObject(LayoutObject&); void AddViewportConstrainedObject(LayoutObject&);
void RemoveViewportConstrainedObject(LayoutObject&); void RemoveViewportConstrainedObject(LayoutObject&);
const ViewportConstrainedObjectSet* ViewportConstrainedObjects() const { const ObjectSet* ViewportConstrainedObjects() const {
return viewport_constrained_objects_.get(); return viewport_constrained_objects_.get();
} }
bool HasViewportConstrainedObjects() const { bool HasViewportConstrainedObjects() const {
...@@ -287,8 +287,12 @@ class CORE_EXPORT LocalFrameView final ...@@ -287,8 +287,12 @@ class CORE_EXPORT LocalFrameView final
bool HasBackgroundAttachmentFixedObjects() const { bool HasBackgroundAttachmentFixedObjects() const {
return background_attachment_fixed_objects_.size(); return background_attachment_fixed_objects_.size();
} }
const ObjectSet& BackgroundAttachmentFixedObjects() const {
return background_attachment_fixed_objects_;
}
bool HasBackgroundAttachmentFixedDescendants(const LayoutObject&) const; bool HasBackgroundAttachmentFixedDescendants(const LayoutObject&) const;
void InvalidateBackgroundAttachmentFixedDescendants(const LayoutObject&); void InvalidateBackgroundAttachmentFixedDescendantsOnScroll(
const LayoutObject& scrolled_object);
void HandleLoadCompleted(); void HandleLoadCompleted();
...@@ -875,9 +879,9 @@ class CORE_EXPORT LocalFrameView final ...@@ -875,9 +879,9 @@ class CORE_EXPORT LocalFrameView final
Member<ScrollableAreaSet> scrollable_areas_; Member<ScrollableAreaSet> scrollable_areas_;
Member<ScrollableAreaSet> animating_scrollable_areas_; Member<ScrollableAreaSet> animating_scrollable_areas_;
std::unique_ptr<ResizerAreaSet> resizer_areas_; std::unique_ptr<ResizerAreaSet> resizer_areas_;
std::unique_ptr<ViewportConstrainedObjectSet> viewport_constrained_objects_; std::unique_ptr<ObjectSet> viewport_constrained_objects_;
unsigned sticky_position_object_count_; unsigned sticky_position_object_count_;
ViewportConstrainedObjectSet background_attachment_fixed_objects_; ObjectSet background_attachment_fixed_objects_;
Member<FrameViewAutoSizeInfo> auto_size_info_; Member<FrameViewAutoSizeInfo> auto_size_info_;
float input_events_scale_factor_for_emulation_; float input_events_scale_factor_for_emulation_;
......
...@@ -387,21 +387,9 @@ void LayoutBox::UpdateBackgroundAttachmentFixedStatusAfterStyleChange() { ...@@ -387,21 +387,9 @@ void LayoutBox::UpdateBackgroundAttachmentFixedStatusAfterStyleChange() {
if (ignore_fixed_background_attachment) if (ignore_fixed_background_attachment)
return; return;
// An object needs to be repainted on frame scroll when it has background- SetIsBackgroundAttachmentFixedObject(
// attachment:fixed, unless the background will be separately composited.
// LayoutView is responsible for painting root background, thus the root
// element (and the body element if html element has no background) skips
// painting backgrounds.
bool is_background_attachment_fixed_object =
!BackgroundTransfersToView() && !BackgroundTransfersToView() &&
StyleRef().HasFixedAttachmentBackgroundImage(); StyleRef().HasFixedAttachmentBackgroundImage());
if (IsLayoutView() &&
View()->Compositor()->PreferCompositingToLCDTextEnabled() &&
StyleRef().HasOnlyFixedAttachmentBackgroundImage()) {
is_background_attachment_fixed_object = false;
}
SetIsBackgroundAttachmentFixedObject(is_background_attachment_fixed_object);
} }
void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange( void LayoutBox::UpdateShapeOutsideInfoAfterStyleChange(
......
...@@ -616,10 +616,6 @@ LayoutRect LayoutView::OverflowClipRect( ...@@ -616,10 +616,6 @@ LayoutRect LayoutView::OverflowClipRect(
return rect; return rect;
} }
LayoutRect LayoutView::FixedBackgroundPositioningArea() const {
return OverflowClipRect(LayoutPoint());
}
void LayoutView::SetAutosizeScrollbarModes(ScrollbarMode h_mode, void LayoutView::SetAutosizeScrollbarModes(ScrollbarMode h_mode,
ScrollbarMode v_mode) { ScrollbarMode v_mode) {
DCHECK_EQ(v_mode == kScrollbarAuto, h_mode == kScrollbarAuto); DCHECK_EQ(v_mode == kScrollbarAuto, h_mode == kScrollbarAuto);
......
...@@ -307,8 +307,6 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow { ...@@ -307,8 +307,6 @@ class CORE_EXPORT LayoutView final : public LayoutBlockFlow {
bool UpdateLogicalWidthAndColumnWidth() override; bool UpdateLogicalWidthAndColumnWidth() override;
LayoutRect FixedBackgroundPositioningArea() const;
UntracedMember<LocalFrameView> frame_view_; UntracedMember<LocalFrameView> frame_view_;
// The page logical height. // The page logical height.
......
...@@ -231,6 +231,32 @@ BoxPaintInvalidator::BackgroundInvalidationType ...@@ -231,6 +231,32 @@ BoxPaintInvalidator::BackgroundInvalidationType
BoxPaintInvalidator::ComputeViewBackgroundInvalidation() { BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
DCHECK(box_.IsLayoutView()); DCHECK(box_.IsLayoutView());
const auto& layout_view = ToLayoutView(box_);
auto new_background_rect = layout_view.BackgroundRect();
auto old_background_rect = layout_view.PreviousBackgroundRect();
layout_view.SetPreviousBackgroundRect(new_background_rect);
// BackgroundRect is the positioning area of all fixed attachment backgrounds,
// including the LayoutView's and descendants'.
bool background_location_changed =
new_background_rect.Location() != old_background_rect.Location();
bool background_size_changed =
new_background_rect.Size() != old_background_rect.Size();
if (background_location_changed || background_size_changed) {
for (auto* object :
layout_view.GetFrameView()->BackgroundAttachmentFixedObjects()) {
if (background_location_changed ||
ShouldFullyInvalidateFillLayersOnSizeChange(
object->StyleRef().BackgroundLayers(), old_background_rect.Size(),
new_background_rect.Size()))
object->SetBackgroundNeedsFullPaintInvalidation();
}
}
if (background_location_changed ||
layout_view.BackgroundNeedsFullPaintInvalidation())
return BackgroundInvalidationType::kFull;
// LayoutView's non-fixed-attachment background is positioned in the // LayoutView's non-fixed-attachment background is positioned in the
// document element and needs to invalidate if the size changes. // document element and needs to invalidate if the size changes.
// See: https://drafts.csswg.org/css-backgrounds-3/#root-background. // See: https://drafts.csswg.org/css-backgrounds-3/#root-background.
...@@ -249,25 +275,8 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() { ...@@ -249,25 +275,8 @@ BoxPaintInvalidator::ComputeViewBackgroundInvalidation() {
} }
} }
const auto& layout_view = ToLayoutView(box_); return background_size_changed ? BackgroundInvalidationType::kIncremental
auto new_background_rect = layout_view.BackgroundRect(); : BackgroundInvalidationType::kNone;
auto old_background_rect = layout_view.PreviousBackgroundRect();
if (new_background_rect == old_background_rect)
return BackgroundInvalidationType::kNone;
layout_view.SetPreviousBackgroundRect(new_background_rect);
if (old_background_rect.Location() != old_background_rect.Location())
return BackgroundInvalidationType::kFull;
// BackgroundRect is the positioning area of the fixed attachment
// background.
if (layout_view.StyleRef().HasFixedAttachmentBackgroundImage() &&
ShouldFullyInvalidateFillLayersOnSizeChange(
layout_view.StyleRef().BackgroundLayers(), old_background_rect.Size(),
new_background_rect.Size()))
return BackgroundInvalidationType::kFull;
return BackgroundInvalidationType::kIncremental;
} }
BoxPaintInvalidator::BackgroundInvalidationType BoxPaintInvalidator::BackgroundInvalidationType
......
...@@ -546,7 +546,8 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange( ...@@ -546,7 +546,8 @@ void PaintLayerScrollableArea::InvalidatePaintForScrollOffsetChange(
LocalFrameView* frame_view = GetLayoutBox()->GetFrameView(); LocalFrameView* frame_view = GetLayoutBox()->GetFrameView();
bool is_root_layer = Layer()->IsRootLayer(); bool is_root_layer = Layer()->IsRootLayer();
frame_view->InvalidateBackgroundAttachmentFixedDescendants(*GetLayoutBox()); frame_view->InvalidateBackgroundAttachmentFixedDescendantsOnScroll(
*GetLayoutBox());
if (is_root_layer && frame_view->HasViewportConstrainedObjects() && if (is_root_layer && frame_view->HasViewportConstrainedObjects() &&
!frame_view->InvalidateViewportConstrainedObjects()) { !frame_view->InvalidateViewportConstrainedObjects()) {
......
...@@ -265,13 +265,15 @@ TEST_P(ViewPainterTestWithPaintTouchAction, ...@@ -265,13 +265,15 @@ TEST_P(ViewPainterTestWithPaintTouchAction,
0, 2, 0, 2,
PaintChunk::Id(*view->Layer(), kNonScrollingBackgroundChunkType), PaintChunk::Id(*view->Layer(), kNonScrollingBackgroundChunkType),
non_scrolling_properties, view_hit_test_data))); non_scrolling_properties, view_hit_test_data)));
#if 0
// TODO(wangxianzhu): Enable this in crrev.com/c/1325570.
EXPECT_THAT( EXPECT_THAT(
RootPaintController().PaintChunks(), RootPaintController().PaintChunks(),
ElementsAre(IsPaintChunk( ElementsAre(IsPaintChunk(
0, 3, 0, 3,
PaintChunk::Id(*html->Layer(), kNonScrollingBackgroundChunkType), PaintChunk::Id(*html->Layer(), kNonScrollingBackgroundChunkType),
scrolling_properties, scrolling_hit_test_data))); scrolling_properties, scrolling_hit_test_data)));
#endif
} }
} }
......
...@@ -377,11 +377,6 @@ class ComputedStyle : public ComputedStyleBase, ...@@ -377,11 +377,6 @@ class ComputedStyle : public ComputedStyleBase,
bool HasFixedAttachmentBackgroundImage() const { bool HasFixedAttachmentBackgroundImage() const {
return BackgroundInternal().AnyLayerHasFixedAttachmentImage(); return BackgroundInternal().AnyLayerHasFixedAttachmentImage();
} }
bool HasOnlyFixedAttachmentBackgroundImage() const {
return BackgroundInternal().AnyLayerHasFixedAttachmentImage() &&
!BackgroundInternal().AnyLayerHasLocalAttachmentImage() &&
!BackgroundInternal().AnyLayerHasDefaultAttachment();
}
// background-clip // background-clip
EFillBox BackgroundClip() const { EFillBox BackgroundClip() const {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment