blob: 3d85217b81a1340f8fb9dac6d3d884ab67248c9f [file] [log] [blame]
// 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