| Index: cc/trees/draw_property_utils.cc
|
| diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc
|
| index fef5d28d672cbc6909cf6eedcb8717d861e8d15a..e027c8ca9cc90a062579a5acdb3b25a1d2a937aa 100644
|
| --- a/cc/trees/draw_property_utils.cc
|
| +++ b/cc/trees/draw_property_utils.cc
|
| @@ -58,106 +58,97 @@ static void ValidateRenderSurfaceForLayer(LayerImpl* layer) {
|
| #endif
|
|
|
| template <typename LayerType>
|
| -void CalculateVisibleRects(
|
| +bool ComputeClipRectInTargetSpace(const LayerType* layer,
|
| + const ClipNode* clip_node,
|
| + const TransformTree& transform_tree,
|
| + int target_node_id,
|
| + gfx::Rect* clip_rect_in_target_space) {
|
| + DCHECK(layer->clip_tree_index() == clip_node->id);
|
| + DCHECK(clip_node->data.target_id != target_node_id);
|
| +
|
| + gfx::Transform clip_to_target;
|
| + if (clip_node->data.target_id > target_node_id) {
|
| + // In this case, layer has a scroll parent. We need to keep the scale
|
| + // at the layer's target but remove the scale at the scroll parent's
|
| + // target.
|
| + if (transform_tree.ComputeTransformWithDestinationSublayerScale(
|
| + clip_node->data.target_id, target_node_id, &clip_to_target)) {
|
| + const TransformNode* source_node =
|
| + transform_tree.Node(clip_node->data.target_id);
|
| + if (source_node->data.sublayer_scale.x() != 0.f &&
|
| + source_node->data.sublayer_scale.y() != 0.f)
|
| + clip_to_target.Scale(1.0f / source_node->data.sublayer_scale.x(),
|
| + 1.0f / source_node->data.sublayer_scale.y());
|
| + *clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(MathUtil::MapClippedRect(
|
| + clip_to_target, clip_node->data.clip_in_target_space));
|
| + } else {
|
| + return false;
|
| + }
|
| + } else {
|
| + if (transform_tree.ComputeTransform(clip_node->data.target_id,
|
| + target_node_id, &clip_to_target)) {
|
| + *clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
|
| + clip_to_target, clip_node->data.clip_in_target_space));
|
| + } else {
|
| + return false;
|
| + }
|
| + }
|
| + return true;
|
| +}
|
| +
|
| +template <typename LayerType>
|
| +void CalculateClipRects(
|
| const typename LayerType::LayerListType& visible_layer_list,
|
| const ClipTree& clip_tree,
|
| const TransformTree& transform_tree,
|
| const EffectTree& effect_tree,
|
| bool non_root_surfaces_enabled) {
|
| for (auto& layer : visible_layer_list) {
|
| - gfx::Size layer_bounds = layer->bounds();
|
| const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
|
| - const bool is_unclipped = clip_node->data.resets_clip &&
|
| - !clip_node->data.applies_local_clip &&
|
| - non_root_surfaces_enabled;
|
| + // The entire layer is visible if it has copy requests.
|
| + const EffectNode* effect_node =
|
| + effect_tree.Node(layer->effect_tree_index());
|
| + if (effect_node->data.has_copy_request &&
|
| + effect_node->owner_id == layer->id())
|
| + continue;
|
| +
|
| + if (!non_root_surfaces_enabled) {
|
| + layer->set_clip_rect(
|
| + gfx::ToEnclosingRect(clip_node->data.clip_in_target_space));
|
| + continue;
|
| + }
|
| +
|
| // When both the layer and the target are unclipped, the entire layer
|
| // content rect is visible.
|
| const bool fully_visible = !clip_node->data.layers_are_clipped &&
|
| - !clip_node->data.target_is_clipped &&
|
| - non_root_surfaces_enabled;
|
| - const TransformNode* transform_node =
|
| - transform_tree.Node(layer->transform_tree_index());
|
| - if (!is_unclipped && !fully_visible) {
|
| - // The entire layer is visible if it has copy requests.
|
| - const EffectNode* effect_node =
|
| - effect_tree.Node(layer->effect_tree_index());
|
| - if (effect_node->data.has_copy_request &&
|
| - effect_node->owner_id == layer->id()) {
|
| - layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| - continue;
|
| - }
|
| + !clip_node->data.target_is_clipped;
|
|
|
| - const TransformNode* target_node =
|
| - non_root_surfaces_enabled
|
| - ? transform_tree.Node(transform_node->data.content_target_id)
|
| - : transform_tree.Node(0);
|
| + if (!fully_visible) {
|
| + const TransformNode* transform_node =
|
| + transform_tree.Node(layer->transform_tree_index());
|
| + int target_node_id = transform_node->data.content_target_id;
|
|
|
| - // The clip node stores clip rect in its target space. If required,
|
| - // this clip rect should be mapped to the current layer's target space.
|
| - gfx::Rect clip_rect_in_target_space;
|
| - gfx::Rect combined_clip_rect_in_target_space;
|
| + // The clip node stores clip rect in its target space.
|
| + gfx::Rect clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(clip_node->data.clip_in_target_space);
|
|
|
| - // When we only have a root surface, the clip node and the layer must
|
| - // necessarily have the same target (the root).
|
| - if (clip_node->data.target_id != target_node->id &&
|
| - non_root_surfaces_enabled) {
|
| + // If required, this clip rect should be mapped to the current layer's
|
| + // target space.
|
| + if (clip_node->data.target_id != target_node_id) {
|
| // In this case, layer has a clip parent or scroll parent (or shares the
|
| // target with an ancestor layer that has clip parent) and the clip
|
| // parent's target is different from the layer's target. As the layer's
|
| // target has unclippped descendants, it is unclippped.
|
| - if (!clip_node->data.layers_are_clipped) {
|
| - layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + if (!clip_node->data.layers_are_clipped)
|
| continue;
|
| - }
|
| - bool success = true;
|
| - gfx::Transform clip_to_target;
|
| - if (clip_node->data.target_id > target_node->id) {
|
| - // In this case, layer has a scroll parent. We need to keep the scale
|
| - // at the layer's target but remove the scale at the scroll parent's
|
| - // target.
|
| - success = transform_tree.ComputeTransformWithDestinationSublayerScale(
|
| - clip_node->data.target_id, target_node->id, &clip_to_target);
|
| - const TransformNode* source_node =
|
| - transform_tree.Node(clip_node->data.target_id);
|
| - if (source_node->data.sublayer_scale.x() != 0.f &&
|
| - source_node->data.sublayer_scale.y() != 0.f)
|
| - clip_to_target.Scale(1.0f / source_node->data.sublayer_scale.x(),
|
| - 1.0f / source_node->data.sublayer_scale.y());
|
| - } else {
|
| - success = transform_tree.ComputeTransform(
|
| - clip_node->data.target_id, target_node->id, &clip_to_target);
|
| - }
|
| - if (!success) {
|
| - // An animated singular transform may become non-singular during the
|
| - // animation, so we still need to compute a visible rect. In this
|
| - // situation, we treat the entire layer as visible.
|
| - layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| +
|
| + // Compute the clip rect in target space and store it.
|
| + if (!ComputeClipRectInTargetSpace(layer, clip_node, transform_tree,
|
| + target_node_id,
|
| + &clip_rect_in_target_space))
|
| continue;
|
| - }
|
| - // We use the clip node's clip_in_target_space (and not
|
| - // combined_clip_in_target_space) here because we want to clip
|
| - // with respect to clip parent's local clip and not its combined clip as
|
| - // the combined clip has even the clip parent's target's clip baked into
|
| - // it and as our target is different, we don't want to use it in our
|
| - // visible rect computation.
|
| - if (clip_node->data.target_id < target_node->id) {
|
| - combined_clip_rect_in_target_space =
|
| - gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
|
| - clip_to_target, clip_node->data.clip_in_target_space));
|
| - } else {
|
| - combined_clip_rect_in_target_space =
|
| - gfx::ToEnclosingRect(MathUtil::MapClippedRect(
|
| - clip_to_target, clip_node->data.clip_in_target_space));
|
| - }
|
| - clip_rect_in_target_space = combined_clip_rect_in_target_space;
|
| - } else {
|
| - clip_rect_in_target_space =
|
| - gfx::ToEnclosingRect(clip_node->data.clip_in_target_space);
|
| - if (clip_node->data.target_is_clipped || !non_root_surfaces_enabled)
|
| - combined_clip_rect_in_target_space = gfx::ToEnclosingRect(
|
| - clip_node->data.combined_clip_in_target_space);
|
| - else
|
| - combined_clip_rect_in_target_space = clip_rect_in_target_space;
|
| }
|
|
|
| if (!clip_rect_in_target_space.IsEmpty()) {
|
| @@ -165,68 +156,167 @@ void CalculateVisibleRects(
|
| } else {
|
| layer->set_clip_rect(gfx::Rect());
|
| }
|
| + }
|
| + }
|
| +}
|
|
|
| - // The clip rect should be intersected with layer rect in target space.
|
| - gfx::Transform content_to_target = non_root_surfaces_enabled
|
| - ? transform_node->data.to_target
|
| - : transform_node->data.to_screen;
|
| +bool GetLayerClipRect(const scoped_refptr<Layer> layer,
|
| + const ClipNode* clip_node,
|
| + const TransformTree& transform_tree,
|
| + int target_node_id,
|
| + gfx::Rect* clip_rect_in_target_space) {
|
| + return ComputeClipRectInTargetSpace(layer.get(), clip_node, transform_tree,
|
| + target_node_id,
|
| + clip_rect_in_target_space);
|
| +}
|
|
|
| - content_to_target.Translate(layer->offset_to_transform_parent().x(),
|
| - layer->offset_to_transform_parent().y());
|
| - gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
|
| - gfx::Rect layer_content_bounds_in_target_space =
|
| - MathUtil::MapEnclosingClippedRect(content_to_target,
|
| - layer_content_rect);
|
| - combined_clip_rect_in_target_space.Intersect(
|
| - layer_content_bounds_in_target_space);
|
| - if (combined_clip_rect_in_target_space.IsEmpty()) {
|
| - layer->set_visible_layer_rect(gfx::Rect());
|
| - continue;
|
| - }
|
| +bool GetLayerClipRect(const LayerImpl* layer,
|
| + const ClipNode* clip_node,
|
| + const TransformTree& transform_tree,
|
| + int target_node_id,
|
| + gfx::Rect* clip_rect_in_target_space) {
|
| + // This is equivalent of calling ComputeClipRectInTargetSpace.
|
| + *clip_rect_in_target_space = layer->clip_rect();
|
| + return transform_tree.Node(target_node_id)->data.ancestors_are_invertible;
|
| +}
|
|
|
| - // If the layer is fully contained within the clip, treat it as fully
|
| - // visible. Since clip_rect_in_target_space has already been intersected
|
| - // with layer_content_bounds_in_target_space, the layer is fully contained
|
| - // within the clip iff these rects are equal.
|
| - if (combined_clip_rect_in_target_space ==
|
| - layer_content_bounds_in_target_space) {
|
| - layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| - continue;
|
| - }
|
| +template <typename LayerType>
|
| +void CalculateVisibleRects(
|
| + const typename LayerType::LayerListType& visible_layer_list,
|
| + const ClipTree& clip_tree,
|
| + const TransformTree& transform_tree,
|
| + const EffectTree& effect_tree,
|
| + bool non_root_surfaces_enabled) {
|
| + for (auto& layer : visible_layer_list) {
|
| + gfx::Size layer_bounds = layer->bounds();
|
|
|
| - gfx::Transform target_to_content;
|
| - gfx::Transform target_to_layer;
|
| - bool success = true;
|
| + const EffectNode* effect_node =
|
| + effect_tree.Node(layer->effect_tree_index());
|
| + if (effect_node->data.has_copy_request &&
|
| + effect_node->owner_id == layer->id()) {
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + continue;
|
| + }
|
| +
|
| + const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
|
| + const TransformNode* transform_node =
|
| + transform_tree.Node(layer->transform_tree_index());
|
| + if (!non_root_surfaces_enabled) {
|
| + // When we only have a root surface, the clip node and the layer must
|
| + // necessarily have the same target (the root).
|
| if (transform_node->data.ancestors_are_invertible) {
|
| - target_to_layer = non_root_surfaces_enabled
|
| - ? transform_node->data.from_target
|
| - : transform_node->data.from_screen;
|
| + gfx::Rect combined_clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space);
|
| + gfx::Transform target_to_content;
|
| + target_to_content.Translate(-layer->offset_to_transform_parent().x(),
|
| + -layer->offset_to_transform_parent().y());
|
| + target_to_content.PreconcatTransform(transform_node->data.from_screen);
|
| +
|
| + gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
|
| + target_to_content, combined_clip_rect_in_target_space);
|
| + visible_rect.Intersect(gfx::Rect(layer_bounds));
|
| + layer->set_visible_layer_rect(visible_rect);
|
| } else {
|
| - success = transform_tree.ComputeTransformWithSourceSublayerScale(
|
| - target_node->id, transform_node->id, &target_to_layer);
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + }
|
| + continue;
|
| + }
|
| +
|
| + // When both the layer and the target are unclipped, the entire layer
|
| + // content rect is visible.
|
| + const bool fully_visible = !clip_node->data.layers_are_clipped &&
|
| + !clip_node->data.target_is_clipped;
|
| +
|
| + if (fully_visible) {
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + continue;
|
| + }
|
| +
|
| + int target_node_id = transform_node->data.content_target_id;
|
| +
|
| + // The clip node stores clip rect in its target space. If required,
|
| + // this clip rect should be mapped to the current layer's target space.
|
| + gfx::Rect combined_clip_rect_in_target_space;
|
| +
|
| + if (clip_node->data.target_id != target_node_id) {
|
| + // In this case, layer has a clip parent or scroll parent (or shares the
|
| + // target with an ancestor layer that has clip parent) and the clip
|
| + // parent's target is different from the layer's target. As the layer's
|
| + // target has unclippped descendants, it is unclippped.
|
| + if (!clip_node->data.layers_are_clipped) {
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + continue;
|
| }
|
|
|
| - if (!success) {
|
| + // We use the clip node's clip_in_target_space (and not
|
| + // combined_clip_in_target_space) here because we want to clip
|
| + // with respect to clip parent's local clip and not its combined clip as
|
| + // the combined clip has even the clip parent's target's clip baked into
|
| + // it and as our target is different, we don't want to use it in our
|
| + // visible rect computation.
|
| + if (!GetLayerClipRect(layer, clip_node, transform_tree, target_node_id,
|
| + &combined_clip_rect_in_target_space)) {
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + continue;
|
| + }
|
| + } else {
|
| + if (clip_node->data.target_is_clipped) {
|
| + combined_clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(clip_node->data.combined_clip_in_target_space);
|
| + } else {
|
| + combined_clip_rect_in_target_space =
|
| + gfx::ToEnclosingRect(clip_node->data.clip_in_target_space);
|
| + }
|
| + }
|
| +
|
| + // The clip rect should be intersected with layer rect in target space.
|
| + gfx::Transform content_to_target = transform_node->data.to_target;
|
| + content_to_target.Translate(layer->offset_to_transform_parent().x(),
|
| + layer->offset_to_transform_parent().y());
|
| + gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
|
| + gfx::Rect layer_content_bounds_in_target_space =
|
| + MathUtil::MapEnclosingClippedRect(content_to_target,
|
| + layer_content_rect);
|
| + combined_clip_rect_in_target_space.Intersect(
|
| + layer_content_bounds_in_target_space);
|
| + if (combined_clip_rect_in_target_space.IsEmpty()) {
|
| + layer->set_visible_layer_rect(gfx::Rect());
|
| + continue;
|
| + }
|
| +
|
| + // If the layer is fully contained within the clip, treat it as fully
|
| + // visible. Since clip_rect_in_target_space has already been intersected
|
| + // with layer_content_bounds_in_target_space, the layer is fully contained
|
| + // within the clip iff these rects are equal.
|
| + if (combined_clip_rect_in_target_space ==
|
| + layer_content_bounds_in_target_space) {
|
| + layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| + continue;
|
| + }
|
| +
|
| + gfx::Transform target_to_layer;
|
| + if (transform_node->data.ancestors_are_invertible) {
|
| + target_to_layer = transform_node->data.from_target;
|
| + } else {
|
| + if (!transform_tree.ComputeTransformWithSourceSublayerScale(
|
| + target_node_id, transform_node->id, &target_to_layer)) {
|
| // An animated singular transform may become non-singular during the
|
| // animation, so we still need to compute a visible rect. In this
|
| // situation, we treat the entire layer as visible.
|
| layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| continue;
|
| }
|
| -
|
| - target_to_content.Translate(-layer->offset_to_transform_parent().x(),
|
| - -layer->offset_to_transform_parent().y());
|
| - target_to_content.PreconcatTransform(target_to_layer);
|
| -
|
| - gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
|
| - target_to_content, combined_clip_rect_in_target_space);
|
| -
|
| - visible_rect.Intersect(gfx::Rect(layer_bounds));
|
| -
|
| - layer->set_visible_layer_rect(visible_rect);
|
| - } else {
|
| - layer->set_visible_layer_rect(gfx::Rect(layer_bounds));
|
| }
|
| +
|
| + gfx::Transform target_to_content;
|
| + target_to_content.Translate(-layer->offset_to_transform_parent().x(),
|
| + -layer->offset_to_transform_parent().y());
|
| + target_to_content.PreconcatTransform(target_to_layer);
|
| +
|
| + gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
|
| + target_to_content, combined_clip_rect_in_target_space);
|
| + visible_rect.Intersect(gfx::Rect(layer_bounds));
|
| + layer->set_visible_layer_rect(visible_rect);
|
| }
|
| }
|
|
|
| @@ -770,6 +860,10 @@ static void ComputeVisibleRectsInternal(
|
| FindLayersThatNeedUpdates(root_layer->layer_tree_impl(),
|
| property_trees->transform_tree,
|
| property_trees->effect_tree, visible_layer_list);
|
| + CalculateClipRects<LayerImpl>(*visible_layer_list, property_trees->clip_tree,
|
| + property_trees->transform_tree,
|
| + property_trees->effect_tree,
|
| + can_render_to_separate_surface);
|
| CalculateVisibleRects<LayerImpl>(
|
| *visible_layer_list, property_trees->clip_tree,
|
| property_trees->transform_tree, property_trees->effect_tree,
|
|
|