OLD | NEW |
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 Loading... |
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) |
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. |
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 shrank 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 shrank when applying outside occlusion. |
| 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 shrank when applying outside occlusi
on. |
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 |
OLD | NEW |