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/base/region.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
>
21 OcclusionTracker
<LayerType
>::OcclusionTracker(
22 const gfx::Rect
& screen_space_clip_rect
)
23 : screen_space_clip_rect_(screen_space_clip_rect
),
24 occluding_screen_space_rects_(NULL
),
25 non_occluding_screen_space_rects_(NULL
) {}
27 template <typename LayerType
>
28 OcclusionTracker
<LayerType
>::~OcclusionTracker() {}
30 template <typename LayerType
>
31 void OcclusionTracker
<LayerType
>::EnterLayer(
32 const LayerIteratorPosition
<LayerType
>& layer_iterator
) {
33 LayerType
* render_target
= layer_iterator
.target_render_surface_layer
;
35 if (layer_iterator
.represents_itself
)
36 EnterRenderTarget(render_target
);
37 else if (layer_iterator
.represents_target_render_surface
)
38 FinishedRenderTarget(render_target
);
41 template <typename LayerType
>
42 void OcclusionTracker
<LayerType
>::LeaveLayer(
43 const LayerIteratorPosition
<LayerType
>& layer_iterator
) {
44 LayerType
* render_target
= layer_iterator
.target_render_surface_layer
;
46 if (layer_iterator
.represents_itself
)
47 MarkOccludedBehindLayer(layer_iterator
.current_layer
);
48 // TODO(danakj): This should be done when entering the contributing surface,
49 // but in a way that the surface's own occlusion won't occlude itself.
50 else if (layer_iterator
.represents_contributing_render_surface
)
51 LeaveToRenderTarget(render_target
);
54 template <typename RenderSurfaceType
>
55 static gfx::Rect
ScreenSpaceClipRectInTargetSurface(
56 const RenderSurfaceType
* target_surface
,
57 const gfx::Rect
& screen_space_clip_rect
) {
58 gfx::Transform
inverse_screen_space_transform(
59 gfx::Transform::kSkipInitialization
);
60 if (!target_surface
->screen_space_transform().GetInverse(
61 &inverse_screen_space_transform
))
62 return target_surface
->content_rect();
64 return MathUtil::ProjectEnclosingClippedRect(inverse_screen_space_transform
,
65 screen_space_clip_rect
);
68 template <typename RenderSurfaceType
>
69 static SimpleEnclosedRegion
TransformSurfaceOpaqueRegion(
70 const SimpleEnclosedRegion
& region
,
72 const gfx::Rect
& clip_rect_in_new_target
,
73 const gfx::Transform
& transform
) {
77 // Verify that rects within the |surface| will remain rects in its target
78 // surface after applying |transform|. If this is true, then apply |transform|
79 // to each rect within |region| in order to transform the entire Region.
81 // TODO(danakj): Find a rect interior to each transformed quad.
82 if (!transform
.Preserves2dAxisAlignment())
83 return SimpleEnclosedRegion();
85 SimpleEnclosedRegion transformed_region
;
86 for (size_t i
= 0; i
< region
.GetRegionComplexity(); ++i
) {
88 gfx::QuadF transformed_quad
=
89 MathUtil::MapQuad(transform
, gfx::QuadF(region
.GetRect(i
)), &clipped
);
90 gfx::Rect transformed_rect
=
91 gfx::ToEnclosedRect(transformed_quad
.BoundingBox());
92 DCHECK(!clipped
); // We only map if the transform preserves axis alignment.
94 transformed_rect
.Intersect(clip_rect_in_new_target
);
95 transformed_region
.Union(transformed_rect
);
97 return transformed_region
;
100 static inline bool LayerOpacityKnown(const Layer
* layer
) {
101 return !layer
->draw_opacity_is_animating();
103 static inline bool LayerOpacityKnown(const LayerImpl
* layer
) {
106 static inline bool LayerTransformsToTargetKnown(const Layer
* layer
) {
107 return !layer
->draw_transform_is_animating();
109 static inline bool LayerTransformsToTargetKnown(const LayerImpl
* layer
) {
113 static inline bool SurfaceOpacityKnown(const RenderSurface
* rs
) {
114 return !rs
->draw_opacity_is_animating();
116 static inline bool SurfaceOpacityKnown(const RenderSurfaceImpl
* rs
) {
119 static inline bool SurfaceTransformsToTargetKnown(const RenderSurface
* rs
) {
120 return !rs
->target_surface_transforms_are_animating();
122 static inline bool SurfaceTransformsToTargetKnown(const RenderSurfaceImpl
* rs
) {
125 static inline bool SurfaceTransformsToScreenKnown(const RenderSurface
* rs
) {
126 return !rs
->screen_space_transforms_are_animating();
128 static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl
* rs
) {
132 static inline bool LayerIsInUnsorted3dRenderingContext(const Layer
* layer
) {
133 return layer
->Is3dSorted();
135 static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl
* layer
) {
139 template <typename LayerType
>
140 static inline bool LayerIsHidden(const LayerType
* layer
) {
141 return layer
->hide_layer_and_subtree() ||
142 (layer
->parent() && LayerIsHidden(layer
->parent()));
145 template <typename LayerType
>
146 void OcclusionTracker
<LayerType
>::EnterRenderTarget(
147 const LayerType
* new_target
) {
148 if (!stack_
.empty() && stack_
.back().target
== new_target
)
151 const LayerType
* old_target
= NULL
;
152 const typename
LayerType::RenderSurfaceType
* old_occlusion_immune_ancestor
=
154 if (!stack_
.empty()) {
155 old_target
= stack_
.back().target
;
156 old_occlusion_immune_ancestor
=
157 old_target
->render_surface()->nearest_occlusion_immune_ancestor();
159 const typename
LayerType::RenderSurfaceType
* new_occlusion_immune_ancestor
=
160 new_target
->render_surface()->nearest_occlusion_immune_ancestor();
162 stack_
.push_back(StackObject(new_target
));
164 // We copy the screen occlusion into the new RenderSurface subtree, but we
165 // never copy in the occlusion from inside the target, since we are looking
166 // at a new RenderSurface target.
168 // If entering an unoccluded subtree, do not carry forward the outside
169 // occlusion calculated so far.
170 bool entering_unoccluded_subtree
=
171 new_occlusion_immune_ancestor
&&
172 new_occlusion_immune_ancestor
!= old_occlusion_immune_ancestor
;
174 bool have_transform_from_screen_to_new_target
= false;
175 gfx::Transform
inverse_new_target_screen_space_transform(
176 // Note carefully, not used if screen space transform is uninvertible.
177 gfx::Transform::kSkipInitialization
);
178 if (SurfaceTransformsToScreenKnown(new_target
->render_surface())) {
179 have_transform_from_screen_to_new_target
=
180 new_target
->render_surface()->screen_space_transform().GetInverse(
181 &inverse_new_target_screen_space_transform
);
184 bool entering_root_target
= new_target
->parent() == NULL
;
186 bool copy_outside_occlusion_forward
=
188 !entering_unoccluded_subtree
&&
189 have_transform_from_screen_to_new_target
&&
190 !entering_root_target
;
191 if (!copy_outside_occlusion_forward
)
194 int last_index
= stack_
.size() - 1;
195 gfx::Transform
old_target_to_new_target_transform(
196 inverse_new_target_screen_space_transform
,
197 old_target
->render_surface()->screen_space_transform());
198 stack_
[last_index
].occlusion_from_outside_target
=
199 TransformSurfaceOpaqueRegion
<typename
LayerType::RenderSurfaceType
>(
200 stack_
[last_index
- 1].occlusion_from_outside_target
,
203 old_target_to_new_target_transform
);
204 stack_
[last_index
].occlusion_from_outside_target
.Union(
205 TransformSurfaceOpaqueRegion
<typename
LayerType::RenderSurfaceType
>(
206 stack_
[last_index
- 1].occlusion_from_inside_target
,
209 old_target_to_new_target_transform
));
212 template <typename LayerType
>
213 void OcclusionTracker
<LayerType
>::FinishedRenderTarget(
214 const LayerType
* finished_target
) {
215 // Make sure we know about the target surface.
216 EnterRenderTarget(finished_target
);
218 typename
LayerType::RenderSurfaceType
* surface
=
219 finished_target
->render_surface();
221 // Readbacks always happen on render targets so we only need to check
222 // for readbacks here.
223 bool target_is_only_for_copy_request
=
224 finished_target
->HasCopyRequest() && LayerIsHidden(finished_target
);
226 // If the occlusion within the surface can not be applied to things outside of
227 // the surface's subtree, then clear the occlusion here so it won't be used.
228 if (finished_target
->mask_layer() || !SurfaceOpacityKnown(surface
) ||
229 surface
->draw_opacity() < 1 ||
230 !finished_target
->uses_default_blend_mode() ||
231 target_is_only_for_copy_request
||
232 finished_target
->filters().HasFilterThatAffectsOpacity()) {
233 stack_
.back().occlusion_from_outside_target
.Clear();
234 stack_
.back().occlusion_from_inside_target
.Clear();
235 } else if (!SurfaceTransformsToTargetKnown(surface
)) {
236 stack_
.back().occlusion_from_inside_target
.Clear();
237 stack_
.back().occlusion_from_outside_target
.Clear();
241 template <typename LayerType
>
242 static void ReduceOcclusionBelowSurface(
243 LayerType
* contributing_layer
,
244 const gfx::Rect
& surface_rect
,
245 const gfx::Transform
& surface_transform
,
246 LayerType
* render_target
,
247 SimpleEnclosedRegion
* occlusion_from_inside_target
) {
248 if (surface_rect
.IsEmpty())
251 gfx::Rect affected_area_in_target
=
252 MathUtil::MapEnclosingClippedRect(surface_transform
, 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 SimpleEnclosedRegion affected_occlusion
= *occlusion_from_inside_target
;
269 affected_occlusion
.Intersect(affected_area_in_target
);
271 occlusion_from_inside_target
->Subtract(affected_area_in_target
);
272 for (size_t i
= 0; i
< affected_occlusion
.GetRegionComplexity(); ++i
) {
273 gfx::Rect occlusion_rect
= affected_occlusion
.GetRect(i
);
275 // Shrink the rect by expanding the non-opaque pixels outside the rect.
277 // The left outset of the filters moves pixels on the right side of
278 // the occlusion_rect into it, shrinking its right edge.
280 occlusion_rect
.x() == affected_area_in_target
.x() ? 0 : outset_right
;
282 occlusion_rect
.y() == affected_area_in_target
.y() ? 0 : outset_bottom
;
284 occlusion_rect
.right() == affected_area_in_target
.right() ?
287 occlusion_rect
.bottom() == affected_area_in_target
.bottom() ?
290 occlusion_rect
.Inset(shrink_left
, shrink_top
, shrink_right
, shrink_bottom
);
292 occlusion_from_inside_target
->Union(occlusion_rect
);
296 template <typename LayerType
>
297 void OcclusionTracker
<LayerType
>::LeaveToRenderTarget(
298 const LayerType
* new_target
) {
299 int last_index
= stack_
.size() - 1;
300 bool surface_will_be_at_top_after_pop
=
301 stack_
.size() > 1 && stack_
[last_index
- 1].target
== new_target
;
303 // We merge the screen occlusion from the current RenderSurfaceImpl subtree
304 // out to its parent target RenderSurfaceImpl. The target occlusion can be
305 // merged out as well but needs to be transformed to the new target.
307 const LayerType
* old_target
= stack_
[last_index
].target
;
308 const typename
LayerType::RenderSurfaceType
* old_surface
=
309 old_target
->render_surface();
311 SimpleEnclosedRegion old_occlusion_from_inside_target_in_new_target
=
312 TransformSurfaceOpaqueRegion
<typename
LayerType::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
<typename
LayerType::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 SimpleEnclosedRegion old_occlusion_from_outside_target_in_new_target
=
327 TransformSurfaceOpaqueRegion
<typename
LayerType::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_surface
->content_rect(), old_surface
->draw_transform());
338 if (old_target
->has_replica()) {
339 unoccluded_replica_rect
= UnoccludedContributingSurfaceContentRect(
340 old_surface
->content_rect(),
341 old_surface
->replica_draw_transform());
345 if (surface_will_be_at_top_after_pop
) {
346 // Merge the top of the stack down.
347 stack_
[last_index
- 1].occlusion_from_inside_target
.Union(
348 old_occlusion_from_inside_target_in_new_target
);
349 // TODO(danakj): Strictly this should subtract the inside target occlusion
351 if (new_target
->parent()) {
352 stack_
[last_index
- 1].occlusion_from_outside_target
.Union(
353 old_occlusion_from_outside_target_in_new_target
);
357 // Replace the top of the stack with the new pushed surface.
358 stack_
.back().target
= new_target
;
359 stack_
.back().occlusion_from_inside_target
=
360 old_occlusion_from_inside_target_in_new_target
;
361 if (new_target
->parent()) {
362 stack_
.back().occlusion_from_outside_target
=
363 old_occlusion_from_outside_target_in_new_target
;
365 stack_
.back().occlusion_from_outside_target
.Clear();
369 if (!old_target
->background_filters().HasFilterThatMovesPixels())
372 ReduceOcclusionBelowSurface(old_target
,
373 unoccluded_surface_rect
,
374 old_surface
->draw_transform(),
376 &stack_
.back().occlusion_from_inside_target
);
377 ReduceOcclusionBelowSurface(old_target
,
378 unoccluded_surface_rect
,
379 old_surface
->draw_transform(),
381 &stack_
.back().occlusion_from_outside_target
);
383 if (!old_target
->has_replica())
385 ReduceOcclusionBelowSurface(old_target
,
386 unoccluded_replica_rect
,
387 old_surface
->replica_draw_transform(),
389 &stack_
.back().occlusion_from_inside_target
);
390 ReduceOcclusionBelowSurface(old_target
,
391 unoccluded_replica_rect
,
392 old_surface
->replica_draw_transform(),
394 &stack_
.back().occlusion_from_outside_target
);
397 template <typename LayerType
>
398 void OcclusionTracker
<LayerType
>::MarkOccludedBehindLayer(
399 const LayerType
* layer
) {
400 DCHECK(!stack_
.empty());
401 DCHECK_EQ(layer
->render_target(), stack_
.back().target
);
403 if (!LayerOpacityKnown(layer
) || layer
->draw_opacity() < 1)
406 if (!layer
->uses_default_blend_mode())
409 if (LayerIsInUnsorted3dRenderingContext(layer
))
412 if (!LayerTransformsToTargetKnown(layer
))
415 SimpleEnclosedRegion opaque_contents
= layer
->VisibleContentOpaqueRegion();
416 if (opaque_contents
.IsEmpty())
419 DCHECK(layer
->visible_content_rect().Contains(opaque_contents
.bounds()));
421 // TODO(danakj): Find a rect interior to each transformed quad.
422 if (!layer
->draw_transform().Preserves2dAxisAlignment())
425 gfx::Rect clip_rect_in_target
= ScreenSpaceClipRectInTargetSurface(
426 layer
->render_target()->render_surface(), screen_space_clip_rect_
);
427 if (layer
->is_clipped()) {
428 clip_rect_in_target
.Intersect(layer
->clip_rect());
430 clip_rect_in_target
.Intersect(
431 layer
->render_target()->render_surface()->content_rect());
434 for (size_t i
= 0; i
< opaque_contents
.GetRegionComplexity(); ++i
) {
436 gfx::QuadF transformed_quad
=
437 MathUtil::MapQuad(layer
->draw_transform(),
438 gfx::QuadF(opaque_contents
.GetRect(i
)),
440 gfx::Rect transformed_rect
=
441 gfx::ToEnclosedRect(transformed_quad
.BoundingBox());
442 DCHECK(!clipped
); // We only map if the transform preserves axis alignment.
443 transformed_rect
.Intersect(clip_rect_in_target
);
444 if (transformed_rect
.width() < minimum_tracking_size_
.width() &&
445 transformed_rect
.height() < minimum_tracking_size_
.height())
447 stack_
.back().occlusion_from_inside_target
.Union(transformed_rect
);
449 if (!occluding_screen_space_rects_
)
452 // Save the occluding area in screen space for debug visualization.
453 gfx::QuadF screen_space_quad
= MathUtil::MapQuad(
454 layer
->render_target()->render_surface()->screen_space_transform(),
455 gfx::QuadF(transformed_rect
), &clipped
);
456 // TODO(danakj): Store the quad in the debug info instead of the bounding
458 gfx::Rect screen_space_rect
=
459 gfx::ToEnclosedRect(screen_space_quad
.BoundingBox());
460 occluding_screen_space_rects_
->push_back(screen_space_rect
);
463 if (!non_occluding_screen_space_rects_
)
466 Region
non_opaque_contents(gfx::Rect(layer
->content_bounds()));
467 non_opaque_contents
.Subtract(opaque_contents
);
469 for (Region::Iterator
non_opaque_content_rects(non_opaque_contents
);
470 non_opaque_content_rects
.has_rect();
471 non_opaque_content_rects
.next()) {
472 // We've already checked for clipping in the MapQuad call above, these calls
473 // should not clip anything further.
474 gfx::Rect transformed_rect
= gfx::ToEnclosedRect(
475 MathUtil::MapClippedRect(layer
->draw_transform(),
476 gfx::RectF(non_opaque_content_rects
.rect())));
477 transformed_rect
.Intersect(clip_rect_in_target
);
478 if (transformed_rect
.IsEmpty())
482 gfx::QuadF screen_space_quad
= MathUtil::MapQuad(
483 layer
->render_target()->render_surface()->screen_space_transform(),
484 gfx::QuadF(transformed_rect
),
486 // TODO(danakj): Store the quad in the debug info instead of the bounding
488 gfx::Rect screen_space_rect
=
489 gfx::ToEnclosedRect(screen_space_quad
.BoundingBox());
490 non_occluding_screen_space_rects_
->push_back(screen_space_rect
);
494 template <typename LayerType
>
495 bool OcclusionTracker
<LayerType
>::Occluded(
496 const LayerType
* render_target
,
497 const gfx::Rect
& content_rect
,
498 const gfx::Transform
& draw_transform
) const {
499 DCHECK(!stack_
.empty());
502 if (content_rect
.IsEmpty())
505 // For tests with no render target.
509 DCHECK_EQ(render_target
->render_target(), render_target
);
510 DCHECK(render_target
->render_surface());
511 DCHECK_EQ(render_target
, stack_
.back().target
);
513 const StackObject
& back
= stack_
.back();
514 if (back
.occlusion_from_inside_target
.IsEmpty() &&
515 back
.occlusion_from_outside_target
.IsEmpty()) {
519 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
520 // partial pixels in the resulting Rect.
521 gfx::Rect unoccluded_rect_in_target_surface
=
522 MathUtil::MapEnclosingClippedRect(draw_transform
, content_rect
);
523 DCHECK_LE(back
.occlusion_from_inside_target
.GetRegionComplexity(), 1u);
524 DCHECK_LE(back
.occlusion_from_outside_target
.GetRegionComplexity(), 1u);
525 // These subtract operations are more lossy than if we did both operations at
527 unoccluded_rect_in_target_surface
.Subtract(
528 stack_
.back().occlusion_from_inside_target
.bounds());
529 unoccluded_rect_in_target_surface
.Subtract(
530 stack_
.back().occlusion_from_outside_target
.bounds());
532 return unoccluded_rect_in_target_surface
.IsEmpty();
535 template <typename LayerType
>
536 gfx::Rect OcclusionTracker
<LayerType
>::UnoccludedContentRect(
537 const gfx::Rect
& content_rect
,
538 const gfx::Transform
& draw_transform
) const {
539 DCHECK(!stack_
.empty());
540 if (content_rect
.IsEmpty())
543 const StackObject
& back
= stack_
.back();
544 if (back
.occlusion_from_inside_target
.IsEmpty() &&
545 back
.occlusion_from_outside_target
.IsEmpty()) {
549 gfx::Transform
inverse_draw_transform(gfx::Transform::kSkipInitialization
);
550 bool ok
= draw_transform
.GetInverse(&inverse_draw_transform
);
553 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
554 // partial pixels in the resulting Rect.
555 gfx::Rect unoccluded_rect_in_target_surface
=
556 MathUtil::MapEnclosingClippedRect(draw_transform
, content_rect
);
557 DCHECK_LE(back
.occlusion_from_inside_target
.GetRegionComplexity(), 1u);
558 DCHECK_LE(back
.occlusion_from_outside_target
.GetRegionComplexity(), 1u);
559 // These subtract operations are more lossy than if we did both operations at
561 unoccluded_rect_in_target_surface
.Subtract(
562 back
.occlusion_from_inside_target
.bounds());
563 unoccluded_rect_in_target_surface
.Subtract(
564 back
.occlusion_from_outside_target
.bounds());
566 if (unoccluded_rect_in_target_surface
.IsEmpty())
569 gfx::Rect unoccluded_rect
= MathUtil::ProjectEnclosingClippedRect(
570 inverse_draw_transform
, unoccluded_rect_in_target_surface
);
571 unoccluded_rect
.Intersect(content_rect
);
573 return unoccluded_rect
;
576 template <typename LayerType
>
577 gfx::Rect OcclusionTracker
<LayerType
>::UnoccludedContributingSurfaceContentRect(
578 const gfx::Rect
& content_rect
,
579 const gfx::Transform
& draw_transform
) const {
580 if (content_rect
.IsEmpty())
583 // A contributing surface doesn't get occluded by things inside its own
584 // surface, so only things outside the surface can occlude it. That occlusion
585 // is found just below the top of the stack (if it exists).
586 bool has_occlusion
= stack_
.size() > 1;
590 const StackObject
& second_last
= stack_
[stack_
.size() - 2];
591 if (second_last
.occlusion_from_inside_target
.IsEmpty() &&
592 second_last
.occlusion_from_outside_target
.IsEmpty())
595 gfx::Transform
inverse_draw_transform(gfx::Transform::kSkipInitialization
);
596 bool ok
= draw_transform
.GetInverse(&inverse_draw_transform
);
599 // Take the ToEnclosingRect at each step, as we want to contain any unoccluded
600 // partial pixels in the resulting Rect.
601 gfx::Rect unoccluded_rect_in_target_surface
=
602 MathUtil::MapEnclosingClippedRect(draw_transform
, content_rect
);
603 DCHECK_LE(second_last
.occlusion_from_inside_target
.GetRegionComplexity(), 1u);
604 DCHECK_LE(second_last
.occlusion_from_outside_target
.GetRegionComplexity(),
606 // These subtract operations are more lossy than if we did both operations at
608 unoccluded_rect_in_target_surface
.Subtract(
609 second_last
.occlusion_from_inside_target
.bounds());
610 unoccluded_rect_in_target_surface
.Subtract(
611 second_last
.occlusion_from_outside_target
.bounds());
613 if (unoccluded_rect_in_target_surface
.IsEmpty())
616 gfx::Rect unoccluded_rect
= MathUtil::ProjectEnclosingClippedRect(
617 inverse_draw_transform
, unoccluded_rect_in_target_surface
);
618 unoccluded_rect
.Intersect(content_rect
);
620 return unoccluded_rect
;
623 template <typename LayerType
>
624 Region OcclusionTracker
<LayerType
>::ComputeVisibleRegionInScreen() const {
625 DCHECK(!stack_
.back().target
->parent());
626 const SimpleEnclosedRegion
& occluded
=
627 stack_
.back().occlusion_from_inside_target
;
628 Region
visible_region(screen_space_clip_rect_
);
629 for (size_t i
= 0; i
< occluded
.GetRegionComplexity(); ++i
)
630 visible_region
.Subtract(occluded
.GetRect(i
));
631 return visible_region
;
634 // Instantiate (and export) templates here for the linker.
635 template class OcclusionTracker
<Layer
>;
636 template class OcclusionTracker
<LayerImpl
>;