| OLD | NEW |
| (Empty) |
| 1 // Copyright 2012 The Chromium Authors. All rights reserved. | |
| 2 // Use of this source code is governed by a BSD-style license that can be | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 | |
| 7 #if USE(ACCELERATED_COMPOSITING) | |
| 8 | |
| 9 #include "CCOcclusionTracker.h" | |
| 10 | |
| 11 #include "CCLayerImpl.h" | |
| 12 #include "CCMathUtil.h" | |
| 13 #include "CCOverdrawMetrics.h" | |
| 14 #include "LayerChromium.h" | |
| 15 #include <algorithm> | |
| 16 | |
| 17 using namespace std; | |
| 18 using WebKit::WebTransformationMatrix; | |
| 19 | |
| 20 namespace cc { | |
| 21 | |
| 22 template<typename LayerType, typename RenderSurfaceType> | |
| 23 CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::CCOcclusionTrackerBase(Int
Rect rootTargetRect, bool recordMetricsForFrame) | |
| 24 : m_rootTargetRect(rootTargetRect) | |
| 25 , m_overdrawMetrics(CCOverdrawMetrics::create(recordMetricsForFrame)) | |
| 26 , m_occludingScreenSpaceRects(0) | |
| 27 { | |
| 28 } | |
| 29 | |
| 30 template<typename LayerType, typename RenderSurfaceType> | |
| 31 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::enterLayer(const CCLa
yerIteratorPosition<LayerType>& layerIterator) | |
| 32 { | |
| 33 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer; | |
| 34 | |
| 35 if (layerIterator.representsItself) | |
| 36 enterRenderTarget(renderTarget); | |
| 37 else if (layerIterator.representsTargetRenderSurface) | |
| 38 finishedRenderTarget(renderTarget); | |
| 39 } | |
| 40 | |
| 41 template<typename LayerType, typename RenderSurfaceType> | |
| 42 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveLayer(const CCLa
yerIteratorPosition<LayerType>& layerIterator) | |
| 43 { | |
| 44 LayerType* renderTarget = layerIterator.targetRenderSurfaceLayer; | |
| 45 | |
| 46 if (layerIterator.representsItself) | |
| 47 markOccludedBehindLayer(layerIterator.currentLayer); | |
| 48 else if (layerIterator.representsContributingRenderSurface) | |
| 49 leaveToRenderTarget(renderTarget); | |
| 50 } | |
| 51 | |
| 52 template<typename LayerType, typename RenderSurfaceType> | |
| 53 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::enterRenderTarget(con
st LayerType* newTarget) | |
| 54 { | |
| 55 if (!m_stack.isEmpty() && m_stack.last().target == newTarget) | |
| 56 return; | |
| 57 | |
| 58 const LayerType* oldTarget = m_stack.isEmpty() ? 0 : m_stack.last().target; | |
| 59 const RenderSurfaceType* oldAncestorThatMovesPixels = !oldTarget ? 0 : oldTa
rget->renderSurface()->nearestAncestorThatMovesPixels(); | |
| 60 const RenderSurfaceType* newAncestorThatMovesPixels = newTarget->renderSurfa
ce()->nearestAncestorThatMovesPixels(); | |
| 61 | |
| 62 m_stack.append(StackObject(newTarget)); | |
| 63 | |
| 64 // We copy the screen occlusion into the new RenderSurface subtree, but we n
ever copy in the | |
| 65 // target occlusion, since we are looking at a new RenderSurface target. | |
| 66 | |
| 67 // If we are entering a subtree that is going to move pixels around, then th
e occlusion we've computed | |
| 68 // so far won't apply to the pixels we're drawing here in the same way. We d
iscard the occlusion thus | |
| 69 // far to be safe, and ensure we don't cull any pixels that are moved such t
hat they become visible. | |
| 70 bool enteringSubtreeThatMovesPixels = newAncestorThatMovesPixels && newAnces
torThatMovesPixels != oldAncestorThatMovesPixels; | |
| 71 | |
| 72 bool copyScreenOcclusionForward = m_stack.size() > 1 && !enteringSubtreeThat
MovesPixels; | |
| 73 if (copyScreenOcclusionForward) { | |
| 74 int lastIndex = m_stack.size() - 1; | |
| 75 m_stack[lastIndex].occlusionInScreen = m_stack[lastIndex - 1].occlusionI
nScreen; | |
| 76 } | |
| 77 } | |
| 78 | |
| 79 static inline bool layerOpacityKnown(const LayerChromium* layer) { return !layer
->drawOpacityIsAnimating(); } | |
| 80 static inline bool layerOpacityKnown(const CCLayerImpl*) { return true; } | |
| 81 static inline bool layerTransformsToTargetKnown(const LayerChromium* layer) { re
turn !layer->drawTransformIsAnimating(); } | |
| 82 static inline bool layerTransformsToTargetKnown(const CCLayerImpl*) { return tru
e; } | |
| 83 static inline bool layerTransformsToScreenKnown(const LayerChromium* layer) { re
turn !layer->screenSpaceTransformIsAnimating(); } | |
| 84 static inline bool layerTransformsToScreenKnown(const CCLayerImpl*) { return tru
e; } | |
| 85 | |
| 86 static inline bool surfaceOpacityKnown(const RenderSurfaceChromium* surface) { r
eturn !surface->drawOpacityIsAnimating(); } | |
| 87 static inline bool surfaceOpacityKnown(const CCRenderSurface*) { return true; } | |
| 88 static inline bool surfaceTransformsToTargetKnown(const RenderSurfaceChromium* s
urface) { return !surface->targetSurfaceTransformsAreAnimating(); } | |
| 89 static inline bool surfaceTransformsToTargetKnown(const CCRenderSurface*) { retu
rn true; } | |
| 90 static inline bool surfaceTransformsToScreenKnown(const RenderSurfaceChromium* s
urface) { return !surface->screenSpaceTransformsAreAnimating(); } | |
| 91 static inline bool surfaceTransformsToScreenKnown(const CCRenderSurface*) { retu
rn true; } | |
| 92 | |
| 93 static inline bool layerIsInUnsorted3dRenderingContext(const LayerChromium* laye
r) { return layer->parent() && layer->parent()->preserves3D(); } | |
| 94 static inline bool layerIsInUnsorted3dRenderingContext(const CCLayerImpl*) { ret
urn false; } | |
| 95 | |
| 96 template<typename LayerType, typename RenderSurfaceType> | |
| 97 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::finishedRenderTarget(
const LayerType* finishedTarget) | |
| 98 { | |
| 99 // Make sure we know about the target surface. | |
| 100 enterRenderTarget(finishedTarget); | |
| 101 | |
| 102 RenderSurfaceType* surface = finishedTarget->renderSurface(); | |
| 103 | |
| 104 // 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. | |
| 105 if (finishedTarget->maskLayer() || !surfaceOpacityKnown(surface) || surface-
>drawOpacity() < 1 || finishedTarget->filters().hasFilterThatAffectsOpacity()) { | |
| 106 m_stack.last().occlusionInScreen = Region(); | |
| 107 m_stack.last().occlusionInTarget = Region(); | |
| 108 } else { | |
| 109 if (!surfaceTransformsToTargetKnown(surface)) | |
| 110 m_stack.last().occlusionInTarget = Region(); | |
| 111 if (!surfaceTransformsToScreenKnown(surface)) | |
| 112 m_stack.last().occlusionInScreen = Region(); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 template<typename RenderSurfaceType> | |
| 117 static inline Region transformSurfaceOpaqueRegion(const RenderSurfaceType* surfa
ce, const Region& region, const WebTransformationMatrix& transform) | |
| 118 { | |
| 119 // Verify that rects within the |surface| will remain rects in its target su
rface after applying |transform|. If this is true, then | |
| 120 // apply |transform| to each rect within |region| in order to transform the
entire Region. | |
| 121 | |
| 122 bool clipped; | |
| 123 FloatQuad transformedBoundsQuad = CCMathUtil::mapQuad(transform, FloatQuad(r
egion.bounds()), clipped); | |
| 124 // FIXME: Find a rect interior to each transformed quad. | |
| 125 if (clipped || !transformedBoundsQuad.isRectilinear()) | |
| 126 return Region(); | |
| 127 | |
| 128 Region transformedRegion; | |
| 129 | |
| 130 Vector<WebCore::IntRect> rects = region.rects(); | |
| 131 for (size_t i = 0; i < rects.size(); ++i) { | |
| 132 // We've already checked for clipping in the mapQuad call above, these c
alls should not clip anything further. | |
| 133 IntRect transformedRect = enclosedIntRect(CCMathUtil::mapClippedRect(tra
nsform, FloatRect(rects[i]))); | |
| 134 if (!surface->clipRect().isEmpty()) | |
| 135 transformedRect.intersect(surface->clipRect()); | |
| 136 transformedRegion.unite(transformedRect); | |
| 137 } | |
| 138 return transformedRegion; | |
| 139 } | |
| 140 | |
| 141 static inline void reduceOcclusion(const IntRect& affectedArea, const IntRect& e
xpandedPixel, Region& occlusion) | |
| 142 { | |
| 143 if (affectedArea.isEmpty()) | |
| 144 return; | |
| 145 | |
| 146 Region affectedOcclusion = intersect(occlusion, affectedArea); | |
| 147 Vector<WebCore::IntRect> affectedOcclusionRects = affectedOcclusion.rects(); | |
| 148 | |
| 149 occlusion.subtract(affectedArea); | |
| 150 for (size_t j = 0; j < affectedOcclusionRects.size(); ++j) { | |
| 151 WebCore::IntRect& occlusionRect = affectedOcclusionRects[j]; | |
| 152 | |
| 153 // Shrink the rect by expanding the non-opaque pixels outside the rect. | |
| 154 | |
| 155 // The expandedPixel is the IntRect for a single pixel after being | |
| 156 // expanded by filters on the layer. The original pixel would be | |
| 157 // IntRect(0, 0, 1, 1), and the expanded pixel is the rect, relative | |
| 158 // to this original rect, that the original pixel can influence after | |
| 159 // being filtered. | |
| 160 // To convert the expandedPixel IntRect back to filter outsets: | |
| 161 // x = -leftOutset | |
| 162 // width = leftOutset + rightOutset | |
| 163 // maxX = x + width = -leftOutset + leftOutset + rightOutset = rightOuts
et | |
| 164 | |
| 165 // The leftOutset of the filters moves pixels on the right side of | |
| 166 // the occlusionRect into it, shrinking its right edge. | |
| 167 int shrinkLeft = occlusionRect.x() == affectedArea.x() ? 0 : expandedPix
el.maxX(); | |
| 168 int shrinkTop = occlusionRect.y() == affectedArea.y() ? 0 : expandedPixe
l.maxY(); | |
| 169 int shrinkRight = occlusionRect.maxX() == affectedArea.maxX() ? 0 : -exp
andedPixel.x(); | |
| 170 int shrinkBottom = occlusionRect.maxY() == affectedArea.maxY() ? 0 : -ex
pandedPixel.y(); | |
| 171 | |
| 172 occlusionRect.move(shrinkLeft, shrinkTop); | |
| 173 occlusionRect.contract(shrinkLeft + shrinkRight, shrinkTop + shrinkBotto
m); | |
| 174 | |
| 175 occlusion.unite(occlusionRect); | |
| 176 } | |
| 177 } | |
| 178 | |
| 179 template<typename LayerType> | |
| 180 static void reduceOcclusionBelowSurface(LayerType* contributingLayer, const IntR
ect& surfaceRect, const WebTransformationMatrix& surfaceTransform, LayerType* re
nderTarget, Region& occlusionInTarget, Region& occlusionInScreen) | |
| 181 { | |
| 182 if (surfaceRect.isEmpty()) | |
| 183 return; | |
| 184 | |
| 185 IntRect boundsInTarget = enclosingIntRect(CCMathUtil::mapClippedRect(surface
Transform, FloatRect(surfaceRect))); | |
| 186 if (!contributingLayer->renderSurface()->clipRect().isEmpty()) | |
| 187 boundsInTarget.intersect(contributingLayer->renderSurface()->clipRect())
; | |
| 188 | |
| 189 int outsetTop, outsetRight, outsetBottom, outsetLeft; | |
| 190 contributingLayer->backgroundFilters().getOutsets(outsetTop, outsetRight, ou
tsetBottom, outsetLeft); | |
| 191 | |
| 192 // The filter can move pixels from outside of the clip, so allow affectedAre
a to expand outside the clip. | |
| 193 boundsInTarget.move(-outsetLeft, -outsetTop); | |
| 194 boundsInTarget.expand(outsetLeft + outsetRight, outsetTop + outsetBottom); | |
| 195 | |
| 196 IntRect boundsInScreen = enclosingIntRect(CCMathUtil::mapClippedRect(renderT
arget->renderSurface()->screenSpaceTransform(), FloatRect(boundsInTarget))); | |
| 197 | |
| 198 IntRect filterOutsetsInTarget(-outsetLeft, -outsetTop, outsetLeft + outsetRi
ght, outsetTop + outsetBottom); | |
| 199 IntRect filterOutsetsInScreen = enclosingIntRect(CCMathUtil::mapClippedRect(
renderTarget->renderSurface()->screenSpaceTransform(), FloatRect(filterOutsetsIn
Target))); | |
| 200 | |
| 201 reduceOcclusion(boundsInTarget, filterOutsetsInTarget, occlusionInTarget); | |
| 202 reduceOcclusion(boundsInScreen, filterOutsetsInScreen, occlusionInScreen); | |
| 203 } | |
| 204 | |
| 205 template<typename LayerType, typename RenderSurfaceType> | |
| 206 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::leaveToRenderTarget(c
onst LayerType* newTarget) | |
| 207 { | |
| 208 int lastIndex = m_stack.size() - 1; | |
| 209 bool surfaceWillBeAtTopAfterPop = m_stack.size() > 1 && m_stack[lastIndex -
1].target == newTarget; | |
| 210 | |
| 211 // We merge the screen occlusion from the current RenderSurface subtree out
to its parent target RenderSurface. | |
| 212 // The target occlusion can be merged out as well but needs to be transforme
d to the new target. | |
| 213 | |
| 214 const LayerType* oldTarget = m_stack[lastIndex].target; | |
| 215 const RenderSurfaceType* oldSurface = oldTarget->renderSurface(); | |
| 216 Region oldTargetOcclusionInNewTarget = transformSurfaceOpaqueRegion<RenderSu
rfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->drawTra
nsform()); | |
| 217 if (oldTarget->hasReplica() && !oldTarget->replicaHasMask()) | |
| 218 oldTargetOcclusionInNewTarget.unite(transformSurfaceOpaqueRegion<RenderS
urfaceType>(oldSurface, m_stack[lastIndex].occlusionInTarget, oldSurface->replic
aDrawTransform())); | |
| 219 | |
| 220 IntRect unoccludedSurfaceRect; | |
| 221 IntRect unoccludedReplicaRect; | |
| 222 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { | |
| 223 unoccludedSurfaceRect = unoccludedContributingSurfaceContentRect(oldTarg
et, false, oldSurface->contentRect()); | |
| 224 if (oldTarget->hasReplica()) | |
| 225 unoccludedReplicaRect = unoccludedContributingSurfaceContentRect(old
Target, true, oldSurface->contentRect()); | |
| 226 } | |
| 227 | |
| 228 if (surfaceWillBeAtTopAfterPop) { | |
| 229 // Merge the top of the stack down. | |
| 230 m_stack[lastIndex - 1].occlusionInScreen.unite(m_stack[lastIndex].occlus
ionInScreen); | |
| 231 m_stack[lastIndex - 1].occlusionInTarget.unite(oldTargetOcclusionInNewTa
rget); | |
| 232 m_stack.removeLast(); | |
| 233 } else { | |
| 234 // Replace the top of the stack with the new pushed surface. Copy the oc
cluded screen region to the top. | |
| 235 m_stack.last().target = newTarget; | |
| 236 m_stack.last().occlusionInTarget = oldTargetOcclusionInNewTarget; | |
| 237 } | |
| 238 | |
| 239 if (oldTarget->backgroundFilters().hasFilterThatMovesPixels()) { | |
| 240 reduceOcclusionBelowSurface(oldTarget, unoccludedSurfaceRect, oldSurface
->drawTransform(), newTarget, m_stack.last().occlusionInTarget, m_stack.last().o
cclusionInScreen); | |
| 241 if (oldTarget->hasReplica()) | |
| 242 reduceOcclusionBelowSurface(oldTarget, unoccludedReplicaRect, oldSur
face->replicaDrawTransform(), newTarget, m_stack.last().occlusionInTarget, m_sta
ck.last().occlusionInScreen); | |
| 243 } | |
| 244 } | |
| 245 | |
| 246 // FIXME: Remove usePaintTracking when paint tracking is on for paint culling. | |
| 247 template<typename LayerType> | |
| 248 static inline void addOcclusionBehindLayer(Region& region, const LayerType* laye
r, const WebTransformationMatrix& transform, const Region& opaqueContents, const
IntRect& clipRectInTarget, const IntSize& minimumTrackingSize, Vector<IntRect>*
occludingScreenSpaceRects) | |
| 249 { | |
| 250 ASSERT(layer->visibleContentRect().contains(opaqueContents.bounds())); | |
| 251 | |
| 252 bool clipped; | |
| 253 FloatQuad visibleTransformedQuad = CCMathUtil::mapQuad(transform, FloatQuad(
layer->visibleContentRect()), clipped); | |
| 254 // FIXME: Find a rect interior to each transformed quad. | |
| 255 if (clipped || !visibleTransformedQuad.isRectilinear()) | |
| 256 return; | |
| 257 | |
| 258 Vector<WebCore::IntRect> contentRects = opaqueContents.rects(); | |
| 259 for (size_t i = 0; i < contentRects.size(); ++i) { | |
| 260 // We've already checked for clipping in the mapQuad call above, these c
alls should not clip anything further. | |
| 261 IntRect transformedRect = enclosedIntRect(CCMathUtil::mapClippedRect(tra
nsform, FloatRect(contentRects[i]))); | |
| 262 transformedRect.intersect(clipRectInTarget); | |
| 263 if (transformedRect.width() >= minimumTrackingSize.width() || transforme
dRect.height() >= minimumTrackingSize.height()) { | |
| 264 if (occludingScreenSpaceRects) | |
| 265 occludingScreenSpaceRects->append(transformedRect); | |
| 266 region.unite(transformedRect); | |
| 267 } | |
| 268 } | |
| 269 } | |
| 270 | |
| 271 template<typename LayerType, typename RenderSurfaceType> | |
| 272 void CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::markOccludedBehindLay
er(const LayerType* layer) | |
| 273 { | |
| 274 ASSERT(!m_stack.isEmpty()); | |
| 275 ASSERT(layer->renderTarget() == m_stack.last().target); | |
| 276 if (m_stack.isEmpty()) | |
| 277 return; | |
| 278 | |
| 279 if (!layerOpacityKnown(layer) || layer->drawOpacity() < 1) | |
| 280 return; | |
| 281 | |
| 282 if (layerIsInUnsorted3dRenderingContext(layer)) | |
| 283 return; | |
| 284 | |
| 285 Region opaqueContents = layer->visibleContentOpaqueRegion(); | |
| 286 if (opaqueContents.isEmpty()) | |
| 287 return; | |
| 288 | |
| 289 IntRect clipRectInTarget = layerClipRectInTarget(layer); | |
| 290 if (layerTransformsToTargetKnown(layer)) | |
| 291 addOcclusionBehindLayer<LayerType>(m_stack.last().occlusionInTarget, lay
er, layer->drawTransform(), opaqueContents, clipRectInTarget, m_minimumTrackingS
ize, 0); | |
| 292 | |
| 293 // 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 | |
| 294 // remain rectilinear, then we don't add any occlusion in screen space. | |
| 295 | |
| 296 if (layerTransformsToScreenKnown(layer)) { | |
| 297 WebTransformationMatrix targetToScreenTransform = m_stack.last().target-
>renderSurface()->screenSpaceTransform(); | |
| 298 bool clipped; | |
| 299 FloatQuad clipQuadInScreen = CCMathUtil::mapQuad(targetToScreenTransform
, FloatQuad(FloatRect(clipRectInTarget)), clipped); | |
| 300 // FIXME: Find a rect interior to the transformed clip quad. | |
| 301 if (clipped || !clipQuadInScreen.isRectilinear()) | |
| 302 return; | |
| 303 IntRect clipRectInScreen = intersection(m_rootTargetRect, enclosedIntRec
t(clipQuadInScreen.boundingBox())); | |
| 304 addOcclusionBehindLayer<LayerType>(m_stack.last().occlusionInScreen, lay
er, layer->screenSpaceTransform(), opaqueContents, clipRectInScreen, m_minimumTr
ackingSize, m_occludingScreenSpaceRects); | |
| 305 } | |
| 306 } | |
| 307 | |
| 308 static inline bool testContentRectOccluded(const IntRect& contentRect, const Web
TransformationMatrix& contentSpaceTransform, const IntRect& clipRectInTarget, co
nst Region& occlusion) | |
| 309 { | |
| 310 FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform
, FloatRect(contentRect)); | |
| 311 // Take the enclosingIntRect, as we want to include partial pixels in the te
st. | |
| 312 IntRect targetRect = intersection(enclosingIntRect(transformedRect), clipRec
tInTarget); | |
| 313 return targetRect.isEmpty() || occlusion.contains(targetRect); | |
| 314 } | |
| 315 | |
| 316 template<typename LayerType, typename RenderSurfaceType> | |
| 317 bool CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::occluded(const LayerT
ype* layer, const IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurfa
ce) const | |
| 318 { | |
| 319 if (hasOcclusionFromOutsideTargetSurface) | |
| 320 *hasOcclusionFromOutsideTargetSurface = false; | |
| 321 | |
| 322 ASSERT(!m_stack.isEmpty()); | |
| 323 if (m_stack.isEmpty()) | |
| 324 return false; | |
| 325 if (contentRect.isEmpty()) | |
| 326 return true; | |
| 327 | |
| 328 ASSERT(layer->renderTarget() == m_stack.last().target); | |
| 329 | |
| 330 if (layerTransformsToTargetKnown(layer) && testContentRectOccluded(contentRe
ct, layer->drawTransform(), layerClipRectInTarget(layer), m_stack.last().occlusi
onInTarget)) | |
| 331 return true; | |
| 332 | |
| 333 if (layerTransformsToScreenKnown(layer) && testContentRectOccluded(contentRe
ct, layer->screenSpaceTransform(), m_rootTargetRect, m_stack.last().occlusionInS
creen)) { | |
| 334 if (hasOcclusionFromOutsideTargetSurface) | |
| 335 *hasOcclusionFromOutsideTargetSurface = true; | |
| 336 return true; | |
| 337 } | |
| 338 | |
| 339 return false; | |
| 340 } | |
| 341 | |
| 342 // Determines what portion of rect, if any, is unoccluded (not occluded by regio
n). If | |
| 343 // the resulting unoccluded region is not rectangular, we return a rect containi
ng it. | |
| 344 static inline IntRect rectSubtractRegion(const IntRect& rect, const Region& regi
on) | |
| 345 { | |
| 346 Region rectRegion(rect); | |
| 347 rectRegion.subtract(region); | |
| 348 return rectRegion.bounds(); | |
| 349 } | |
| 350 | |
| 351 static inline IntRect computeUnoccludedContentRect(const IntRect& contentRect, c
onst WebTransformationMatrix& contentSpaceTransform, const IntRect& clipRectInTa
rget, const Region& occlusion) | |
| 352 { | |
| 353 if (!contentSpaceTransform.isInvertible()) | |
| 354 return contentRect; | |
| 355 | |
| 356 // Take the enclosingIntRect at each step, as we want to contain any unocclu
ded partial pixels in the resulting IntRect. | |
| 357 FloatRect transformedRect = CCMathUtil::mapClippedRect(contentSpaceTransform
, FloatRect(contentRect)); | |
| 358 IntRect shrunkRect = rectSubtractRegion(intersection(enclosingIntRect(transf
ormedRect), clipRectInTarget), occlusion); | |
| 359 IntRect unoccludedRect = enclosingIntRect(CCMathUtil::projectClippedRect(con
tentSpaceTransform.inverse(), FloatRect(shrunkRect))); | |
| 360 // 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. | |
| 361 return intersection(unoccludedRect, contentRect); | |
| 362 } | |
| 363 | |
| 364 template<typename LayerType, typename RenderSurfaceType> | |
| 365 IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContentR
ect(const LayerType* layer, const IntRect& contentRect, bool* hasOcclusionFromOu
tsideTargetSurface) const | |
| 366 { | |
| 367 ASSERT(!m_stack.isEmpty()); | |
| 368 if (m_stack.isEmpty()) | |
| 369 return contentRect; | |
| 370 if (contentRect.isEmpty()) | |
| 371 return contentRect; | |
| 372 | |
| 373 ASSERT(layer->renderTarget() == m_stack.last().target); | |
| 374 | |
| 375 // We want to return a rect that contains all the visible parts of |contentR
ect| in both screen space and in the target surface. | |
| 376 // So we find the visible parts of |contentRect| in each space, and take the
intersection. | |
| 377 | |
| 378 IntRect unoccludedInScreen = contentRect; | |
| 379 if (layerTransformsToScreenKnown(layer)) | |
| 380 unoccludedInScreen = computeUnoccludedContentRect(contentRect, layer->sc
reenSpaceTransform(), m_rootTargetRect, m_stack.last().occlusionInScreen); | |
| 381 | |
| 382 IntRect unoccludedInTarget = contentRect; | |
| 383 if (layerTransformsToTargetKnown(layer)) | |
| 384 unoccludedInTarget = computeUnoccludedContentRect(contentRect, layer->dr
awTransform(), layerClipRectInTarget(layer), m_stack.last().occlusionInTarget); | |
| 385 | |
| 386 if (hasOcclusionFromOutsideTargetSurface) | |
| 387 *hasOcclusionFromOutsideTargetSurface = (intersection(unoccludedInScreen
, unoccludedInTarget) != unoccludedInTarget); | |
| 388 | |
| 389 return intersection(unoccludedInScreen, unoccludedInTarget); | |
| 390 } | |
| 391 | |
| 392 template<typename LayerType, typename RenderSurfaceType> | |
| 393 IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::unoccludedContribu
tingSurfaceContentRect(const LayerType* layer, bool forReplica, const IntRect& c
ontentRect, bool* hasOcclusionFromOutsideTargetSurface) const | |
| 394 { | |
| 395 ASSERT(!m_stack.isEmpty()); | |
| 396 // The layer is a contributing renderTarget so it should have a surface. | |
| 397 ASSERT(layer->renderSurface()); | |
| 398 // The layer is a contributing renderTarget so its target should be itself. | |
| 399 ASSERT(layer->renderTarget() == layer); | |
| 400 // The layer should not be the root, else what is is contributing to? | |
| 401 ASSERT(layer->parent()); | |
| 402 // This should be called while the layer is still considered the current tar
get in the occlusion tracker. | |
| 403 ASSERT(layer == m_stack.last().target); | |
| 404 | |
| 405 if (contentRect.isEmpty()) | |
| 406 return contentRect; | |
| 407 | |
| 408 RenderSurfaceType* surface = layer->renderSurface(); | |
| 409 | |
| 410 IntRect surfaceClipRect = surface->clipRect(); | |
| 411 if (surfaceClipRect.isEmpty()) { | |
| 412 LayerType* contributingSurfaceRenderTarget = layer->parent()->renderTarg
et(); | |
| 413 surfaceClipRect = intersection(contributingSurfaceRenderTarget->renderSu
rface()->contentRect(), enclosingIntRect(surface->drawableContentRect())); | |
| 414 } | |
| 415 | |
| 416 // 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 | |
| 417 // found just below the top of the stack (if it exists). | |
| 418 bool hasOcclusion = m_stack.size() > 1; | |
| 419 | |
| 420 const WebTransformationMatrix& transformToScreen = forReplica ? surface->rep
licaScreenSpaceTransform() : surface->screenSpaceTransform(); | |
| 421 const WebTransformationMatrix& transformToTarget = forReplica ? surface->rep
licaDrawTransform() : surface->drawTransform(); | |
| 422 | |
| 423 IntRect unoccludedInScreen = contentRect; | |
| 424 if (surfaceTransformsToScreenKnown(surface)) { | |
| 425 if (hasOcclusion) { | |
| 426 const StackObject& secondLast = m_stack[m_stack.size() - 2]; | |
| 427 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans
formToScreen, m_rootTargetRect, secondLast.occlusionInScreen); | |
| 428 } else | |
| 429 unoccludedInScreen = computeUnoccludedContentRect(contentRect, trans
formToScreen, m_rootTargetRect, Region()); | |
| 430 } | |
| 431 | |
| 432 IntRect unoccludedInTarget = contentRect; | |
| 433 if (surfaceTransformsToTargetKnown(surface)) { | |
| 434 if (hasOcclusion) { | |
| 435 const StackObject& secondLast = m_stack[m_stack.size() - 2]; | |
| 436 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans
formToTarget, surfaceClipRect, secondLast.occlusionInTarget); | |
| 437 } else | |
| 438 unoccludedInTarget = computeUnoccludedContentRect(contentRect, trans
formToTarget, surfaceClipRect, Region()); | |
| 439 } | |
| 440 | |
| 441 if (hasOcclusionFromOutsideTargetSurface) | |
| 442 *hasOcclusionFromOutsideTargetSurface = (intersection(unoccludedInScreen
, unoccludedInTarget) != unoccludedInTarget); | |
| 443 | |
| 444 return intersection(unoccludedInScreen, unoccludedInTarget); | |
| 445 } | |
| 446 | |
| 447 template<typename LayerType, typename RenderSurfaceType> | |
| 448 IntRect CCOcclusionTrackerBase<LayerType, RenderSurfaceType>::layerClipRectInTar
get(const LayerType* layer) const | |
| 449 { | |
| 450 // FIXME: we could remove this helper function, but unit tests currently ove
rride this | |
| 451 // function, and they need to be verified/adjusted before this can be
removed. | |
| 452 return layer->drawableContentRect(); | |
| 453 } | |
| 454 | |
| 455 // Declare the possible functions here for the linker. | |
| 456 template CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::CCOcclusi
onTrackerBase(IntRect rootTargetRect, bool recordMetricsForFrame); | |
| 457 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::ente
rLayer(const CCLayerIteratorPosition<LayerChromium>&); | |
| 458 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::leav
eLayer(const CCLayerIteratorPosition<LayerChromium>&); | |
| 459 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::ente
rRenderTarget(const LayerChromium* newTarget); | |
| 460 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::fini
shedRenderTarget(const LayerChromium* finishedTarget); | |
| 461 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::leav
eToRenderTarget(const LayerChromium* newTarget); | |
| 462 template void CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::mark
OccludedBehindLayer(const LayerChromium*); | |
| 463 template bool CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::occl
uded(const LayerChromium*, const IntRect& contentRect, bool* hasOcclusionFromOut
sideTargetSurface) const; | |
| 464 template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::u
noccludedContentRect(const LayerChromium*, const IntRect& contentRect, bool* has
OcclusionFromOutsideTargetSurface) const; | |
| 465 template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::u
noccludedContributingSurfaceContentRect(const LayerChromium*, bool forReplica, c
onst IntRect& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const; | |
| 466 template IntRect CCOcclusionTrackerBase<LayerChromium, RenderSurfaceChromium>::l
ayerClipRectInTarget(const LayerChromium*) const; | |
| 467 | |
| 468 template CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::CCOcclusionTracke
rBase(IntRect rootTargetRect, bool recordMetricsForFrame); | |
| 469 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::enterLayer(c
onst CCLayerIteratorPosition<CCLayerImpl>&); | |
| 470 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::leaveLayer(c
onst CCLayerIteratorPosition<CCLayerImpl>&); | |
| 471 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::enterRenderT
arget(const CCLayerImpl* newTarget); | |
| 472 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::finishedRend
erTarget(const CCLayerImpl* finishedTarget); | |
| 473 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::leaveToRende
rTarget(const CCLayerImpl* newTarget); | |
| 474 template void CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::markOccluded
BehindLayer(const CCLayerImpl*); | |
| 475 template bool CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::occluded(con
st CCLayerImpl*, const IntRect& contentRect, bool* hasOcclusionFromOutsideTarget
Surface) const; | |
| 476 template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::unocclude
dContentRect(const CCLayerImpl*, const IntRect& contentRect, bool* hasOcclusionF
romOutsideTargetSurface) const; | |
| 477 template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::unocclude
dContributingSurfaceContentRect(const CCLayerImpl*, bool forReplica, const IntRe
ct& contentRect, bool* hasOcclusionFromOutsideTargetSurface) const; | |
| 478 template IntRect CCOcclusionTrackerBase<CCLayerImpl, CCRenderSurface>::layerClip
RectInTarget(const CCLayerImpl*) const; | |
| 479 | |
| 480 | |
| 481 } // namespace cc | |
| 482 #endif // USE(ACCELERATED_COMPOSITING) | |
| OLD | NEW |