blob: 5c2b8267cc71ea8563c129952da2f77964acc59d [file] [log] [blame]
/*
* Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011, 2012 Apple Inc. All rights
* reserved.
*
* Portions are Copyright (C) 1998 Netscape Communications Corporation.
*
* Other contributors:
* Robert O'Callahan <roc+@cs.cmu.edu>
* David Baron <dbaron@fas.harvard.edu>
* Christian Biesinger <cbiesinger@web.de>
* Randall Jesup <rjesup@wgate.com>
* Roland Mainz <roland.mainz@informatik.med.uni-giessen.de>
* Josh Soref <timeless@mac.com>
* Boris Zbarsky <bzbarsky@mit.edu>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*
* Alternatively, the contents of this file may be used under the terms
* of either the Mozilla Public License Version 1.1, found at
* http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
* License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
* (the "GPL"), in which case the provisions of the MPL or the GPL are
* applicable instead of those above. If you wish to allow use of your
* version of this file only under the terms of one of those two
* licenses (the MPL or the GPL) and not to allow others to use your
* version of this file under the LGPL, indicate your decision by
* deletingthe provisions above and replace them with the notice and
* other provisions required by the MPL or the GPL, as the case may be.
* If you do not delete the provisions above, a recipient may use your
* version of this file under any of the LGPL, the MPL or the GPL.
*/
#include "third_party/blink/renderer/core/paint/paint_layer_clipper.h"
#include "third_party/blink/renderer/core/frame/local_frame.h"
#include "third_party/blink/renderer/core/frame/local_frame_view.h"
#include "third_party/blink/renderer/core/frame/settings.h"
#include "third_party/blink/renderer/core/layout/layout_view.h"
#include "third_party/blink/renderer/core/page/scrolling/root_scroller_util.h"
#include "third_party/blink/renderer/core/paint/compositing/compositing_reason_finder.h"
#include "third_party/blink/renderer/core/paint/object_paint_properties.h"
#include "third_party/blink/renderer/core/paint/paint_layer.h"
#include "third_party/blink/renderer/core/paint/paint_layer_scrollable_area.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
namespace blink {
static bool HasOverflowClip(
const PaintLayer& layer) {
if (!layer.GetLayoutObject().IsBox())
return false;
const LayoutBox& box = ToLayoutBox(layer.GetLayoutObject());
return box.ShouldClipOverflow();
}
bool ClipRectsContext::ShouldRespectRootLayerClip() const {
return respect_overflow_clip == kRespectOverflowClip;
}
static void AdjustClipRectsForChildren(
const LayoutBoxModelObject& layout_object,
ClipRects& clip_rects) {
EPosition position = layout_object.StyleRef().GetPosition();
// A fixed object is essentially the root of its containing block hierarchy,
// so when we encounter such an object, we reset our clip rects to the
// fixedClipRect.
if (position == EPosition::kFixed) {
clip_rects.SetPosClipRect(clip_rects.FixedClipRect());
clip_rects.SetOverflowClipRect(clip_rects.FixedClipRect());
clip_rects.SetFixed(true);
} else if (position == EPosition::kRelative) {
clip_rects.SetPosClipRect(clip_rects.OverflowClipRect());
} else if (position == EPosition::kAbsolute) {
clip_rects.SetOverflowClipRect(clip_rects.PosClipRect());
}
}
static void ApplyClipRects(const ClipRectsContext& context,
const LayoutBoxModelObject& layout_object,
LayoutPoint offset,
ClipRects& clip_rects) {
DCHECK(layout_object.IsBox());
const LayoutBox& box = *ToLayoutBox(&layout_object);
DCHECK(box.ShouldClipOverflow() || box.HasClip());
LayoutView* view = box.View();
DCHECK(view);
if (box.ShouldClipOverflow()) {
ClipRect new_overflow_clip =
box.OverflowClipRect(offset, context.overlay_scrollbar_clip_behavior);
new_overflow_clip.SetHasRadius(box.StyleRef().HasBorderRadius());
clip_rects.SetOverflowClipRect(
Intersection(new_overflow_clip, clip_rects.OverflowClipRect()));
if (box.IsPositioned())
clip_rects.SetPosClipRect(
Intersection(new_overflow_clip, clip_rects.PosClipRect()));
if (box.CanContainFixedPositionObjects())
clip_rects.SetFixedClipRect(
Intersection(new_overflow_clip, clip_rects.FixedClipRect()));
if (box.ShouldApplyPaintContainment())
clip_rects.SetPosClipRect(
Intersection(new_overflow_clip, clip_rects.PosClipRect()));
}
if (box.HasClip()) {
LayoutRect new_clip = box.ClipRect(offset);
clip_rects.SetPosClipRect(Intersection(new_clip, clip_rects.PosClipRect()));
clip_rects.SetOverflowClipRect(
Intersection(new_clip, clip_rects.OverflowClipRect()));
clip_rects.SetFixedClipRect(
Intersection(new_clip, clip_rects.FixedClipRect()));
}
}
PaintLayerClipper::PaintLayerClipper(const PaintLayer& layer,
bool usegeometry_mapper)
: layer_(layer), use_geometry_mapper_(usegeometry_mapper) {}
ClipRects* PaintLayerClipper::ClipRectsIfCached(
const ClipRectsContext& context) const {
DCHECK(context.UsesCache());
if (!layer_.GetClipRectsCache())
return nullptr;
ClipRectsCache::Entry& entry =
layer_.GetClipRectsCache()->Get(context.CacheSlot());
// FIXME: We used to ASSERT that we always got a consistent root layer.
// We should add a test that has an inconsistent root. See
// http://crbug.com/366118 for an example.
if (context.root_layer != entry.root)
return nullptr;
#if DCHECK_IS_ON()
DCHECK(entry.overlay_scrollbar_clip_behavior ==
context.overlay_scrollbar_clip_behavior);
#endif
return entry.clip_rects.get();
}
ClipRects& PaintLayerClipper::StoreClipRectsInCache(
const ClipRectsContext& context,
ClipRects* parent_clip_rects,
const ClipRects& clip_rects) const {
ClipRectsCache::Entry& entry =
layer_.EnsureClipRectsCache().Get(context.CacheSlot());
entry.root = context.root_layer;
#if DCHECK_IS_ON()
entry.overlay_scrollbar_clip_behavior =
context.overlay_scrollbar_clip_behavior;
#endif
if (parent_clip_rects) {
// If our clip rects match the clip rects of our parent, we share storage.
if (clip_rects == *parent_clip_rects) {
entry.clip_rects = parent_clip_rects;
return *parent_clip_rects;
}
}
entry.clip_rects = ClipRects::Create(clip_rects);
return *entry.clip_rects;
}
ClipRects& PaintLayerClipper::GetClipRects(
const ClipRectsContext& context) const {
DCHECK(!use_geometry_mapper_);
if (ClipRects* result = ClipRectsIfCached(context))
return *result;
// Note that it's important that we call getClipRects on our parent
// before we call calculateClipRects so that calculateClipRects will hit
// the cache.
ClipRects* parent_clip_rects = nullptr;
if (context.root_layer != &layer_ && layer_.Parent()) {
parent_clip_rects =
&PaintLayerClipper(*layer_.Parent(), false).GetClipRects(context);
}
scoped_refptr<ClipRects> clip_rects = ClipRects::Create();
CalculateClipRects(context, *clip_rects);
return StoreClipRectsInCache(context, parent_clip_rects, *clip_rects);
}
void PaintLayerClipper::ClearCache(ClipRectsCacheSlot cache_slot) {
if (cache_slot == kNumberOfClipRectsCacheSlots)
layer_.ClearClipRectsCache();
else if (ClipRectsCache* cache = layer_.GetClipRectsCache())
cache->Clear(cache_slot);
}
void PaintLayerClipper::ClearClipRectsIncludingDescendants() {
ClearClipRectsIncludingDescendants(kNumberOfClipRectsCacheSlots);
}
void PaintLayerClipper::ClearClipRectsIncludingDescendants(
ClipRectsCacheSlot cache_slot) {
std::stack<const PaintLayer*> layers;
layers.push(&layer_);
while (!layers.empty()) {
const PaintLayer* current_layer = layers.top();
layers.pop();
PaintLayerClipper(*current_layer, use_geometry_mapper_)
.ClearCache(cache_slot);
for (const PaintLayer* layer = current_layer->FirstChild(); layer;
layer = layer->NextSibling())
layers.push(layer);
}
}
LayoutRect PaintLayerClipper::LocalClipRect(
const PaintLayer& clipping_root_layer) const {
ClipRectsContext context(
&clipping_root_layer,
&clipping_root_layer.GetLayoutObject().FirstFragment(),
kPaintingClipRects);
if (use_geometry_mapper_) {
ClipRect clip_rect;
CalculateBackgroundClipRectWithGeometryMapper(
context, layer_.GetLayoutObject().FirstFragment(), kRespectOverflowClip,
clip_rect);
if (clip_rect.IsInfinite())
return clip_rect.Rect();
LayoutRect premapped_rect = clip_rect.Rect();
// The rect now needs to be transformed to the local space of this
// PaintLayer.
// TODO(chrishtr): not correct for fragmentation.
premapped_rect.MoveBy(context.root_fragment->PaintOffset());
const auto* clip_root_layer_transform =
context.root_fragment->LocalBorderBoxProperties().Transform();
const auto* layer_transform = layer_.GetLayoutObject()
.FirstFragment()
.LocalBorderBoxProperties()
.Transform();
FloatRect clipped_rect_in_local_space(premapped_rect);
GeometryMapper::SourceToDestinationRect(clip_root_layer_transform,
layer_transform,
clipped_rect_in_local_space);
// TODO(chrishtr): not correct for fragmentation.
clipped_rect_in_local_space.MoveBy(
-FloatPoint(layer_.GetLayoutObject().FirstFragment().PaintOffset()));
return LayoutRect(clipped_rect_in_local_space);
}
LayoutRect layer_bounds;
ClipRect background_rect, foreground_rect;
CalculateRects(context, nullptr, nullptr, layer_bounds, background_rect,
foreground_rect);
if (background_rect.IsInfinite())
return background_rect.Rect();
LayoutRect clip_rect = background_rect.Rect();
LayoutPoint clipping_root_offset;
layer_.ConvertToLayerCoords(&clipping_root_layer, clipping_root_offset);
clip_rect.MoveBy(-clipping_root_offset);
return clip_rect;
}
void PaintLayerClipper::CalculateRectsWithGeometryMapper(
const ClipRectsContext& context,
const FragmentData& fragment_data,
const CullRect* cull_rect,
LayoutRect& layer_bounds,
ClipRect& background_rect,
ClipRect& foreground_rect,
const LayoutPoint* offset_from_root) const {
layer_bounds.SetSize(LayoutSize(layer_.PixelSnappedSize()));
if (offset_from_root) {
layer_bounds.SetLocation(*offset_from_root);
} else {
layer_bounds.SetLocation(LayoutPoint(context.sub_pixel_accumulation));
if (&layer_ == context.root_layer) {
DCHECK_EQ(&fragment_data, context.root_fragment);
} else {
layer_bounds.MoveBy(fragment_data.PaintOffset());
GeometryMapper::SourceToDestinationRect(
fragment_data.PreTransform(),
context.root_fragment->LocalBorderBoxProperties().Transform(),
layer_bounds);
layer_bounds.MoveBy(-context.root_fragment->PaintOffset());
}
}
CalculateBackgroundClipRectWithGeometryMapper(
context, fragment_data, kRespectOverflowClip, background_rect);
foreground_rect.Reset();
if (cull_rect)
background_rect.Intersect(LayoutRect(cull_rect->Rect()));
if (ShouldClipOverflow(context)) {
LayoutBoxModelObject& layout_object = layer_.GetLayoutObject();
foreground_rect =
ToLayoutBox(layout_object)
.OverflowClipRect(layer_bounds.Location(),
context.overlay_scrollbar_clip_behavior);
if (layout_object.StyleRef().HasBorderRadius())
foreground_rect.SetHasRadius(true);
foreground_rect.Intersect(background_rect);
} else {
foreground_rect = background_rect;
}
}
void PaintLayerClipper::CalculateRects(
const ClipRectsContext& context,
const FragmentData* fragment_data,
const CullRect* cull_rect,
LayoutRect& layer_bounds,
ClipRect& background_rect,
ClipRect& foreground_rect,
const LayoutPoint* offset_from_root) const {
// This feature is not supported for this method.
DCHECK(context.respect_overflow_clip != kIgnoreOverflowClipAndScroll);
if (use_geometry_mapper_) {
DCHECK(fragment_data);
DCHECK(fragment_data->HasLocalBorderBoxProperties());
// TODO(chrishtr): find the root cause of not having a fragment and fix it.
if (!fragment_data->HasLocalBorderBoxProperties())
return;
CalculateRectsWithGeometryMapper(context, *fragment_data, cull_rect,
layer_bounds, background_rect,
foreground_rect, offset_from_root);
return;
}
DCHECK(!fragment_data);
bool is_clipping_root = &layer_ == context.root_layer;
LayoutBoxModelObject& layout_object = layer_.GetLayoutObject();
if (!is_clipping_root && layer_.Parent()) {
CalculateBackgroundClipRect(context, background_rect);
background_rect.Move(context.sub_pixel_accumulation);
}
if (cull_rect)
background_rect.Intersect(LayoutRect(cull_rect->Rect()));
foreground_rect = background_rect;
LayoutPoint offset(context.sub_pixel_accumulation);
if (offset_from_root)
offset = *offset_from_root;
else
layer_.ConvertToLayerCoords(context.root_layer, offset);
layer_bounds = LayoutRect(offset, LayoutSize(layer_.PixelSnappedSize()));
// Update the clip rects that will be passed to child layers.
if (ShouldClipOverflow(context)) {
LayoutRect overflow_and_clip_rect =
ToLayoutBox(layout_object)
.OverflowClipRect(offset, context.overlay_scrollbar_clip_behavior);
foreground_rect.Intersect(overflow_and_clip_rect);
if (layout_object.StyleRef().HasBorderRadius())
foreground_rect.SetHasRadius(true);
// FIXME: Does not do the right thing with columns yet, since we don't yet
// factor in the individual column boxes as overflow.
LayoutRect layer_bounds_with_visual_overflow = LocalVisualRect(context);
layer_bounds_with_visual_overflow.MoveBy(offset);
background_rect.Intersect(layer_bounds_with_visual_overflow);
}
// CSS clip (different than clipping due to overflow) can clip to any box,
// even if it falls outside of the border box.
if (layout_object.HasClip()) {
// Clip applies to *us* as well, so go ahead and update the damageRect.
LayoutRect new_pos_clip = ToLayoutBox(layout_object).ClipRect(offset);
background_rect.Intersect(new_pos_clip);
foreground_rect.Intersect(new_pos_clip);
}
}
void PaintLayerClipper::CalculateClipRects(const ClipRectsContext& context,
ClipRects& clip_rects) const {
const LayoutBoxModelObject& layout_object = layer_.GetLayoutObject();
bool is_clipping_root = &layer_ == context.root_layer;
if (is_clipping_root && !context.ShouldRespectRootLayerClip()) {
clip_rects.Reset(LayoutRect(LayoutRect::InfiniteIntRect()));
if (layout_object.StyleRef().GetPosition() == EPosition::kFixed)
clip_rects.SetFixed(true);
return;
}
// For transformed layers, the root layer was shifted to be us, so there is no
// need to examine the parent. We want to cache clip rects with us as the
// root.
PaintLayer* parent_layer = !is_clipping_root ? layer_.Parent() : nullptr;
// Ensure that our parent's clip has been calculated so that we can examine
// the values.
if (parent_layer) {
PaintLayerClipper(*parent_layer, use_geometry_mapper_)
.GetOrCalculateClipRects(context, clip_rects);
} else {
clip_rects.Reset(LayoutRect(LayoutRect::InfiniteIntRect()));
}
AdjustClipRectsForChildren(layout_object, clip_rects);
// Computing paint offset is expensive, skip the computation if the object
// is known to have no clip. This check is redundant otherwise.
if (HasOverflowClip(layer_) || layout_object.HasClip()) {
// This offset cannot use convertToLayerCoords, because sometimes our
// rootLayer may be across some transformed layer boundary, for example, in
// the PaintLayerCompositor overlapMap, where clipRects are needed in view
// space.
LayoutPoint offset(layout_object.LocalToAncestorPoint(
FloatPoint(), &context.root_layer->GetLayoutObject()));
if (context.respect_overflow_clip == kIgnoreOverflowClipAndScroll &&
context.root_layer->GetScrollableArea() &&
layer_.IsAffectedByScrollOf(context.root_layer)) {
offset.Move(LayoutSize(
context.root_layer->GetScrollableArea()->GetScrollOffset()));
}
ApplyClipRects(context, layout_object, offset, clip_rects);
}
}
static ClipRect BackgroundClipRectForPosition(const ClipRects& parent_rects,
EPosition position) {
if (position == EPosition::kFixed)
return parent_rects.FixedClipRect();
if (position == EPosition::kAbsolute)
return parent_rects.PosClipRect();
return parent_rects.OverflowClipRect();
}
void PaintLayerClipper::CalculateBackgroundClipRectWithGeometryMapper(
const ClipRectsContext& context,
const FragmentData& fragment_data,
ShouldRespectOverflowClipType should_apply_self_overflow_clip,
ClipRect& output) const {
DCHECK(use_geometry_mapper_);
output.Reset();
bool is_clipping_root = &layer_ == context.root_layer;
if (is_clipping_root && !context.ShouldRespectRootLayerClip())
return;
PropertyTreeState source_property_tree_state(nullptr, nullptr, nullptr);
PropertyTreeState destination_property_tree_state(nullptr, nullptr, nullptr);
InitializeCommonClipRectState(context, fragment_data,
source_property_tree_state,
destination_property_tree_state);
// The background rect applies all clips *above* m_layer, but not the overflow
// clip of m_layer. It also applies a clip to the total painting bounds
// of m_layer, because nothing in m_layer or its children within the clip can
// paint outside of those bounds.
// The total painting bounds includes any visual overflow (such as shadow) and
// filter bounds.
//
// TODO(chrishtr): sourceToDestinationVisualRect and
// sourceToDestinationClipRect may not compute tight results in the presence
// of transforms. Tight results are required for most use cases of these
// rects, so we should add methods to GeometryMapper that guarantee there
// are tight results, or else signal an error.
if ((should_apply_self_overflow_clip == kRespectOverflowClip) &&
HasOverflowClip(layer_)) {
// Implement the following special case: if computing clip rects with
// respect to the root, don't exclude overlay scrollbars for the background
// rect if layer_ is the same as the root.
OverlayScrollbarClipBehavior clip_behavior =
context.overlay_scrollbar_clip_behavior;
if (is_clipping_root)
clip_behavior = kIgnorePlatformOverlayScrollbarSize;
FloatClipRect clip_rect(FloatRect(LocalVisualRect(context)));
clip_rect.MoveBy(FloatPoint(fragment_data.PaintOffset()));
GeometryMapper::LocalToAncestorVisualRect(source_property_tree_state,
destination_property_tree_state,
clip_rect, clip_behavior);
output.SetRect(clip_rect);
} else if (source_property_tree_state.Clip() !=
destination_property_tree_state.Clip()) {
const FloatClipRect& clipped_rect_in_root_layer_space =
GeometryMapper::LocalToAncestorClipRect(
source_property_tree_state, destination_property_tree_state,
context.overlay_scrollbar_clip_behavior);
output.SetRect(clipped_rect_in_root_layer_space);
}
if (!output.IsInfinite()) {
// TODO(chrishtr): generalize to multiple fragments.
output.MoveBy(-context.root_fragment->PaintOffset());
output.Move(context.sub_pixel_accumulation);
}
}
void PaintLayerClipper::InitializeCommonClipRectState(
const ClipRectsContext& context,
const FragmentData& fragment_data,
PropertyTreeState& source_property_tree_state,
PropertyTreeState& destination_property_tree_state) const {
DCHECK(use_geometry_mapper_);
DCHECK(fragment_data.HasLocalBorderBoxProperties());
source_property_tree_state = fragment_data.LocalBorderBoxProperties();
DCHECK(context.root_fragment->HasLocalBorderBoxProperties());
destination_property_tree_state =
context.root_fragment->LocalBorderBoxProperties();
if (context.ShouldRespectRootLayerClip()) {
destination_property_tree_state.SetClip(context.root_fragment->PreClip());
} else {
destination_property_tree_state.SetClip(
context.root_fragment->PostOverflowClip());
}
}
LayoutRect PaintLayerClipper::LocalVisualRect(
const ClipRectsContext& context) const {
const LayoutObject& layout_object = layer_.GetLayoutObject();
// The LayoutView or Global Root Scroller is special since its overflow
// clipping rect may be larger than its box rect (crbug.com/492871).
bool affected_by_url_bar = layout_object.IsGlobalRootScroller();
LayoutRect layer_bounds_with_visual_overflow =
affected_by_url_bar ? layout_object.View()->ViewRect()
: ToLayoutBox(layout_object).VisualOverflowRect();
ToLayoutBox(layout_object)
.FlipForWritingMode(
// PaintLayer are in physical coordinates, so the overflow has to be
// flipped.
layer_bounds_with_visual_overflow);
// At this point layer_bounds_with_visual_overflow only includes the visual
// overflow induced by paint, prior to applying filters. This function is
// expected the return the final visual rect after filtering.
if (layer_.PaintsWithFilters() &&
// If we use GeometryMapper to map to an ancestor layer, GeometryMapper
// will handle filter effects.
(!use_geometry_mapper_ || context.root_layer == &layer_)) {
layer_bounds_with_visual_overflow =
layer_.MapLayoutRectForFilter(layer_bounds_with_visual_overflow);
}
return layer_bounds_with_visual_overflow;
}
void PaintLayerClipper::CalculateBackgroundClipRect(
const ClipRectsContext& context,
ClipRect& output) const {
if (use_geometry_mapper_) {
const auto& fragment_data = layer_.GetLayoutObject().FirstFragment();
DCHECK(fragment_data.HasLocalBorderBoxProperties());
// TODO(chrishtr): find the root cause of not having a fragment and fix it.
if (!fragment_data.HasLocalBorderBoxProperties())
return;
CalculateBackgroundClipRectWithGeometryMapper(context, fragment_data,
kIgnoreOverflowClip, output);
return;
}
DCHECK(layer_.Parent());
LayoutView* layout_view = layer_.GetLayoutObject().View();
DCHECK(layout_view);
scoped_refptr<ClipRects> parent_clip_rects = ClipRects::Create();
if (&layer_ == context.root_layer) {
parent_clip_rects->Reset(LayoutRect(LayoutRect::InfiniteIntRect()));
} else {
PaintLayerClipper(*layer_.Parent(), use_geometry_mapper_)
.GetOrCalculateClipRects(context, *parent_clip_rects);
}
output = BackgroundClipRectForPosition(
*parent_clip_rects, layer_.GetLayoutObject().StyleRef().GetPosition());
output.Move(context.sub_pixel_accumulation);
// Note: infinite clipRects should not be scrolled here, otherwise they will
// accidentally no longer be considered infinite.
if (parent_clip_rects->Fixed() &&
&context.root_layer->GetLayoutObject() == layout_view &&
output != LayoutRect(LayoutRect::InfiniteIntRect()))
output.Move(LayoutSize(layout_view->OffsetForFixedPosition()));
}
void PaintLayerClipper::GetOrCalculateClipRects(const ClipRectsContext& context,
ClipRects& clip_rects) const {
DCHECK(!use_geometry_mapper_);
if (context.UsesCache())
clip_rects = GetClipRects(context);
else
CalculateClipRects(context, clip_rects);
}
bool PaintLayerClipper::ShouldClipOverflow(
const ClipRectsContext& context) const {
if (&layer_ == context.root_layer && !context.ShouldRespectRootLayerClip())
return false;
// Embedded objects with border radius need to compute clip rects when
// painting child mask layers. We do not have access to paint phases here,
// so always claim to clip and ignore it later when painting the foreground
// phases.
return HasOverflowClip(layer_) ||
(layer_.GetLayoutObject().IsLayoutEmbeddedContent() &&
layer_.GetLayoutObject().StyleRef().HasBorderRadius());
}
} // namespace blink