Chromium Code Reviews| 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) |
|
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 |
| OLD | NEW |