Index: cc/trees/occlusion_tracker.cc |
diff --git a/cc/trees/occlusion_tracker.cc b/cc/trees/occlusion_tracker.cc |
deleted file mode 100644 |
index 0f0ce158400add99977bb525b0a1b334d0f782a9..0000000000000000000000000000000000000000 |
--- a/cc/trees/occlusion_tracker.cc |
+++ /dev/null |
@@ -1,486 +0,0 @@ |
-// Copyright 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "cc/trees/occlusion_tracker.h" |
- |
-#include <algorithm> |
- |
-#include "cc/base/math_util.h" |
-#include "cc/base/region.h" |
-#include "cc/layers/layer.h" |
-#include "cc/layers/layer_impl.h" |
-#include "cc/layers/render_surface.h" |
-#include "cc/layers/render_surface_impl.h" |
-#include "ui/gfx/geometry/quad_f.h" |
-#include "ui/gfx/geometry/rect_conversions.h" |
- |
-namespace cc { |
- |
-template <typename LayerType> |
-OcclusionTracker<LayerType>::OcclusionTracker( |
- const gfx::Rect& screen_space_clip_rect) |
- : screen_space_clip_rect_(screen_space_clip_rect) { |
-} |
- |
-template <typename LayerType> |
-OcclusionTracker<LayerType>::~OcclusionTracker() { |
-} |
- |
-template <typename LayerType> |
-Occlusion OcclusionTracker<LayerType>::GetCurrentOcclusionForLayer( |
- const gfx::Transform& draw_transform) const { |
- DCHECK(!stack_.empty()); |
- const StackObject& back = stack_.back(); |
- return Occlusion(draw_transform, |
- back.occlusion_from_outside_target, |
- back.occlusion_from_inside_target); |
-} |
- |
-template <typename LayerType> |
-Occlusion |
-OcclusionTracker<LayerType>::GetCurrentOcclusionForContributingSurface( |
- const gfx::Transform& draw_transform) const { |
- DCHECK(!stack_.empty()); |
- if (stack_.size() < 2) |
- return Occlusion(); |
- // A contributing surface doesn't get occluded by things inside its own |
- // surface, so only things outside the surface can occlude it. That occlusion |
- // is found just below the top of the stack (if it exists). |
- const StackObject& second_last = stack_[stack_.size() - 2]; |
- return Occlusion(draw_transform, second_last.occlusion_from_outside_target, |
- second_last.occlusion_from_inside_target); |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::EnterLayer( |
- const LayerIteratorPosition<LayerType>& layer_iterator) { |
- LayerType* render_target = layer_iterator.target_render_surface_layer; |
- |
- if (layer_iterator.represents_itself) |
- EnterRenderTarget(render_target); |
- else if (layer_iterator.represents_target_render_surface) |
- FinishedRenderTarget(render_target); |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::LeaveLayer( |
- const LayerIteratorPosition<LayerType>& layer_iterator) { |
- LayerType* render_target = layer_iterator.target_render_surface_layer; |
- |
- if (layer_iterator.represents_itself) |
- MarkOccludedBehindLayer(layer_iterator.current_layer); |
- // TODO(danakj): This should be done when entering the contributing surface, |
- // but in a way that the surface's own occlusion won't occlude itself. |
- else if (layer_iterator.represents_contributing_render_surface) |
- LeaveToRenderTarget(render_target); |
-} |
- |
-template <typename RenderSurfaceType> |
-static gfx::Rect ScreenSpaceClipRectInTargetSurface( |
- const RenderSurfaceType* target_surface, |
- const gfx::Rect& screen_space_clip_rect) { |
- gfx::Transform inverse_screen_space_transform( |
- gfx::Transform::kSkipInitialization); |
- if (!target_surface->screen_space_transform().GetInverse( |
- &inverse_screen_space_transform)) |
- return target_surface->content_rect(); |
- |
- return MathUtil::ProjectEnclosingClippedRect(inverse_screen_space_transform, |
- screen_space_clip_rect); |
-} |
- |
-template <typename RenderSurfaceType> |
-static SimpleEnclosedRegion TransformSurfaceOpaqueRegion( |
- const SimpleEnclosedRegion& region, |
- bool have_clip_rect, |
- const gfx::Rect& clip_rect_in_new_target, |
- const gfx::Transform& transform) { |
- if (region.IsEmpty()) |
- return region; |
- |
- // Verify that rects within the |surface| will remain rects in its target |
- // surface after applying |transform|. If this is true, then apply |transform| |
- // to each rect within |region| in order to transform the entire Region. |
- |
- // TODO(danakj): Find a rect interior to each transformed quad. |
- if (!transform.Preserves2dAxisAlignment()) |
- return SimpleEnclosedRegion(); |
- |
- SimpleEnclosedRegion transformed_region; |
- for (size_t i = 0; i < region.GetRegionComplexity(); ++i) { |
- gfx::Rect transformed_rect = |
- MathUtil::MapEnclosedRectWith2dAxisAlignedTransform(transform, |
- region.GetRect(i)); |
- if (have_clip_rect) |
- transformed_rect.Intersect(clip_rect_in_new_target); |
- transformed_region.Union(transformed_rect); |
- } |
- return transformed_region; |
-} |
- |
-static inline bool LayerOpacityKnown(const Layer* layer) { |
- return !layer->draw_opacity_is_animating(); |
-} |
-static inline bool LayerOpacityKnown(const LayerImpl* layer) { |
- return true; |
-} |
-static inline bool LayerTransformsToTargetKnown(const Layer* layer) { |
- return !layer->draw_transform_is_animating(); |
-} |
-static inline bool LayerTransformsToTargetKnown(const LayerImpl* layer) { |
- return true; |
-} |
- |
-static inline bool SurfaceOpacityKnown(const RenderSurface* rs) { |
- return !rs->draw_opacity_is_animating(); |
-} |
-static inline bool SurfaceOpacityKnown(const RenderSurfaceImpl* rs) { |
- return true; |
-} |
-static inline bool SurfaceTransformsToTargetKnown(const RenderSurface* rs) { |
- return !rs->target_surface_transforms_are_animating(); |
-} |
-static inline bool SurfaceTransformsToTargetKnown(const RenderSurfaceImpl* rs) { |
- return true; |
-} |
-static inline bool SurfaceTransformsToScreenKnown(const RenderSurface* rs) { |
- return !rs->screen_space_transforms_are_animating(); |
-} |
-static inline bool SurfaceTransformsToScreenKnown(const RenderSurfaceImpl* rs) { |
- return true; |
-} |
- |
-static inline bool LayerIsInUnsorted3dRenderingContext(const Layer* layer) { |
- return layer->Is3dSorted(); |
-} |
-static inline bool LayerIsInUnsorted3dRenderingContext(const LayerImpl* layer) { |
- return layer->Is3dSorted(); |
-} |
- |
-template <typename LayerType> |
-static inline bool LayerIsHidden(const LayerType* layer) { |
- return layer->hide_layer_and_subtree() || |
- (layer->parent() && LayerIsHidden(layer->parent())); |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::EnterRenderTarget( |
- const LayerType* new_target) { |
- if (!stack_.empty() && stack_.back().target == new_target) |
- return; |
- |
- const LayerType* old_target = NULL; |
- const typename LayerType::RenderSurfaceType* old_occlusion_immune_ancestor = |
- NULL; |
- if (!stack_.empty()) { |
- old_target = stack_.back().target; |
- old_occlusion_immune_ancestor = |
- old_target->render_surface()->nearest_occlusion_immune_ancestor(); |
- } |
- const typename LayerType::RenderSurfaceType* new_occlusion_immune_ancestor = |
- new_target->render_surface()->nearest_occlusion_immune_ancestor(); |
- |
- stack_.push_back(StackObject(new_target)); |
- |
- // We copy the screen occlusion into the new RenderSurface subtree, but we |
- // never copy in the occlusion from inside the target, since we are looking |
- // at a new RenderSurface target. |
- |
- // If entering an unoccluded subtree, do not carry forward the outside |
- // occlusion calculated so far. |
- bool entering_unoccluded_subtree = |
- new_occlusion_immune_ancestor && |
- new_occlusion_immune_ancestor != old_occlusion_immune_ancestor; |
- |
- bool have_transform_from_screen_to_new_target = false; |
- gfx::Transform inverse_new_target_screen_space_transform( |
- // Note carefully, not used if screen space transform is uninvertible. |
- gfx::Transform::kSkipInitialization); |
- if (SurfaceTransformsToScreenKnown(new_target->render_surface())) { |
- have_transform_from_screen_to_new_target = |
- new_target->render_surface()->screen_space_transform().GetInverse( |
- &inverse_new_target_screen_space_transform); |
- } |
- |
- bool entering_root_target = new_target->parent() == NULL; |
- |
- bool copy_outside_occlusion_forward = |
- stack_.size() > 1 && |
- !entering_unoccluded_subtree && |
- have_transform_from_screen_to_new_target && |
- !entering_root_target; |
- if (!copy_outside_occlusion_forward) |
- return; |
- |
- int last_index = stack_.size() - 1; |
- gfx::Transform old_target_to_new_target_transform( |
- inverse_new_target_screen_space_transform, |
- old_target->render_surface()->screen_space_transform()); |
- stack_[last_index].occlusion_from_outside_target = |
- TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
- stack_[last_index - 1].occlusion_from_outside_target, |
- false, |
- gfx::Rect(), |
- old_target_to_new_target_transform); |
- stack_[last_index].occlusion_from_outside_target.Union( |
- TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
- stack_[last_index - 1].occlusion_from_inside_target, |
- false, |
- gfx::Rect(), |
- old_target_to_new_target_transform)); |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::FinishedRenderTarget( |
- const LayerType* finished_target) { |
- // Make sure we know about the target surface. |
- EnterRenderTarget(finished_target); |
- |
- typename LayerType::RenderSurfaceType* surface = |
- finished_target->render_surface(); |
- |
- // Readbacks always happen on render targets so we only need to check |
- // for readbacks here. |
- bool target_is_only_for_copy_request = |
- finished_target->HasCopyRequest() && LayerIsHidden(finished_target); |
- |
- // 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. |
- if (finished_target->mask_layer() || !SurfaceOpacityKnown(surface) || |
- surface->draw_opacity() < 1 || |
- !finished_target->uses_default_blend_mode() || |
- target_is_only_for_copy_request || |
- finished_target->filters().HasFilterThatAffectsOpacity()) { |
- stack_.back().occlusion_from_outside_target.Clear(); |
- stack_.back().occlusion_from_inside_target.Clear(); |
- } else if (!SurfaceTransformsToTargetKnown(surface)) { |
- stack_.back().occlusion_from_inside_target.Clear(); |
- stack_.back().occlusion_from_outside_target.Clear(); |
- } |
-} |
- |
-template <typename LayerType> |
-static void ReduceOcclusionBelowSurface( |
- LayerType* contributing_layer, |
- const gfx::Rect& surface_rect, |
- const gfx::Transform& surface_transform, |
- LayerType* render_target, |
- SimpleEnclosedRegion* occlusion_from_inside_target) { |
- if (surface_rect.IsEmpty()) |
- return; |
- |
- gfx::Rect affected_area_in_target = |
- MathUtil::MapEnclosingClippedRect(surface_transform, surface_rect); |
- if (contributing_layer->render_surface()->is_clipped()) { |
- affected_area_in_target.Intersect( |
- contributing_layer->render_surface()->clip_rect()); |
- } |
- if (affected_area_in_target.IsEmpty()) |
- return; |
- |
- int outset_top, outset_right, outset_bottom, outset_left; |
- contributing_layer->background_filters().GetOutsets( |
- &outset_top, &outset_right, &outset_bottom, &outset_left); |
- |
- // The filter can move pixels from outside of the clip, so allow affected_area |
- // to expand outside the clip. |
- affected_area_in_target.Inset( |
- -outset_left, -outset_top, -outset_right, -outset_bottom); |
- SimpleEnclosedRegion affected_occlusion = *occlusion_from_inside_target; |
- affected_occlusion.Intersect(affected_area_in_target); |
- |
- occlusion_from_inside_target->Subtract(affected_area_in_target); |
- for (size_t i = 0; i < affected_occlusion.GetRegionComplexity(); ++i) { |
- gfx::Rect occlusion_rect = affected_occlusion.GetRect(i); |
- |
- // Shrink the rect by expanding the non-opaque pixels outside the rect. |
- |
- // The left outset of the filters moves pixels on the right side of |
- // the occlusion_rect into it, shrinking its right edge. |
- int shrink_left = |
- occlusion_rect.x() == affected_area_in_target.x() ? 0 : outset_right; |
- int shrink_top = |
- occlusion_rect.y() == affected_area_in_target.y() ? 0 : outset_bottom; |
- int shrink_right = |
- occlusion_rect.right() == affected_area_in_target.right() ? |
- 0 : outset_left; |
- int shrink_bottom = |
- occlusion_rect.bottom() == affected_area_in_target.bottom() ? |
- 0 : outset_top; |
- |
- occlusion_rect.Inset(shrink_left, shrink_top, shrink_right, shrink_bottom); |
- |
- occlusion_from_inside_target->Union(occlusion_rect); |
- } |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::LeaveToRenderTarget( |
- const LayerType* new_target) { |
- int last_index = stack_.size() - 1; |
- bool surface_will_be_at_top_after_pop = |
- stack_.size() > 1 && stack_[last_index - 1].target == new_target; |
- |
- // We merge the screen occlusion from the current RenderSurfaceImpl subtree |
- // out to its parent target RenderSurfaceImpl. The target occlusion can be |
- // merged out as well but needs to be transformed to the new target. |
- |
- const LayerType* old_target = stack_[last_index].target; |
- const typename LayerType::RenderSurfaceType* old_surface = |
- old_target->render_surface(); |
- |
- SimpleEnclosedRegion old_occlusion_from_inside_target_in_new_target = |
- TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
- stack_[last_index].occlusion_from_inside_target, |
- old_surface->is_clipped(), |
- old_surface->clip_rect(), |
- old_surface->draw_transform()); |
- if (old_target->has_replica() && !old_target->replica_has_mask()) { |
- old_occlusion_from_inside_target_in_new_target.Union( |
- TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
- stack_[last_index].occlusion_from_inside_target, |
- old_surface->is_clipped(), |
- old_surface->clip_rect(), |
- old_surface->replica_draw_transform())); |
- } |
- |
- SimpleEnclosedRegion old_occlusion_from_outside_target_in_new_target = |
- TransformSurfaceOpaqueRegion<typename LayerType::RenderSurfaceType>( |
- stack_[last_index].occlusion_from_outside_target, |
- false, |
- gfx::Rect(), |
- old_surface->draw_transform()); |
- |
- gfx::Rect unoccluded_surface_rect; |
- gfx::Rect unoccluded_replica_rect; |
- if (old_target->background_filters().HasFilterThatMovesPixels()) { |
- Occlusion surface_occlusion = GetCurrentOcclusionForContributingSurface( |
- old_surface->draw_transform()); |
- unoccluded_surface_rect = |
- surface_occlusion.GetUnoccludedContentRect(old_surface->content_rect()); |
- if (old_target->has_replica()) { |
- Occlusion replica_occlusion = GetCurrentOcclusionForContributingSurface( |
- old_surface->replica_draw_transform()); |
- unoccluded_replica_rect = replica_occlusion.GetUnoccludedContentRect( |
- old_surface->content_rect()); |
- } |
- } |
- |
- if (surface_will_be_at_top_after_pop) { |
- // Merge the top of the stack down. |
- stack_[last_index - 1].occlusion_from_inside_target.Union( |
- old_occlusion_from_inside_target_in_new_target); |
- // TODO(danakj): Strictly this should subtract the inside target occlusion |
- // before union. |
- if (new_target->parent()) { |
- stack_[last_index - 1].occlusion_from_outside_target.Union( |
- old_occlusion_from_outside_target_in_new_target); |
- } |
- stack_.pop_back(); |
- } else { |
- // Replace the top of the stack with the new pushed surface. |
- stack_.back().target = new_target; |
- stack_.back().occlusion_from_inside_target = |
- old_occlusion_from_inside_target_in_new_target; |
- if (new_target->parent()) { |
- stack_.back().occlusion_from_outside_target = |
- old_occlusion_from_outside_target_in_new_target; |
- } else { |
- stack_.back().occlusion_from_outside_target.Clear(); |
- } |
- } |
- |
- if (!old_target->background_filters().HasFilterThatMovesPixels()) |
- return; |
- |
- ReduceOcclusionBelowSurface(old_target, |
- unoccluded_surface_rect, |
- old_surface->draw_transform(), |
- new_target, |
- &stack_.back().occlusion_from_inside_target); |
- ReduceOcclusionBelowSurface(old_target, |
- unoccluded_surface_rect, |
- old_surface->draw_transform(), |
- new_target, |
- &stack_.back().occlusion_from_outside_target); |
- |
- if (!old_target->has_replica()) |
- return; |
- ReduceOcclusionBelowSurface(old_target, |
- unoccluded_replica_rect, |
- old_surface->replica_draw_transform(), |
- new_target, |
- &stack_.back().occlusion_from_inside_target); |
- ReduceOcclusionBelowSurface(old_target, |
- unoccluded_replica_rect, |
- old_surface->replica_draw_transform(), |
- new_target, |
- &stack_.back().occlusion_from_outside_target); |
-} |
- |
-template <typename LayerType> |
-void OcclusionTracker<LayerType>::MarkOccludedBehindLayer( |
- const LayerType* layer) { |
- DCHECK(!stack_.empty()); |
- DCHECK_EQ(layer->render_target(), stack_.back().target); |
- |
- if (!LayerOpacityKnown(layer) || layer->draw_opacity() < 1) |
- return; |
- |
- if (!layer->uses_default_blend_mode()) |
- return; |
- |
- if (LayerIsInUnsorted3dRenderingContext(layer)) |
- return; |
- |
- if (!LayerTransformsToTargetKnown(layer)) |
- return; |
- |
- SimpleEnclosedRegion opaque_contents = layer->VisibleContentOpaqueRegion(); |
- if (opaque_contents.IsEmpty()) |
- return; |
- |
- DCHECK(layer->visible_content_rect().Contains(opaque_contents.bounds())); |
- |
- // TODO(danakj): Find a rect interior to each transformed quad. |
- if (!layer->draw_transform().Preserves2dAxisAlignment()) |
- return; |
- |
- gfx::Rect clip_rect_in_target = ScreenSpaceClipRectInTargetSurface( |
- layer->render_target()->render_surface(), screen_space_clip_rect_); |
- if (layer->is_clipped()) { |
- clip_rect_in_target.Intersect(layer->clip_rect()); |
- } else { |
- clip_rect_in_target.Intersect( |
- layer->render_target()->render_surface()->content_rect()); |
- } |
- |
- for (size_t i = 0; i < opaque_contents.GetRegionComplexity(); ++i) { |
- gfx::Rect transformed_rect = |
- MathUtil::MapEnclosedRectWith2dAxisAlignedTransform( |
- layer->draw_transform(), opaque_contents.GetRect(i)); |
- transformed_rect.Intersect(clip_rect_in_target); |
- if (transformed_rect.width() < minimum_tracking_size_.width() && |
- transformed_rect.height() < minimum_tracking_size_.height()) |
- continue; |
- stack_.back().occlusion_from_inside_target.Union(transformed_rect); |
- } |
-} |
- |
-template <typename LayerType> |
-Region OcclusionTracker<LayerType>::ComputeVisibleRegionInScreen() const { |
- DCHECK(!stack_.back().target->parent()); |
- const SimpleEnclosedRegion& occluded = |
- stack_.back().occlusion_from_inside_target; |
- Region visible_region(screen_space_clip_rect_); |
- for (size_t i = 0; i < occluded.GetRegionComplexity(); ++i) |
- visible_region.Subtract(occluded.GetRect(i)); |
- return visible_region; |
-} |
- |
-// Instantiate (and export) templates here for the linker. |
-template class OcclusionTracker<Layer>; |
-template class OcclusionTracker<LayerImpl>; |
- |
-} // namespace cc |