Revert "Reworks the clipping logic" and follow-up.

This change reverts commit
f5bd7257166f313f8bed1ceffa2802e6540b53da and
25907d23a2b4a963c879fb44c18ed05ad388f00e.

The change has been the cause of numerous regressions
(painting and hit-testing clip rects wrongly computed)
and several performance regressions.

Reverting the change so that I can investigate offline
and reland in a smaller bits.

BUG=518215,521452,522829,518219

Review URL: https://codereview.chromium.org/1307203004

git-svn-id: svn://svn.chromium.org/blink/trunk@201739 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent d9dad42c
......@@ -2480,14 +2480,6 @@ void FrameView::updateLifecyclePhasesInternal(LifeCycleUpdateOption phases)
|| (RuntimeEnabledFeatures::slimmingPaintV2Enabled() && lifecycle().state() == DocumentLifecycle::CompositingForSlimmingPaintV2Clean));
}
}
#ifndef NDEBUG
// TODO(jchaffraix): We will want to clear the clip rects in release too
// to reduce our long-term memory consumption. However this requires us
// to migrate all of the clip rects to the state machine and evaluate
// the performance impacts of this.
layoutView()->layer()->clipper().clearClipRectsIncludingDescendants(AbsoluteClipRects);
#endif
}
void FrameView::paintForSlimmingPaintV2()
......
......@@ -28,21 +28,14 @@
#include "platform/geometry/LayoutRect.h"
#include "wtf/FastAllocBase.h"
#include "wtf/PassOwnPtr.h"
namespace blink {
class DeprecatedPaintLayer;
class HitTestLocation;
class ClipRect {
WTF_MAKE_FAST_ALLOCATED(ClipRect);
public:
static PassOwnPtr<ClipRect> create(const ClipRect& other)
{
return adoptPtr(new ClipRect(other));
}
ClipRect()
: m_hasRadius(false)
{ }
......@@ -75,18 +68,7 @@ public:
bool isEmpty() const { return m_rect.isEmpty(); }
bool intersects(const HitTestLocation&) const;
const DeprecatedPaintLayer* rootLayer() const
{
return m_rootLayer;
}
void setRootLayer(const DeprecatedPaintLayer* rootLayer)
{
m_rootLayer = rootLayer;
}
private:
const DeprecatedPaintLayer* m_rootLayer;
LayoutRect m_rect;
bool m_hasRadius;
};
......
......@@ -31,15 +31,20 @@
namespace blink {
class DeprecatedPaintLayer;
class ClipRects {
class ClipRects : public RefCounted<ClipRects> {
WTF_MAKE_FAST_ALLOCATED(ClipRects);
public:
static PassRefPtr<ClipRects> create()
{
return adoptRef(new ClipRects);
}
static PassRefPtr<ClipRects> create(const ClipRects& other)
{
return adoptRef(new ClipRects(other));
}
ClipRects()
: m_rootLayer(nullptr)
, m_fixed(0)
: m_fixed(0)
{
}
......@@ -77,24 +82,12 @@ public:
m_fixedClipRect = other.fixedClipRect();
m_posClipRect = other.posClipRect();
m_fixed = other.fixed();
m_rootLayer = other.m_rootLayer;
return *this;
}
void setRootLayer(const DeprecatedPaintLayer* layer)
{
m_rootLayer = layer;
}
const DeprecatedPaintLayer* rootLayer()
{
return m_rootLayer;
}
private:
ClipRects(const LayoutRect& r)
: m_rootLayer(nullptr)
, m_overflowClipRect(r)
: m_overflowClipRect(r)
, m_fixedClipRect(r)
, m_posClipRect(r)
, m_fixed(0)
......@@ -102,18 +95,13 @@ private:
}
ClipRects(const ClipRects& other)
: m_rootLayer(other.m_rootLayer)
, m_overflowClipRect(other.overflowClipRect())
: m_overflowClipRect(other.overflowClipRect())
, m_fixedClipRect(other.fixedClipRect())
, m_posClipRect(other.posClipRect())
, m_fixed(other.fixed())
{
}
// ClipRects are accumulated relative to this layer. Its clips and the clips
// of its descendents are intersected down to the layer being calculated. It
// also determines the coordinate space of the clips.
const DeprecatedPaintLayer* m_rootLayer;
ClipRect m_overflowClipRect;
ClipRect m_fixedClipRect;
ClipRect m_posClipRect;
......
......@@ -15,14 +15,12 @@ namespace blink {
class DeprecatedPaintLayer;
// TODO: Because this is mostly empty, this should be moved to a better place
enum ClipRectsCacheSlot {
// Relative to the ancestor treated as the root (e.g. transformed layer). Used for hit testing.
RootRelativeClipRects,
RootRelativeClipRectsIgnoringViewportClip,
// Relative to the LayoutView's layer. Used for compositing overlap testing.
// Computed during the compositing update step (see CompositingInputsUpdater::update).
AbsoluteClipRects,
// Relative to painting ancestor. Used for painting.
......@@ -33,6 +31,37 @@ enum ClipRectsCacheSlot {
UncachedClipRects,
};
class ClipRectsCache {
WTF_MAKE_FAST_ALLOCATED(ClipRectsCache);
public:
struct Entry {
Entry()
: root(nullptr)
#if ENABLE(ASSERT)
, scrollbarRelevancy(IgnoreOverlayScrollbarSize)
#endif
{
}
const DeprecatedPaintLayer* root;
RefPtr<ClipRects> clipRects;
#if ENABLE(ASSERT)
OverlayScrollbarSizeRelevancy scrollbarRelevancy;
#endif
};
Entry& get(ClipRectsCacheSlot slot)
{
ASSERT(slot < NumberOfClipRectsCacheSlots);
return m_entries[slot];
}
void clear(ClipRectsCacheSlot slot)
{
ASSERT(slot < NumberOfClipRectsCacheSlots);
m_entries[slot] = Entry();
}
private:
Entry m_entries[NumberOfClipRectsCacheSlots];
};
} // namespace blink
#endif // ClipRectsCache_h
......@@ -26,7 +26,6 @@ CompositingInputsUpdater::~CompositingInputsUpdater()
void CompositingInputsUpdater::update()
{
TRACE_EVENT0("blink", "CompositingInputsUpdater::update");
m_rootLayer->clipper().precalculateAbsoluteClipRects();
updateRecursive(m_rootLayer, DoNotForceUpdate, AncestorInfo());
}
......
......@@ -376,6 +376,8 @@ void DeprecatedPaintLayer::updateTransform(const ComputedStyle* oldStyle, const
// DeprecatedPaintLayers with transforms act as clip rects roots, so clear the cached clip rects here.
m_clipper.clearClipRectsIncludingDescendants();
} else if (hasTransform) {
m_clipper.clearClipRectsIncludingDescendants(AbsoluteClipRects);
}
updateTransformationMatrix();
......@@ -1400,10 +1402,7 @@ void DeprecatedPaintLayer::collectFragments(DeprecatedPaintLayerFragments& fragm
// Calculate clip rects relative to the enclosingPaginationLayer. The purpose of this call is to determine our bounds clipped to intermediate
// layers between us and the pagination context. It's important to minimize the number of fragments we need to create and this helps with that.
// This code uses a non-standard root layer, which can populate our cache with unexpected values.
// Thus we bypass the clip rect cache by ignoring |clipRectsCacheSlot| and passing UncachedClipRects.
// TODO(chadarmstrong): If possible, this code should use the cache (one way would be by computing the root layer relative to |clipRectsCacheSlot|).
ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), UncachedClipRects, inOverlayScrollbarSizeRelevancy);
ClipRectsContext paginationClipRectsContext(enclosingPaginationLayer(), clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
if (respectOverflowClip == IgnoreOverflowClip)
paginationClipRectsContext.setIgnoreOverflowClip();
LayoutRect layerBoundsInFlowThread;
......@@ -1442,10 +1441,7 @@ void DeprecatedPaintLayer::collectFragments(DeprecatedPaintLayerFragments& fragm
ClipRect ancestorClipRect = dirtyRect;
if (const DeprecatedPaintLayer* paginationParentLayer = enclosingPaginationLayer()->parent()) {
const DeprecatedPaintLayer* ancestorLayer = rootLayerIsInsidePaginationLayer ? paginationParentLayer : rootLayer;
// This code uses a non-standard root layer, which can populate our cache with unexpected values.
// Thus we bypass the clip rect cache by ignoring |clipRectsCacheSlot| and passing UncachedClipRects.
// TODO(chadarmstrong): If possible, this code should use the cache (one way would be by computing the root layer relative to |clipRectsCacheSlot|).
ClipRectsContext clipRectsContext(ancestorLayer, UncachedClipRects, inOverlayScrollbarSizeRelevancy);
ClipRectsContext clipRectsContext(ancestorLayer, clipRectsCacheSlot, inOverlayScrollbarSizeRelevancy);
if (respectOverflowClip == IgnoreOverflowClip)
clipRectsContext.setIgnoreOverflowClip();
ancestorClipRect = enclosingPaginationLayer()->clipper().backgroundClipRect(clipRectsContext);
......
......@@ -50,24 +50,119 @@
namespace blink {
static void adjustClipRectsForChildren(const LayoutObject& layoutObject, ClipRects& clipRects)
{
EPosition position = layoutObject.style()->position();
// 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 == FixedPosition) {
clipRects.setPosClipRect(clipRects.fixedClipRect());
clipRects.setOverflowClipRect(clipRects.fixedClipRect());
clipRects.setFixed(true);
} else if (position == RelativePosition) {
clipRects.setPosClipRect(clipRects.overflowClipRect());
} else if (position == AbsolutePosition) {
clipRects.setOverflowClipRect(clipRects.posClipRect());
}
}
static void applyClipRects(const ClipRectsContext& context, LayoutObject& layoutObject, LayoutPoint offset, ClipRects& clipRects)
{
ASSERT(layoutObject.hasOverflowClip() || layoutObject.hasClip());
LayoutView* view = layoutObject.view();
ASSERT(view);
if (clipRects.fixed() && context.rootLayer->layoutObject() == view)
offset -= toIntSize(view->frameView()->scrollPosition());
if (layoutObject.hasOverflowClip()) {
ClipRect newOverflowClip = toLayoutBox(layoutObject).overflowClipRect(offset, context.scrollbarRelevancy);
newOverflowClip.setHasRadius(layoutObject.style()->hasBorderRadius());
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
if (layoutObject.isPositioned())
clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
if (layoutObject.isLayoutView())
clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect()));
}
if (layoutObject.hasClip()) {
LayoutRect newClip = toLayoutBox(layoutObject).clipRect(offset);
clipRects.setPosClipRect(intersection(newClip, clipRects.posClipRect()));
clipRects.setOverflowClipRect(intersection(newClip, clipRects.overflowClipRect()));
clipRects.setFixedClipRect(intersection(newClip, clipRects.fixedClipRect()));
}
}
DeprecatedPaintLayerClipper::DeprecatedPaintLayerClipper(LayoutBoxModelObject& layoutObject)
: m_layoutObject(layoutObject)
{
}
ClipRects* DeprecatedPaintLayerClipper::clipRectsIfCached(const ClipRectsContext& context) const
{
ASSERT(context.usesCache());
if (!m_cache)
return 0;
ClipRectsCache::Entry& entry = m_cache->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.rootLayer != entry.root)
return 0;
ASSERT(entry.scrollbarRelevancy == context.scrollbarRelevancy);
#ifdef CHECK_CACHED_CLIP_RECTS
// This code is useful to check cached clip rects, but is too expensive to leave enabled in debug builds by default.
ClipRectsContext tempContext(context);
tempContext.cacheSlot = UncachedClipRects;
RefPtr<ClipRects> clipRects = ClipRects::create();
calculateClipRects(tempContext, *clipRects);
ASSERT(clipRects == *entry.clipRects);
#endif
return entry.clipRects.get();
}
ClipRects* DeprecatedPaintLayerClipper::storeClipRectsInCache(const ClipRectsContext& context, ClipRects* parentClipRects, const ClipRects& clipRects) const
{
ClipRectsCache::Entry& entry = cache().get(context.cacheSlot());
entry.root = context.rootLayer;
#if ENABLE(ASSERT)
entry.scrollbarRelevancy = context.scrollbarRelevancy;
#endif
if (parentClipRects) {
// If our clip rects match the clip rects of our parent, we share storage.
if (clipRects == *parentClipRects) {
entry.clipRects = parentClipRects;
return parentClipRects;
}
}
entry.clipRects = ClipRects::create(clipRects);
return entry.clipRects.get();
}
ClipRects* DeprecatedPaintLayerClipper::getClipRects(const ClipRectsContext& context) const
{
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* parentClipRects = 0;
if (context.rootLayer != m_layoutObject.layer() && m_layoutObject.layer()->parent())
parentClipRects = m_layoutObject.layer()->parent()->clipper().getClipRects(context);
RefPtr<ClipRects> clipRects = ClipRects::create();
calculateClipRects(context, *clipRects);
return storeClipRectsInCache(context, parentClipRects, *clipRects);
}
void DeprecatedPaintLayerClipper::clearClipRectsIncludingDescendants()
{
m_cache = nullptr;
for (DeprecatedPaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) {
for (int i = 0; i < NumberOfClipRectsCacheSlots; i++)
layer->clipper().m_clips[i] = nullptr;
layer->clipper().clearClipRectsIncludingDescendants();
}
}
void DeprecatedPaintLayerClipper::clearClipRectsIncludingDescendants(ClipRectsCacheSlot cacheSlot)
{
if (m_cache)
m_cache->clear(cacheSlot);
for (DeprecatedPaintLayer* layer = m_layoutObject.layer()->firstChild(); layer; layer = layer->nextSibling()) {
layer->clipper().m_clips[cacheSlot] = nullptr;
layer->clipper().clearClipRectsIncludingDescendants(cacheSlot);
}
}
......@@ -170,260 +265,81 @@ void DeprecatedPaintLayerClipper::calculateRects(const ClipRectsContext& context
}
}
void precalculate(const ClipRectsContext& context)
void DeprecatedPaintLayerClipper::calculateClipRects(const ClipRectsContext& context, ClipRects& clipRects) const
{
bool isComputingPaintingRect = context.isComputingPaintingRect();
ClipRectComputationState rects;
const DeprecatedPaintLayer* rootLayer = context.rootLayer;
if (isComputingPaintingRect) {
// Starting arbitrarily in the tree when calculating painting clipRects will
// not allow you to fill in all layers cache because some intermediate layer
// may need clips with respect to an ancestor further up. For efficiency we
// start at the top in order to fill in the cache for all layers.
rootLayer = context.rootLayer->layoutObject()->view()->layer();
rects.stackingContextClipRects.setRootLayer(rootLayer);
}
rects.currentClipRects.setRootLayer(rootLayer);
rootLayer->clipper().calculateClipRects(context, rects);
}
void DeprecatedPaintLayerClipper::precalculateAbsoluteClipRects()
{
ASSERT(m_layoutObject.layer()->isRootLayer());
// The absolute rectangles rely on layout sizes and position only.
ASSERT(m_layoutObject.document().lifecycle().state() >= DocumentLifecycle::LayoutClean);
precalculate(ClipRectsContext(m_layoutObject.layer(), AbsoluteClipRects));
}
// Calculates clipRect for each element in the section of the tree starting with context.rootLayer
// For painting, context.rootLayer is ignored and the entire tree is calculated.
// TODO(chadarmstrong): When using the cache context shouldn't be able to specify the rootLayer. This affects
// what is stored in the 5 caches, and should therefore be enforced internally. Currently
// different callers have different ideas of what the rootLayer should be for a particular
// cacheSlot, which can fill the cache with bad data. If this can be made consistent it should
// be possible to eliminate rootLayer.
ClipRect DeprecatedPaintLayerClipper::backgroundClipRect(const ClipRectsContext& context) const
{
ASSERT(m_layoutObject.layer()->parent());
ASSERT(m_layoutObject.view());
// Ideally backgroundClipRect would not be called with itself as the rootLayer.
// This behavior can be seen in the following test
// LayoutTests/compositing/squashing/abspos-under-abspos-overflow-scroll.html
if (m_layoutObject.layer() == context.rootLayer)
return LayoutRect(LayoutRect::infiniteIntRect());
// TODO(chadarmstrong): If possible, all queries should use one of the clipRectsCacheSlots.
// Without caching this operation involves walking all the way to rootLayer.
if (!context.usesCache())
return uncachedBackgroundClipRect(context);
// TODO(chadarmstrong): precalculation for painting should be moved to updateLifecyclePhasesInternal
// and precalculation could be done for all hit testing. This would let us avoid clearing the cache
if (!m_clips[context.cacheSlot()]) {
// AbsoluteClipRects should have been updated during compositing updates so we shouldn't miss here.
ASSERT(context.cacheSlot() != AbsoluteClipRects);
precalculate(context);
bool rootLayerScrolls = m_layoutObject.document().settings() && m_layoutObject.document().settings()->rootLayerScrolls();
if (!m_layoutObject.layer()->parent() && !rootLayerScrolls) {
// The root layer's clip rect is always infinite.
clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
return;
}
// TODO(chadarmstrong): eliminate this if possible.
// It is necessary only because of a seemingly atypical use of rootLayer that
// can be seen in LayoutTests/fullscreen/full-screen-line-boxes-crash.html and
// fast/block/multicol-paint-invalidation-assert.html.
if (!m_clips[context.cacheSlot()])
return uncachedBackgroundClipRect(context);
// As soon as crbug.com/517173 is resolved this assert should be enabled in place of the check
// ASSERT(m_clips[context.cacheSlot()]->rootLayer() == context.rootLayer);
if (m_clips[context.cacheSlot()]->rootLayer() != context.rootLayer)
return uncachedBackgroundClipRect(context);
return *m_clips[context.cacheSlot()];
}
static bool shouldStopClipRectCalculation(LayoutBoxModelObject& layoutObject, const ClipRectsContext& context)
{
// The entire tree is calculated for both painting and absolutClipRects
if (context.cacheSlot() == PaintingClipRectsIgnoringOverflowClip || context.cacheSlot() == PaintingClipRects || context.cacheSlot() == AbsoluteClipRects)
return false;
DeprecatedPaintLayer* layer = layoutObject.layer();
return layer->transform() || layer == layer->enclosingPaginationLayer();
}
bool isClippingRoot = m_layoutObject.layer() == context.rootLayer;
// Updates clipRects so that descendants can calculate
// clipping relative to different root layers.
static void resetPaintRects(LayoutBoxModelObject& layoutObject, ClipRectComputationState& rects, ClipRectsCacheSlot slot)
{
const DeprecatedPaintLayer* layer = layoutObject.layer();
if (layer->isPaintInvalidationContainer() || layer->transform()) {
// If this element is hardware accelerated, we let the compositor handle the
// clipping (in case we want to paint bigger than a scrollable area for smooth
// scrolling) so we reset the clip rects.
// If the element has a transform, the clip rect could become a quad so we
// reset the layer and let the paint code apply the CTM during paint to
// transform the clip during paint.
rects.currentClipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
rects.currentClipRects.setRootLayer(layoutObject.layer());
rects.currentClipRects.setFixed(false);
// 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.
DeprecatedPaintLayer* parentLayer = !isClippingRoot ? m_layoutObject.layer()->parent() : 0;
// Ensure that our parent's clip has been calculated so that we can examine the values.
if (parentLayer) {
// FIXME: Why don't we just call getClipRects here?
if (context.usesCache() && parentLayer->clipper().cachedClipRects(context)) {
clipRects = *parentLayer->clipper().cachedClipRects(context);
} else {
parentLayer->clipper().calculateClipRects(context, clipRects);
}
if (layer->stackingNode()->isStackingContext()) {
rects.stackingContextClipRects = rects.currentClipRects;
} else {
clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
}
}
void DeprecatedPaintLayerClipper::addClipsFromThisObject(const ClipRectsContext& context, ClipRects& clipRects) const
{
LayoutView* view = m_layoutObject.view();
ASSERT(view);
adjustClipRectsForChildren(m_layoutObject, clipRects);
if ((m_layoutObject.hasOverflowClip() && shouldRespectOverflowClip(context)) || m_layoutObject.hasClip()) {
// This offset cannot use convertToLayerCoords, because sometimes our rootLayer may be across
// some transformed layer boundary, for example, in the DeprecatedPaintLayerCompositor overlapMap, where
// clipRects are needed in view space.
LayoutPoint offset = roundedLayoutPoint(m_layoutObject.localToContainerPoint(FloatPoint(), context.rootLayer->layoutObject()));
if (clipRects.fixed() && context.rootLayer->layoutObject() == view)
offset -= toIntSize(view->frameView()->scrollPosition());
// The condition for hasClip here seems wrong. See https://crbug.com/504577
// (overflowClips can be applied even when shouldRespectOverflowClip returns false)
if (m_layoutObject.hasOverflowClip() && (shouldRespectOverflowClip(context) || m_layoutObject.hasClip())) {
ClipRect newOverflowClip = toLayoutBox(m_layoutObject).overflowClipRect(offset, context.scrollbarRelevancy);
newOverflowClip.setHasRadius(m_layoutObject.style()->hasBorderRadius());
clipRects.setOverflowClipRect(intersection(newOverflowClip, clipRects.overflowClipRect()));
if (m_layoutObject.isPositioned())
clipRects.setPosClipRect(intersection(newOverflowClip, clipRects.posClipRect()));
if (m_layoutObject.isLayoutView())
clipRects.setFixedClipRect(intersection(newOverflowClip, clipRects.fixedClipRect()));
applyClipRects(context, m_layoutObject, roundedLayoutPoint(m_layoutObject.localToContainerPoint(FloatPoint(), context.rootLayer->layoutObject())), clipRects);
}
if (m_layoutObject.hasClip())
clipRects.setFixedClipRect(intersection(toLayoutBox(m_layoutObject).clipRect(offset), clipRects.fixedClipRect()));
}
void DeprecatedPaintLayerClipper::calculateClipRects(const ClipRectsContext& context, ClipRectComputationState& rects) const
static ClipRect backgroundClipRectForPosition(const ClipRects& parentRects, EPosition position)
{
bool isComputingPaintingRect = context.isComputingPaintingRect();
// backgroundClipRect does not include clips from yourself
ClipRectsContext current = context;
current.rootLayer = rects.currentClipRects.rootLayer();
addClipsFromThisObject(current, rects.currentClipRects);
if (isComputingPaintingRect) {
current.rootLayer = rects.stackingContextClipRects.rootLayer();
addClipsFromThisObject(current, rects.stackingContextClipRects);
}
if (position == FixedPosition)
return parentRects.fixedClipRect();
for (DeprecatedPaintLayer* child = m_layoutObject.layer()->firstChild(); child; child = child->nextSibling()) {
child->clipper().setClipRect(context, rects);
}
}
if (position == AbsolutePosition)
return parentRects.posClipRect();
// This function propagate the appropriate clip down to descendants. It is required
// as CSS overflow clips are inherited based on the containing blocks chain:
// ['overflow'] "affects the clipping of all of the element's content
// except any descendant elements (and their respective content and descendants)
// whose containing block is the viewport or an ancestor of the element."
void DeprecatedPaintLayerClipper::updateClipRectBasedOnPosition(ClipRects* clipRects) const
{
switch (m_layoutObject.style()->position()) {
case FixedPosition:
// Clip is applied to all descendants but overflow does not propogate to fixed
// position elements.
clipRects->setPosClipRect(ClipRect(LayoutRect(LayoutRect::infiniteIntRect())));
clipRects->setOverflowClipRect(ClipRect(LayoutRect(LayoutRect::infiniteIntRect())));
clipRects->setFixed(true);
break;
case AbsolutePosition:
// Overflow clips from staticly positioned elements can be escaped by absolute and fixed
// position elements.
clipRects->setOverflowClipRect(clipRects->posClipRect());
break;
case RelativePosition:
// Overflow clips that apply to a relative position element are not escaped by absolute
// position elements further down the tree. (Because the relative position element is a
// containing block.
clipRects->setPosClipRect(clipRects->overflowClipRect());
break;
case StaticPosition:
case StickyPosition:
// TODO(flakr): Position sticky should inherit the clip like relative position does (crbug.com/231752).
break;
}
return parentRects.overflowClipRect();
}
void DeprecatedPaintLayerClipper::setClipRect(const ClipRectsContext& context, const ClipRectComputationState& parentRects) const
ClipRect DeprecatedPaintLayerClipper::backgroundClipRect(const ClipRectsContext& context) const
{
bool isComputingPaintingRect = context.isComputingPaintingRect();
ClipRectComputationState rects;
rects.currentClipRects = parentRects.currentClipRects;
if (isComputingPaintingRect)
rects.stackingContextClipRects = parentRects.stackingContextClipRects;
updateClipRectBasedOnPosition(&rects.currentClipRects);
if (isComputingPaintingRect)
updateClipRectBasedOnPosition(&rects.stackingContextClipRects);
ClipRects* clipRects;
if (isComputingPaintingRect && (m_layoutObject.isPositioned() || m_layoutObject.layer()->transform()))
clipRects = &rects.stackingContextClipRects;
else
clipRects = &rects.currentClipRects;
m_clips[context.cacheSlot()] = ClipRect::create(intersection(clipRects->overflowClipRect(), clipRects->fixedClipRect()));
m_clips[context.cacheSlot()]->setRootLayer(clipRects->rootLayer());
// Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
if (clipRects->fixed() && clipRects->rootLayer()->layoutObject() == m_layoutObject.view() && *m_clips[context.cacheSlot()] != LayoutRect(LayoutRect::infiniteIntRect()))
m_clips[context.cacheSlot()]->move(toIntSize(m_layoutObject.view()->frameView()->scrollPosition()));
if (shouldStopClipRectCalculation(m_layoutObject, context))
return;
if (isComputingPaintingRect)
resetPaintRects(m_layoutObject, rects, context.cacheSlot());
calculateClipRects(context, rects);
}
ASSERT(m_layoutObject.layer()->parent());
ASSERT(m_layoutObject.view());
ClipRect DeprecatedPaintLayerClipper::uncachedBackgroundClipRect(const ClipRectsContext& context) const
{
ClipRects clipRects;
m_layoutObject.layer()->parent()->clipper().uncachedCalculateClipRects(context, clipRects);
RefPtr<ClipRects> parentClipRects = ClipRects::create();
if (m_layoutObject.layer() == context.rootLayer)
parentClipRects->reset(LayoutRect(LayoutRect::infiniteIntRect()));
else
m_layoutObject.layer()->parent()->clipper().getOrCalculateClipRects(context, *parentClipRects);
updateClipRectBasedOnPosition(&clipRects);
ClipRect result(intersection(clipRects.overflowClipRect(), clipRects.fixedClipRect()));
ClipRect result = backgroundClipRectForPosition(*parentClipRects, m_layoutObject.style()->position());
// Note: infinite clipRects should not be scrolled here, otherwise they will accidentally no longer be considered infinite.
if (clipRects.fixed() && context.rootLayer->layoutObject() == m_layoutObject.view() && result != LayoutRect(LayoutRect::infiniteIntRect()))
if (parentClipRects->fixed() && context.rootLayer->layoutObject() == m_layoutObject.view() && result != LayoutRect(LayoutRect::infiniteIntRect()))
result.move(toIntSize(m_layoutObject.view()->frameView()->scrollPosition()));
return result;
}
void DeprecatedPaintLayerClipper::uncachedCalculateClipRects(const ClipRectsContext& context, ClipRects& clipRects) const
void DeprecatedPaintLayerClipper::getOrCalculateClipRects(const ClipRectsContext& context, ClipRects& clipRects) const
{
bool rootLayerScrolls = m_layoutObject.document().settings() && m_layoutObject.document().settings()->rootLayerScrolls();
if (!m_layoutObject.layer()->parent() && !rootLayerScrolls) {
// The root layer's clip rect is always infinite.
clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
return;
}
bool isClippingRoot = m_layoutObject.layer() == context.rootLayer;
// 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.
DeprecatedPaintLayer* parentLayer = !isClippingRoot ? m_layoutObject.layer()->parent() : 0;
// Ensure that our parent's clip has been calculated so that we can examine the values.
if (parentLayer) {
parentLayer->clipper().uncachedCalculateClipRects(context, clipRects);
} else {
clipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
}
updateClipRectBasedOnPosition(&clipRects);
addClipsFromThisObject(context, clipRects);
if (context.usesCache())
clipRects = *getClipRects(context);
else
calculateClipRects(context, clipRects);
}
// TODO(chadarmstrong): Clipping roots should be consistent for a given clipRectsCacheSlot
// As things are, different callers clash over the same slot because they use
// different root layers.
DeprecatedPaintLayer* DeprecatedPaintLayerClipper::clippingRootForPainting() const
{
const DeprecatedPaintLayer* current = m_layoutObject.layer();
......
......@@ -45,7 +45,6 @@
#ifndef DeprecatedPaintLayerClipper_h
#define DeprecatedPaintLayerClipper_h
#include "core/layout/ClipRects.h"
#include "core/layout/ClipRectsCache.h"
#include "core/layout/LayoutBox.h"
#include "wtf/Allocator.h"
......@@ -54,25 +53,6 @@ namespace blink {
class DeprecatedPaintLayer;
// This is the state information passed down
// on the stack for calculating clip rects.
struct ClipRectComputationState {
STACK_ALLOCATED();
ClipRectComputationState()
{
currentClipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
stackingContextClipRects.reset(LayoutRect(LayoutRect::infiniteIntRect()));
}
// Depending on the value of context.isComputingPaintingRect() can have different meanings
// In painting, this ClipRects is used for statically positioned elements,
// outside painting, it is the only ClipRects, and is used for all elements.
ClipRects currentClipRects;
// During painting this ClipRects is used for positioned elements. It can have
// a rootLayer further up the tree than currentClipRects because its root must be
// beyond the enclosing stacking context. See resetPaintRects.
ClipRects stackingContextClipRects;
};
enum ShouldRespectOverflowClip {
IgnoreOverflowClip,
RespectOverflowClip
......@@ -149,25 +129,33 @@ public:
// Pass offsetFromRoot if known.
void calculateRects(const ClipRectsContext&, const LayoutRect& paintDirtyRect, LayoutRect& layerBounds,
ClipRect& backgroundRect, ClipRect& foregroundRect, ClipRect& outlineRect, const LayoutPoint* offsetFromRoot = 0) const;
void calculateClipRects(const ClipRectsContext&, ClipRectComputationState&) const;
DeprecatedPaintLayer* clippingRootForPainting() const;
private:
void calculateClipRects(const ClipRectsContext&, ClipRects&) const;
ClipRects* clipRectsIfCached(const ClipRectsContext&) const;
ClipRects* storeClipRectsInCache(const ClipRectsContext&, ClipRects* parentClipRects, const ClipRects&) const;
void precalculateAbsoluteClipRects();
// cachedClipRects looks buggy: It doesn't check whether context.rootLayer and entry.root match.
// FIXME: Move callers to clipRectsIfCached, which does the proper checks.
ClipRects* cachedClipRects(const ClipRectsContext& context) const
{
return m_cache ? m_cache->get(context.cacheSlot()).clipRects.get() : 0;
}
void getOrCalculateClipRects(const ClipRectsContext&, ClipRects&) const;
private:
void setClipRect(const ClipRectsContext&, const ClipRectComputationState&) const;
void addClipsFromThisObject(const ClipRectsContext&, ClipRects&) const;
void updateClipRectBasedOnPosition(ClipRects*) const;
DeprecatedPaintLayer* clippingRootForPainting() const;
ClipRect uncachedBackgroundClipRect(const ClipRectsContext&) const;
void uncachedCalculateClipRects(const ClipRectsContext&, ClipRects&) const;
ClipRectsCache& cache() const
{
if (!m_cache)
m_cache = adoptPtr(new ClipRectsCache);
return *m_cache;
}
bool shouldRespectOverflowClip(const ClipRectsContext&) const;
// FIXME: Could this be a LayoutBox?
LayoutBoxModelObject& m_layoutObject;
mutable OwnPtr<ClipRect> m_clips[NumberOfClipRectsCacheSlots];
mutable OwnPtr<ClipRectsCache> m_cache;
};
} // namespace blink
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment