1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/occlusion_tracker.h"
10 #include "cc/layer_impl.h"
11 #include "cc/math_util.h"
12 #include "cc/overdraw_metrics.h"
13 #include "ui/gfx/quad_f.h"
14 #include "ui/gfx/rect_conversions.h"
20 template<typename LayerType
, typename RenderSurfaceType
>
21 OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::OcclusionTrackerBase(gfx::Rect rootTargetRect
, bool recordMetricsForFrame
)
22 : m_rootTargetRect(rootTargetRect
)
23 , m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame
))
24 , m_occludingScreenSpaceRects(0)
25 , m_nonOccludingScreenSpaceRects(0)
29 template<typename LayerType
, typename RenderSurfaceType
>
30 OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::~OcclusionTrackerBase()
34 template<typename LayerType
, typename RenderSurfaceType
>
35 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::enterLayer(const LayerIteratorPosition
<LayerType
>& layerIterator
)
37 LayerType
* renderTarget
= layerIterator
.targetRenderSurfaceLayer
;
39 if (layerIterator
.representsItself
)
40 enterRenderTarget(renderTarget
);
41 else if (layerIterator
.representsTargetRenderSurface
)
42 finishedRenderTarget(renderTarget
);
45 template<typename LayerType
, typename RenderSurfaceType
>
46 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::leaveLayer(const LayerIteratorPosition
<LayerType
>& layerIterator
)
48 LayerType
* renderTarget
= layerIterator
.targetRenderSurfaceLayer
;
50 if (layerIterator
.representsItself
)
51 markOccludedBehindLayer(layerIterator
.currentLayer
);
52 else if (layerIterator
.representsContributingRenderSurface
)
53 leaveToRenderTarget(renderTarget
);
56 template<typename LayerType
, typename RenderSurfaceType
>
57 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::enterRenderTarget(const LayerType
* newTarget
)
59 if (!m_stack
.empty() && m_stack
.back().target
== newTarget
)
62 const LayerType
* oldTarget
= m_stack
.empty() ? 0 : m_stack
.back().target
;
63 const RenderSurfaceType
* oldAncestorThatMovesPixels
= !oldTarget
? 0 : oldTarget
->renderSurface()->nearestAncestorThatMovesPixels();
64 const RenderSurfaceType
* newAncestorThatMovesPixels
= newTarget
->renderSurface()->nearestAncestorThatMovesPixels();
66 m_stack
.push_back(StackObject(newTarget
));
68 // We copy the screen occlusion into the new RenderSurfaceImpl subtree, but we never copy in the
69 // target occlusion, since we are looking at a new RenderSurfaceImpl target.
71 // If we are entering a subtree that is going to move pixels around, then the occlusion we've computed
72 // so far won't apply to the pixels we're drawing here in the same way. We discard the occlusion thus
73 // far to be safe, and ensure we don't cull any pixels that are moved such that they become visible.
74 bool enteringSubtreeThatMovesPixels
= newAncestorThatMovesPixels
&& newAncestorThatMovesPixels
!= oldAncestorThatMovesPixels
;
76 bool copyScreenOcclusionForward
= m_stack
.size() > 1 && !enteringSubtreeThatMovesPixels
;
77 if (copyScreenOcclusionForward
) {
78 int lastIndex
= m_stack
.size() - 1;
79 m_stack
[lastIndex
].occlusionInScreen
= m_stack
[lastIndex
- 1].occlusionInScreen
;
83 static inline bool layerOpacityKnown(const Layer
* layer
) { return !layer
->drawOpacityIsAnimating(); }
84 static inline bool layerOpacityKnown(const LayerImpl
*) { return true; }
85 static inline bool layerTransformsToTargetKnown(const Layer
* layer
) { return !layer
->drawTransformIsAnimating(); }
86 static inline bool layerTransformsToTargetKnown(const LayerImpl
*) { return true; }
87 static inline bool layerTransformsToScreenKnown(const Layer
* layer
) { return !layer
->screenSpaceTransformIsAnimating(); }
88 static inline bool layerTransformsToScreenKnown(const LayerImpl
*) { return true; }
90 static inline bool surfaceOpacityKnown(const RenderSurface
* surface
) { return !surface
->drawOpacityIsAnimating(); }
91 static inline bool surfaceOpacityKnown(const RenderSurfaceImpl
*) { return true; }
92 static inline bool surfaceTransformsToTargetKnown(const RenderSurface
* surface
) { return !surface
->targetSurfaceTransformsAreAnimating(); }
93 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceImpl
*) { return true; }
94 static inline bool surfaceTransformsToScreenKnown(const RenderSurface
* surface
) { return !surface
->screenSpaceTransformsAreAnimating(); }
95 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceImpl
*) { return true; }
97 static inline bool layerIsInUnsorted3dRenderingContext(const Layer
* layer
) { return layer
->parent() && layer
->parent()->preserves3D(); }
98 static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl
*) { return false; }
100 template<typename LayerType
, typename RenderSurfaceType
>
101 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::finishedRenderTarget(const LayerType
* finishedTarget
)
103 // Make sure we know about the target surface.
104 enterRenderTarget(finishedTarget
);
106 RenderSurfaceType
* surface
= finishedTarget
->renderSurface();
108 // 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.
109 // TODO(senorblanco): Make this smarter for SkImageFilter case: once
110 // SkImageFilters can report affectsOpacity(), call that.
111 if (finishedTarget
->maskLayer() || !surfaceOpacityKnown(surface
) || surface
->drawOpacity() < 1 || finishedTarget
->filters().hasFilterThatAffectsOpacity() || finishedTarget
->filter()) {
112 m_stack
.back().occlusionInScreen
.Clear();
113 m_stack
.back().occlusionInTarget
.Clear();
115 if (!surfaceTransformsToTargetKnown(surface
))
116 m_stack
.back().occlusionInTarget
.Clear();
117 if (!surfaceTransformsToScreenKnown(surface
))
118 m_stack
.back().occlusionInScreen
.Clear();
122 template<typename RenderSurfaceType
>
123 static inline Region
transformSurfaceOpaqueRegion(const RenderSurfaceType
* surface
, const Region
& region
, const gfx::Transform
& transform
)
125 // Verify that rects within the |surface| will remain rects in its target surface after applying |transform|. If this is true, then
126 // apply |transform| to each rect within |region| in order to transform the entire Region.
129 gfx::QuadF transformedBoundsQuad
= MathUtil::mapQuad(transform
, gfx::QuadF(region
.bounds()), clipped
);
130 // FIXME: Find a rect interior to each transformed quad.
131 if (clipped
|| !transformedBoundsQuad
.IsRectilinear())
134 Region transformedRegion
;
136 for (Region::Iterator
rects(region
); rects
.has_rect(); rects
.next()) {
137 // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
138 gfx::Rect transformedRect
= gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform
, gfx::RectF(rects
.rect())));
139 if (!surface
->clipRect().IsEmpty())
140 transformedRect
.Intersect(surface
->clipRect());
141 transformedRegion
.Union(transformedRect
);
143 return transformedRegion
;
146 static inline void reduceOcclusion(const gfx::Rect
& affectedArea
, const gfx::Rect
& expandedPixel
, Region
& occlusion
)
148 if (affectedArea
.IsEmpty())
151 Region affectedOcclusion
= IntersectRegions(occlusion
, affectedArea
);
152 Region::Iterator
affectedOcclusionRects(affectedOcclusion
);
154 occlusion
.Subtract(affectedArea
);
155 for (; affectedOcclusionRects
.has_rect(); affectedOcclusionRects
.next()) {
156 gfx::Rect occlusionRect
= affectedOcclusionRects
.rect();
158 // Shrink the rect by expanding the non-opaque pixels outside the rect.
160 // The expandedPixel is the Rect for a single pixel after being
161 // expanded by filters on the layer. The original pixel would be
162 // Rect(0, 0, 1, 1), and the expanded pixel is the rect, relative
163 // to this original rect, that the original pixel can influence after
165 // To convert the expandedPixel Rect back to filter outsets:
167 // width = leftOutset + rightOutset
168 // right = x + width = -leftOutset + leftOutset + rightOutset = rightOutset
170 // The leftOutset of the filters moves pixels on the right side of
171 // the occlusionRect into it, shrinking its right edge.
172 int shrinkLeft
= occlusionRect
.x() == affectedArea
.x() ? 0 : expandedPixel
.right();
173 int shrinkTop
= occlusionRect
.y() == affectedArea
.y() ? 0 : expandedPixel
.bottom();
174 int shrinkRight
= occlusionRect
.right() == affectedArea
.right() ? 0 : -expandedPixel
.x();
175 int shrinkBottom
= occlusionRect
.bottom() == affectedArea
.bottom() ? 0 : -expandedPixel
.y();
177 occlusionRect
.Inset(shrinkLeft
, shrinkTop
, shrinkRight
, shrinkBottom
);
179 occlusion
.Union(occlusionRect
);
183 template<typename LayerType
>
184 static void reduceOcclusionBelowSurface(LayerType
* contributingLayer
, const gfx::Rect
& surfaceRect
, const gfx::Transform
& surfaceTransform
, LayerType
* renderTarget
, Region
& occlusionInTarget
, Region
& occlusionInScreen
)
186 if (surfaceRect
.IsEmpty())
189 gfx::Rect boundsInTarget
= gfx::ToEnclosingRect(MathUtil::mapClippedRect(surfaceTransform
, gfx::RectF(surfaceRect
)));
190 if (!contributingLayer
->renderSurface()->clipRect().IsEmpty())
191 boundsInTarget
.Intersect(contributingLayer
->renderSurface()->clipRect());
193 int outsetTop
, outsetRight
, outsetBottom
, outsetLeft
;
194 contributingLayer
->backgroundFilters().getOutsets(outsetTop
, outsetRight
, outsetBottom
, outsetLeft
);
196 // The filter can move pixels from outside of the clip, so allow affectedArea to expand outside the clip.
197 boundsInTarget
.Inset(-outsetLeft
, -outsetTop
, -outsetRight
, -outsetBottom
);
199 gfx::Rect boundsInScreen
= gfx::ToEnclosingRect(MathUtil::mapClippedRect(renderTarget
->renderSurface()->screenSpaceTransform(), gfx::RectF(boundsInTarget
)));
201 gfx::Rect
filterOutsetsInTarget(-outsetLeft
, -outsetTop
, outsetLeft
+ outsetRight
, outsetTop
+ outsetBottom
);
202 gfx::Rect filterOutsetsInScreen
= gfx::ToEnclosingRect(MathUtil::mapClippedRect(renderTarget
->renderSurface()->screenSpaceTransform(), gfx::RectF(filterOutsetsInTarget
)));
204 reduceOcclusion(boundsInTarget
, filterOutsetsInTarget
, occlusionInTarget
);
205 reduceOcclusion(boundsInScreen
, filterOutsetsInScreen
, occlusionInScreen
);
208 template<typename LayerType
, typename RenderSurfaceType
>
209 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::leaveToRenderTarget(const LayerType
* newTarget
)
211 int lastIndex
= m_stack
.size() - 1;
212 bool surfaceWillBeAtTopAfterPop
= m_stack
.size() > 1 && m_stack
[lastIndex
- 1].target
== newTarget
;
214 // We merge the screen occlusion from the current RenderSurfaceImpl subtree out to its parent target RenderSurfaceImpl.
215 // The target occlusion can be merged out as well but needs to be transformed to the new target.
217 const LayerType
* oldTarget
= m_stack
[lastIndex
].target
;
218 const RenderSurfaceType
* oldSurface
= oldTarget
->renderSurface();
219 Region oldTargetOcclusionInNewTarget
= transformSurfaceOpaqueRegion
<RenderSurfaceType
>(oldSurface
, m_stack
[lastIndex
].occlusionInTarget
, oldSurface
->drawTransform());
220 if (oldTarget
->hasReplica() && !oldTarget
->replicaHasMask())
221 oldTargetOcclusionInNewTarget
.Union(transformSurfaceOpaqueRegion
<RenderSurfaceType
>(oldSurface
, m_stack
[lastIndex
].occlusionInTarget
, oldSurface
->replicaDrawTransform()));
223 gfx::Rect unoccludedSurfaceRect
;
224 gfx::Rect unoccludedReplicaRect
;
225 if (oldTarget
->backgroundFilters().hasFilterThatMovesPixels()) {
226 unoccludedSurfaceRect
= unoccludedContributingSurfaceContentRect(oldTarget
, false, oldSurface
->contentRect());
227 if (oldTarget
->hasReplica())
228 unoccludedReplicaRect
= unoccludedContributingSurfaceContentRect(oldTarget
, true, oldSurface
->contentRect());
231 if (surfaceWillBeAtTopAfterPop
) {
232 // Merge the top of the stack down.
233 m_stack
[lastIndex
- 1].occlusionInScreen
.Union(m_stack
[lastIndex
].occlusionInScreen
);
234 m_stack
[lastIndex
- 1].occlusionInTarget
.Union(oldTargetOcclusionInNewTarget
);
237 // Replace the top of the stack with the new pushed surface. Copy the occluded screen region to the top.
238 m_stack
.back().target
= newTarget
;
239 m_stack
.back().occlusionInTarget
= oldTargetOcclusionInNewTarget
;
242 if (oldTarget
->backgroundFilters().hasFilterThatMovesPixels()) {
243 reduceOcclusionBelowSurface(oldTarget
, unoccludedSurfaceRect
, oldSurface
->drawTransform(), newTarget
, m_stack
.back().occlusionInTarget
, m_stack
.back().occlusionInScreen
);
244 if (oldTarget
->hasReplica())
245 reduceOcclusionBelowSurface(oldTarget
, unoccludedReplicaRect
, oldSurface
->replicaDrawTransform(), newTarget
, m_stack
.back().occlusionInTarget
, m_stack
.back().occlusionInScreen
);
249 // FIXME: Remove usePaintTracking when paint tracking is on for paint culling.
250 template<typename LayerType
>
251 static inline void addOcclusionBehindLayer(Region
& region
, const LayerType
* layer
, const gfx::Transform
& transform
, const Region
& opaqueContents
, const gfx::Rect
& clipRectInTarget
, const gfx::Size
& minimumTrackingSize
, std::vector
<gfx::Rect
>* occludingScreenSpaceRects
, std::vector
<gfx::Rect
>* nonOccludingScreenSpaceRects
)
253 DCHECK(layer
->visibleContentRect().Contains(opaqueContents
.bounds()));
256 gfx::QuadF visibleTransformedQuad
= MathUtil::mapQuad(transform
, gfx::QuadF(layer
->visibleContentRect()), clipped
);
257 // FIXME: Find a rect interior to each transformed quad.
258 if (clipped
|| !visibleTransformedQuad
.IsRectilinear())
261 for (Region::Iterator
opaqueContentRects(opaqueContents
); opaqueContentRects
.has_rect(); opaqueContentRects
.next()) {
262 // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
263 gfx::Rect transformedRect
= gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform
, gfx::RectF(opaqueContentRects
.rect())));
264 transformedRect
.Intersect(clipRectInTarget
);
265 if (transformedRect
.width() >= minimumTrackingSize
.width() || transformedRect
.height() >= minimumTrackingSize
.height()) {
266 if (occludingScreenSpaceRects
)
267 occludingScreenSpaceRects
->push_back(transformedRect
);
268 region
.Union(transformedRect
);
272 if (nonOccludingScreenSpaceRects
) {
273 Region nonOpaqueContents
= SubtractRegions(gfx::Rect(layer
->contentBounds()), opaqueContents
);
274 for (Region::Iterator
nonOpaqueContentRects(nonOpaqueContents
); nonOpaqueContentRects
.has_rect(); nonOpaqueContentRects
.next()) {
275 // We've already checked for clipping in the mapQuad call above, these calls should not clip anything further.
276 gfx::Rect transformedRect
= gfx::ToEnclosedRect(MathUtil::mapClippedRect(transform
, gfx::RectF(nonOpaqueContentRects
.rect())));
277 transformedRect
.Intersect(clipRectInTarget
);
278 if (transformedRect
.IsEmpty())
280 nonOccludingScreenSpaceRects
->push_back(transformedRect
);
285 template<typename LayerType
, typename RenderSurfaceType
>
286 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::markOccludedBehindLayer(const LayerType
* layer
)
288 DCHECK(!m_stack
.empty());
289 DCHECK(layer
->renderTarget() == m_stack
.back().target
);
293 if (!layerOpacityKnown(layer
) || layer
->drawOpacity() < 1)
296 if (layerIsInUnsorted3dRenderingContext(layer
))
299 Region opaqueContents
= layer
->visibleContentOpaqueRegion();
300 if (opaqueContents
.IsEmpty())
303 gfx::Rect clipRectInTarget
= layerClipRectInTarget(layer
);
304 if (layerTransformsToTargetKnown(layer
))
305 addOcclusionBehindLayer
<LayerType
>(m_stack
.back().occlusionInTarget
, layer
, layer
->drawTransform(), opaqueContents
, clipRectInTarget
, m_minimumTrackingSize
, 0, 0);
307 // 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
308 // remain rectilinear, then we don't add any occlusion in screen space.
310 if (layerTransformsToScreenKnown(layer
)) {
311 gfx::Transform targetToScreenTransform
= m_stack
.back().target
->renderSurface()->screenSpaceTransform();
313 gfx::QuadF clipQuadInScreen
= MathUtil::mapQuad(targetToScreenTransform
, gfx::QuadF(clipRectInTarget
), clipped
);
314 // FIXME: Find a rect interior to the transformed clip quad.
315 if (clipped
|| !clipQuadInScreen
.IsRectilinear())
317 gfx::Rect clipRectInScreen
= gfx::IntersectRects(m_rootTargetRect
, gfx::ToEnclosedRect(clipQuadInScreen
.BoundingBox()));
318 addOcclusionBehindLayer
<LayerType
>(m_stack
.back().occlusionInScreen
, layer
, layer
->screenSpaceTransform(), opaqueContents
, clipRectInScreen
, m_minimumTrackingSize
, m_occludingScreenSpaceRects
, m_nonOccludingScreenSpaceRects
);
322 static inline bool testContentRectOccluded(const gfx::Rect
& contentRect
, const gfx::Transform
& contentSpaceTransform
, const gfx::Rect
& clipRectInTarget
, const Region
& occlusion
)
324 gfx::RectF transformedRect
= MathUtil::mapClippedRect(contentSpaceTransform
, gfx::RectF(contentRect
));
325 // Take the gfx::ToEnclosingRect, as we want to include partial pixels in the test.
326 gfx::Rect targetRect
= gfx::IntersectRects(gfx::ToEnclosingRect(transformedRect
), clipRectInTarget
);
327 return occlusion
.Contains(targetRect
);
330 template<typename LayerType
, typename RenderSurfaceType
>
331 bool OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::occluded(const LayerType
* renderTarget
, const gfx::Rect
& contentRect
, const gfx::Transform
& drawTransform
, bool implDrawTransformIsUnknown
, const gfx::Rect
& clippedRectInTarget
, bool* hasOcclusionFromOutsideTargetSurface
) const
333 if (hasOcclusionFromOutsideTargetSurface
)
334 *hasOcclusionFromOutsideTargetSurface
= false;
336 DCHECK(!m_stack
.empty());
339 if (contentRect
.IsEmpty())
342 DCHECK(renderTarget
== m_stack
.back().target
);
344 if (!implDrawTransformIsUnknown
&& testContentRectOccluded(contentRect
, drawTransform
, clippedRectInTarget
, m_stack
.back().occlusionInTarget
))
347 // renderTarget can be NULL in some tests.
348 bool transformToScreenKnown
= renderTarget
&& !implDrawTransformIsUnknown
&& layerTransformsToScreenKnown(renderTarget
);
349 if (transformToScreenKnown
&& testContentRectOccluded(contentRect
, renderTarget
->renderSurface()->screenSpaceTransform() * drawTransform
, m_rootTargetRect
, m_stack
.back().occlusionInScreen
)) {
350 if (hasOcclusionFromOutsideTargetSurface
)
351 *hasOcclusionFromOutsideTargetSurface
= true;
358 // Determines what portion of rect, if any, is unoccluded (not occluded by region). If
359 // the resulting unoccluded region is not rectangular, we return a rect containing it.
360 static inline gfx::Rect
rectSubtractRegion(const gfx::Rect
& rect
, const Region
& region
)
362 if (region
.IsEmpty())
365 Region
rectRegion(rect
);
366 rectRegion
.Subtract(region
);
367 return rectRegion
.bounds();
370 static inline gfx::Rect
computeUnoccludedContentRect(const gfx::Rect
& contentRect
, const gfx::Transform
& contentSpaceTransform
, const gfx::Rect
& clipRectInTarget
, const Region
& occlusion
)
372 if (!contentSpaceTransform
.IsInvertible())
375 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded partial pixels in the resulting Rect.
376 gfx::RectF transformedRect
= MathUtil::mapClippedRect(contentSpaceTransform
, gfx::RectF(contentRect
));
377 gfx::Rect shrunkRect
= rectSubtractRegion(gfx::IntersectRects(gfx::ToEnclosingRect(transformedRect
), clipRectInTarget
), occlusion
);
378 gfx::Rect unoccludedRect
= gfx::ToEnclosingRect(MathUtil::projectClippedRect(MathUtil::inverse(contentSpaceTransform
), gfx::RectF(shrunkRect
)));
379 // The rect back in content space is a bounding box and may extend outside of the original contentRect, so clamp it to the contentRectBounds.
380 return gfx::IntersectRects(unoccludedRect
, contentRect
);
383 template<typename LayerType
, typename RenderSurfaceType
>
384 gfx::Rect OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::unoccludedContentRect(const LayerType
* renderTarget
, const gfx::Rect
& contentRect
, const gfx::Transform
& drawTransform
, bool implDrawTransformIsUnknown
, const gfx::Rect
& clippedRectInTarget
, bool* hasOcclusionFromOutsideTargetSurface
) const
386 DCHECK(!m_stack
.empty());
389 if (contentRect
.IsEmpty())
392 DCHECK(renderTarget
->renderTarget() == renderTarget
);
393 DCHECK(renderTarget
->renderSurface());
394 DCHECK(renderTarget
== m_stack
.back().target
);
396 // We want to return a rect that contains all the visible parts of |contentRect| in both screen space and in the target surface.
397 // So we find the visible parts of |contentRect| in each space, and take the intersection.
399 gfx::Rect unoccludedInScreen
= contentRect
;
400 if (layerTransformsToScreenKnown(renderTarget
) && !implDrawTransformIsUnknown
)
401 unoccludedInScreen
= computeUnoccludedContentRect(contentRect
, renderTarget
->renderSurface()->screenSpaceTransform() * drawTransform
, m_rootTargetRect
, m_stack
.back().occlusionInScreen
);
403 gfx::Rect unoccludedInTarget
= contentRect
;
404 if (!implDrawTransformIsUnknown
)
405 unoccludedInTarget
= computeUnoccludedContentRect(contentRect
, drawTransform
, clippedRectInTarget
, m_stack
.back().occlusionInTarget
);
407 if (hasOcclusionFromOutsideTargetSurface
)
408 *hasOcclusionFromOutsideTargetSurface
= (gfx::IntersectRects(unoccludedInScreen
, unoccludedInTarget
) != unoccludedInTarget
);
410 return gfx::IntersectRects(unoccludedInScreen
, unoccludedInTarget
);
413 template<typename LayerType
, typename RenderSurfaceType
>
414 gfx::Rect OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::unoccludedContributingSurfaceContentRect(const LayerType
* layer
, bool forReplica
, const gfx::Rect
& contentRect
, bool* hasOcclusionFromOutsideTargetSurface
) const
416 DCHECK(!m_stack
.empty());
417 // The layer is a contributing renderTarget so it should have a surface.
418 DCHECK(layer
->renderSurface());
419 // The layer is a contributing renderTarget so its target should be itself.
420 DCHECK(layer
->renderTarget() == layer
);
421 // The layer should not be the root, else what is is contributing to?
422 DCHECK(layer
->parent());
423 // This should be called while the layer is still considered the current target in the occlusion tracker.
424 DCHECK(layer
== m_stack
.back().target
);
426 if (contentRect
.IsEmpty())
429 RenderSurfaceType
* surface
= layer
->renderSurface();
431 gfx::Rect surfaceClipRect
= surface
->clipRect();
432 if (surfaceClipRect
.IsEmpty()) {
433 const LayerType
* contributingSurfaceRenderTarget
= layer
->parent()->renderTarget();
434 surfaceClipRect
= gfx::IntersectRects(contributingSurfaceRenderTarget
->renderSurface()->contentRect(), gfx::ToEnclosingRect(surface
->drawableContentRect()));
437 // 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
438 // found just below the top of the stack (if it exists).
439 bool hasOcclusion
= m_stack
.size() > 1;
441 const gfx::Transform
& transformToScreen
= forReplica
? surface
->replicaScreenSpaceTransform() : surface
->screenSpaceTransform();
442 const gfx::Transform
& transformToTarget
= forReplica
? surface
->replicaDrawTransform() : surface
->drawTransform();
444 gfx::Rect unoccludedInScreen
= contentRect
;
445 if (surfaceTransformsToScreenKnown(surface
)) {
447 const StackObject
& secondLast
= m_stack
[m_stack
.size() - 2];
448 unoccludedInScreen
= computeUnoccludedContentRect(contentRect
, transformToScreen
, m_rootTargetRect
, secondLast
.occlusionInScreen
);
450 unoccludedInScreen
= computeUnoccludedContentRect(contentRect
, transformToScreen
, m_rootTargetRect
, Region());
453 gfx::Rect unoccludedInTarget
= contentRect
;
454 if (surfaceTransformsToTargetKnown(surface
)) {
456 const StackObject
& secondLast
= m_stack
[m_stack
.size() - 2];
457 unoccludedInTarget
= computeUnoccludedContentRect(contentRect
, transformToTarget
, surfaceClipRect
, secondLast
.occlusionInTarget
);
459 unoccludedInTarget
= computeUnoccludedContentRect(contentRect
, transformToTarget
, surfaceClipRect
, Region());
462 if (hasOcclusionFromOutsideTargetSurface
)
463 *hasOcclusionFromOutsideTargetSurface
= (gfx::IntersectRects(unoccludedInScreen
, unoccludedInTarget
) != unoccludedInTarget
);
465 return gfx::IntersectRects(unoccludedInScreen
, unoccludedInTarget
);
468 template<typename LayerType
, typename RenderSurfaceType
>
469 gfx::Rect OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::layerClipRectInTarget(const LayerType
* layer
) const
471 // FIXME: we could remove this helper function, but unit tests currently override this
472 // function, and they need to be verified/adjusted before this can be removed.
473 return layer
->drawableContentRect();
476 // Instantiate (and export) templates here for the linker.
477 template class OcclusionTrackerBase
<Layer
, RenderSurface
>;
478 template class OcclusionTrackerBase
<LayerImpl
, RenderSurfaceImpl
>;