| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "core/paint/LayerClipRecorder.h" |
| |
| #include "core/layout/LayoutView.h" |
| #include "core/paint/ClipRect.h" |
| #include "core/paint/PaintLayer.h" |
| #include "platform/geometry/IntRect.h" |
| #include "platform/graphics/GraphicsContext.h" |
| #include "platform/graphics/GraphicsLayer.h" |
| #include "platform/graphics/paint/ClipRecorder.h" |
| #include "platform/graphics/paint/PaintController.h" |
| |
| namespace blink { |
| |
| LayerClipRecorder::LayerClipRecorder(GraphicsContext& graphics_context, |
| const PaintLayer& paint_layer, |
| DisplayItem::Type clip_type, |
| const ClipRect& clip_rect, |
| const PaintLayer* clip_root, |
| const LayoutPoint& fragment_offset, |
| PaintLayerFlags paint_flags, |
| const DisplayItemClient& client, |
| BorderRadiusClippingRule rule) |
| : graphics_context_(graphics_context), |
| client_(client), |
| clip_type_(clip_type) { |
| if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) |
| return; |
| IntRect snapped_clip_rect = PixelSnappedIntRect(clip_rect.Rect()); |
| bool painting_masks = |
| (paint_flags & kPaintLayerPaintingChildClippingMaskPhase || |
| paint_flags & kPaintLayerPaintingAncestorClippingMaskPhase); |
| Vector<FloatRoundedRect> rounded_rects; |
| if (clip_root && (clip_rect.HasRadius() || painting_masks)) { |
| CollectRoundedRectClips(paint_layer, clip_root, fragment_offset, |
| painting_masks, rule, rounded_rects); |
| } |
| |
| graphics_context_.GetPaintController().CreateAndAppend<ClipDisplayItem>( |
| client_, clip_type_, snapped_clip_rect, rounded_rects); |
| } |
| |
| static bool InContainingBlockChain(const PaintLayer* start_layer, |
| const PaintLayer* end_layer) { |
| if (start_layer == end_layer) |
| return true; |
| |
| LayoutView* view = start_layer->GetLayoutObject().View(); |
| for (const LayoutBlock* current_block = |
| start_layer->GetLayoutObject().ContainingBlock(); |
| current_block && current_block != view; |
| current_block = current_block->ContainingBlock()) { |
| if (current_block->Layer() == end_layer) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void LayerClipRecorder::CollectRoundedRectClips( |
| const PaintLayer& paint_layer, |
| const PaintLayer* clip_root, |
| const LayoutPoint& offset_within_layer, |
| bool cross_composited_scrollers, |
| BorderRadiusClippingRule rule, |
| Vector<FloatRoundedRect>& rounded_rect_clips) { |
| // If the clip rect has been tainted by a border radius, then we have to walk |
| // up our layer chain applying the clips from any layers with overflow. The |
| // condition for being able to apply these clips is that the overflow object |
| // be in our containing block chain so we check that also. |
| for (const PaintLayer* layer = rule == kIncludeSelfForBorderRadius |
| ? &paint_layer |
| : paint_layer.Parent(); |
| layer; layer = layer->Parent()) { |
| // Composited scrolling layers handle border-radius clip in the compositor |
| // via a mask layer. We do not want to apply a border-radius clip to the |
| // layer contents itself, because that would require re-rastering every |
| // frame to update the clip. We only want to make sure that the mask layer |
| // is properly clipped so that it can in turn clip the scrolled contents in |
| // the compositor. |
| if (!cross_composited_scrollers && layer->NeedsCompositedScrolling()) |
| break; |
| |
| if (layer->GetLayoutObject().HasOverflowClip() && |
| layer->GetLayoutObject().Style()->HasBorderRadius() && |
| InContainingBlockChain(&paint_layer, layer)) { |
| LayoutPoint delta(offset_within_layer); |
| layer->ConvertToLayerCoords(clip_root, delta); |
| |
| // The PaintLayer's size is pixel-snapped if it is a LayoutBox. We can't |
| // use a pre-snapped border rect for clipping, since |
| // getRoundedInnerBorderFor assumes it has not been snapped yet. |
| LayoutSize size(layer->GetLayoutBox() |
| ? ToLayoutBox(layer->GetLayoutObject()).Size() |
| : LayoutSize(layer->size())); |
| rounded_rect_clips.push_back( |
| layer->GetLayoutObject().Style()->GetRoundedInnerBorderFor( |
| LayoutRect(delta, size))); |
| } |
| |
| if (layer == clip_root) |
| break; |
| } |
| } |
| |
| LayerClipRecorder::~LayerClipRecorder() { |
| if (RuntimeEnabledFeatures::SlimmingPaintV2Enabled()) |
| return; |
| graphics_context_.GetPaintController().EndItem<EndClipDisplayItem>( |
| client_, DisplayItem::ClipTypeToEndClipType(clip_type_)); |
| } |
| |
| } // namespace blink |