summaryrefslogtreecommitdiffstats
path: root/cc/occlusion_tracker.cc
diff options
context:
space:
mode:
authorenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-12 22:43:41 +0000
committerenne@chromium.org <enne@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-10-12 22:43:41 +0000
commitcd57cc5a246367c2558fefa04ae9eca8f4d545d2 (patch)
treea2235045e9c5e4ff028d641b76f5d01aa5461b26 /cc/occlusion_tracker.cc
parent3fe7ba055be580443445895c0ee01ada3b628487 (diff)
downloadchromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.zip
chromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.tar.gz
chromium_src-cd57cc5a246367c2558fefa04ae9eca8f4d545d2.tar.bz2
[cc] Rename all cc/ filenames to Chromium style
BUG=155413 Review URL: https://codereview.chromium.org/11122003 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161671 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'cc/occlusion_tracker.cc')
-rw-r--r--cc/occlusion_tracker.cc482
1 files changed, 482 insertions, 0 deletions
diff --git a/cc/occlusion_tracker.cc b/cc/occlusion_tracker.cc
new file mode 100644
index 0000000..bedb80c
--- /dev/null
+++ b/cc/occlusion_tracker.cc
@@ -0,0 +1,482 @@
+// Copyright 2012 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 "config.h"
+
+#if USE(ACCELERATED_COMPOSITING)
+
+#include "CCOcclusionTracker.h"
+
+#include "CCLayerImpl.h"
+#include "CCMathUtil.h"
+#include "CCOverdrawMetrics.h"
+#include "LayerChromium.h"
+#include <algorithm>
+
+using namespace std;
+using WebKit::WebTransformationMatrix;
+
+namespace cc {
+
+template<typename LayerType, typename RenderSurfaceType>
+CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::CCOcclusionTrackerBase(IntRect rootTargetRect, bool recordMetricsForFrame)
+ : m_rootTargetRect(rootTargetRect)
+ , m_overdrawMetrics(CCOverdrawMetrics::create(recordMetricsForFrame))
+ , m_occludingScreenSpaceRects(0)
+{
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::enterLayer(const CCLayerIteratorPosition<LayerType>& layerIterator)
+{
+ LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer;
+
+ if (layerIterator.representsItself)
+ enterRenderTarget(renderTarget);
+ else if (layerIterator.representsTargetRenderSurface)
+ finishedRenderTarget(renderTarget);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const CCLayerIteratorPosition<LayerType>& layerIterator)
+{
+ LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer;
+
+ if (layerIterator.representsItself)
+ markOccludedBehindLayer(layerIterator.currentLayer);
+ else if (layerIterator.representsContributingRenderSurface)
+ leaveToRenderTarget(renderTarget);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget)
+{
+ if (!m_stack.isEmpty() && m_stack.last().target == newTarget)
+ return;
+
+ const LayerType* oldTarget = m_stack.isEmpty() ? 0 : m_stack.last().target;
+ const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTarget->renderSurface()->nearestAncestorThatMovesPixels();
+ const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurface()->nearestAncestorThatMovesPixels();
+
+ m_stack.append(StackObject(newTarget));
+
+ // We copy the screen occlusion into the new RenderSurface subtree, but we never copy in the
+ // target occlusion, since we are looking at a new RenderSurface target.
+
+ // If we are entering a subtree that is going to move pixels around, then the occlusion we've computed
+ // so far won't apply to the pixels we're drawing here in the same way. We discard the occlusion thus
+ // far to be safe, and ensure we don't cull any pixels that are moved such that they become visible.
+ bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAncestorThatMovesPixels != oldAncestorThatMovesPixels;
+
+ bool copyScreenOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThatMovesPixels;
+ if (copyScreenOcclusionForward) {
+ int lastIndex = m_stack.size() - 1;
+ m_stack[lastIndex].occlusionInScreen = m_stack[lastIndex - 1].occlusionInScreen;
+ }
+}
+
+static inline bool layerOpacityKnown(const LayerChromium* layer) { return !layer->drawOpacityIsAnimating(); }
+static inline bool layerOpacityKnown(const CCLayerImpl*) { return true; }
+static inline bool layerTransformsToTargetKnown(const LayerChromium* layer) { return !layer->drawTransformIsAnimating(); }
+static inline bool layerTransformsToTargetKnown(const CCLayerImpl*) { return true; }
+static inline bool layerTransformsToScreenKnown(const LayerChromium* layer) { return !layer->screenSpaceTransformIsAnimating(); }
+static inline bool layerTransformsToScreenKnown(const CCLayerImpl*) { return true; }
+
+static inline bool surfaceOpacityKnown(const RenderSurfaceChromium* surface) { return !surface->drawOpacityIsAnimating(); }
+static inline bool surfaceOpacityKnown(const CCRenderSurface*) { return true; }
+static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceChromium* surface) { return !surface->targetSurfaceTransformsAreAnimating(); }
+static inline bool surfaceTransformsToTargetKnown(const CCRenderSurface*) { return true; }
+static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceChromium* surface) { return !surface->screenSpaceTransformsAreAnimating(); }
+static inline bool surfaceTransformsToScreenKnown(const CCRenderSurface*) { return true; }
+
+static inline bool layerIsInUnsorted3dRenderingContext(const LayerChromium* layer) { return layer->parent() && layer->parent()->preserves3D(); }
+static inline bool layerIsInUnsorted3dRenderingContext(const CCLayerImpl*) { return false; }
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(const LayerType* finishedTarget)
+{
+ // Make sure we know about the target surface.
+ enterRenderTarget(finishedTarget);
+
+ RenderSurfaceType* surface = finishedTarget->renderSurface();
+
+ // If the occlusion within the surface can not be applied to things outside of the surface's subtree, then clear the occlusion here so it won't be used.
+ if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface->drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity()) {
+ m_stack.last().occlusionInScreen = Region();
+ m_stack.last().occlusionInTarget = Region();
+ } else {
+ if (!surfaceTransformsToTargetKnown(surface))
+ m_stack.last().occlusionInTarget = Region();
+ if (!surfaceTransformsToScreenKnown(surface))
+ m_stack.last().occlusionInScreen = Region();
+ }
+}
+
+template<typename RenderSurfaceType>
+static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surface, const Region& region, const WebTransformationMatrix& transform)
+{
+ // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then
+ // apply |transform| to each rect within |region| in order to transform the entire Region.
+
+ bool clipped;
+ FloatQuad transformedBoundsQuad = CCMathUtil::mapQuad(transform, FloatQuad(region.bounds()), clipped);
+ // FIXME: Find a rect interior to each transformed quad.
+ if (clipped || !transformedBoundsQuad.isRectilinear())
+ return Region();
+
+ Region transformedRegion;
+
+ Vector<WebCore::IntRect> rects = region.rects();
+ for (size_t i = 0; i < rects.size(); ++i) {
+ // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
+ IntRect transformedRect = enclosedIntRect(CCMathUtil::mapClippedRect(transform, FloatRect(rects[i])));
+ if (!surface->clipRect().isEmpty())
+ transformedRect.intersect(surface->clipRect());
+ transformedRegion.unite(transformedRect);
+ }
+ return transformedRegion;
+}
+
+static inline void reduceOcclusion(const IntRect& affectedArea, const IntRect& expandedPixel, Region& occlusion)
+{
+ if (affectedArea.isEmpty())
+ return;
+
+ Region affectedOcclusion = intersect(occlusion, affectedArea);
+ Vector<WebCore::IntRect> affectedOcclusionRects = affectedOcclusion.rects();
+
+ occlusion.subtract(affectedArea);
+ for (size_t j = 0; j < affectedOcclusionRects.size(); ++j) {
+ WebCore::IntRect& occlusionRect = affectedOcclusionRects[j];
+
+ // Shrink the rect by expanding the non-opaque pixels outside the rect.
+
+ // The expandedPixel is the IntRect for a single pixel after being
+ // expanded by filters on the layer. The original pixel would be
+ // IntRect(0, 0, 1, 1), and the expanded pixel is the rect, relative
+ // to this original rect, that the original pixel can influence after
+ // being filtered.
+ // To convert the expandedPixel IntRect back to filter outsets:
+ // x = -leftOutset
+ // width = leftOutset + rightOutset
+ // maxX = x + width = -leftOutset + leftOutset + rightOutset = rightOutset
+
+ // The leftOutset of the filters moves pixels on the right side of
+ // the occlusionRect into it, shrinking its right edge.
+ int shrinkLeft = occlusionRect.x() == affectedArea.x() ? 0 : expandedPixel.maxX();
+ int shrinkTop = occlusionRect.y() == affectedArea.y() ? 0 : expandedPixel.maxY();
+ int shrinkRight = occlusionRect.maxX() == affectedArea.maxX() ? 0 : -expandedPixel.x();
+ int shrinkBottom = occlusionRect.maxY() == affectedArea.maxY() ? 0 : -expandedPixel.y();
+
+ occlusionRect.move(shrinkLeft, shrinkTop);
+ occlusionRect.contract(shrinkLeft + shrinkRight, shrinkTop + shrinkBottom);
+
+ occlusion.unite(occlusionRect);
+ }
+}
+
+template<typename LayerType>
+static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const IntRect& surfaceRect, const WebTransformationMatrix& surfaceTransform, LayerType* renderTarget, Region& occlusionInTarget, Region& occlusionInScreen)
+{
+ if (surfaceRect.isEmpty())
+ return;
+
+ IntRect boundsInTarget = enclosingIntRect(CCMathUtil::mapClippedRect(surfaceTransform, FloatRect(surfaceRect)));
+ if (!contributingLayer->renderSurface()->clipRect().isEmpty())
+ boundsInTarget.intersect(contributingLayer->renderSurface()->clipRect());
+
+ int outsetTop, outsetRight, outsetBottom, outsetLeft;
+ contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, outsetBottom, outsetLeft);
+
+ // The filter can move pixels from outside of the clip, so allow affectedArea to expand outside the clip.
+ boundsInTarget.move(-outsetLeft, -outsetTop);
+ boundsInTarget.expand(outsetLeft + outsetRight, outsetTop + outsetBottom);
+
+ IntRect boundsInScreen = enclosingIntRect(CCMathUtil::mapClippedRect(renderTarget->renderSurface()->screenSpaceTransform(), FloatRect(boundsInTarget)));
+
+ IntRect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outsetRight, outsetTop + outsetBottom);
+ IntRect filterOutsetsInScreen = enclosingIntRect(CCMathUtil::mapClippedRect(renderTarget->renderSurface()->screenSpaceTransform(), FloatRect(filterOutsetsInTarget)));
+
+ reduceOcclusion(boundsInTarget, filterOutsetsInTarget, occlusionInTarget);
+ reduceOcclusion(boundsInScreen, filterOutsetsInScreen, occlusionInScreen);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(const LayerType* newTarget)
+{
+ int lastIndex = m_stack.size() - 1;
+ bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex - 1].target == newTarget;
+
+ // We merge the screen occlusion from the current RenderSurface subtree out to its parent target RenderSurface.
+ // The target occlusion can be merged out as well but needs to be transformed to the new target.
+
+ const LayerType* oldTarget = m_stack[lastIndex].target;
+ const RenderSurfaceType* oldSurface = oldTarget->renderSurface();
+ Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSurfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->drawTransform());
+ if (oldTarget->hasReplica() && !oldTarget->replicaHasMask())
+ oldTargetOcclusionInNewTarget.unite(transformSurfaceOpaqueRegion<RenderSurfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->replicaDrawTransform()));
+
+ IntRect unoccludedSurfaceRect;
+ IntRect unoccludedReplicaRect;
+ if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) {
+ unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarget, false, oldSurface->contentRect());
+ if (oldTarget->hasReplica())
+ unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(oldTarget, true, oldSurface->contentRect());
+ }
+
+ if (surfaceWillBeAtTopAfterPop) {
+ // Merge the top of the stack down.
+ m_stack[lastIndex - 1].occlusionInScreen.unite(m_stack[lastIndex].occlusionInScreen);
+ m_stack[lastIndex - 1].occlusionInTarget.unite(oldTargetOcclusionInNewTarget);
+ m_stack.removeLast();
+ } else {
+ // Replace the top of the stack with the new pushed surface. Copy the occluded screen region to the top.
+ m_stack.last().target = newTarget;
+ m_stack.last().occlusionInTarget = oldTargetOcclusionInNewTarget;
+ }
+
+ if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) {
+ reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->drawTransform(), newTarget, m_stack.last().occlusionInTarget, m_stack.last().occlusionInScreen);
+ if (oldTarget->hasReplica())
+ reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->replicaDrawTransform(), newTarget, m_stack.last().occlusionInTarget, m_stack.last().occlusionInScreen);
+ }
+}
+
+// FIXME: Remove usePaintTracking when paint tracking is on for paint culling.
+template<typename LayerType>
+static inline void addOcclusionBehindLayer(Region& region, const LayerType* layer, const WebTransformationMatrix& transform, const Region& opaqueContents, const IntRect& clipRectInTarget, const IntSize& minimumTrackingSize, Vector<IntRect>* occludingScreenSpaceRects)
+{
+ ASSERT(layer->visibleContentRect().contains(opaqueContents.bounds()));
+
+ bool clipped;
+ FloatQuad visibleTransformedQuad = CCMathUtil::mapQuad(transform, FloatQuad(layer->visibleContentRect()), clipped);
+ // FIXME: Find a rect interior to each transformed quad.
+ if (clipped || !visibleTransformedQuad.isRectilinear())
+ return;
+
+ Vector<WebCore::IntRect> contentRects = opaqueContents.rects();
+ for (size_t i = 0; i < contentRects.size(); ++i) {
+ // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
+ IntRect transformedRect = enclosedIntRect(CCMathUtil::mapClippedRect(transform, FloatRect(contentRects[i])));
+ transformedRect.intersect(clipRectInTarget);
+ if (transformedRect.width() >= minimumTrackingSize.width() || transformedRect.height() >= minimumTrackingSize.height()) {
+ if (occludingScreenSpaceRects)
+ occludingScreenSpaceRects->append(transformedRect);
+ region.unite(transformedRect);
+ }
+ }
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer(const LayerType* layer)
+{
+ ASSERT(!m_stack.isEmpty());
+ ASSERT(layer->renderTarget() == m_stack.last().target);
+ if (m_stack.isEmpty())
+ return;
+
+ if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1)
+ return;
+
+ if (layerIsInUnsorted3dRenderingContext(layer))
+ return;
+
+ Region opaqueContents = layer->visibleContentOpaqueRegion();
+ if (opaqueContents.isEmpty())
+ return;
+
+ IntRect clipRectInTarget = layerClipRectInTarget(layer);
+ if (layerTransformsToTargetKnown(layer))
+ addOcclusionBehindLayer<LayerType>(m_stack.last().occlusionInTarget, layer, layer->drawTransform(), opaqueContents, clipRectInTarget, m_minimumTrackingSize, 0);
+
+ // We must clip the occlusion within the layer's clipRectInTarget within screen space as well. If the clip rect can't be moved to screen space and
+ // remain rectilinear, then we don't add any occlusion in screen space.
+
+ if (layerTransformsToScreenKnown(layer)) {
+ WebTransformationMatrix targetToScreenTransform = m_stack.last().target->renderSurface()->screenSpaceTransform();
+ bool clipped;
+ FloatQuad clipQuadInScreen = CCMathUtil::mapQuad(targetToScreenTransform, FloatQuad(FloatRect(clipRectInTarget)), clipped);
+ // FIXME: Find a rect interior to the transformed clip quad.
+ if (clipped || !clipQuadInScreen.isRectilinear())
+ return;
+ IntRect clipRectInScreen = intersection(m_rootTargetRect, enclosedIntRect(clipQuadInScreen.boundingBox()));
+ addOcclusionBehindLayer<LayerType>(m_stack.last().occlusionInScreen, layer, layer->screenSpaceTransform(), opaqueContents, clipRectInScreen, m_minimumTrackingSize, m_occludingScreenSpaceRects);
+ }
+}
+
+static inline bool testContentRectOccluded(const IntRect& contentRect, const WebTransformationMatrix& contentSpaceTransform, const IntRect& clipRectInTarget, const Region& occlusion)
+{
+ FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform, FloatRect(contentRect));
+ // Take the enclosingIntRect, as we want to include partial pixels in the test.
+ IntRect targetRect = intersection(enclosingIntRect(transformedRect), clipRectInTarget);
+ return targetRect.isEmpty() || occlusion.contains(targetRect);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+bool CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerType* layer, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const
+{
+ if (hasOcclusionFromOutsideTargetSurface)
+ *hasOcclusionFromOutsideTargetSurface = false;
+
+ ASSERT(!m_stack.isEmpty());
+ if (m_stack.isEmpty())
+ return false;
+ if (contentRect.isEmpty())
+ return true;
+
+ ASSERT(layer->renderTarget() == m_stack.last().target);
+
+ if (layerTransformsToTargetKnown(layer) && testContentRectOccluded(contentRect, layer->drawTransform(), layerClipRectInTarget(layer), m_stack.last().occlusionInTarget))
+ return true;
+
+ if (layerTransformsToScreenKnown(layer) && testContentRectOccluded(contentRect, layer->screenSpaceTransform(), m_rootTargetRect, m_stack.last().occlusionInScreen)) {
+ if (hasOcclusionFromOutsideTargetSurface)
+ *hasOcclusionFromOutsideTargetSurface = true;
+ return true;
+ }
+
+ return false;
+}
+
+// Determines what portion of rect, if any, is unoccluded (not occluded by region). If
+// the resulting unoccluded region is not rectangular, we return a rect containing it.
+static inline IntRect rectSubtractRegion(const IntRect& rect, const Region& region)
+{
+ Region rectRegion(rect);
+ rectRegion.subtract(region);
+ return rectRegion.bounds();
+}
+
+static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, const WebTransformationMatrix& contentSpaceTransform, const IntRect& clipRectInTarget, const Region& occlusion)
+{
+ if (!contentSpaceTransform.isInvertible())
+ return contentRect;
+
+ // Take the enclosingIntRect at each step, as we want to contain any unoccluded partial pixels in the resulting IntRect.
+ FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform, FloatRect(contentRect));
+ IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transformedRect), clipRectInTarget), occlusion);
+ IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectClippedRect(contentSpaceTransform.inverse(), FloatRect(shrunkRect)));
+ // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
+ return intersection(unoccludedRect, contentRect);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentRect(const LayerType* layer, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const
+{
+ ASSERT(!m_stack.isEmpty());
+ if (m_stack.isEmpty())
+ return contentRect;
+ if (contentRect.isEmpty())
+ return contentRect;
+
+ ASSERT(layer->renderTarget() == m_stack.last().target);
+
+ // We want to return a rect that contains all the visible parts of |contentRect| in both screen space and in the target surface.
+ // So we find the visible parts of |contentRect| in each space, and take the intersection.
+
+ IntRect unoccludedInScreen = contentRect;
+ if (layerTransformsToScreenKnown(layer))
+ unoccludedInScreen = computeUnoccludedContentRect(contentRect, layer->screenSpaceTransform(), m_rootTargetRect, m_stack.last().occlusionInScreen);
+
+ IntRect unoccludedInTarget = contentRect;
+ if (layerTransformsToTargetKnown(layer))
+ unoccludedInTarget = computeUnoccludedContentRect(contentRect, layer->drawTransform(), layerClipRectInTarget(layer), m_stack.last().occlusionInTarget);
+
+ if (hasOcclusionFromOutsideTargetSurface)
+ *hasOcclusionFromOutsideTargetSurface = (intersection(unoccludedInScreen, unoccludedInTarget) != unoccludedInTarget);
+
+ return intersection(unoccludedInScreen, unoccludedInTarget);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContributingSurfaceContentRect(const LayerType* layer, bool forReplica, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const
+{
+ ASSERT(!m_stack.isEmpty());
+ // The layer is a contributing renderTarget so it should have a surface.
+ ASSERT(layer->renderSurface());
+ // The layer is a contributing renderTarget so its target should be itself.
+ ASSERT(layer->renderTarget() == layer);
+ // The layer should not be the root, else what is is contributing to?
+ ASSERT(layer->parent());
+ // This should be called while the layer is still considered the current target in the occlusion tracker.
+ ASSERT(layer == m_stack.last().target);
+
+ if (contentRect.isEmpty())
+ return contentRect;
+
+ RenderSurfaceType* surface = layer->renderSurface();
+
+ IntRect surfaceClipRect = surface->clipRect();
+ if (surfaceClipRect.isEmpty()) {
+ LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTarget();
+ surfaceClipRect = intersection(contributingSurfaceRenderTarget->renderSurface()->contentRect(), enclosingIntRect(surface->drawableContentRect()));
+ }
+
+ // A contributing surface doesn't get occluded by things inside its own surface, so only things outside the surface can occlude it. That occlusion is
+ // found just below the top of the stack (if it exists).
+ bool hasOcclusion = m_stack.size() > 1;
+
+ const WebTransformationMatrix& transformToScreen = forReplica ? surface->replicaScreenSpaceTransform() : surface->screenSpaceTransform();
+ const WebTransformationMatrix& transformToTarget = forReplica ? surface->replicaDrawTransform() : surface->drawTransform();
+
+ IntRect unoccludedInScreen = contentRect;
+ if (surfaceTransformsToScreenKnown(surface)) {
+ if (hasOcclusion) {
+ const StackObject& secondLast = m_stack[m_stack.size() - 2];
+ unoccludedInScreen = computeUnoccludedContentRect(contentRect, transformToScreen, m_rootTargetRect, secondLast.occlusionInScreen);
+ } else
+ unoccludedInScreen = computeUnoccludedContentRect(contentRect, transformToScreen, m_rootTargetRect, Region());
+ }
+
+ IntRect unoccludedInTarget = contentRect;
+ if (surfaceTransformsToTargetKnown(surface)) {
+ if (hasOcclusion) {
+ const StackObject& secondLast = m_stack[m_stack.size() - 2];
+ unoccludedInTarget = computeUnoccludedContentRect(contentRect, transformToTarget, surfaceClipRect, secondLast.occlusionInTarget);
+ } else
+ unoccludedInTarget = computeUnoccludedContentRect(contentRect, transformToTarget, surfaceClipRect, Region());
+ }
+
+ if (hasOcclusionFromOutsideTargetSurface)
+ *hasOcclusionFromOutsideTargetSurface = (intersection(unoccludedInScreen, unoccludedInTarget) != unoccludedInTarget);
+
+ return intersection(unoccludedInScreen, unoccludedInTarget);
+}
+
+template<typename LayerType, typename RenderSurfaceType>
+IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTarget(const LayerType* layer) const
+{
+ // FIXME: we could remove this helper function, but unit tests currently override this
+ // function, and they need to be verified/adjusted before this can be removed.
+ return layer->drawableContentRect();
+}
+
+// Declare the possible functions here for the linker.
+template CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::CCOcclusionTrackerBase(IntRect rootTargetRect, bool recordMetricsForFrame);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::enterLayer(const CCLayerIteratorPosition<LayerChromium>&);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::leaveLayer(const CCLayerIteratorPosition<LayerChromium>&);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::enterRenderTarget(const LayerChromium* newTarget);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::finishedRenderTarget(const LayerChromium* finishedTarget);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::leaveToRenderTarget(const LayerChromium* newTarget);
+template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::markOccludedBehindLayer(const LayerChromium*);
+template bool CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::occluded(const LayerChromium*, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::unoccludedContentRect(const LayerChromium*, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::unoccludedContributingSurfaceContentRect(const LayerChromium*, bool forReplica, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::layerClipRectInTarget(const LayerChromium*) const;
+
+template CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::CCOcclusionTrackerBase(IntRect rootTargetRect, bool recordMetricsForFrame);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::enterLayer(const CCLayerIteratorPosition<CCLayerImpl>&);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::leaveLayer(const CCLayerIteratorPosition<CCLayerImpl>&);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::enterRenderTarget(const CCLayerImpl* newTarget);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::finishedRenderTarget(const CCLayerImpl* finishedTarget);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::leaveToRenderTarget(const CCLayerImpl* newTarget);
+template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::markOccludedBehindLayer(const CCLayerImpl*);
+template bool CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::occluded(const CCLayerImpl*, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::unoccludedContentRect(const CCLayerImpl*, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::unoccludedContributingSurfaceContentRect(const CCLayerImpl*, bool forReplica, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const;
+template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::layerClipRectInTarget(const CCLayerImpl*) const;
+
+
+} // namespace cc
+#endif // USE(ACCELERATED_COMPOSITING)