1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/occlusion_tracker.h"
9 #include "cc/base/math_util.h"
10 #include "cc/debug/overdraw_metrics.h"
11 #include "cc/layers/layer.h"
12 #include "cc/layers/layer_impl.h"
13 #include "cc/layers/render_surface.h"
14 #include "cc/layers/render_surface_impl.h"
15 #include "ui/gfx/quad_f.h"
16 #include "ui/gfx/rect_conversions.h"
20 template <typename LayerType
, typename RenderSurfaceType
>
21 OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::OcclusionTrackerBase(
22 const gfx::Rect
& screen_space_clip_rect
, bool record_metrics_for_frame
)
23 : screen_space_clip_rect_(screen_space_clip_rect
),
24 overdraw_metrics_(OverdrawMetrics::Create(record_metrics_for_frame
)),
25 occluding_screen_space_rects_(NULL
),
26 non_occluding_screen_space_rects_(NULL
) {}
28 template <typename LayerType
, typename RenderSurfaceType
>
29 OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::~OcclusionTrackerBase() {}
31 template <typename LayerType
, typename RenderSurfaceType
>
32 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::EnterLayer(
33 const LayerIteratorPosition
<LayerType
>& layer_iterator
) {
34 LayerType
* render_target
= layer_iterator
.target_render_surface_layer
;
36 if (layer_iterator
.represents_itself
)
37 EnterRenderTarget(render_target
);
38 else if (layer_iterator
.represents_target_render_surface
)
39 FinishedRenderTarget(render_target
);
42 template <typename LayerType
, typename RenderSurfaceType
>
43 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::LeaveLayer(
44 const LayerIteratorPosition
<LayerType
>& layer_iterator
) {
45 LayerType
* render_target
= layer_iterator
.target_render_surface_layer
;
47 if (layer_iterator
.represents_itself
)
48 MarkOccludedBehindLayer(layer_iterator
.current_layer
);
49 // TODO(danakj): This should be done when entering the contributing surface,
50 // but in a way that the surface's own occlusion won't occlude itself.
51 else if (layer_iterator
.represents_contributing_render_surface
)
52 LeaveToRenderTarget(render_target
);
55 template <typename RenderSurfaceType
>
56 static gfx::Rect
ScreenSpaceClipRectInTargetSurface(
57 const RenderSurfaceType
* target_surface
,
58 const gfx::Rect
& screen_space_clip_rect
) {
59 gfx::Transform
inverse_screen_space_transform(
60 gfx::Transform::kSkipInitialization
);
61 if (!target_surface
->screen_space_transform().GetInverse(
62 &inverse_screen_space_transform
))
63 return target_surface
->content_rect();
65 return gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
66 inverse_screen_space_transform
, screen_space_clip_rect
));
69 template <typename RenderSurfaceType
>
70 static Region
TransformSurfaceOpaqueRegion(
73 const gfx::Rect
& clip_rect_in_new_target
,
74 const gfx::Transform
& transform
) {
78 // Verify that rects within the |surface| will remain rects in its target
79 // surface after applying |transform|. If this is true, then apply |transform|
80 // to each rect within |region| in order to transform the entire Region.
82 // TODO(danakj): Find a rect interior to each transformed quad.
83 if (!transform
.Preserves2dAxisAlignment())
86 // TODO(danakj): If the Region is too complex, degrade gracefully here by
87 // skipping rects in it.
88 Region transformed_region
;
89 for (Region::Iterator
rects(region
); rects
.has_rect(); rects
.next()) {
91 gfx::QuadF transformed_quad
=
92 MathUtil::MapQuad(transform
, gfx::QuadF(rects
.rect()), &clipped
);
93 gfx::Rect transformed_rect
=
94 gfx::ToEnclosedRect(transformed_quad
.BoundingBox());
95 DCHECK(!clipped
); // We only map if the transform preserves axis alignment.
97 transformed_rect
.Intersect(clip_rect_in_new_target
);
98 transformed_region
.Union(transformed_rect
);
100 return transformed_region
;
103 static inline bool LayerOpacityKnown(const Layer
* layer
) {
104 return !layer
->draw_opacity_is_animating();
106 static inline bool LayerOpacityKnown(const LayerImpl
* layer
) {
109 static inline bool LayerTransformsToTargetKnown(const Layer
* layer
) {
110 return !layer
->draw_transform_is_animating();
112 static inline bool LayerTransformsToTargetKnown(const LayerImpl
* layer
) {
116 static inline bool SurfaceOpacityKnown(const RenderSurface
* rs
) {
117 return !rs
->draw_opacity_is_animating();
119 static inline bool SurfaceOpacityKnown(const RenderSurfaceImpl
* rs
) {
122 static inline bool SurfaceTransformsToTargetKnown(const RenderSurface
* rs
) {
123 return !rs
->target_surface_transforms_are_animating();
125 static inline bool SurfaceTransformsToTargetKnown(const RenderSurfaceImpl
* rs
) {
128 static inline bool SurfaceTransformsToScreenKnown(const RenderSurface
* rs
) {
129 return !rs
->screen_space_transforms_are_animating();
131 static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl
* rs
) {
135 static inline bool LayerIsInUnsorted3dRenderingContext(const Layer
* layer
) {
136 return layer
->parent() && layer
->parent()->preserves_3d();
138 static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl
* layer
) {
142 template <typename LayerType
>
143 static inline bool LayerIsHidden(const LayerType
* layer
) {
144 return layer
->hide_layer_and_subtree() ||
145 (layer
->parent() && LayerIsHidden(layer
->parent()));
148 template <typename LayerType
, typename RenderSurfaceType
>
149 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::EnterRenderTarget(
150 const LayerType
* new_target
) {
151 if (!stack_
.empty() && stack_
.back().target
== new_target
)
154 const LayerType
* old_target
= NULL
;
155 const RenderSurfaceType
* old_occlusion_immune_ancestor
= NULL
;
156 if (!stack_
.empty()) {
157 old_target
= stack_
.back().target
;
158 old_occlusion_immune_ancestor
=
159 old_target
->render_surface()->nearest_occlusion_immune_ancestor();
161 const RenderSurfaceType
* new_occlusion_immune_ancestor
=
162 new_target
->render_surface()->nearest_occlusion_immune_ancestor();
164 stack_
.push_back(StackObject(new_target
));
166 // We copy the screen occlusion into the new RenderSurface subtree, but we
167 // never copy in the occlusion from inside the target, since we are looking
168 // at a new RenderSurface target.
170 // If entering an unoccluded subtree, do not carry forward the outside
171 // occlusion calculated so far.
172 bool entering_unoccluded_subtree
=
173 new_occlusion_immune_ancestor
&&
174 new_occlusion_immune_ancestor
!= old_occlusion_immune_ancestor
;
176 bool have_transform_from_screen_to_new_target
= false;
177 gfx::Transform
inverse_new_target_screen_space_transform(
178 // Note carefully, not used if screen space transform is uninvertible.
179 gfx::Transform::kSkipInitialization
);
180 if (SurfaceTransformsToScreenKnown(new_target
->render_surface())) {
181 have_transform_from_screen_to_new_target
=
182 new_target
->render_surface()->screen_space_transform().GetInverse(
183 &inverse_new_target_screen_space_transform
);
186 bool entering_root_target
= new_target
->parent() == NULL
;
188 bool copy_outside_occlusion_forward
=
190 !entering_unoccluded_subtree
&&
191 have_transform_from_screen_to_new_target
&&
192 !entering_root_target
;
193 if (!copy_outside_occlusion_forward
)
196 int last_index
= stack_
.size() - 1;
197 gfx::Transform
old_target_to_new_target_transform(
198 inverse_new_target_screen_space_transform
,
199 old_target
->render_surface()->screen_space_transform());
200 stack_
[last_index
].occlusion_from_outside_target
=
201 TransformSurfaceOpaqueRegion
<RenderSurfaceType
>(
202 stack_
[last_index
- 1].occlusion_from_outside_target
,
205 old_target_to_new_target_transform
);
206 stack_
[last_index
].occlusion_from_outside_target
.Union(
207 TransformSurfaceOpaqueRegion
<RenderSurfaceType
>(
208 stack_
[last_index
- 1].occlusion_from_inside_target
,
211 old_target_to_new_target_transform
));
214 template <typename LayerType
, typename RenderSurfaceType
>
215 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::FinishedRenderTarget(
216 const LayerType
* finished_target
) {
217 // Make sure we know about the target surface.
218 EnterRenderTarget(finished_target
);
220 RenderSurfaceType
* surface
= finished_target
->render_surface();
222 // Readbacks always happen on render targets so we only need to check
223 // for readbacks here.
224 bool target_is_only_for_copy_request
=
225 finished_target
->HasCopyRequest() && LayerIsHidden(finished_target
);
227 // If the occlusion within the surface can not be applied to things outside of
228 // the surface's subtree, then clear the occlusion here so it won't be used.
229 if (finished_target
->mask_layer() || !SurfaceOpacityKnown(surface
) ||
230 surface
->draw_opacity() < 1 ||
231 !finished_target
->uses_default_blend_mode() ||
232 target_is_only_for_copy_request
||
233 finished_target
->filters().HasFilterThatAffectsOpacity()) {
234 stack_
.back().occlusion_from_outside_target
.Clear();
235 stack_
.back().occlusion_from_inside_target
.Clear();
236 } else if (!SurfaceTransformsToTargetKnown(surface
)) {
237 stack_
.back().occlusion_from_inside_target
.Clear();
238 stack_
.back().occlusion_from_outside_target
.Clear();
242 template <typename LayerType
>
243 static void ReduceOcclusionBelowSurface(LayerType
* contributing_layer
,
244 const gfx::Rect
& surface_rect
,
245 const gfx::Transform
& surface_transform
,
246 LayerType
* render_target
,
247 Region
* occlusion_from_inside_target
) {
248 if (surface_rect
.IsEmpty())
251 gfx::Rect affected_area_in_target
= gfx::ToEnclosingRect(
252 MathUtil::MapClippedRect(surface_transform
, gfx::RectF(surface_rect
)));
253 if (contributing_layer
->render_surface()->is_clipped()) {
254 affected_area_in_target
.Intersect(
255 contributing_layer
->render_surface()->clip_rect());
257 if (affected_area_in_target
.IsEmpty())
260 int outset_top
, outset_right
, outset_bottom
, outset_left
;
261 contributing_layer
->background_filters().GetOutsets(
262 &outset_top
, &outset_right
, &outset_bottom
, &outset_left
);
264 // The filter can move pixels from outside of the clip, so allow affected_area
265 // to expand outside the clip.
266 affected_area_in_target
.Inset(
267 -outset_left
, -outset_top
, -outset_right
, -outset_bottom
);
268 Region affected_occlusion
= IntersectRegions(*occlusion_from_inside_target
,
269 affected_area_in_target
);
270 Region::Iterator
affected_occlusion_rects(affected_occlusion
);
272 occlusion_from_inside_target
->Subtract(affected_area_in_target
);
273 for (; affected_occlusion_rects
.has_rect(); affected_occlusion_rects
.next()) {
274 gfx::Rect occlusion_rect
= affected_occlusion_rects
.rect();
276 // Shrink the rect by expanding the non-opaque pixels outside the rect.
278 // The left outset of the filters moves pixels on the right side of
279 // the occlusion_rect into it, shrinking its right edge.
281 occlusion_rect
.x() == affected_area_in_target
.x() ? 0 : outset_right
;
283 occlusion_rect
.y() == affected_area_in_target
.y() ? 0 : outset_bottom
;
285 occlusion_rect
.right() == affected_area_in_target
.right() ?
288 occlusion_rect
.bottom() == affected_area_in_target
.bottom() ?
291 occlusion_rect
.Inset(shrink_left
, shrink_top
, shrink_right
, shrink_bottom
);
293 occlusion_from_inside_target
->Union(occlusion_rect
);
297 template <typename LayerType
, typename RenderSurfaceType
>
298 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::LeaveToRenderTarget(
299 const LayerType
* new_target
) {
300 int last_index
= stack_
.size() - 1;
301 bool surface_will_be_at_top_after_pop
=
302 stack_
.size() > 1 && stack_
[last_index
- 1].target
== new_target
;
304 // We merge the screen occlusion from the current RenderSurfaceImpl subtree
305 // out to its parent target RenderSurfaceImpl. The target occlusion can be
306 // merged out as well but needs to be transformed to the new target.
308 const LayerType
* old_target
= stack_
[last_index
].target
;
309 const RenderSurfaceType
* old_surface
= old_target
->render_surface();
311 Region old_occlusion_from_inside_target_in_new_target
=
312 TransformSurfaceOpaqueRegion
<RenderSurfaceType
>(
313 stack_
[last_index
].occlusion_from_inside_target
,
314 old_surface
->is_clipped(),
315 old_surface
->clip_rect(),
316 old_surface
->draw_transform());
317 if (old_target
->has_replica() && !old_target
->replica_has_mask()) {
318 old_occlusion_from_inside_target_in_new_target
.Union(
319 TransformSurfaceOpaqueRegion
<RenderSurfaceType
>(
320 stack_
[last_index
].occlusion_from_inside_target
,
321 old_surface
->is_clipped(),
322 old_surface
->clip_rect(),
323 old_surface
->replica_draw_transform()));
326 Region old_occlusion_from_outside_target_in_new_target
=
327 TransformSurfaceOpaqueRegion
<RenderSurfaceType
>(
328 stack_
[last_index
].occlusion_from_outside_target
,
331 old_surface
->draw_transform());
333 gfx::Rect unoccluded_surface_rect
;
334 gfx::Rect unoccluded_replica_rect
;
335 if (old_target
->background_filters().HasFilterThatMovesPixels()) {
336 unoccluded_surface_rect
= UnoccludedContributingSurfaceContentRect(
337 old_target
, false, old_surface
->content_rect());
338 if (old_target
->has_replica()) {
339 unoccluded_replica_rect
= UnoccludedContributingSurfaceContentRect(
340 old_target
, true, old_surface
->content_rect());
344 if (surface_will_be_at_top_after_pop
) {
345 // Merge the top of the stack down.
346 stack_
[last_index
- 1].occlusion_from_inside_target
.Union(
347 old_occlusion_from_inside_target_in_new_target
);
348 // TODO(danakj): Strictly this should subtract the inside target occlusion
350 if (new_target
->parent()) {
351 stack_
[last_index
- 1].occlusion_from_outside_target
.Union(
352 old_occlusion_from_outside_target_in_new_target
);
356 // Replace the top of the stack with the new pushed surface.
357 stack_
.back().target
= new_target
;
358 stack_
.back().occlusion_from_inside_target
=
359 old_occlusion_from_inside_target_in_new_target
;
360 if (new_target
->parent()) {
361 stack_
.back().occlusion_from_outside_target
=
362 old_occlusion_from_outside_target_in_new_target
;
364 stack_
.back().occlusion_from_outside_target
.Clear();
368 if (!old_target
->background_filters().HasFilterThatMovesPixels())
371 ReduceOcclusionBelowSurface(old_target
,
372 unoccluded_surface_rect
,
373 old_surface
->draw_transform(),
375 &stack_
.back().occlusion_from_inside_target
);
376 ReduceOcclusionBelowSurface(old_target
,
377 unoccluded_surface_rect
,
378 old_surface
->draw_transform(),
380 &stack_
.back().occlusion_from_outside_target
);
382 if (!old_target
->has_replica())
384 ReduceOcclusionBelowSurface(old_target
,
385 unoccluded_replica_rect
,
386 old_surface
->replica_draw_transform(),
388 &stack_
.back().occlusion_from_inside_target
);
389 ReduceOcclusionBelowSurface(old_target
,
390 unoccluded_replica_rect
,
391 old_surface
->replica_draw_transform(),
393 &stack_
.back().occlusion_from_outside_target
);
396 template <typename LayerType
, typename RenderSurfaceType
>
397 void OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::
398 MarkOccludedBehindLayer(const LayerType
* layer
) {
399 DCHECK(!stack_
.empty());
400 DCHECK_EQ(layer
->render_target(), stack_
.back().target
);
404 if (!layer
->DrawsContent())
407 if (!LayerOpacityKnown(layer
) || layer
->draw_opacity() < 1)
410 if (!layer
->uses_default_blend_mode())
413 if (LayerIsInUnsorted3dRenderingContext(layer
))
416 if (!LayerTransformsToTargetKnown(layer
))
419 Region opaque_contents
= layer
->VisibleContentOpaqueRegion();
420 if (opaque_contents
.IsEmpty())
423 DCHECK(layer
->visible_content_rect().Contains(opaque_contents
.bounds()));
425 // TODO(danakj): Find a rect interior to each transformed quad.
426 if (!layer
->draw_transform().Preserves2dAxisAlignment())
429 gfx::Rect clip_rect_in_target
= ScreenSpaceClipRectInTargetSurface(
430 layer
->render_target()->render_surface(), screen_space_clip_rect_
);
431 if (layer
->is_clipped()) {
432 clip_rect_in_target
.Intersect(layer
->clip_rect());
434 clip_rect_in_target
.Intersect(
435 layer
->render_target()->render_surface()->content_rect());
438 for (Region::Iterator
opaque_content_rects(opaque_contents
);
439 opaque_content_rects
.has_rect();
440 opaque_content_rects
.next()) {
442 gfx::QuadF transformed_quad
= MathUtil::MapQuad(
443 layer
->draw_transform(),
444 gfx::QuadF(opaque_content_rects
.rect()),
446 gfx::Rect transformed_rect
=
447 gfx::ToEnclosedRect(transformed_quad
.BoundingBox());
448 DCHECK(!clipped
); // We only map if the transform preserves axis alignment.
449 transformed_rect
.Intersect(clip_rect_in_target
);
450 if (transformed_rect
.width() < minimum_tracking_size_
.width() &&
451 transformed_rect
.height() < minimum_tracking_size_
.height())
453 stack_
.back().occlusion_from_inside_target
.Union(transformed_rect
);
455 if (!occluding_screen_space_rects_
)
458 // Save the occluding area in screen space for debug visualization.
459 gfx::QuadF screen_space_quad
= MathUtil::MapQuad(
460 layer
->render_target()->render_surface()->screen_space_transform(),
461 gfx::QuadF(transformed_rect
), &clipped
);
462 // TODO(danakj): Store the quad in the debug info instead of the bounding
464 gfx::Rect screen_space_rect
=
465 gfx::ToEnclosedRect(screen_space_quad
.BoundingBox());
466 occluding_screen_space_rects_
->push_back(screen_space_rect
);
469 if (!non_occluding_screen_space_rects_
)
472 Region non_opaque_contents
=
473 SubtractRegions(gfx::Rect(layer
->content_bounds()), opaque_contents
);
474 for (Region::Iterator
non_opaque_content_rects(non_opaque_contents
);
475 non_opaque_content_rects
.has_rect();
476 non_opaque_content_rects
.next()) {
477 // We've already checked for clipping in the MapQuad call above, these calls
478 // should not clip anything further.
479 gfx::Rect transformed_rect
= gfx::ToEnclosedRect(
480 MathUtil::MapClippedRect(layer
->draw_transform(),
481 gfx::RectF(non_opaque_content_rects
.rect())));
482 transformed_rect
.Intersect(clip_rect_in_target
);
483 if (transformed_rect
.IsEmpty())
487 gfx::QuadF screen_space_quad
= MathUtil::MapQuad(
488 layer
->render_target()->render_surface()->screen_space_transform(),
489 gfx::QuadF(transformed_rect
),
491 // TODO(danakj): Store the quad in the debug info instead of the bounding
493 gfx::Rect screen_space_rect
=
494 gfx::ToEnclosedRect(screen_space_quad
.BoundingBox());
495 non_occluding_screen_space_rects_
->push_back(screen_space_rect
);
499 template <typename LayerType
, typename RenderSurfaceType
>
500 bool OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::Occluded(
501 const LayerType
* render_target
,
502 const gfx::Rect
& content_rect
,
503 const gfx::Transform
& draw_transform
,
504 bool impl_draw_transform_is_unknown
) const {
505 DCHECK(!stack_
.empty());
508 if (content_rect
.IsEmpty())
510 if (impl_draw_transform_is_unknown
)
513 // For tests with no render target.
517 DCHECK_EQ(render_target
->render_target(), render_target
);
518 DCHECK(render_target
->render_surface());
519 DCHECK_EQ(render_target
, stack_
.back().target
);
521 if (stack_
.back().occlusion_from_inside_target
.IsEmpty() &&
522 stack_
.back().occlusion_from_outside_target
.IsEmpty()) {
526 gfx::Transform
inverse_draw_transform(gfx::Transform::kSkipInitialization
);
527 if (!draw_transform
.GetInverse(&inverse_draw_transform
))
530 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
531 // partial pixels in the resulting Rect.
532 Region unoccluded_region_in_target_surface
= gfx::ToEnclosingRect(
533 MathUtil::MapClippedRect(draw_transform
, gfx::RectF(content_rect
)));
534 unoccluded_region_in_target_surface
.Subtract(
535 stack_
.back().occlusion_from_inside_target
);
536 gfx::RectF unoccluded_rect_in_target_surface_without_outside_occlusion
=
537 unoccluded_region_in_target_surface
.bounds();
538 unoccluded_region_in_target_surface
.Subtract(
539 stack_
.back().occlusion_from_outside_target
);
541 gfx::RectF unoccluded_rect_in_target_surface
=
542 unoccluded_region_in_target_surface
.bounds();
544 return unoccluded_rect_in_target_surface
.IsEmpty();
547 template <typename LayerType
, typename RenderSurfaceType
>
548 gfx::Rect OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::
549 UnoccludedContentRect(
550 const LayerType
* render_target
,
551 const gfx::Rect
& content_rect
,
552 const gfx::Transform
& draw_transform
,
553 bool impl_draw_transform_is_unknown
) const {
554 DCHECK(!stack_
.empty());
557 if (content_rect
.IsEmpty())
559 if (impl_draw_transform_is_unknown
)
562 // For tests with no render target.
566 DCHECK_EQ(render_target
->render_target(), render_target
);
567 DCHECK(render_target
->render_surface());
568 DCHECK_EQ(render_target
, stack_
.back().target
);
570 if (stack_
.back().occlusion_from_inside_target
.IsEmpty() &&
571 stack_
.back().occlusion_from_outside_target
.IsEmpty()) {
575 gfx::Transform
inverse_draw_transform(gfx::Transform::kSkipInitialization
);
576 if (!draw_transform
.GetInverse(&inverse_draw_transform
))
579 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
580 // partial pixels in the resulting Rect.
581 Region unoccluded_region_in_target_surface
= gfx::ToEnclosingRect(
582 MathUtil::MapClippedRect(draw_transform
, gfx::RectF(content_rect
)));
583 unoccluded_region_in_target_surface
.Subtract(
584 stack_
.back().occlusion_from_inside_target
);
585 unoccluded_region_in_target_surface
.Subtract(
586 stack_
.back().occlusion_from_outside_target
);
588 gfx::RectF unoccluded_rect_in_target_surface
=
589 unoccluded_region_in_target_surface
.bounds();
590 gfx::Rect unoccluded_rect
= gfx::ToEnclosingRect(
591 MathUtil::ProjectClippedRect(inverse_draw_transform
,
592 unoccluded_rect_in_target_surface
));
593 unoccluded_rect
.Intersect(content_rect
);
595 return unoccluded_rect
;
598 template <typename LayerType
, typename RenderSurfaceType
>
599 gfx::Rect OcclusionTrackerBase
<LayerType
, RenderSurfaceType
>::
600 UnoccludedContributingSurfaceContentRect(
601 const LayerType
* layer
,
603 const gfx::Rect
& content_rect
) const {
604 DCHECK(!stack_
.empty());
605 // The layer is a contributing render_target so it should have a surface.
606 DCHECK(layer
->render_surface());
607 // The layer is a contributing render_target so its target should be itself.
608 DCHECK_EQ(layer
->render_target(), layer
);
609 // The layer should not be the root, else what is is contributing to?
610 DCHECK(layer
->parent());
611 // This should be called while the layer is still considered the current
612 // target in the occlusion tracker.
613 DCHECK_EQ(layer
, stack_
.back().target
);
615 if (content_rect
.IsEmpty())
618 const RenderSurfaceType
* surface
= layer
->render_surface();
619 const LayerType
* contributing_surface_render_target
=
620 layer
->parent()->render_target();
622 if (!SurfaceTransformsToTargetKnown(surface
))
625 gfx::Transform draw_transform
=
626 for_replica
? surface
->replica_draw_transform()
627 : surface
->draw_transform();
628 gfx::Transform
inverse_draw_transform(gfx::Transform::kSkipInitialization
);
629 if (!draw_transform
.GetInverse(&inverse_draw_transform
))
632 // A contributing surface doesn't get occluded by things inside its own
633 // surface, so only things outside the surface can occlude it. That occlusion
634 // is found just below the top of the stack (if it exists).
635 bool has_occlusion
= stack_
.size() > 1;
637 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
638 // partial pixels in the resulting Rect.
639 Region unoccluded_region_in_target_surface
= gfx::ToEnclosingRect(
640 MathUtil::MapClippedRect(draw_transform
, gfx::RectF(content_rect
)));
641 // Layers can't clip across surfaces, so count this as internal occlusion.
642 if (surface
->is_clipped())
643 unoccluded_region_in_target_surface
.Intersect(surface
->clip_rect());
645 const StackObject
& second_last
= stack_
[stack_
.size() - 2];
646 unoccluded_region_in_target_surface
.Subtract(
647 second_last
.occlusion_from_inside_target
);
648 unoccluded_region_in_target_surface
.Subtract(
649 second_last
.occlusion_from_outside_target
);
652 // Treat other clipping as occlusion from outside the target surface.
653 unoccluded_region_in_target_surface
.Intersect(
654 contributing_surface_render_target
->render_surface()->content_rect());
655 unoccluded_region_in_target_surface
.Intersect(
656 ScreenSpaceClipRectInTargetSurface(
657 contributing_surface_render_target
->render_surface(),
658 screen_space_clip_rect_
));
660 gfx::RectF unoccluded_rect_in_target_surface
=
661 unoccluded_region_in_target_surface
.bounds();
662 gfx::Rect unoccluded_rect
= gfx::ToEnclosingRect(
663 MathUtil::ProjectClippedRect(inverse_draw_transform
,
664 unoccluded_rect_in_target_surface
));
665 unoccluded_rect
.Intersect(content_rect
);
667 return unoccluded_rect
;
670 // Instantiate (and export) templates here for the linker.
671 template class OcclusionTrackerBase
<Layer
, RenderSurface
>;
672 template class OcclusionTrackerBase
<LayerImpl
, RenderSurfaceImpl
>;