diff options
author | Andras Becsi <andras.becsi@digia.com> | 2013-12-11 21:33:03 +0100 |
---|---|---|
committer | Andras Becsi <andras.becsi@digia.com> | 2013-12-13 12:34:07 +0100 |
commit | f2a33ff9cbc6d19943f1c7fbddd1f23d23975577 (patch) | |
tree | 0586a32aa390ade8557dfd6b4897f43a07449578 /chromium/cc/trees/layer_tree_host_common.cc | |
parent | 5362912cdb5eea702b68ebe23702468d17c3017a (diff) | |
download | qtwebengine-chromium-f2a33ff9cbc6d19943f1c7fbddd1f23d23975577.tar.gz |
Update Chromium to branch 1650 (31.0.1650.63)
Change-Id: I57d8c832eaec1eb2364e0a8e7352a6dd354db99f
Reviewed-by: Jocelyn Turcotte <jocelyn.turcotte@digia.com>
Diffstat (limited to 'chromium/cc/trees/layer_tree_host_common.cc')
-rw-r--r-- | chromium/cc/trees/layer_tree_host_common.cc | 562 |
1 files changed, 424 insertions, 138 deletions
diff --git a/chromium/cc/trees/layer_tree_host_common.cc b/chromium/cc/trees/layer_tree_host_common.cc index 68dadd5f9b9..8017fa9a933 100644 --- a/chromium/cc/trees/layer_tree_host_common.cc +++ b/chromium/cc/trees/layer_tree_host_common.cc @@ -40,6 +40,29 @@ static void SortLayers(LayerImplList::iterator first, layer_sorter->Sort(first, end); } +template <typename LayerType> +static gfx::Vector2dF GetEffectiveScrollDelta(LayerType* layer) { + gfx::Vector2dF scroll_delta = layer->ScrollDelta(); + // The scroll parent's scroll delta is the amount we've scrolled on the + // compositor thread since the commit for this layer tree's source frame. + // we last reported to the main thread. I.e., it's the discrepancy between + // a scroll parent's scroll delta and offset, so we must add it here. + if (layer->scroll_parent()) + scroll_delta += layer->scroll_parent()->ScrollDelta(); + return scroll_delta; +} + +template <typename LayerType> +static gfx::Vector2dF GetEffectiveTotalScrollOffset(LayerType* layer) { + gfx::Vector2dF offset = layer->TotalScrollOffset(); + // The scroll parent's total scroll offset (scroll offset + scroll delta) + // can't be used because its scroll offset has already been applied to the + // scroll children's positions by the main thread layer positioning code. + if (layer->scroll_parent()) + offset += layer->scroll_parent()->ScrollDelta(); + return offset; +} + inline gfx::Rect CalculateVisibleRectWithCachedLayerRect( gfx::Rect target_surface_rect, gfx::Rect layer_bound_rect, @@ -58,6 +81,9 @@ inline gfx::Rect CalculateVisibleRectWithCachedLayerRect( gfx::Rect minimal_surface_rect = target_surface_rect; minimal_surface_rect.Intersect(layer_rect_in_target_space); + if (minimal_surface_rect.IsEmpty()) + return gfx::Rect(); + // Project the corners of the target surface rect into the layer space. // This bounding rectangle may be larger than it needs to be (being // axis-aligned), but is a reasonable filter on the space to consider. @@ -65,11 +91,10 @@ inline gfx::Rect CalculateVisibleRectWithCachedLayerRect( gfx::Transform surface_to_layer(gfx::Transform::kSkipInitialization); if (!transform.GetInverse(&surface_to_layer)) { - // TODO(shawnsingh): Some uninvertible transforms may be visible, but - // their behaviour is undefined thoughout the compositor. Make their - // behaviour well-defined and allow the visible content rect to be non- - // empty when needed. - return gfx::Rect(); + // Because we cannot use the surface bounds to determine what portion of + // the layer is visible, we must conservatively assume the full layer is + // visible. + return layer_bound_rect; } gfx::Rect layer_rect = gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( @@ -88,6 +113,201 @@ gfx::Rect LayerTreeHostCommon::CalculateVisibleRect( target_surface_rect, layer_bound_rect, layer_in_surface_space, transform); } +template <typename LayerType> +static LayerType* NextTargetSurface(LayerType* layer) { + return layer->parent() ? layer->parent()->render_target() : 0; +} + +// Given two layers, this function finds their respective render targets and, +// computes a change of basis translation. It does this by accumulating the +// translation components of the draw transforms of each target between the +// ancestor and descendant. These transforms must be 2D translations, and this +// requirement is enforced at every step. +template <typename LayerType, typename RenderSurfaceType> +static gfx::Vector2dF ComputeChangeOfBasisTranslation( + const LayerType& ancestor_layer, + const LayerType& descendant_layer) { + DCHECK(descendant_layer.HasAncestor(&ancestor_layer)); + const LayerType* descendant_target = descendant_layer.render_target(); + DCHECK(descendant_target); + const LayerType* ancestor_target = ancestor_layer.render_target(); + DCHECK(ancestor_target); + + gfx::Vector2dF translation; + for (const LayerType* target = descendant_target; target != ancestor_target; + target = NextTargetSurface(target)) { + const gfx::Transform& trans = target->render_surface()->draw_transform(); + // Ensure that this translation is truly 2d. + DCHECK(trans.IsIdentityOrTranslation()); + DCHECK_EQ(0.f, trans.matrix().get(2, 3)); + translation += trans.To2dTranslation(); + } + + return translation; +} + +enum TranslateRectDirection { + TranslateRectDirectionToAncestor, + TranslateRectDirectionToDescendant +}; + +template <typename LayerType, typename RenderSurfaceType> +static gfx::Rect TranslateRectToTargetSpace(const LayerType& ancestor_layer, + const LayerType& descendant_layer, + gfx::Rect rect, + TranslateRectDirection direction) { + gfx::Vector2dF translation = + ComputeChangeOfBasisTranslation<LayerType, RenderSurfaceType>( + ancestor_layer, descendant_layer); + if (direction == TranslateRectDirectionToDescendant) + translation.Scale(-1.f); + return gfx::ToEnclosingRect( + gfx::RectF(rect.origin() + translation, rect.size())); +} + +// Attempts to update the clip rects for the given layer. If the layer has a +// clip_parent, it may not inherit its immediate ancestor's clip. +template <typename LayerType, typename RenderSurfaceType> +static void UpdateClipRectsForClipChild( + const LayerType* layer, + gfx::Rect* clip_rect_in_parent_target_space, + bool* subtree_should_be_clipped) { + // If the layer has no clip_parent, or the ancestor is the same as its actual + // parent, then we don't need special clip rects. Bail now and leave the out + // parameters untouched. + const LayerType* clip_parent = layer->clip_parent(); + if (!clip_parent || clip_parent == layer->parent()) + return; + + // The root layer is never a clip child. + DCHECK(layer->parent()); + + // Grab the cached values. + *clip_rect_in_parent_target_space = clip_parent->clip_rect(); + *subtree_should_be_clipped = clip_parent->is_clipped(); + + // We may have to project the clip rect into our parent's target space. Note, + // it must be our parent's target space, not ours. For one, we haven't + // computed our transforms, so we couldn't put it in our space yet even if we + // wanted to. But more importantly, this matches the expectations of + // CalculateDrawPropertiesInternal. If we, say, create a render surface, these + // clip rects will want to be in its target space, not ours. + *clip_rect_in_parent_target_space = + TranslateRectToTargetSpace<LayerType, RenderSurfaceType>( + *clip_parent, + *layer->parent(), + *clip_rect_in_parent_target_space, + TranslateRectDirectionToDescendant); +} + +// We collect an accumulated drawable content rect per render surface. +// Typically, a layer will contribute to only one surface, the surface +// associated with its render target. Clip children, however, may affect +// several surfaces since there may be several surfaces between the clip child +// and its parent. +// +// NB: we accumulate the layer's *clipped* drawable content rect. +template <typename LayerType> +struct AccumulatedSurfaceState { + explicit AccumulatedSurfaceState(LayerType* render_target) + : render_target(render_target) {} + + // The accumulated drawable content rect for the surface associated with the + // given |render_target|. + gfx::Rect drawable_content_rect; + + // The target owning the surface. (We hang onto the target rather than the + // surface so that we can DCHECK that the surface's draw transform is simply + // a translation when |render_target| reports that it has no unclipped + // descendants). + LayerType* render_target; +}; + +template <typename LayerType, typename RenderSurfaceType> +void UpdateAccumulatedSurfaceState( + LayerType* layer, + gfx::Rect drawable_content_rect, + std::vector<AccumulatedSurfaceState<LayerType> >* + accumulated_surface_state) { + if (IsRootLayer(layer)) + return; + + // We will apply our drawable content rect to the accumulated rects for all + // surfaces between us and |render_target| (inclusive). This is either our + // clip parent's target if we are a clip child, or else simply our parent's + // target. We use our parent's target because we're either the owner of a + // render surface and we'll want to add our rect to our *surface's* target, or + // we're not and our target is the same as our parent's. In both cases, the + // parent's target gives us what we want. + LayerType* render_target = layer->clip_parent() + ? layer->clip_parent()->render_target() + : layer->parent()->render_target(); + + // If the layer owns a surface, then the content rect is in the wrong space. + // Instead, we will use the surface's DrawableContentRect which is in target + // space as required. + gfx::Rect target_rect = drawable_content_rect; + if (layer->render_surface()) { + target_rect = + gfx::ToEnclosedRect(layer->render_surface()->DrawableContentRect()); + } + + if (render_target->is_clipped()) { + gfx::Rect clip_rect = render_target->clip_rect(); + // If the layer has a clip parent, the clip rect may be in the wrong space, + // so we'll need to transform it before it is applied. + if (layer->clip_parent()) { + clip_rect = TranslateRectToTargetSpace<LayerType, RenderSurfaceType>( + *layer->clip_parent(), + *layer, + clip_rect, + TranslateRectDirectionToDescendant); + } + target_rect.Intersect(clip_rect); + } + + // We must have at least one entry in the vector for the root. + DCHECK_LT(0ul, accumulated_surface_state->size()); + + typedef typename std::vector<AccumulatedSurfaceState<LayerType> > + AccumulatedSurfaceStateVector; + typedef typename AccumulatedSurfaceStateVector::reverse_iterator + AccumulatedSurfaceStateIterator; + AccumulatedSurfaceStateIterator current_state = + accumulated_surface_state->rbegin(); + + // Add this rect to the accumulated content rect for all surfaces until we + // reach the target surface. + bool found_render_target = false; + for (; current_state != accumulated_surface_state->rend(); ++current_state) { + current_state->drawable_content_rect.Union(target_rect); + + // If we've reached |render_target| our work is done and we can bail. + if (current_state->render_target == render_target) { + found_render_target = true; + break; + } + + // Transform rect from the current target's space to the next. + LayerType* current_target = current_state->render_target; + DCHECK(current_target->render_surface()); + const gfx::Transform& current_draw_transform = + current_target->render_surface()->draw_transform(); + + // If we have unclipped descendants, the draw transform is a translation. + DCHECK(current_target->num_unclipped_descendants() == 0 || + current_draw_transform.IsIdentityOrTranslation()); + + target_rect = gfx::ToEnclosingRect( + MathUtil::MapClippedRect(current_draw_transform, target_rect)); + } + + // It is an error to not reach |render_target|. If this happens, it means that + // either the clip parent is not an ancestor of the clip child or the surface + // state vector is empty, both of which should be impossible. + DCHECK(found_render_target); +} + template <typename LayerType> static inline bool IsRootLayer(LayerType* layer) { return !layer->parent(); } @@ -414,10 +634,6 @@ static bool SubtreeShouldRenderToSeparateSurface( return false; } -static LayerImpl* NextTargetSurface(LayerImpl* layer) { - return layer->parent() ? layer->parent()->render_target() : 0; -} - // This function returns a translation matrix that can be applied on a vector // that's in the layer's target surface coordinate, while the position offset is // specified in some ancestor layer's coordinate. @@ -526,7 +742,8 @@ void ApplyPositionAdjustment( gfx::Transform ComputeScrollCompensationForThisLayer( LayerImpl* scrolling_layer, - const gfx::Transform& parent_matrix) { + const gfx::Transform& parent_matrix, + gfx::Vector2dF scroll_delta) { // For every layer that has non-zero scroll_delta, we have to compute a // transform that can undo the scroll_delta translation. In particular, we // want this matrix to premultiply a fixed-position layer's parent_matrix, so @@ -549,8 +766,8 @@ gfx::Transform ComputeScrollCompensationForThisLayer( gfx::Transform scroll_compensation_for_this_layer = parent_matrix; // Step 3 scroll_compensation_for_this_layer.Translate( - scrolling_layer->ScrollDelta().x(), - scrolling_layer->ScrollDelta().y()); // Step 2 + scroll_delta.x(), + scroll_delta.y()); // Step 2 gfx::Transform inverse_parent_matrix(gfx::Transform::kSkipInitialization); if (!parent_matrix.GetInverse(&inverse_parent_matrix)) { @@ -565,7 +782,8 @@ gfx::Transform ComputeScrollCompensationForThisLayer( gfx::Transform ComputeScrollCompensationMatrixForChildren( Layer* current_layer, const gfx::Transform& current_parent_matrix, - const gfx::Transform& current_scroll_compensation) { + const gfx::Transform& current_scroll_compensation, + gfx::Vector2dF scroll_delta) { // The main thread (i.e. Layer) does not need to worry about scroll // compensation. So we can just return an identity matrix here. return gfx::Transform(); @@ -574,7 +792,8 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren( gfx::Transform ComputeScrollCompensationMatrixForChildren( LayerImpl* layer, const gfx::Transform& parent_matrix, - const gfx::Transform& current_scroll_compensation_matrix) { + const gfx::Transform& current_scroll_compensation_matrix, + gfx::Vector2dF scroll_delta) { // "Total scroll compensation" is the transform needed to cancel out all // scroll_delta translations that occurred since the nearest container layer, // even if there are render_surfaces in-between. @@ -600,7 +819,7 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren( // initialization/copy) if we know that the scroll compensation doesn't need // to be reset or adjusted. if (!layer->IsContainerForFixedPositionLayers() && - layer->ScrollDelta().IsZero() && !layer->render_surface()) + scroll_delta.IsZero() && !layer->render_surface()) return current_scroll_compensation_matrix; // Start as identity matrix. @@ -614,10 +833,10 @@ gfx::Transform ComputeScrollCompensationMatrixForChildren( // If the current layer has a non-zero scroll_delta, then we should compute // its local scroll compensation and accumulate it to the // next_scroll_compensation_matrix. - if (!layer->ScrollDelta().IsZero()) { + if (!scroll_delta.IsZero()) { gfx::Transform scroll_compensation_for_this_layer = ComputeScrollCompensationForThisLayer( - layer, parent_matrix); + layer, parent_matrix, scroll_delta); next_scroll_compensation_matrix.PreconcatTransform( scroll_compensation_for_this_layer); } @@ -783,13 +1002,17 @@ static inline void RemoveSurfaceForEarlyExit( struct PreCalculateMetaInformationRecursiveData { bool layer_or_descendant_has_copy_request; + int num_unclipped_descendants; PreCalculateMetaInformationRecursiveData() - : layer_or_descendant_has_copy_request(false) {} + : layer_or_descendant_has_copy_request(false), + num_unclipped_descendants(0) {} void Merge(const PreCalculateMetaInformationRecursiveData& data) { layer_or_descendant_has_copy_request |= data.layer_or_descendant_has_copy_request; + num_unclipped_descendants += + data.num_unclipped_descendants; } }; @@ -812,6 +1035,9 @@ static void PreCalculateMetaInformation( descendants_can_clip_selves = false; } + if (layer->clip_parent()) + recursive_data->num_unclipped_descendants++; + for (size_t i = 0; i < layer->children().size(); ++i) { LayerType* child_layer = LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i); @@ -837,11 +1063,19 @@ static void PreCalculateMetaInformation( recursive_data->Merge(data_for_child); } + if (layer->clip_children()) { + int num_clip_children = layer->clip_children()->size(); + DCHECK_GE(recursive_data->num_unclipped_descendants, num_clip_children); + recursive_data->num_unclipped_descendants -= num_clip_children; + } + if (layer->HasCopyRequest()) recursive_data->layer_or_descendant_has_copy_request = true; layer->draw_properties().num_descendants_that_draw_content = num_descendants_that_draw_content; + layer->draw_properties().num_unclipped_descendants = + recursive_data->num_unclipped_descendants; layer->draw_properties().descendants_can_clip_selves = descendants_can_clip_selves; layer->draw_properties().layer_or_descendant_has_copy_request = @@ -915,7 +1149,8 @@ static void CalculateDrawPropertiesInternal( const DataForRecursion<LayerType, RenderSurfaceType>& data_from_ancestor, LayerListType* render_surface_layer_list, LayerListType* layer_list, - gfx::Rect* drawable_content_rect_of_subtree) { + std::vector<AccumulatedSurfaceState<LayerType> >* + accumulated_surface_state) { // This function computes the new matrix transformations recursively for this // layer and all its descendants. It also computes the appropriate render // surfaces. @@ -1043,10 +1278,6 @@ static void CalculateDrawPropertiesInternal( DCHECK(globals.page_scale_application_layer || (globals.page_scale_factor == 1.f)); - // If we early-exit anywhere in this function, the drawable_content_rect of - // this subtree should be considered empty. - *drawable_content_rect_of_subtree = gfx::Rect(); - DataForRecursion<LayerType, RenderSurfaceType> data_for_children; RenderSurfaceType* nearest_ancestor_surface_that_moves_pixels = data_from_ancestor.nearest_ancestor_surface_that_moves_pixels; @@ -1065,8 +1296,25 @@ static void CalculateDrawPropertiesInternal( layer_is_visible = true; // The root layer cannot skip CalcDrawProperties. - if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_visible)) + if (!IsRootLayer(layer) && SubtreeShouldBeSkipped(layer, layer_is_visible)) { + if (layer->render_surface()) + layer->ClearRenderSurface(); return; + } + + // We need to circumvent the normal recursive flow of information for clip + // children (they don't inherit their direct ancestor's clip information). + // This is unfortunate, and would be unnecessary if we were to formally + // separate the clipping hierarchy from the layer hierarchy. + bool ancestor_clips_subtree = data_from_ancestor.ancestor_clips_subtree; + gfx::Rect ancestor_clip_rect_in_target_space = + data_from_ancestor.clip_rect_in_target_space; + + // Update our clipping state. If we have a clip parent we will need to pull + // from the clip state cache rather than using the clip state passed from our + // immediate ancestor. + UpdateClipRectsForClipChild<LayerType, RenderSurfaceType>( + layer, &ancestor_clip_rect_in_target_space, &ancestor_clips_subtree); // As this function proceeds, these are the properties for the current // layer that actually get computed. To avoid unnecessary copies @@ -1106,7 +1354,8 @@ static void CalculateDrawPropertiesInternal( gfx::Size bounds = layer->bounds(); gfx::PointF anchor_point = layer->anchor_point(); - gfx::PointF position = layer->position() - layer->TotalScrollOffset(); + gfx::Vector2dF scroll_offset = GetEffectiveTotalScrollOffset(layer); + gfx::PointF position = layer->position() - scroll_offset; gfx::Transform combined_transform = data_from_ancestor.parent_matrix; if (!layer->transform().IsIdentity()) { @@ -1125,12 +1374,19 @@ static void CalculateDrawPropertiesInternal( combined_transform.Translate(position.x(), position.y()); } + gfx::Vector2dF effective_scroll_delta = GetEffectiveScrollDelta(layer); if (!animating_transform_to_target && layer->scrollable() && combined_transform.IsScaleOrTranslation()) { // Align the scrollable layer's position to screen space pixels to avoid // blurriness. To avoid side-effects, do this only if the transform is // simple. + gfx::Vector2dF previous_translation = combined_transform.To2dTranslation(); RoundTranslationComponents(&combined_transform); + gfx::Vector2dF current_translation = combined_transform.To2dTranslation(); + + // This rounding changes the scroll delta, and so must be included + // in the scroll compensation matrix. + effective_scroll_delta -= current_translation - previous_translation; } // Apply adjustment from position constraints. @@ -1166,8 +1422,9 @@ static void CalculateDrawPropertiesInternal( // case, the render_surface re-parents the transforms. layer_draw_properties.target_space_transform = combined_transform; // M[draw] = M[parent] * LT * S[layer2content] - layer_draw_properties.target_space_transform.Scale - (1.f / layer->contents_scale_x(), 1.f / layer->contents_scale_y()); + layer_draw_properties.target_space_transform.Scale( + SK_MScalar1 / layer->contents_scale_x(), + SK_MScalar1 / layer->contents_scale_y()); // The layer's screen_space_transform represents the transform between root // layer's "screen space" and local content space. @@ -1212,8 +1469,10 @@ static void CalculateDrawPropertiesInternal( // Check back-face visibility before continuing with this surface and its // subtree if (!layer->double_sided() && TransformToParentIsKnown(layer) && - IsSurfaceBackFaceVisible(layer, combined_transform)) + IsSurfaceBackFaceVisible(layer, combined_transform)) { + layer->ClearRenderSurface(); return; + } RenderSurfaceType* render_surface = CreateOrReuseRenderSurface(layer); @@ -1283,13 +1542,6 @@ static void CalculateDrawPropertiesInternal( data_for_children.full_hierarchy_matrix.PreconcatTransform( render_surface->draw_transform()); - // The new render_surface here will correctly clip the entire subtree. So, - // we do not need to continue propagating the clipping state further down - // the tree. This way, we can avoid transforming clip rects from ancestor - // target surface space to current target surface space that could cause - // more w < 0 headaches. - layer_or_ancestor_clips_descendants = false; - if (layer->mask_layer()) { DrawProperties<LayerType, RenderSurfaceType>& mask_layer_draw_properties = layer->mask_layer()->draw_properties(); @@ -1312,14 +1564,15 @@ static void CalculateDrawPropertiesInternal( if (layer->filters().HasFilterThatMovesPixels() || layer->filter()) nearest_ancestor_surface_that_moves_pixels = render_surface; - // The render surface clip rect is expressed in the space where this surface - // draws, i.e. the same space as - // data_from_ancestor.clip_rect_in_target_space. - render_surface->SetIsClipped(data_from_ancestor.ancestor_clips_subtree); - if (data_from_ancestor.ancestor_clips_subtree) { - render_surface->SetClipRect( - data_from_ancestor.clip_rect_in_target_space); + render_surface->SetNearestAncestorThatMovesPixels( + nearest_ancestor_surface_that_moves_pixels); + layer_or_ancestor_clips_descendants = false; + bool subtree_is_clipped_by_surface_bounds = false; + if (ancestor_clips_subtree) { + // It may be the layer or the surface doing the clipping of the subtree, + // but in either case, we'll be clipping to the projected clip rect of our + // ancestor. gfx::Transform inverse_surface_draw_transform( gfx::Transform::kSkipInitialization); if (!render_surface->draw_transform().GetInverse( @@ -1327,18 +1580,48 @@ static void CalculateDrawPropertiesInternal( // TODO(shawnsingh): Either we need to handle uninvertible transforms // here, or DCHECK that the transform is invertible. } - clip_rect_of_target_surface_in_target_space = - gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( - inverse_surface_draw_transform, render_surface->clip_rect())); - } else { + + gfx::Rect projected_surface_rect = gfx::ToEnclosingRect( + MathUtil::ProjectClippedRect(inverse_surface_draw_transform, + ancestor_clip_rect_in_target_space)); + + if (layer_draw_properties.num_unclipped_descendants > 0) { + // If we have unclipped descendants, we cannot count on the render + // surface's bounds clipping our subtree: the unclipped descendants + // could cause us to expand our bounds. In this case, we must rely on + // layer clipping for correctess. NB: since we can only encounter + // translations between a clip child and its clip parent, clipping is + // guaranteed to be exact in this case. + layer_or_ancestor_clips_descendants = true; + clip_rect_in_target_space = projected_surface_rect; + } else { + // The new render_surface here will correctly clip the entire subtree. + // So, we do not need to continue propagating the clipping state further + // down the tree. This way, we can avoid transforming clip rects from + // ancestor target surface space to current target surface space that + // could cause more w < 0 headaches. The render surface clip rect is + // expressed in the space where this surface draws, i.e. the same space + // as clip_rect_from_ancestor_in_ancestor_target_space. + render_surface->SetClipRect(ancestor_clip_rect_in_target_space); + clip_rect_of_target_surface_in_target_space = projected_surface_rect; + subtree_is_clipped_by_surface_bounds = true; + } + } + + DCHECK(layer->render_surface()); + DCHECK(!layer->parent() || layer->parent()->render_target() == + accumulated_surface_state->back().render_target); + + accumulated_surface_state->push_back( + AccumulatedSurfaceState<LayerType>(layer)); + + render_surface->SetIsClipped(subtree_is_clipped_by_surface_bounds); + if (!subtree_is_clipped_by_surface_bounds) { render_surface->SetClipRect(gfx::Rect()); clip_rect_of_target_surface_in_target_space = data_from_ancestor.clip_rect_of_target_surface_in_target_space; } - render_surface->SetNearestAncestorThatMovesPixels( - nearest_ancestor_surface_that_moves_pixels); - // If the new render surface is drawn translucent or with a non-integral // translation then the subtree that gets drawn on this render surface // cannot use LCD text. @@ -1364,11 +1647,10 @@ static void CalculateDrawPropertiesInternal( // Layers without render_surfaces directly inherit the ancestor's clip // status. - layer_or_ancestor_clips_descendants = - data_from_ancestor.ancestor_clips_subtree; - if (data_from_ancestor.ancestor_clips_subtree) { + layer_or_ancestor_clips_descendants = ancestor_clips_subtree; + if (ancestor_clips_subtree) { clip_rect_in_target_space = - data_from_ancestor.clip_rect_in_target_space; + ancestor_clip_rect_in_target_space; } // The surface's cached clip rect value propagates regardless of what @@ -1404,37 +1686,28 @@ static void CalculateDrawPropertiesInternal( if (LayerClipsSubtree(layer)) { layer_or_ancestor_clips_descendants = true; - if (data_from_ancestor.ancestor_clips_subtree && !layer->render_surface()) { + if (ancestor_clips_subtree && !layer->render_surface()) { // A layer without render surface shares the same target as its ancestor. clip_rect_in_target_space = - data_from_ancestor.clip_rect_in_target_space; + ancestor_clip_rect_in_target_space; clip_rect_in_target_space.Intersect(rect_in_target_space); } else { clip_rect_in_target_space = rect_in_target_space; } } - if (layer == globals.page_scale_application_layer) { - data_for_children.parent_matrix.Scale( - globals.page_scale_factor, - globals.page_scale_factor); - data_for_children.in_subtree_of_page_scale_application_layer = true; - } - - // Flatten to 2D if the layer doesn't preserve 3D. - if (!layer->preserves_3d()) - data_for_children.parent_matrix.FlattenTo2d(); - - // Apply the sublayer transform at the anchor point of the layer. - if (!layer->sublayer_transform().IsIdentity()) { - data_for_children.parent_matrix.Translate( - layer->anchor_point().x() * bounds.width(), - layer->anchor_point().y() * bounds.height()); - data_for_children.parent_matrix.PreconcatTransform( - layer->sublayer_transform()); - data_for_children.parent_matrix.Translate( - -layer->anchor_point().x() * bounds.width(), - -layer->anchor_point().y() * bounds.height()); + // Tell the layer the rect that it's clipped by. In theory we could use a + // tighter clip rect here (drawable_content_rect), but that actually does not + // reduce how much would be drawn, and instead it would create unnecessary + // changes to scissor state affecting GPU performance. Our clip information + // is used in the recursion below, so we must set it beforehand. + layer_draw_properties.is_clipped = layer_or_ancestor_clips_descendants; + if (layer_or_ancestor_clips_descendants) { + layer_draw_properties.clip_rect = clip_rect_in_target_space; + } else { + // Initialize the clip rect to a safe value that will not clip the + // layer, just in case clipping is still accidentally used. + layer_draw_properties.clip_rect = rect_in_target_space; } LayerListType& descendants = @@ -1448,25 +1721,50 @@ static void CalculateDrawPropertiesInternal( if (!LayerShouldBeSkipped(layer, layer_is_visible)) descendants.push_back(layer); - data_for_children.scroll_compensation_matrix = - ComputeScrollCompensationMatrixForChildren( - layer, - data_from_ancestor.parent_matrix, - data_from_ancestor.scroll_compensation_matrix); - data_for_children.fixed_container = - layer->IsContainerForFixedPositionLayers() ? - layer : data_from_ancestor.fixed_container; - - data_for_children.clip_rect_in_target_space = clip_rect_in_target_space; - data_for_children.clip_rect_of_target_surface_in_target_space = - clip_rect_of_target_surface_in_target_space; - data_for_children.ancestor_clips_subtree = - layer_or_ancestor_clips_descendants; - data_for_children.nearest_ancestor_surface_that_moves_pixels = - nearest_ancestor_surface_that_moves_pixels; - data_for_children.subtree_is_visible_from_ancestor = layer_is_visible; - - gfx::Rect accumulated_drawable_content_rect_of_children; + if (!layer->children().empty()) { + if (layer == globals.page_scale_application_layer) { + data_for_children.parent_matrix.Scale( + globals.page_scale_factor, + globals.page_scale_factor); + data_for_children.in_subtree_of_page_scale_application_layer = true; + } + + // Flatten to 2D if the layer doesn't preserve 3D. + if (!layer->preserves_3d()) + data_for_children.parent_matrix.FlattenTo2d(); + + // Apply the sublayer transform at the anchor point of the layer. + if (!layer->sublayer_transform().IsIdentity()) { + data_for_children.parent_matrix.Translate( + layer->anchor_point().x() * bounds.width(), + layer->anchor_point().y() * bounds.height()); + data_for_children.parent_matrix.PreconcatTransform( + layer->sublayer_transform()); + data_for_children.parent_matrix.Translate( + -layer->anchor_point().x() * bounds.width(), + -layer->anchor_point().y() * bounds.height()); + } + + data_for_children.scroll_compensation_matrix = + ComputeScrollCompensationMatrixForChildren( + layer, + data_from_ancestor.parent_matrix, + data_from_ancestor.scroll_compensation_matrix, + effective_scroll_delta); + data_for_children.fixed_container = + layer->IsContainerForFixedPositionLayers() ? + layer : data_from_ancestor.fixed_container; + + data_for_children.clip_rect_in_target_space = clip_rect_in_target_space; + data_for_children.clip_rect_of_target_surface_in_target_space = + clip_rect_of_target_surface_in_target_space; + data_for_children.ancestor_clips_subtree = + layer_or_ancestor_clips_descendants; + data_for_children.nearest_ancestor_surface_that_moves_pixels = + nearest_ancestor_surface_that_moves_pixels; + data_for_children.subtree_is_visible_from_ancestor = layer_is_visible; + } + for (size_t i = 0; i < layer->children().size(); ++i) { LayerType* child = LayerTreeHostCommon::get_child_as_raw_ptr(layer->children(), i); @@ -1480,29 +1778,34 @@ static void CalculateDrawPropertiesInternal( data_for_children, render_surface_layer_list, &descendants, - &drawable_content_rect_of_child_subtree); - if (!drawable_content_rect_of_child_subtree.IsEmpty()) { - accumulated_drawable_content_rect_of_children.Union( - drawable_content_rect_of_child_subtree); - if (child->render_surface()) - descendants.push_back(child); + accumulated_surface_state); + if (child->render_surface() && + !child->render_surface()->content_rect().IsEmpty()) { + descendants.push_back(child); } } + // Compute the total drawable_content_rect for this subtree (the rect is in + // target surface space). + gfx::Rect local_drawable_content_rect_of_subtree = + accumulated_surface_state->back().drawable_content_rect; + if (layer->render_surface()) { + DCHECK(accumulated_surface_state->back().render_target == layer); + accumulated_surface_state->pop_back(); + } + if (layer->render_surface() && !IsRootLayer(layer) && layer->render_surface()->layer_list().empty()) { RemoveSurfaceForEarlyExit(layer, render_surface_layer_list); return; } - // Compute the total drawable_content_rect for this subtree (the rect is in - // target surface space). - gfx::Rect local_drawable_content_rect_of_subtree = - accumulated_drawable_content_rect_of_children; - if (layer->DrawsContent()) - local_drawable_content_rect_of_subtree.Union(rect_in_target_space); - if (layer_or_ancestor_clips_descendants) - local_drawable_content_rect_of_subtree.Intersect(clip_rect_in_target_space); + if (layer->DrawsContent()) { + gfx::Rect local_drawable_content_rect = rect_in_target_space; + if (layer_or_ancestor_clips_descendants) + local_drawable_content_rect.Intersect(clip_rect_in_target_space); + local_drawable_content_rect_of_subtree.Union(local_drawable_content_rect); + } // Compute the layer's drawable content rect (the rect is in target surface // space). @@ -1512,19 +1815,6 @@ static void CalculateDrawPropertiesInternal( Intersect(clip_rect_in_target_space); } - // Tell the layer the rect that is clipped by. In theory we could use a - // tighter clip rect here (drawable_content_rect), but that actually does not - // reduce how much would be drawn, and instead it would create unnecessary - // changes to scissor state affecting GPU performance. - layer_draw_properties.is_clipped = layer_or_ancestor_clips_descendants; - if (layer_or_ancestor_clips_descendants) { - layer_draw_properties.clip_rect = clip_rect_in_target_space; - } else { - // Initialize the clip rect to a safe value that will not clip the - // layer, just in case clipping is still accidentally used. - layer_draw_properties.clip_rect = rect_in_target_space; - } - // Compute the layer's visible content rect (the rect is in content space). layer_draw_properties.visible_content_rect = CalculateVisibleContentRect( layer, clip_rect_of_target_surface_in_target_space, rect_in_target_space); @@ -1535,7 +1825,7 @@ static void CalculateDrawPropertiesInternal( // The root layer's surface's content_rect is always the entire viewport. DCHECK(layer->render_surface()); layer->render_surface()->SetContentRect( - data_from_ancestor.clip_rect_in_target_space); + ancestor_clip_rect_in_target_space); } else if (layer->render_surface() && !IsRootLayer(layer)) { RenderSurfaceType* render_surface = layer->render_surface(); gfx::Rect clipped_content_rect = local_drawable_content_rect_of_subtree; @@ -1548,8 +1838,7 @@ static void CalculateDrawPropertiesInternal( // Note, it is correct to use data_from_ancestor.ancestor_clips_subtree // here, because we are looking at this layer's render_surface, not the // layer itself. - if (data_from_ancestor.ancestor_clips_subtree && - !clipped_content_rect.IsEmpty()) { + if (render_surface->is_clipped() && !clipped_content_rect.IsEmpty()) { gfx::Rect surface_clip_rect = LayerTreeHostCommon::CalculateVisibleRect( render_surface->clip_rect(), clipped_content_rect, @@ -1620,8 +1909,10 @@ static void CalculateDrawPropertiesInternal( SavePaintPropertiesLayer(layer); // If neither this layer nor any of its children were added, early out. - if (sorting_start_index == descendants.size()) + if (sorting_start_index == descendants.size()) { + DCHECK(!layer->render_surface() || IsRootLayer(layer)); return; + } // If preserves-3d then sort all the descendants in 3D so that they can be // drawn from back to front. If the preserves-3d property is also set on the @@ -1634,12 +1925,8 @@ static void CalculateDrawPropertiesInternal( globals.layer_sorter); } - if (layer->render_surface()) { - *drawable_content_rect_of_subtree = - gfx::ToEnclosingRect(layer->render_surface()->DrawableContentRect()); - } else { - *drawable_content_rect_of_subtree = local_drawable_content_rect_of_subtree; - } + UpdateAccumulatedSurfaceState<LayerType, RenderSurfaceType>( + layer, local_drawable_content_rect_of_subtree, accumulated_surface_state); if (layer->HasContributingDelegatedRenderPasses()) { layer->render_target()->render_surface()-> @@ -1652,7 +1939,6 @@ void LayerTreeHostCommon::CalculateDrawProperties( DCHECK(inputs->root_layer); DCHECK(IsRootLayer(inputs->root_layer)); DCHECK(inputs->render_surface_layer_list); - gfx::Rect total_drawable_content_rect; gfx::Transform identity_matrix; gfx::Transform scaled_device_transform = inputs->device_transform; scaled_device_transform.Scale(inputs->device_scale_factor, @@ -1687,14 +1973,14 @@ void LayerTreeHostCommon::CalculateDrawProperties( PreCalculateMetaInformationRecursiveData recursive_data; PreCalculateMetaInformation(inputs->root_layer, &recursive_data); - + std::vector<AccumulatedSurfaceState<Layer> > accumulated_surface_state; CalculateDrawPropertiesInternal<Layer, RenderSurfaceLayerList, RenderSurface>( inputs->root_layer, globals, data_for_recursion, inputs->render_surface_layer_list, &dummy_layer_list, - &total_drawable_content_rect); + &accumulated_surface_state); // The dummy layer list should not have been used. DCHECK_EQ(0u, dummy_layer_list.size()); @@ -1709,7 +1995,6 @@ void LayerTreeHostCommon::CalculateDrawProperties( DCHECK(IsRootLayer(inputs->root_layer)); DCHECK(inputs->render_surface_layer_list); - gfx::Rect total_drawable_content_rect; gfx::Transform identity_matrix; gfx::Transform scaled_device_transform = inputs->device_transform; scaled_device_transform.Scale(inputs->device_scale_factor, @@ -1745,14 +2030,15 @@ void LayerTreeHostCommon::CalculateDrawProperties( PreCalculateMetaInformationRecursiveData recursive_data; PreCalculateMetaInformation(inputs->root_layer, &recursive_data); - + std::vector<AccumulatedSurfaceState<LayerImpl> > + accumulated_surface_state; CalculateDrawPropertiesInternal<LayerImpl, LayerImplList, RenderSurfaceImpl>( inputs->root_layer, globals, data_for_recursion, inputs->render_surface_layer_list, &dummy_layer_list, - &total_drawable_content_rect); + &accumulated_surface_state); // The dummy layer list should not have been used. DCHECK_EQ(0u, dummy_layer_list.size()); |