Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(138)

Side by Side Diff: cc/occlusion_tracker.cc

Issue 11583005: cc: Make occlusion tracker always work in target space. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Rebased Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2012 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "cc/occlusion_tracker.h" 5 #include "cc/occlusion_tracker.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 8
9 #include "cc/layer.h" 9 #include "cc/layer.h"
10 #include "cc/layer_impl.h" 10 #include "cc/layer_impl.h"
11 #include "cc/math_util.h" 11 #include "cc/math_util.h"
12 #include "cc/overdraw_metrics.h" 12 #include "cc/overdraw_metrics.h"
13 #include "ui/gfx/quad_f.h" 13 #include "ui/gfx/quad_f.h"
14 #include "ui/gfx/rect_conversions.h" 14 #include "ui/gfx/rect_conversions.h"
15 15
16 using namespace std; 16 using namespace std;
17 17
18 namespace cc { 18 namespace cc {
19 19
20 template<typename LayerType, typename RenderSurfaceType> 20 template<typename LayerType, typename RenderSurfaceType>
21 OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Re ct rootTargetRect, bool recordMetricsForFrame) 21 OcclusionTrackerBase<LayerType, RenderSurfaceType>::OcclusionTrackerBase(gfx::Re ct screenSpaceClipRect, bool recordMetricsForFrame)
22 : m_rootTargetRect(rootTargetRect) 22 : m_screenSpaceClipRect(screenSpaceClipRect)
23 , m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame)) 23 , m_overdrawMetrics(OverdrawMetrics::create(recordMetricsForFrame))
24 , m_occludingScreenSpaceRects(0) 24 , m_occludingScreenSpaceRects(0)
25 , m_nonOccludingScreenSpaceRects(0) 25 , m_nonOccludingScreenSpaceRects(0)
26 { 26 {
27 } 27 }
28 28
29 template<typename LayerType, typename RenderSurfaceType> 29 template<typename LayerType, typename RenderSurfaceType>
30 OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase() 30 OcclusionTrackerBase<LayerType, RenderSurfaceType>::~OcclusionTrackerBase()
31 { 31 {
32 } 32 }
(...skipping 13 matching lines...) Expand all
46 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const LayerI teratorPosition<LayerType>& layerIterator) 46 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const LayerI teratorPosition<LayerType>& layerIterator)
47 { 47 {
48 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer; 48 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer;
49 49
50 if (layerIterator.representsItself) 50 if (layerIterator.representsItself)
51 markOccludedBehindLayer(layerIterator.currentLayer); 51 markOccludedBehindLayer(layerIterator.currentLayer);
52 else if (layerIterator.representsContributingRenderSurface) 52 else if (layerIterator.representsContributingRenderSurface)
53 leaveToRenderTarget(renderTarget); 53 leaveToRenderTarget(renderTarget);
54 } 54 }
55 55
56 template<typename LayerType, typename RenderSurfaceType> 56 template<typename RenderSurfaceType>
57 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget) 57 static gfx::Rect screenSpaceClipRectInTargetSurface(const RenderSurfaceType* tar getSurface, gfx::Rect screenSpaceClipRect)
enne (OOO) 2012/12/16 19:44:25 Do we not make this projection anywhere in LayerTr
danakj 2012/12/16 20:16:52 This looks a lot like clipRectFromAncestor for con
58 { 58 {
59 if (!m_stack.empty() && m_stack.back().target == newTarget) 59 gfx::Transform inverseScreenSpaceTransform;
60 return; 60 if (!targetSurface->screenSpaceTransform().GetInverse(&inverseScreenSpaceTra nsform))
61 return targetSurface->contentRect();
61 62
62 const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target; 63 return gfx::ToEnclosingRect(MathUtil::projectClippedRect(inverseScreenSpaceT ransform, screenSpaceClipRect));
63 const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTa rget->renderSurface()->nearestAncestorThatMovesPixels(); 64 }
64 const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurfa ce()->nearestAncestorThatMovesPixels();
65 65
66 m_stack.push_back(StackObject(newTarget)); 66 template<typename RenderSurfaceType>
67 static Region transformSurfaceOpaqueRegion(const Region& region, bool haveClipRe ct, gfx::Rect clipRectInNewTarget, const gfx::Transform& transform)
68 {
69 if (region.IsEmpty())
70 return Region();
67 71
68 // We copy the screen occlusion into the new RenderSurfaceImpl subtree, but we never copy in the 72 // Verify that rects within the |surface| will remain rects in its target su rface after applying |transform|. If this is true, then
69 // target occlusion, since we are looking at a new RenderSurfaceImpl target. 73 // apply |transform| to each rect within |region| in order to transform the entire Region.
70 74
71 // If we are entering a subtree that is going to move pixels around, then th e occlusion we've computed 75 bool clipped;
72 // so far won't apply to the pixels we're drawing here in the same way. We d iscard the occlusion thus 76 gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(r egion.bounds()), clipped);
73 // far to be safe, and ensure we don't cull any pixels that are moved such t hat they become visible. 77 // FIXME: Find a rect interior to each transformed quad.
74 bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAnces torThatMovesPixels != oldAncestorThatMovesPixels; 78 if (clipped || !transformedBoundsQuad.IsRectilinear())
79 return Region();
75 80
76 bool copyScreenOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThat MovesPixels; 81 // TODO(danakj): If the Region is too complex, degrade gracefully here by sk ipping rects in it.
enne (OOO) 2012/12/16 19:44:25 I think it'd be great if we had a Region-derived c
danakj 2012/12/16 20:16:52 I will make a bug for this too.
77 if (copyScreenOcclusionForward) { 82 Region transformedRegion;
78 int lastIndex = m_stack.size() - 1; 83 for (Region::Iterator rects(region); rects.has_rect(); rects.next()) {
79 m_stack[lastIndex].occlusionInScreen = m_stack[lastIndex - 1].occlusionI nScreen; 84 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(transf orm, gfx::QuadF(rects.rect()), clipped).BoundingBox());
85 DCHECK(!clipped); // We only map if the transform preserves axis alignme nt.
86 if (haveClipRect)
87 transformedRect.Intersect(clipRectInNewTarget);
88 transformedRegion.Union(transformedRect);
80 } 89 }
90 return transformedRegion;
81 } 91 }
82 92
83 static inline bool layerOpacityKnown(const Layer* layer) { return !layer->drawOp acityIsAnimating(); } 93 static inline bool layerOpacityKnown(const Layer* layer) { return !layer->drawOp acityIsAnimating(); }
84 static inline bool layerOpacityKnown(const LayerImpl*) { return true; } 94 static inline bool layerOpacityKnown(const LayerImpl*) { return true; }
85 static inline bool layerTransformsToTargetKnown(const Layer* layer) { return !la yer->drawTransformIsAnimating(); } 95 static inline bool layerTransformsToTargetKnown(const Layer* layer) { return !la yer->drawTransformIsAnimating(); }
86 static inline bool layerTransformsToTargetKnown(const LayerImpl*) { return true; } 96 static inline bool layerTransformsToTargetKnown(const LayerImpl*) { return true; }
87 static inline bool layerTransformsToScreenKnown(const Layer* layer) { return !la yer->screenSpaceTransformIsAnimating(); }
88 static inline bool layerTransformsToScreenKnown(const LayerImpl*) { return true; }
89 97
90 static inline bool surfaceOpacityKnown(const RenderSurface* surface) { return !s urface->drawOpacityIsAnimating(); } 98 static inline bool surfaceOpacityKnown(const RenderSurface* surface) { return !s urface->drawOpacityIsAnimating(); }
91 static inline bool surfaceOpacityKnown(const RenderSurfaceImpl*) { return true; } 99 static inline bool surfaceOpacityKnown(const RenderSurfaceImpl*) { return true; }
92 static inline bool surfaceTransformsToTargetKnown(const RenderSurface* surface) { return !surface->targetSurfaceTransformsAreAnimating(); } 100 static inline bool surfaceTransformsToTargetKnown(const RenderSurface* surface) { return !surface->targetSurfaceTransformsAreAnimating(); }
93 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceImpl*) { re turn true; } 101 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceImpl*) { re turn true; }
94 static inline bool surfaceTransformsToScreenKnown(const RenderSurface* surface) { return !surface->screenSpaceTransformsAreAnimating(); } 102 static inline bool surfaceTransformsToScreenKnown(const RenderSurface* surface) { return !surface->screenSpaceTransformsAreAnimating(); }
95 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceImpl*) { re turn true; } 103 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceImpl*) { re turn true; }
96 104
97 static inline bool layerIsInUnsorted3dRenderingContext(const Layer* layer) { ret urn layer->parent() && layer->parent()->preserves3D(); } 105 static inline bool layerIsInUnsorted3dRenderingContext(const Layer* layer) { ret urn layer->parent() && layer->parent()->preserves3D(); }
98 static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl*) { retur n false; } 106 static inline bool layerIsInUnsorted3dRenderingContext(const LayerImpl*) { retur n false; }
99 107
100 template<typename LayerType, typename RenderSurfaceType> 108 template<typename LayerType, typename RenderSurfaceType>
109 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(const LayerType* newTarget)
110 {
111 if (!m_stack.empty() && m_stack.back().target == newTarget)
112 return;
113
114 const LayerType* oldTarget = m_stack.empty() ? 0 : m_stack.back().target;
115 const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTa rget->renderSurface()->nearestAncestorThatMovesPixels();
116 const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurfa ce()->nearestAncestorThatMovesPixels();
117
118 m_stack.push_back(StackObject(newTarget));
119
120 // We copy the screen occlusion into the new RenderSurface subtree, but we n ever copy in the
121 // occlusion from inside the target, since we are looking at a new RenderSur face target.
122
123 // If we are entering a subtree that is going to move pixels around, then th e occlusion we've computed
124 // so far won't apply to the pixels we're drawing here in the same way. We d iscard the occlusion thus
125 // far to be safe, and ensure we don't cull any pixels that are moved such t hat they become visible.
126 bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAnces torThatMovesPixels != oldAncestorThatMovesPixels;
127
128 bool haveTransformFromScreenToNewTarget = false;
129 gfx::Transform inverseNewTargetScreenSpaceTransform;
130 if (surfaceTransformsToScreenKnown(newTarget->renderSurface()))
131 haveTransformFromScreenToNewTarget = newTarget->renderSurface()->screenS paceTransform().GetInverse(&inverseNewTargetScreenSpaceTransform);
132
133 bool enteringRootTarget = newTarget->parent() == NULL;
134
135 bool copyOutsideOcclusionForward = m_stack.size() > 1 && !enteringSubtreeTha tMovesPixels && haveTransformFromScreenToNewTarget && !enteringRootTarget;
136 if (!copyOutsideOcclusionForward)
137 return;
138
139 int lastIndex = m_stack.size() - 1;
140 gfx::Transform oldTargetToNewTargetTransform(inverseNewTargetScreenSpaceTran sform, oldTarget->renderSurface()->screenSpaceTransform());
141 m_stack[lastIndex].occlusionFromOutsideTarget = transformSurfaceOpaqueRegion <RenderSurfaceType>(
142 m_stack[lastIndex - 1].occlusionFromOutsideTarget,
143 false,
144 gfx::Rect(),
145 oldTargetToNewTargetTransform);
146 m_stack[lastIndex].occlusionFromOutsideTarget.Union(transformSurfaceOpaqueRe gion<RenderSurfaceType>(
147 m_stack[lastIndex - 1].occlusionFromInsideTarget,
148 false,
149 gfx::Rect(),
150 oldTargetToNewTargetTransform));
151 }
152
153 template<typename LayerType, typename RenderSurfaceType>
101 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(co nst LayerType* finishedTarget) 154 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(co nst LayerType* finishedTarget)
102 { 155 {
103 // Make sure we know about the target surface. 156 // Make sure we know about the target surface.
104 enterRenderTarget(finishedTarget); 157 enterRenderTarget(finishedTarget);
105 158
106 RenderSurfaceType* surface = finishedTarget->renderSurface(); 159 RenderSurfaceType* surface = finishedTarget->renderSurface();
107 160
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. 161 // 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 162 // TODO(senorblanco): Make this smarter for SkImageFilter case: once
110 // SkImageFilters can report affectsOpacity(), call that. 163 // SkImageFilters can report affectsOpacity(), call that.
111 if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface- >drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity() || finishedTarget->filter()) { 164 if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface- >drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity() || finishedTarget->filter()) {
112 m_stack.back().occlusionInScreen.Clear(); 165 m_stack.back().occlusionFromOutsideTarget.Clear();
113 m_stack.back().occlusionInTarget.Clear(); 166 m_stack.back().occlusionFromInsideTarget.Clear();
114 } else { 167 } else if (!surfaceTransformsToTargetKnown(surface)) {
115 if (!surfaceTransformsToTargetKnown(surface)) 168 m_stack.back().occlusionFromInsideTarget.Clear();
116 m_stack.back().occlusionInTarget.Clear(); 169 m_stack.back().occlusionFromOutsideTarget.Clear();
117 if (!surfaceTransformsToScreenKnown(surface))
118 m_stack.back().occlusionInScreen.Clear();
119 } 170 }
120 } 171 }
121 172
122 template<typename RenderSurfaceType> 173 template<typename LayerType>
123 static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surfa ce, const Region& region, const gfx::Transform& transform) 174 static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx: :Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTar get, Region& occlusionFromInsideTarget)
124 { 175 {
125 // Verify that rects within the |surface| will remain rects in its target su rface after applying |transform|. If this is true, then 176 if (surfaceRect.IsEmpty())
126 // apply |transform| to each rect within |region| in order to transform the entire Region.
127
128 bool clipped;
129 gfx::QuadF transformedBoundsQuad = MathUtil::mapQuad(transform, gfx::QuadF(r egion.bounds()), clipped);
130 // FIXME: Find a rect interior to each transformed quad.
131 if (clipped || !transformedBoundsQuad.IsRectilinear())
132 return Region();
133
134 Region transformedRegion;
135
136 for (Region::Iterator rects(region); rects.has_rect(); rects.next()) {
137 // We've already checked for clipping in the mapQuad call above, these c alls 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);
142 }
143 return transformedRegion;
144 }
145
146 static inline void reduceOcclusion(const gfx::Rect& affectedArea, const gfx::Rec t& expandedPixel, Region& occlusion)
147 {
148 if (affectedArea.IsEmpty())
149 return; 177 return;
150 178
151 Region affectedOcclusion = IntersectRegions(occlusion, affectedArea); 179 gfx::Rect affectedAreaInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRe ct(surfaceTransform, gfx::RectF(surfaceRect)));
180 if (contributingLayer->renderSurface()->isClipped())
181 affectedAreaInTarget.Intersect(contributingLayer->renderSurface()->clipR ect());
182 if (affectedAreaInTarget.IsEmpty())
183 return;
184
185 int outsetTop, outsetRight, outsetBottom, outsetLeft;
186 contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, ou tsetBottom, outsetLeft);
187
188 // The filter can move pixels from outside of the clip, so allow affectedAre a to expand outside the clip.
189 affectedAreaInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBot tom);
190
191 gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outset Right, outsetTop + outsetBottom);
192
193 Region affectedOcclusion = IntersectRegions(occlusionFromInsideTarget, affec tedAreaInTarget);
152 Region::Iterator affectedOcclusionRects(affectedOcclusion); 194 Region::Iterator affectedOcclusionRects(affectedOcclusion);
153 195
154 occlusion.Subtract(affectedArea); 196 occlusionFromInsideTarget.Subtract(affectedAreaInTarget);
155 for (; affectedOcclusionRects.has_rect(); affectedOcclusionRects.next()) { 197 for (; affectedOcclusionRects.has_rect(); affectedOcclusionRects.next()) {
156 gfx::Rect occlusionRect = affectedOcclusionRects.rect(); 198 gfx::Rect occlusionRect = affectedOcclusionRects.rect();
157 199
158 // Shrink the rect by expanding the non-opaque pixels outside the rect. 200 // Shrink the rect by expanding the non-opaque pixels outside the rect.
159 201
160 // The expandedPixel is the Rect for a single pixel after being 202 // The left outset of the filters moves pixels on the right side of
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
164 // being filtered.
165 // To convert the expandedPixel Rect back to filter outsets:
166 // x = -leftOutset
167 // width = leftOutset + rightOutset
168 // right = x + width = -leftOutset + leftOutset + rightOutset = rightOut set
169
170 // The leftOutset of the filters moves pixels on the right side of
171 // the occlusionRect into it, shrinking its right edge. 203 // the occlusionRect into it, shrinking its right edge.
172 int shrinkLeft = occlusionRect.x() == affectedArea.x() ? 0 : expandedPix el.right(); 204 int shrinkLeft = occlusionRect.x() == affectedAreaInTarget.x() ? 0 : out setRight;
173 int shrinkTop = occlusionRect.y() == affectedArea.y() ? 0 : expandedPixe l.bottom(); 205 int shrinkTop = occlusionRect.y() == affectedAreaInTarget.y() ? 0 : outs etBottom;
174 int shrinkRight = occlusionRect.right() == affectedArea.right() ? 0 : -e xpandedPixel.x(); 206 int shrinkRight = occlusionRect.right() == affectedAreaInTarget.right() ? 0 : outsetLeft;
175 int shrinkBottom = occlusionRect.bottom() == affectedArea.bottom() ? 0 : -expandedPixel.y(); 207 int shrinkBottom = occlusionRect.bottom() == affectedAreaInTarget.bottom () ? 0 : outsetTop;
176 208
177 occlusionRect.Inset(shrinkLeft, shrinkTop, shrinkRight, shrinkBottom); 209 occlusionRect.Inset(shrinkLeft, shrinkTop, shrinkRight, shrinkBottom);
178 210
179 occlusion.Union(occlusionRect); 211 occlusionFromInsideTarget.Union(occlusionRect);
180 } 212 }
181 } 213 }
182 214
183 template<typename LayerType>
184 static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const gfx: :Rect& surfaceRect, const gfx::Transform& surfaceTransform, LayerType* renderTar get, Region& occlusionInTarget, Region& occlusionInScreen)
185 {
186 if (surfaceRect.IsEmpty())
187 return;
188
189 gfx::Rect boundsInTarget = gfx::ToEnclosingRect(MathUtil::mapClippedRect(sur faceTransform, gfx::RectF(surfaceRect)));
190 if (!contributingLayer->renderSurface()->clipRect().IsEmpty())
191 boundsInTarget.Intersect(contributingLayer->renderSurface()->clipRect()) ;
192
193 int outsetTop, outsetRight, outsetBottom, outsetLeft;
194 contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, ou tsetBottom, outsetLeft);
195
196 // The filter can move pixels from outside of the clip, so allow affectedAre a to expand outside the clip.
197 boundsInTarget.Inset(-outsetLeft, -outsetTop, -outsetRight, -outsetBottom);
198
199 gfx::Rect boundsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedRect(ren derTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(boundsInTarget))) ;
200
201 gfx::Rect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outset Right, outsetTop + outsetBottom);
202 gfx::Rect filterOutsetsInScreen = gfx::ToEnclosingRect(MathUtil::mapClippedR ect(renderTarget->renderSurface()->screenSpaceTransform(), gfx::RectF(filterOuts etsInTarget)));
203
204 reduceOcclusion(boundsInTarget, filterOutsetsInTarget, occlusionInTarget);
205 reduceOcclusion(boundsInScreen, filterOutsetsInScreen, occlusionInScreen);
206 }
207
208 template<typename LayerType, typename RenderSurfaceType> 215 template<typename LayerType, typename RenderSurfaceType>
209 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con st LayerType* newTarget) 216 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(con st LayerType* newTarget)
210 { 217 {
211 int lastIndex = m_stack.size() - 1; 218 int lastIndex = m_stack.size() - 1;
212 bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex - 1].target == newTarget; 219 bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex - 1].target == newTarget;
213 220
214 // We merge the screen occlusion from the current RenderSurfaceImpl subtree out to its parent target RenderSurfaceImpl. 221 // 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 transforme d to the new target. 222 // The target occlusion can be merged out as well but needs to be transforme d to the new target.
216 223
217 const LayerType* oldTarget = m_stack[lastIndex].target; 224 const LayerType* oldTarget = m_stack[lastIndex].target;
218 const RenderSurfaceType* oldSurface = oldTarget->renderSurface(); 225 const RenderSurfaceType* oldSurface = oldTarget->renderSurface();
219 Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSu rfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->drawTra nsform()); 226
227 Region oldOcclusionFromInsideTargetInNewTarget = transformSurfaceOpaqueRegio n<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface->i sClipped(), oldSurface->clipRect(), oldSurface->drawTransform());
220 if (oldTarget->hasReplica() && !oldTarget->replicaHasMask()) 228 if (oldTarget->hasReplica() && !oldTarget->replicaHasMask())
221 oldTargetOcclusionInNewTarget.Union(transformSurfaceOpaqueRegion<RenderS urfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->replic aDrawTransform())); 229 oldOcclusionFromInsideTargetInNewTarget.Union(transformSurfaceOpaqueRegi on<RenderSurfaceType>(m_stack[lastIndex].occlusionFromInsideTarget, oldSurface-> isClipped(), oldSurface->clipRect(), oldSurface->replicaDrawTransform()));
230
231 Region oldOcclusionFromOutsideTargetInNewTarget = transformSurfaceOpaqueRegi on<RenderSurfaceType>(m_stack[lastIndex].occlusionFromOutsideTarget, false, gfx: :Rect(), oldSurface->drawTransform());
222 232
223 gfx::Rect unoccludedSurfaceRect; 233 gfx::Rect unoccludedSurfaceRect;
224 gfx::Rect unoccludedReplicaRect; 234 gfx::Rect unoccludedReplicaRect;
225 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { 235 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) {
226 unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarg et, false, oldSurface->contentRect()); 236 unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarg et, false, oldSurface->contentRect());
227 if (oldTarget->hasReplica()) 237 if (oldTarget->hasReplica())
228 unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(old Target, true, oldSurface->contentRect()); 238 unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(old Target, true, oldSurface->contentRect());
229 } 239 }
230 240
231 if (surfaceWillBeAtTopAfterPop) { 241 if (surfaceWillBeAtTopAfterPop) {
232 // Merge the top of the stack down. 242 // Merge the top of the stack down.
233 m_stack[lastIndex - 1].occlusionInScreen.Union(m_stack[lastIndex].occlus ionInScreen); 243 m_stack[lastIndex - 1].occlusionFromInsideTarget.Union(oldOcclusionFromI nsideTargetInNewTarget);
234 m_stack[lastIndex - 1].occlusionInTarget.Union(oldTargetOcclusionInNewTa rget); 244 // TODO(danakj): Strictly this should subtract the inside target occlusi on before union.
245 if (newTarget->parent())
246 m_stack[lastIndex - 1].occlusionFromOutsideTarget.Union(oldOcclusion FromOutsideTargetInNewTarget);
235 m_stack.pop_back(); 247 m_stack.pop_back();
236 } else { 248 } else {
237 // Replace the top of the stack with the new pushed surface. Copy the oc cluded screen region to the top. 249 // Replace the top of the stack with the new pushed surface.
238 m_stack.back().target = newTarget; 250 m_stack.back().target = newTarget;
239 m_stack.back().occlusionInTarget = oldTargetOcclusionInNewTarget; 251 m_stack.back().occlusionFromInsideTarget = oldOcclusionFromInsideTargetI nNewTarget;
252 if (newTarget->parent())
253 m_stack.back().occlusionFromOutsideTarget = oldOcclusionFromOutsideT argetInNewTarget;
254 else
255 m_stack.back().occlusionFromOutsideTarget.Clear();
240 } 256 }
241 257
242 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { 258 if (!oldTarget->backgroundFilters().hasFilterThatMovesPixels())
243 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface ->drawTransform(), newTarget, m_stack.back().occlusionInTarget, m_stack.back().o cclusionInScreen);
244 if (oldTarget->hasReplica())
245 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSur face->replicaDrawTransform(), newTarget, m_stack.back().occlusionInTarget, m_sta ck.back().occlusionInScreen);
246 }
247 }
248
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* laye r, const gfx::Transform& transform, const Region& opaqueContents, const gfx::Rec t& clipRectInTarget, const gfx::Size& minimumTrackingSize, std::vector<gfx::Rect >* occludingScreenSpaceRects, std::vector<gfx::Rect>* nonOccludingScreenSpaceRec ts)
252 {
253 DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds()));
254
255 bool clipped;
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())
259 return; 259 return;
260 260
261 for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects .has_rect(); opaqueContentRects.next()) { 261 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->dr awTransform(), newTarget, m_stack.back().occlusionFromInsideTarget);
262 // We've already checked for clipping in the mapQuad call above, these c alls should not clip anything further. 262 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface->dr awTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget);
263 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect (transform, gfx::RectF(opaqueContentRects.rect())));
264 transformedRect.Intersect(clipRectInTarget);
265 if (transformedRect.width() >= minimumTrackingSize.width() || transforme dRect.height() >= minimumTrackingSize.height()) {
266 if (occludingScreenSpaceRects)
267 occludingScreenSpaceRects->push_back(transformedRect);
268 region.Union(transformedRect);
269 }
270 }
271 263
272 if (nonOccludingScreenSpaceRects) { 264 if (!oldTarget->hasReplica())
273 Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBound s()), opaqueContents); 265 return;
274 for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqu eContentRects.has_rect(); nonOpaqueContentRects.next()) { 266 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->re plicaDrawTransform(), newTarget, m_stack.back().occlusionFromInsideTarget);
275 // We've already checked for clipping in the mapQuad call above, the se calls should not clip anything further. 267 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSurface->re plicaDrawTransform(), newTarget, m_stack.back().occlusionFromOutsideTarget);
276 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClipped Rect(transform, gfx::RectF(nonOpaqueContentRects.rect())));
277 transformedRect.Intersect(clipRectInTarget);
278 if (transformedRect.IsEmpty())
279 continue;
280 nonOccludingScreenSpaceRects->push_back(transformedRect);
281 }
282 }
283 } 268 }
284 269
285 template<typename LayerType, typename RenderSurfaceType> 270 template<typename LayerType, typename RenderSurfaceType>
286 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer (const LayerType* layer) 271 void OcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLayer (const LayerType* layer)
287 { 272 {
288 DCHECK(!m_stack.empty()); 273 DCHECK(!m_stack.empty());
289 DCHECK(layer->renderTarget() == m_stack.back().target); 274 DCHECK(layer->renderTarget() == m_stack.back().target);
290 if (m_stack.empty()) 275 if (m_stack.empty())
291 return; 276 return;
292 277
293 if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1) 278 if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1)
294 return; 279 return;
295 280
296 if (layerIsInUnsorted3dRenderingContext(layer)) 281 if (layerIsInUnsorted3dRenderingContext(layer))
297 return; 282 return;
298 283
299 Region opaqueContents = layer->visibleContentOpaqueRegion(); 284 Region opaqueContents = layer->visibleContentOpaqueRegion();
300 if (opaqueContents.IsEmpty()) 285 if (opaqueContents.IsEmpty())
301 return; 286 return;
302 287
303 gfx::Rect clipRectInTarget = layerClipRectInTarget(layer); 288 DCHECK(layer->visibleContentRect().Contains(opaqueContents.bounds()));
304 if (layerTransformsToTargetKnown(layer))
305 addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInTarget, lay er, layer->drawTransform(), opaqueContents, clipRectInTarget, m_minimumTrackingS ize, 0, 0);
306 289
307 // We must clip the occlusion within the layer's clipRectInTarget within scr een space as well. If the clip rect can't be moved to screen space and 290 if (!layerTransformsToTargetKnown(layer))
308 // remain rectilinear, then we don't add any occlusion in screen space. 291 return;
309 292
310 if (layerTransformsToScreenKnown(layer)) { 293 bool clipped;
311 gfx::Transform targetToScreenTransform = m_stack.back().target->renderSu rface()->screenSpaceTransform(); 294 gfx::QuadF visibleTransformedQuad = MathUtil::mapQuad(layer->drawTransform() , gfx::QuadF(opaqueContents.bounds()), clipped);
312 bool clipped; 295 // FIXME: Find a rect interior to each transformed quad.
313 gfx::QuadF clipQuadInScreen = MathUtil::mapQuad(targetToScreenTransform, gfx::QuadF(clipRectInTarget), clipped); 296 if (clipped || !visibleTransformedQuad.IsRectilinear())
314 // FIXME: Find a rect interior to the transformed clip quad. 297 return;
315 if (clipped || !clipQuadInScreen.IsRectilinear()) 298
316 return; 299 gfx::Rect clipRectInTarget = gfx::IntersectRects(
317 gfx::Rect clipRectInScreen = gfx::IntersectRects(m_rootTargetRect, gfx:: ToEnclosedRect(clipQuadInScreen.BoundingBox())); 300 layerClipRectInTarget(layer),
318 addOcclusionBehindLayer<LayerType>(m_stack.back().occlusionInScreen, lay er, layer->screenSpaceTransform(), opaqueContents, clipRectInScreen, m_minimumTr ackingSize, m_occludingScreenSpaceRects, m_nonOccludingScreenSpaceRects); 301 screenSpaceClipRectInTargetSurface(layer->renderTarget()->renderSurface( ), m_screenSpaceClipRect));
302
303 for (Region::Iterator opaqueContentRects(opaqueContents); opaqueContentRects .has_rect(); opaqueContentRects.next()) {
304 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapQuad(layer- >drawTransform(), gfx::QuadF(opaqueContentRects.rect()), clipped).BoundingBox()) ;
305 DCHECK(!clipped); // We only map if the transform preserves axis alignme nt.
306 transformedRect.Intersect(clipRectInTarget);
307 if (transformedRect.width() < m_minimumTrackingSize.width() && transform edRect.height() < m_minimumTrackingSize.height())
308 continue;
309 m_stack.back().occlusionFromInsideTarget.Union(transformedRect);
310
311 if (!m_occludingScreenSpaceRects)
312 continue;
313
314 // Save the occluding area in screen space for debug visualization.
315 gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->re nderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped);
316 // TODO(danakj): Store the quad in the debug info instead of the boundin g box.
317 gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.Bounding Box());
318 m_occludingScreenSpaceRects->push_back(screenSpaceRect);
319 } 319 }
320 }
321 320
322 static inline bool testContentRectOccluded(const gfx::Rect& contentRect, const g fx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarget, const R egion& occlusion) 321 if (!m_nonOccludingScreenSpaceRects)
323 { 322 return;
324 gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect)); 323
325 // Take the gfx::ToEnclosingRect, as we want to include partial pixels in th e test. 324 Region nonOpaqueContents = SubtractRegions(gfx::Rect(layer->contentBounds()) , opaqueContents);
326 gfx::Rect targetRect = gfx::IntersectRects(gfx::ToEnclosingRect(transformedR ect), clipRectInTarget); 325 for (Region::Iterator nonOpaqueContentRects(nonOpaqueContents); nonOpaqueCon tentRects.has_rect(); nonOpaqueContentRects.next()) {
327 return occlusion.Contains(targetRect); 326 // We've already checked for clipping in the mapQuad call above, these c alls should not clip anything further.
327 gfx::Rect transformedRect = gfx::ToEnclosedRect(MathUtil::mapClippedRect (layer->drawTransform(), gfx::RectF(nonOpaqueContentRects.rect())));
328 transformedRect.Intersect(clipRectInTarget);
329 if (transformedRect.IsEmpty())
330 continue;
331
332 gfx::QuadF screenSpaceQuad = MathUtil::mapQuad(layer->renderTarget()->re nderSurface()->screenSpaceTransform(), gfx::QuadF(transformedRect), clipped);
333 // TODO(danakj): Store the quad in the debug info instead of the boundin g box.
334 gfx::Rect screenSpaceRect = gfx::ToEnclosedRect(screenSpaceQuad.Bounding Box());
335 m_nonOccludingScreenSpaceRects->push_back(screenSpaceRect);
336 }
328 } 337 }
329 338
330 template<typename LayerType, typename RenderSurfaceType> 339 template<typename LayerType, typename RenderSurfaceType>
331 bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerTyp e* renderTarget, const gfx::Rect& contentRect, const gfx::Transform& drawTransfo rm, bool implDrawTransformIsUnknown, const gfx::Rect& clippedRectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const 340 bool OcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerTyp e* renderTarget, const gfx::Rect& contentRect, const gfx::Transform& drawTransfo rm, bool implDrawTransformIsUnknown, const gfx::Rect& clippedRectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const
332 { 341 {
333 if (hasOcclusionFromOutsideTargetSurface)
334 *hasOcclusionFromOutsideTargetSurface = false;
335
336 DCHECK(!m_stack.empty()); 342 DCHECK(!m_stack.empty());
337 if (m_stack.empty()) 343 if (m_stack.empty())
338 return false; 344 return false;
339 if (contentRect.IsEmpty()) 345 if (contentRect.IsEmpty())
340 return true; 346 return true;
347 if (implDrawTransformIsUnknown)
348 return false;
341 349
350 // For tests with no render target.
351 if (!renderTarget)
352 return false;
353
354 DCHECK(renderTarget->renderTarget() == renderTarget);
355 DCHECK(renderTarget->renderSurface());
342 DCHECK(renderTarget == m_stack.back().target); 356 DCHECK(renderTarget == m_stack.back().target);
343 357
344 if (!implDrawTransformIsUnknown && testContentRectOccluded(contentRect, draw Transform, clippedRectInTarget, m_stack.back().occlusionInTarget)) 358 gfx::Transform inverseDrawTransform;
345 return true; 359 if (!drawTransform.GetInverse(&inverseDrawTransform))
360 return false;
346 361
347 // renderTarget can be NULL in some tests. 362 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect.
348 bool transformToScreenKnown = renderTarget && !implDrawTransformIsUnknown && layerTransformsToScreenKnown(renderTarget); 363 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect)));
349 if (transformToScreenKnown && testContentRectOccluded(contentRect, renderTar get->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen)) { 364 contentRectInTargetSurface.Intersect(clippedRectInTarget);
350 if (hasOcclusionFromOutsideTargetSurface) 365 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(rend erTarget->renderSurface(), m_screenSpaceClipRect));
351 *hasOcclusionFromOutsideTargetSurface = true; 366
352 return true; 367 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
368 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideT arget);
369 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccluded RegionInTargetSurface.bounds();
370 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutside Target);
371
372 gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.b ounds();
373
374 if (hasOcclusionFromOutsideTargetSurface) {
375 // Check if the unoccluded rect shank when applying outside occlusion.
376 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRe ctInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty ();
353 } 377 }
354 378
355 return false; 379 return unoccludedRectInTargetSurface.IsEmpty();
356 }
357
358 // Determines what portion of rect, if any, is unoccluded (not occluded by regio n). If
359 // the resulting unoccluded region is not rectangular, we return a rect containi ng it.
360 static inline gfx::Rect rectSubtractRegion(const gfx::Rect& rect, const Region& region)
361 {
362 if (region.IsEmpty())
363 return rect;
364
365 Region rectRegion(rect);
366 rectRegion.Subtract(region);
367 return rectRegion.bounds();
368 }
369
370 static inline gfx::Rect computeUnoccludedContentRect(const gfx::Rect& contentRec t, const gfx::Transform& contentSpaceTransform, const gfx::Rect& clipRectInTarge t, const Region& occlusion)
371 {
372 if (!contentSpaceTransform.IsInvertible())
373 return contentRect;
374
375 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect.
376 gfx::RectF transformedRect = MathUtil::mapClippedRect(contentSpaceTransform, gfx::RectF(contentRect));
377 gfx::Rect shrunkRect = rectSubtractRegion(gfx::IntersectRects(gfx::ToEnclosi ngRect(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 o f the original contentRect, so clamp it to the contentRectBounds.
380 return gfx::IntersectRects(unoccludedRect, contentRect);
381 } 380 }
382 381
383 template<typename LayerType, typename RenderSurfaceType> 382 template<typename LayerType, typename RenderSurfaceType>
384 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR ect(const LayerType* renderTarget, const gfx::Rect& contentRect, const gfx::Tran sform& drawTransform, bool implDrawTransformIsUnknown, const gfx::Rect& clippedR ectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const 383 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR ect(const LayerType* renderTarget, const gfx::Rect& contentRect, const gfx::Tran sform& drawTransform, bool implDrawTransformIsUnknown, const gfx::Rect& clippedR ectInTarget, bool* hasOcclusionFromOutsideTargetSurface) const
385 { 384 {
386 DCHECK(!m_stack.empty()); 385 DCHECK(!m_stack.empty());
387 if (m_stack.empty()) 386 if (m_stack.empty())
388 return contentRect; 387 return contentRect;
389 if (contentRect.IsEmpty()) 388 if (contentRect.IsEmpty())
390 return contentRect; 389 return contentRect;
390 if (implDrawTransformIsUnknown)
391 return contentRect;
392
393 // For tests with no render target.
394 if (!renderTarget)
395 return contentRect;
391 396
392 DCHECK(renderTarget->renderTarget() == renderTarget); 397 DCHECK(renderTarget->renderTarget() == renderTarget);
393 DCHECK(renderTarget->renderSurface()); 398 DCHECK(renderTarget->renderSurface());
394 DCHECK(renderTarget == m_stack.back().target); 399 DCHECK(renderTarget == m_stack.back().target);
395 400
396 // We want to return a rect that contains all the visible parts of |contentR ect| in both screen space and in the target surface. 401 gfx::Transform inverseDrawTransform;
397 // So we find the visible parts of |contentRect| in each space, and take the intersection. 402 if (!drawTransform.GetInverse(&inverseDrawTransform))
403 return contentRect;
398 404
399 gfx::Rect unoccludedInScreen = contentRect; 405 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect.
400 if (layerTransformsToScreenKnown(renderTarget) && !implDrawTransformIsUnknow n) 406 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect)));
401 unoccludedInScreen = computeUnoccludedContentRect(contentRect, renderTar get->renderSurface()->screenSpaceTransform() * drawTransform, m_rootTargetRect, m_stack.back().occlusionInScreen); 407 contentRectInTargetSurface.Intersect(clippedRectInTarget);
408 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(rend erTarget->renderSurface(), m_screenSpaceClipRect));
402 409
403 gfx::Rect unoccludedInTarget = contentRect; 410 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
404 if (!implDrawTransformIsUnknown) 411 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromInsideT arget);
405 unoccludedInTarget = computeUnoccludedContentRect(contentRect, drawTrans form, clippedRectInTarget, m_stack.back().occlusionInTarget); 412 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccluded RegionInTargetSurface.bounds();
413 unoccludedRegionInTargetSurface.Subtract(m_stack.back().occlusionFromOutside Target);
406 414
407 if (hasOcclusionFromOutsideTargetSurface) 415 gfx::RectF unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.b ounds();
408 *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedI nScreen, unoccludedInTarget) != unoccludedInTarget); 416 gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect (inverseDrawTransform, unoccludedRectInTargetSurface));
417 unoccludedRect.Intersect(contentRect);
409 418
410 return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget); 419 if (hasOcclusionFromOutsideTargetSurface) {
420 // Check if the unoccluded rect shank when applying outside occlusion.
jamesr 2012/12/16 00:27:54 typo shank -> shrank
danakj 2012/12/16 21:30:03 Done.
421 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unoccludedRe ctInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsEmpty ();
422 }
423
424 return unoccludedRect;
411 } 425 }
412 426
413 template<typename LayerType, typename RenderSurfaceType> 427 template<typename LayerType, typename RenderSurfaceType>
414 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu tingSurfaceContentRect(const LayerType* layer, bool forReplica, const gfx::Rect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const 428 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu tingSurfaceContentRect(const LayerType* layer, bool forReplica, const gfx::Rect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const
415 { 429 {
416 DCHECK(!m_stack.empty()); 430 DCHECK(!m_stack.empty());
417 // The layer is a contributing renderTarget so it should have a surface. 431 // The layer is a contributing renderTarget so it should have a surface.
418 DCHECK(layer->renderSurface()); 432 DCHECK(layer->renderSurface());
419 // The layer is a contributing renderTarget so its target should be itself. 433 // The layer is a contributing renderTarget so its target should be itself.
420 DCHECK(layer->renderTarget() == layer); 434 DCHECK(layer->renderTarget() == layer);
421 // The layer should not be the root, else what is is contributing to? 435 // The layer should not be the root, else what is is contributing to?
422 DCHECK(layer->parent()); 436 DCHECK(layer->parent());
423 // This should be called while the layer is still considered the current tar get in the occlusion tracker. 437 // This should be called while the layer is still considered the current tar get in the occlusion tracker.
424 DCHECK(layer == m_stack.back().target); 438 DCHECK(layer == m_stack.back().target);
425 439
426 if (contentRect.IsEmpty()) 440 if (contentRect.IsEmpty())
427 return contentRect; 441 return contentRect;
428 442
429 RenderSurfaceType* surface = layer->renderSurface(); 443 const RenderSurfaceType* surface = layer->renderSurface();
444 const LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTa rget();
430 445
431 gfx::Rect surfaceClipRect = surface->clipRect(); 446 if (!surfaceTransformsToTargetKnown(surface))
432 if (surfaceClipRect.IsEmpty()) { 447 return contentRect;
433 const LayerType* contributingSurfaceRenderTarget = layer->parent()->rend erTarget(); 448
434 surfaceClipRect = gfx::IntersectRects(contributingSurfaceRenderTarget->r enderSurface()->contentRect(), gfx::ToEnclosingRect(surface->drawableContentRect ())); 449 gfx::Transform drawTransform = forReplica ? surface->replicaDrawTransform() : surface->drawTransform();
450 gfx::Transform inverseDrawTransform;
451 if (!drawTransform.GetInverse(&inverseDrawTransform))
452 return contentRect;
453
454 // Take the ToEnclosingRect at each step, as we want to contain any unocclud ed partial pixels in the resulting Rect.
455 gfx::Rect contentRectInTargetSurface = gfx::ToEnclosingRect(MathUtil::mapCli ppedRect(drawTransform, gfx::RectF(contentRect)));
456 if (surface->isClipped()) {
457 contentRectInTargetSurface.Intersect(surface->clipRect());
458 } else {
459 contentRectInTargetSurface.Intersect(contributingSurfaceRenderTarget->re nderSurface()->contentRect());
460 contentRectInTargetSurface.Intersect(gfx::ToEnclosingRect(surface->drawa bleContentRect()));
435 } 461 }
462 contentRectInTargetSurface.Intersect(screenSpaceClipRectInTargetSurface(cont ributingSurfaceRenderTarget->renderSurface(), m_screenSpaceClipRect));
463
464 gfx::RectF unoccludedRectInTargetSurface;
436 465
437 // A contributing surface doesn't get occluded by things inside its own surf ace, so only things outside the surface can occlude it. That occlusion is 466 // A contributing surface doesn't get occluded by things inside its own surf ace, so only things outside the surface can occlude it. That occlusion is
438 // found just below the top of the stack (if it exists). 467 // found just below the top of the stack (if it exists).
439 bool hasOcclusion = m_stack.size() > 1; 468 bool hasOcclusion = m_stack.size() > 1;
469 if (hasOcclusion) {
470 const StackObject& secondLast = m_stack[m_stack.size() - 2];
471 Region unoccludedRegionInTargetSurface = contentRectInTargetSurface;
472 unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromInsideT arget);
473 gfx::RectF unoccludedRectInTargetSurfaceWithoutOutsideOcclusion = unoccl udedRegionInTargetSurface.bounds();
474 unoccludedRegionInTargetSurface.Subtract(secondLast.occlusionFromOutside Target);
440 475
441 const gfx::Transform& transformToScreen = forReplica ? surface->replicaScree nSpaceTransform() : surface->screenSpaceTransform(); 476 unoccludedRectInTargetSurface = unoccludedRegionInTargetSurface.bounds() ;
442 const gfx::Transform& transformToTarget = forReplica ? surface->replicaDrawT ransform() : surface->drawTransform();
443 477
444 gfx::Rect unoccludedInScreen = contentRect; 478 if (hasOcclusionFromOutsideTargetSurface) {
445 if (surfaceTransformsToScreenKnown(surface)) { 479 // Check if the unoccluded rect shank when applying outside occlusio n.
jamesr 2012/12/16 00:27:54 same typo
danakj 2012/12/16 21:30:03 Done.
446 if (hasOcclusion) { 480 *hasOcclusionFromOutsideTargetSurface = !gfx::SubtractRects(unocclud edRectInTargetSurfaceWithoutOutsideOcclusion, unoccludedRectInTargetSurface).IsE mpty();
447 const StackObject& secondLast = m_stack[m_stack.size() - 2]; 481 }
448 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans formToScreen, m_rootTargetRect, secondLast.occlusionInScreen); 482 } else {
449 } else 483 unoccludedRectInTargetSurface = contentRectInTargetSurface;
450 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans formToScreen, m_rootTargetRect, Region()); 484 if (hasOcclusionFromOutsideTargetSurface)
485 *hasOcclusionFromOutsideTargetSurface = false;
451 } 486 }
452 487
453 gfx::Rect unoccludedInTarget = contentRect; 488 gfx::Rect unoccludedRect = gfx::ToEnclosingRect(MathUtil::projectClippedRect (inverseDrawTransform, unoccludedRectInTargetSurface));
454 if (surfaceTransformsToTargetKnown(surface)) { 489 unoccludedRect.Intersect(contentRect);
455 if (hasOcclusion) {
456 const StackObject& secondLast = m_stack[m_stack.size() - 2];
457 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans formToTarget, surfaceClipRect, secondLast.occlusionInTarget);
458 } else
459 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans formToTarget, surfaceClipRect, Region());
460 }
461 490
462 if (hasOcclusionFromOutsideTargetSurface) 491 return unoccludedRect;
463 *hasOcclusionFromOutsideTargetSurface = (gfx::IntersectRects(unoccludedI nScreen, unoccludedInTarget) != unoccludedInTarget);
464
465 return gfx::IntersectRects(unoccludedInScreen, unoccludedInTarget);
466 } 492 }
467 493
468 template<typename LayerType, typename RenderSurfaceType> 494 template<typename LayerType, typename RenderSurfaceType>
469 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTar get(const LayerType* layer) const 495 gfx::Rect OcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTar get(const LayerType* layer) const
470 { 496 {
471 // FIXME: we could remove this helper function, but unit tests currently ove rride this 497 // TODO(danakj): Can we remove this use of drawableContentRect and just use the clipRect() and target surface contentRect?
472 // function, and they need to be verified/adjusted before this can be removed.
473 return layer->drawableContentRect(); 498 return layer->drawableContentRect();
474 } 499 }
475 500
476 // Instantiate (and export) templates here for the linker. 501 // Instantiate (and export) templates here for the linker.
477 template class OcclusionTrackerBase<Layer, RenderSurface>; 502 template class OcclusionTrackerBase<Layer, RenderSurface>;
478 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>; 503 template class OcclusionTrackerBase<LayerImpl, RenderSurfaceImpl>;
479 504
480 } // namespace cc 505 } // namespace cc
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698