summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc')
-rw-r--r--chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc276
1 files changed, 141 insertions, 135 deletions
diff --git a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
index 8f3cfc4a409..9b54fcb0c36 100644
--- a/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
+++ b/chromium/third_party/blink/renderer/core/paint/paint_layer_painter.cc
@@ -111,7 +111,7 @@ static bool ShouldCreateSubsequence(
const GraphicsContext& context,
const PaintLayerPaintingInfo& painting_info) {
// Caching is not needed during printing or painting previews.
- if (context.Printing() || context.IsPaintingPreview())
+ if (paint_layer.GetLayoutObject().GetDocument().IsPrintingOrPaintingPreview())
return false;
if (context.GetPaintController().IsSkippingCache())
@@ -147,25 +147,45 @@ static bool ShouldRepaintSubsequence(
// Repaint if previously the layer may be clipped by cull rect, and cull rect
// changes.
- if ((paint_layer.PreviousPaintResult() == kMayBeClippedByCullRect ||
- // When PaintUnderInvalidationChecking is enabled, always repaint the
- // subsequence when the paint rect changes because we will strictly match
- // new and cached subsequences. Normally we can reuse the cached fully
- // painted subsequence even if we would partially paint this time.
- RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled()) &&
- paint_layer.PreviousCullRect() != painting_info.cull_rect)
- return true;
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ paint_layer.PreviousCullRect() != painting_info.cull_rect) {
+ if (paint_layer.PreviousPaintResult() == kMayBeClippedByCullRect)
+ return true;
+ // When PaintUnderInvalidationChecking is enabled, always repaint the
+ // subsequence when the paint rect changes because we will strictly match
+ // new and cached subsequences. Normally we can reuse the cached fully
+ // painted subsequence even if we would partially paint this time.
+ if (RuntimeEnabledFeatures::PaintUnderInvalidationCheckingEnabled())
+ return true;
+ }
return false;
}
-static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
- const PaintLayer& layer,
- PaintLayerPaintingInfo& painting_info) {
+static bool IsUnclippedLayoutView(const PaintLayer& layer) {
+ // If MainFrameClipsContent is false which means that WebPreferences::
+ // record_whole_document is true, we should not cull the scrolling contents
+ // of the main frame.
+ if (IsA<LayoutView>(layer.GetLayoutObject())) {
+ const auto* frame = layer.GetLayoutObject().GetFrame();
+ if (frame && !frame->ClipsContent())
+ return true;
+ }
+ return false;
+}
+
+bool PaintLayerPainter::ShouldUseInfiniteCullRect(
+ GlobalPaintFlags global_flags) {
+ bool is_printing = paint_layer_.GetLayoutObject().GetDocument().Printing();
+ if (IsUnclippedLayoutView(paint_layer_) && !is_printing)
+ return true;
+
// Cull rects and clips can't be propagated across a filter which moves
// pixels, since the input of the filter may be outside the cull rect /
// clips yet still result in painted output.
- if (layer.HasFilterThatMovesPixels() &&
+ // TODO(wangxianzhu): With CullRectUpdate, we can let CullRect support
+ // mapping for pixel moving filters to avoid this infinite cull rect.
+ if (paint_layer_.HasFilterThatMovesPixels() &&
// However during printing, we don't want filter outset to cross page
// boundaries. This also avoids performance issue because the PDF renderer
// is super slow for big filters. Otherwise all filtered contents would
@@ -173,12 +193,12 @@ static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
// TODO(crbug.com/1098995): For now we don't adjust cull rect for clips.
// When we do, we need to check if we are painting under a real clip.
// This won't be a problem when we use block fragments for printing.
- !context.Printing())
+ !is_printing)
return true;
// Cull rect mapping doesn't work under perspective in some cases.
// See http://crbug.com/887558 for details.
- if (painting_info.root_layer->GetLayoutObject().StyleRef().HasPerspective())
+ if (paint_layer_.GetLayoutObject().StyleRef().HasPerspective())
return true;
// We do not apply cull rect optimizations across transforms for two
@@ -187,44 +207,29 @@ static bool ShouldUseInfiniteCullRect(const GraphicsContext& context,
// 2) Complexity: Difficulty updating clips when ancestor transforms
// change.
// For these reasons, we use an infinite dirty rect here.
- if (layer.PaintsWithTransform(painting_info.GetGlobalPaintFlags()) &&
+ // The reasons don't apply for CullRectUpdate.
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled() &&
+ paint_layer_.PaintsWithTransform(global_flags) &&
// The reasons don't apply for printing though, because when we enter and
// leaving printing mode, full invalidations occur.
- !context.Printing())
+ !is_printing)
return true;
return false;
}
-static bool IsUnclippedLayoutView(const PaintLayer& layer) {
- // If MainFrameClipsContent is false which means that WebPreferences::
- // record_whole_document is true, we should not cull the scrolling contents
- // of the main frame.
- if (IsA<LayoutView>(layer.GetLayoutObject())) {
- const auto* frame = layer.GetLayoutObject().GetFrame();
- if (frame && frame->IsMainFrame() && !frame->ClipsContent())
- return true;
- // True regardless whether this is the main frame when painting a preview.
- if (frame && frame->GetDocument()->IsPaintingPreview())
- return true;
- }
- return false;
-}
-
void PaintLayerPainter::AdjustForPaintProperties(
const GraphicsContext& context,
PaintLayerPaintingInfo& painting_info,
PaintLayerFlags& paint_flags) {
const auto& first_fragment = paint_layer_.GetLayoutObject().FirstFragment();
- bool is_unclipped_layout_view = IsUnclippedLayoutView(paint_layer_);
bool should_use_infinite_cull_rect =
- is_unclipped_layout_view ||
- ShouldUseInfiniteCullRect(context, paint_layer_, painting_info);
+ ShouldUseInfiniteCullRect(painting_info.GetGlobalPaintFlags());
if (should_use_infinite_cull_rect) {
painting_info.cull_rect = CullRect::Infinite();
// Avoid clipping during CollectFragments.
- if (is_unclipped_layout_view)
+ if (IsUnclippedLayoutView(paint_layer_))
paint_flags |= kPaintLayerPaintingOverflowContents;
}
@@ -254,7 +259,8 @@ void PaintLayerPainter::AdjustForPaintProperties(
// transform space. Convert cull_rect from the root layer's local space.
cull_rect.MoveBy(RoundedIntPoint(first_root_fragment.PaintOffset()));
base::Optional<CullRect> old_cull_rect;
- if (!paint_layer_.SelfOrDescendantNeedsRepaint()) {
+ if (!paint_layer_.SelfOrDescendantNeedsRepaint() &&
+ !RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
old_cull_rect = paint_layer_.PreviousCullRect();
// Convert old_cull_rect into the layer's transform space.
old_cull_rect->MoveBy(RoundedIntPoint(first_fragment.PaintOffset()));
@@ -312,36 +318,35 @@ PaintResult PaintLayerPainter::PaintLayerContents(
DCHECK(paint_layer_.IsSelfPaintingLayer() ||
paint_layer_.HasSelfPaintingLayerDescendant());
+ const auto& object = paint_layer_.GetLayoutObject();
PaintResult result = kFullyPainted;
- if (paint_layer_.GetLayoutObject().GetFrameView()->ShouldThrottleRendering())
+ if (object.GetFrameView()->ShouldThrottleRendering())
return result;
// A paint layer should always have LocalBorderBoxProperties when it's ready
// for paint.
- if (!paint_layer_.GetLayoutObject()
- .FirstFragment()
- .HasLocalBorderBoxProperties()) {
+ if (!object.FirstFragment().HasLocalBorderBoxProperties()) {
// TODO(crbug.com/848056): This can happen e.g. when we paint a filter
// referencing a SVG foreign object through feImage, especially when there
// is circular references. Should find a better solution.
- paint_layer_.SetPreviousCullRect(CullRect());
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ paint_layer_.SetPreviousCullRect(CullRect());
return kMayBeClippedByCullRect;
}
bool selection_drag_image_only = painting_info_arg.GetGlobalPaintFlags() &
kGlobalPaintSelectionDragImageOnly;
- if (selection_drag_image_only && !paint_layer_.GetLayoutObject().IsSelected())
+ if (selection_drag_image_only && !object.IsSelected())
return result;
IgnorePaintTimingScope ignore_paint_timing;
- if (paint_layer_.GetLayoutObject().StyleRef().Opacity() == 0.0f) {
+ if (object.StyleRef().Opacity() == 0.0f) {
IgnorePaintTimingScope::IncrementIgnoreDepth();
}
// Explicitly compute opacity of documentElement, as it is special-cased in
// Largest Contentful Paint.
bool is_document_element_invisible = false;
- if (const auto* document_element =
- paint_layer_.GetLayoutObject().GetDocument().documentElement()) {
+ if (const auto* document_element = object.GetDocument().documentElement()) {
if (document_element->GetLayoutObject() &&
document_element->GetLayoutObject()->StyleRef().Opacity() == 0.0f) {
is_document_element_invisible = true;
@@ -374,8 +379,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
// is not scrolled and should be above scrolled content.
bool should_paint_self_outline =
is_self_painting_layer && !is_painting_overlay_overflow_controls &&
- is_painting_composited_decoration &&
- paint_layer_.GetLayoutObject().StyleRef().HasOutline();
+ is_painting_composited_decoration && object.StyleRef().HasOutline();
PhysicalOffset subpixel_accumulation =
(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
@@ -386,7 +390,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
: painting_info.sub_pixel_accumulation;
ShouldRespectOverflowClipType respect_overflow_clip =
- ShouldRespectOverflowClip(paint_flags, paint_layer_.GetLayoutObject());
+ ShouldRespectOverflowClip(paint_flags, object);
bool should_paint_content =
paint_layer_.HasVisibleContent() &&
@@ -411,13 +415,33 @@ PaintResult PaintLayerPainter::PaintLayerContents(
subsequence_recorder.emplace(context, paint_layer_);
}
- PhysicalOffset offset_from_root;
- paint_layer_.ConvertToLayerCoords(painting_info.root_layer, offset_from_root);
+ PhysicalOffset offset_from_root =
+ paint_layer_.GetLayoutObject().FirstFragment().PaintOffset();
+ if (const PaintLayer* root = painting_info.root_layer)
+ offset_from_root -= root->GetLayoutObject().FirstFragment().PaintOffset();
offset_from_root += subpixel_accumulation;
- PhysicalRect bounds = paint_layer_.PhysicalBoundingBox(offset_from_root);
- if (!PhysicalRect(painting_info.cull_rect.Rect()).Contains(bounds))
- result = kMayBeClippedByCullRect;
+ IntRect visual_rect = FirstFragmentVisualRect(object);
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ if (object.FirstFragment().NextFragment()) {
+ result = kMayBeClippedByCullRect;
+ } else if (!object.FirstFragment().GetCullRect().Rect().Contains(
+ visual_rect)) {
+ result = kMayBeClippedByCullRect;
+ } else if (const auto* box = DynamicTo<LayoutBox>(object)) {
+ PhysicalRect contents_visual_rect =
+ box->PhysicalContentsVisualOverflowRect();
+ contents_visual_rect.Move(object.FirstFragment().PaintOffset());
+ if (!PhysicalRect(object.FirstFragment().GetContentsCullRect().Rect())
+ .Contains(contents_visual_rect)) {
+ result = kMayBeClippedByCullRect;
+ }
+ }
+ } else {
+ PhysicalRect bounds = paint_layer_.PhysicalBoundingBox(offset_from_root);
+ if (!PhysicalRect(painting_info.cull_rect.Rect()).Contains(bounds))
+ result = kMayBeClippedByCullRect;
+ }
PaintLayerPaintingInfo local_painting_info(painting_info);
local_painting_info.sub_pixel_accumulation = subpixel_accumulation;
@@ -463,24 +487,20 @@ PaintResult PaintLayerPainter::PaintLayerContents(
bool should_paint_normal_flow_and_pos_z_order_lists =
is_painting_composited_foreground &&
!is_painting_overlay_overflow_controls;
- bool is_video = IsA<LayoutVideo>(paint_layer_.GetLayoutObject());
+ bool is_video = IsA<LayoutVideo>(object);
base::Optional<ScopedPaintChunkHint> paint_chunk_hint;
- base::Optional<IntRect> visual_rect;
if (should_paint_content) {
- visual_rect.emplace(
- FirstFragmentVisualRect(paint_layer_.GetLayoutObject()));
paint_chunk_hint.emplace(context.GetPaintController(),
- paint_layer_.GetLayoutObject()
- .FirstFragment()
- .LocalBorderBoxProperties(),
+ object.FirstFragment().LocalBorderBoxProperties(),
paint_layer_, DisplayItem::kLayerChunk,
- *visual_rect);
+ visual_rect);
}
if (should_paint_background) {
- PaintBackgroundForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfBlockBackgroundOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (should_paint_neg_z_order_list) {
@@ -496,7 +516,7 @@ PaintResult PaintLayerPainter::PaintLayerContents(
// paint chunk after the previous forced paint chunks a stable id.
paint_chunk_hint_foreground.emplace(
context.GetPaintController(), paint_layer_,
- DisplayItem::kLayerChunkForeground, *visual_rect);
+ DisplayItem::kLayerChunkForeground, visual_rect);
}
if (selection_drag_image_only) {
PaintForegroundForFragmentsWithPhase(PaintPhase::kSelectionDragImage,
@@ -509,8 +529,9 @@ PaintResult PaintLayerPainter::PaintLayerContents(
}
if (!is_video && should_paint_self_outline) {
- PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfOutlineOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (should_paint_normal_flow_and_pos_z_order_lists) {
@@ -532,17 +553,17 @@ PaintResult PaintLayerPainter::PaintLayerContents(
if (is_video && should_paint_self_outline) {
// We paint outlines for video later so that they aren't obscured by the
// video controls.
- PaintSelfOutlineForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kSelfOutlineOnly,
+ layer_fragments, context,
+ local_painting_info, paint_flags);
}
if (is_painting_mask && should_paint_content && !selection_drag_image_only) {
- const auto* properties =
- paint_layer_.GetLayoutObject().FirstFragment().PaintProperties();
- if (properties) {
+ if (const auto* properties = object.FirstFragment().PaintProperties()) {
if (properties->Mask()) {
- PaintMaskForFragments(layer_fragments, context, local_painting_info,
- paint_flags);
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kMask, layer_fragments,
+ context, local_painting_info,
+ paint_flags);
}
if (properties->ClipPathMask()) {
PhysicalOffset visual_offset_from_root =
@@ -550,15 +571,15 @@ PaintResult PaintLayerPainter::PaintLayerContents(
? paint_layer_.VisualOffsetFromAncestor(
local_painting_info.root_layer, subpixel_accumulation)
: offset_from_root;
- ClipPathClipper::PaintClipPathAsMaskImage(
- context, paint_layer_.GetLayoutObject(),
- paint_layer_.GetLayoutObject(), visual_offset_from_root);
+ ClipPathClipper::PaintClipPathAsMaskImage(context, object, object,
+ visual_offset_from_root);
}
}
}
paint_layer_.SetPreviousPaintResult(result);
- paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
+ if (!RuntimeEnabledFeatures::CullRectUpdateEnabled())
+ paint_layer_.SetPreviousCullRect(local_painting_info.cull_rect);
return result;
}
@@ -655,21 +676,16 @@ void PaintLayerPainter::PaintOverlayOverflowControlsForFragments(
paint_layer_.GetScrollableArea()->HasLayerForScrollCorner())
return;
- ForAllFragments(
- context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- if (!fragment.background_rect.IsEmpty()) {
- PaintFragmentWithPhase(PaintPhase::kOverlayOverflowControls, fragment,
- context, fragment.background_rect,
- painting_info, paint_flags);
- }
- });
+ PaintBackgroundForFragmentsWithPhase(PaintPhase::kOverlayOverflowControls,
+ layer_fragments, context, painting_info,
+ paint_flags);
}
void PaintLayerPainter::PaintFragmentWithPhase(
PaintPhase phase,
const PaintLayerFragment& fragment,
GraphicsContext& context,
- const ClipRect& clip_rect,
+ const CullRect& cull_rect,
const PaintLayerPaintingInfo& painting_info,
PaintLayerFlags paint_flags) {
DCHECK(paint_layer_.IsSelfPaintingLayer());
@@ -685,19 +701,11 @@ void PaintLayerPainter::PaintFragmentWithPhase(
context.GetPaintController(), chunk_properties, paint_layer_,
DisplayItem::PaintPhaseToDrawingType(phase));
- PhysicalRect new_cull_rect(clip_rect.Rect());
- // Now |new_cull_rect| is in the pixel-snapped border box space of
- // |fragment.root_fragment_data|. Adjust it to the containing transform node's
- // space in which we will paint.
- new_cull_rect.Move(PhysicalOffset(
- RoundedIntPoint(fragment.root_fragment_data->PaintOffset())));
-
- PaintInfo paint_info(context, PixelSnappedIntRect(new_cull_rect), phase,
- painting_info.GetGlobalPaintFlags(), paint_flags,
- &painting_info.root_layer->GetLayoutObject(),
- fragment.fragment_data
- ? fragment.fragment_data->LogicalTopInFlowThread()
- : LayoutUnit());
+ PaintInfo paint_info(
+ context, cull_rect, phase, painting_info.GetGlobalPaintFlags(),
+ paint_flags, &painting_info.root_layer->GetLayoutObject(),
+ fragment.fragment_data ? fragment.fragment_data->LogicalTopInFlowThread()
+ : LayoutUnit());
if (paint_layer_.GetLayoutObject().ChildPaintBlockedByDisplayLock())
paint_info.SetDescendantPaintingBlocked(true);
@@ -707,16 +715,34 @@ void PaintLayerPainter::PaintFragmentWithPhase(
paint_layer_.GetLayoutObject().Paint(paint_info);
}
-void PaintLayerPainter::PaintBackgroundForFragments(
+static CullRect LegacyCullRect(const PaintLayerFragment& fragment,
+ const ClipRect& clip_rect) {
+ DCHECK(!RuntimeEnabledFeatures::CullRectUpdateEnabled());
+ PhysicalRect new_cull_rect(clip_rect.Rect());
+ // Now |new_cull_rect| is in the pixel-snapped border box space of
+ // |fragment.root_fragment_data|. Adjust it to the containing transform node's
+ // space in which we will paint.
+ new_cull_rect.Move(PhysicalOffset(
+ RoundedIntPoint(fragment.root_fragment_data->PaintOffset())));
+ return CullRect(PixelSnappedIntRect(new_cull_rect));
+}
+
+void PaintLayerPainter::PaintBackgroundForFragmentsWithPhase(
+ PaintPhase phase,
const PaintLayerFragments& layer_fragments,
GraphicsContext& context,
const PaintLayerPaintingInfo& local_painting_info,
PaintLayerFlags paint_flags) {
ForAllFragments(
context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- PaintFragmentWithPhase(PaintPhase::kSelfBlockBackgroundOnly, fragment,
- context, fragment.background_rect,
- local_painting_info, paint_flags);
+ CullRect cull_rect =
+ RuntimeEnabledFeatures::CullRectUpdateEnabled()
+ ? fragment.fragment_data->GetCullRect()
+ : LegacyCullRect(fragment, fragment.background_rect);
+ if (!cull_rect.Rect().IsEmpty()) {
+ PaintFragmentWithPhase(phase, fragment, context, cull_rect,
+ local_painting_info, paint_flags);
+ }
});
}
@@ -760,44 +786,24 @@ void PaintLayerPainter::PaintForegroundForFragmentsWithPhase(
GraphicsContext& context,
const PaintLayerPaintingInfo& local_painting_info,
PaintLayerFlags paint_flags) {
- ForAllFragments(context, layer_fragments,
- [&](const PaintLayerFragment& fragment) {
- if (!fragment.foreground_rect.IsEmpty()) {
- PaintFragmentWithPhase(phase, fragment, context,
- fragment.foreground_rect,
- local_painting_info, paint_flags);
- }
- });
-}
-
-void PaintLayerPainter::PaintSelfOutlineForFragments(
- const PaintLayerFragments& layer_fragments,
- GraphicsContext& context,
- const PaintLayerPaintingInfo& local_painting_info,
- PaintLayerFlags paint_flags) {
ForAllFragments(
context, layer_fragments, [&](const PaintLayerFragment& fragment) {
- if (!fragment.background_rect.IsEmpty()) {
- PaintFragmentWithPhase(PaintPhase::kSelfOutlineOnly, fragment,
- context, fragment.background_rect,
+ CullRect cull_rect;
+ if (RuntimeEnabledFeatures::CullRectUpdateEnabled()) {
+ // In CullRectUpdate, this function is the same as
+ // PaintBackgroundForFragmentsWithPhase(). The contents cull rect will
+ // be applied by ScopedBoxContentsPaintState.
+ cull_rect = fragment.fragment_data->GetCullRect();
+ } else {
+ cull_rect = LegacyCullRect(fragment, fragment.foreground_rect);
+ }
+ if (!cull_rect.Rect().IsEmpty()) {
+ PaintFragmentWithPhase(phase, fragment, context, cull_rect,
local_painting_info, paint_flags);
}
});
}
-void PaintLayerPainter::PaintMaskForFragments(
- const PaintLayerFragments& layer_fragments,
- GraphicsContext& context,
- const PaintLayerPaintingInfo& local_painting_info,
- PaintLayerFlags paint_flags) {
- ForAllFragments(context, layer_fragments,
- [&](const PaintLayerFragment& fragment) {
- PaintFragmentWithPhase(PaintPhase::kMask, fragment, context,
- fragment.background_rect,
- local_painting_info, paint_flags);
- });
-}
-
void PaintLayerPainter::PaintOverlayOverflowControls(
GraphicsContext& context,
const CullRect& cull_rect,