| // 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/ClipRect.h" |
| #include "core/layout/LayoutView.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& graphicsContext, |
| const LayoutBoxModelObject& layoutObject, |
| DisplayItem::Type clipType, |
| const ClipRect& clipRect, |
| const PaintLayer* clipRoot, |
| const LayoutPoint& fragmentOffset, |
| PaintLayerFlags paintFlags, |
| BorderRadiusClippingRule rule) |
| : m_graphicsContext(graphicsContext), |
| m_layoutObject(layoutObject), |
| m_clipType(clipType) { |
| IntRect snappedClipRect = pixelSnappedIntRect(clipRect.rect()); |
| Vector<FloatRoundedRect> roundedRects; |
| if (clipRoot && clipRect.hasRadius()) { |
| collectRoundedRectClips(*layoutObject.layer(), clipRoot, graphicsContext, |
| fragmentOffset, paintFlags, rule, roundedRects); |
| } |
| |
| m_graphicsContext.getPaintController().createAndAppend<ClipDisplayItem>( |
| layoutObject, m_clipType, snappedClipRect, roundedRects); |
| } |
| |
| static bool inContainingBlockChain(PaintLayer* startLayer, |
| PaintLayer* endLayer) { |
| if (startLayer == endLayer) |
| return true; |
| |
| LayoutView* view = startLayer->layoutObject()->view(); |
| for (const LayoutBlock* currentBlock = |
| startLayer->layoutObject()->containingBlock(); |
| currentBlock && currentBlock != view; |
| currentBlock = currentBlock->containingBlock()) { |
| if (currentBlock->layer() == endLayer) |
| return true; |
| } |
| |
| return false; |
| } |
| |
| void LayerClipRecorder::collectRoundedRectClips( |
| PaintLayer& paintLayer, |
| const PaintLayer* clipRoot, |
| GraphicsContext& context, |
| const LayoutPoint& fragmentOffset, |
| PaintLayerFlags paintFlags, |
| BorderRadiusClippingRule rule, |
| Vector<FloatRoundedRect>& roundedRectClips) { |
| // 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 (PaintLayer* layer = rule == IncludeSelfForBorderRadius |
| ? &paintLayer |
| : paintLayer.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 (layer->needsCompositedScrolling() && |
| !(paintFlags & PaintLayerPaintingChildClippingMaskPhase || |
| paintFlags & PaintLayerPaintingAncestorClippingMaskPhase)) |
| break; |
| |
| if (layer->layoutObject()->hasOverflowClip() && |
| layer->layoutObject()->style()->hasBorderRadius() && |
| inContainingBlockChain(&paintLayer, layer)) { |
| LayoutPoint delta(fragmentOffset); |
| layer->convertToLayerCoords(clipRoot, 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->layoutBox() |
| ? toLayoutBox(layer->layoutObject())->size() |
| : LayoutSize(layer->size())); |
| roundedRectClips.append( |
| layer->layoutObject()->style()->getRoundedInnerBorderFor( |
| LayoutRect(delta, size))); |
| } |
| |
| if (layer == clipRoot) |
| break; |
| } |
| } |
| |
| LayerClipRecorder::~LayerClipRecorder() { |
| m_graphicsContext.getPaintController().endItem<EndClipDisplayItem>( |
| m_layoutObject, DisplayItem::clipTypeToEndClipType(m_clipType)); |
| } |
| |
| } // namespace blink |