diff options
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.cc | 276 |
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, |