Chromium Code Reviews| Index: cc/trees/draw_property_utils.cc |
| diff --git a/cc/trees/draw_property_utils.cc b/cc/trees/draw_property_utils.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6e99a3a175e8685a009a71f305595b93225bcf71 |
| --- /dev/null |
| +++ b/cc/trees/draw_property_utils.cc |
| @@ -0,0 +1,192 @@ |
| +// Copyright 2014 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/draw_property_utils.h" |
| + |
| +#include <vector> |
| + |
| +#include "cc/base/math_util.h" |
| +#include "cc/layers/layer.h" |
| +#include "cc/trees/property_tree.h" |
| +#include "cc/trees/property_tree_builder.h" |
| +#include "ui/gfx/geometry/rect_conversions.h" |
| + |
| +namespace cc { |
| + |
| +namespace { |
| + |
| +void CalculateVisibleRects( |
| + const std::vector<Layer*>& layers_that_need_visible_rects, |
| + const ClipTree& clip_tree, |
| + const TransformTree& transform_tree) { |
| + for (size_t i = 0; i < layers_that_need_visible_rects.size(); ++i) { |
| + Layer* layer = layers_that_need_visible_rects[i]; |
| + |
| + // TODO(ajuma): Compute content_scale rather than using it. Note that for |
|
enne (OOO)
2014/12/10 23:45:59
I do wonder if we could punt on this until impl-si
enne (OOO)
2014/12/10 23:45:59
I do wonder if we could punt on this until impl-si
Ian Vollick
2014/12/12 03:01:47
sgtm! I've added another comment saying that once
|
| + // PictureLayer and PictureImageLayers, content_bounds == bounds and |
| + // content_scale_x == content_scale_y == 1.0. |
| + gfx::Size layer_content_bounds = layer->content_bounds(); |
| + float contents_scale_x = layer->contents_scale_x(); |
| + float contents_scale_y = layer->contents_scale_y(); |
| + const bool has_clip = layer->clip_tree_index() > 0; |
| + if (has_clip && layer->has_render_target()) { |
| + const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index()); |
| + const TransformNode* clip_transform_node = |
| + transform_tree.Node(clip_node->data.transform_id); |
| + const TransformNode* transform_node = |
| + transform_tree.Node(layer->transform_tree_index()); |
| + const TransformNode* target_node = |
| + transform_tree.Node(layer->render_target()->transform_tree_index()); |
| + |
| + gfx::Transform clip_to_target; |
| + gfx::Transform content_to_target; |
| + gfx::Transform target_to_content; |
| + |
| + target_to_content.Scale(contents_scale_x, contents_scale_y); |
| + target_to_content.Translate(-layer->offset_to_transform_parent().x(), |
| + -layer->offset_to_transform_parent().y()); |
| + |
| + bool success = ComputeTransform(transform_tree, clip_transform_node->id, |
| + target_node->id, &clip_to_target) && |
| + ComputeTransform(transform_tree, transform_node->id, |
| + target_node->id, &content_to_target) && |
| + ComputeTransform(transform_tree, target_node->id, |
| + transform_node->id, &target_to_content); |
| + |
| + if (!success) |
|
enne (OOO)
2014/12/10 23:45:59
What happens if this doesn't succeed? When does th
Ian Vollick
2014/12/12 03:01:47
If this doesn't succeed it means that an ancestor
enne (OOO)
2014/12/12 19:05:49
Could this just be a DCHECK instead?
Ian Vollick
2014/12/15 21:45:17
Done.
|
| + continue; |
| + |
| + content_to_target.Translate(layer->offset_to_transform_parent().x(), |
| + layer->offset_to_transform_parent().y()); |
| + content_to_target.Scale(1.0 / contents_scale_x, 1.0 / contents_scale_y); |
| + |
| + gfx::Rect layer_content_rect = gfx::Rect(layer_content_bounds); |
| + gfx::RectF layer_content_bounds_in_target_space = |
| + MathUtil::MapClippedRect(content_to_target, layer_content_rect); |
| + gfx::RectF clip_rect_in_target_space; |
| + if (target_node->id > clip_node->id) { |
| + clip_rect_in_target_space = MathUtil::ProjectClippedRect( |
| + clip_to_target, clip_node->data.combined_clip); |
| + } else { |
| + clip_rect_in_target_space = MathUtil::MapClippedRect( |
| + clip_to_target, clip_node->data.combined_clip); |
| + } |
| + |
| + clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space); |
| + |
| + gfx::Rect visible_rect = |
| + gfx::ToEnclosingRect(MathUtil::ProjectClippedRect( |
| + target_to_content, clip_rect_in_target_space)); |
| + |
| + visible_rect.Intersect(gfx::Rect(layer_content_bounds)); |
| + |
| + layer->set_debug_visible_rect(visible_rect); |
| + } else { |
| + layer->set_debug_visible_rect(gfx::Rect(layer_content_bounds)); |
| + } |
| + } |
| +} |
| + |
| +void FindLayersThatNeedVisibleRects(Layer* layer, |
| + std::vector<Layer*>* layers_to_update) { |
| + if (layer->NeedsVisibleRectUpdated()) |
| + layers_to_update->push_back(layer); |
| + |
| + for (size_t i = 0; i < layer->children().size(); ++i) { |
| + FindLayersThatNeedVisibleRects(layer->children()[i].get(), |
| + layers_to_update); |
| + } |
| +} |
| + |
| +} // namespace |
| + |
| +void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) { |
| + for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) { |
| + ClipNode* clip_node = clip_tree->Node(i); |
| + |
| + // Only descendants of a real clipping layer (i.e., not 0) may have their |
| + // clip adjusted due to intersecting with an ancestor clip. |
| + const bool is_clipped = clip_node->parent_id > 0; |
| + if (!is_clipped) { |
| + clip_node->data.combined_clip = clip_node->data.clip; |
| + continue; |
| + } |
| + |
| + ClipNode* parent_clip_node = clip_tree->parent(clip_node); |
| + const TransformNode* parent_transform_node = |
| + transform_tree.Node(parent_clip_node->data.transform_id); |
| + const TransformNode* transform_node = |
| + transform_tree.Node(clip_node->data.transform_id); |
| + |
| + // Clips must be combined in target space. We cannot, for example, combine |
| + // clips in the space of the child clip. The reason is non-affine |
| + // transforms. Say we have the following tree T->A->B->C, and B clips C, but |
| + // draw into target T. It may be the case that A applies a perspective |
| + // transform, and B and C are at different z positions. When projected into |
| + // target space, the relative sizes and positions of B and C can shift. |
| + // Since it's the relationship in target space that matters, that's where we |
| + // must combine clips. |
| + gfx::Transform parent_to_target; |
| + gfx::Transform clip_to_target; |
| + gfx::Transform target_to_clip; |
| + |
| + bool success = |
| + ComputeTransform(transform_tree, parent_transform_node->id, |
| + clip_node->data.target_id, &parent_to_target) && |
| + ComputeTransform(transform_tree, transform_node->id, |
| + clip_node->data.target_id, &clip_to_target) && |
| + ComputeTransform(transform_tree, clip_node->data.target_id, |
| + transform_node->id, &target_to_clip); |
| + |
| + if (!success) |
|
enne (OOO)
2014/12/10 23:45:59
What happens if this doesn't succeed?
Ian Vollick
2014/12/12 03:01:47
Added a comment with an explanation.
|
| + continue; |
| + |
| + // In order to intersect with as small a rect as possible, we do a |
| + // preliminary clip in target space so that when we project back, there's |
| + // less likelihood of intersecting the view plane. |
| + gfx::RectF inherited_clip_in_target_space = MathUtil::MapClippedRect( |
| + parent_to_target, parent_clip_node->data.combined_clip); |
| + |
| + gfx::RectF clip_in_target_space = |
| + MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip); |
| + |
| + gfx::RectF intersected_in_target_space = gfx::IntersectRects( |
| + inherited_clip_in_target_space, clip_in_target_space); |
| + |
| + clip_node->data.combined_clip = MathUtil::ProjectClippedRect( |
| + target_to_clip, intersected_in_target_space); |
| + |
| + clip_node->data.combined_clip.Intersect(clip_node->data.clip); |
| + } |
| +} |
| + |
| +void ComputeTransforms(TransformTree* transform_tree) { |
| + for (int i = 0; i < static_cast<int>(transform_tree->size()); ++i) |
| + UpdateScreenSpaceTransform(transform_tree, i); |
| +} |
| + |
| +void ComputeVisibleRectsUsingPropertyTrees( |
| + Layer* root_layer, |
| + const Layer* page_scale_layer, |
| + float page_scale_factor, |
| + float device_scale_factor, |
| + const gfx::Rect& viewport, |
| + const gfx::Transform& device_transform, |
| + TransformTree* transform_tree, |
| + ClipTree* clip_tree) { |
| + std::vector<Layer*> layers_to_update; |
| + FindLayersThatNeedVisibleRects(root_layer, &layers_to_update); |
| + |
| + if (!layers_to_update.empty()) { |
| + PropertyTreeBuilder::BuildPropertyTrees( |
| + root_layer, page_scale_layer, page_scale_factor, device_scale_factor, |
| + viewport, device_transform, transform_tree, clip_tree); |
| + |
| + ComputeTransforms(transform_tree); |
| + ComputeClips(clip_tree, *transform_tree); |
| + CalculateVisibleRects(layers_to_update, *clip_tree, *transform_tree); |
| + } |
| +} |
| + |
| +} // namespace cc |