Index: cc/trees/property_tree.cc |
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc |
index 95c2b5a7730b570330e9d346cf42e8c241799fbf..25d42aad7451c90e13b3eddfa1f38cd86172076a 100644 |
--- a/cc/trees/property_tree.cc |
+++ b/cc/trees/property_tree.cc |
@@ -5,6 +5,7 @@ |
#include <set> |
#include "base/logging.h" |
+#include "cc/base/math_util.h" |
#include "cc/trees/property_tree.h" |
namespace cc { |
@@ -35,11 +36,16 @@ template class PropertyTree<ClipNode>; |
TransformNodeData::TransformNodeData() |
: target_id(-1), |
+ content_target_id(-1), |
+ needs_local_transform_update(true), |
is_invertible(true), |
ancestors_are_invertible(true), |
is_animated(false), |
to_screen_is_animated(false), |
- flattens(false) { |
+ flattens(false), |
+ scrolls(false), |
+ needs_sublayer_scale(false), |
+ layer_scale_factor(1.0f) { |
} |
TransformNodeData::~TransformNodeData() { |
@@ -79,47 +85,18 @@ bool TransformTree::Are2DAxisAligned(int source_id, int dest_id) const { |
transform.Preserves2dAxisAlignment(); |
} |
-void TransformTree::UpdateScreenSpaceTransform(int id) { |
- TransformNode* current_node = Node(id); |
- TransformNode* parent_node = parent(current_node); |
- TransformNode* target_node = Node(current_node->data.target_id); |
- |
- if (!parent_node) { |
- current_node->data.to_screen = current_node->data.to_parent; |
- current_node->data.ancestors_are_invertible = true; |
- current_node->data.to_screen_is_animated = false; |
- } else if (parent_node->data.flattens) { |
- // Flattening is tricky. Once a layer is drawn into its render target, it |
- // cannot escape, so we only need to consider transforms between the layer |
- // and its target when flattening (i.e., its draw transform). To compute the |
- // screen space transform when flattening is involved we combine three |
- // transforms, A * B * C, where A is the screen space transform of the |
- // target, B is the flattened draw transform of the layer's parent, and C is |
- // the local transform. |
- current_node->data.to_screen = target_node->data.to_screen; |
- gfx::Transform flattened; |
- ComputeTransform(parent_node->id, target_node->id, &flattened); |
- flattened.FlattenTo2d(); |
- current_node->data.to_screen.PreconcatTransform(flattened); |
- current_node->data.to_screen.PreconcatTransform( |
- current_node->data.to_parent); |
- current_node->data.ancestors_are_invertible = |
- parent_node->data.ancestors_are_invertible; |
- } else { |
- current_node->data.to_screen = parent_node->data.to_screen; |
- current_node->data.to_screen.PreconcatTransform( |
- current_node->data.to_parent); |
- current_node->data.ancestors_are_invertible = |
- parent_node->data.ancestors_are_invertible; |
- } |
- if (!current_node->data.to_screen.GetInverse(¤t_node->data.from_screen)) |
- current_node->data.ancestors_are_invertible = false; |
- |
- if (parent_node) { |
- current_node->data.to_screen_is_animated = |
- current_node->data.is_animated || |
- parent_node->data.to_screen_is_animated; |
- } |
+void TransformTree::UpdateTransforms(int id) { |
+ TransformNode* node = Node(id); |
+ TransformNode* parent_node = parent(node); |
+ TransformNode* target_node = Node(node->data.target_id); |
+ if (node->data.needs_local_transform_update) |
+ UpdateLocalTransform(node); |
+ UpdateLocalTransform(node); |
+ UpdateScreenSpaceTransform(node, parent_node, target_node); |
+ UpdateSublayerScale(node); |
+ UpdateTargetSpaceTransform(node, target_node); |
+ UpdateIsAnimated(node, parent_node); |
+ UpdateSnapping(node); |
} |
bool TransformTree::IsDescendant(int desc_id, int source_id) const { |
@@ -196,4 +173,123 @@ bool TransformTree::CombineInversesBetween(int source_id, |
return all_are_invertible; |
} |
+void TransformTree::UpdateLocalTransform(TransformNode* node) { |
+ gfx::Transform transform = node->data.post_local; |
+ transform.Translate(-node->data.scroll_offset.x(), |
+ -node->data.scroll_offset.y()); |
+ transform.PreconcatTransform(node->data.local); |
+ transform.PreconcatTransform(node->data.pre_local); |
+ node->data.set_to_parent(transform); |
+ node->data.needs_local_transform_update = false; |
+} |
+ |
+void TransformTree::UpdateScreenSpaceTransform(TransformNode* node, |
+ TransformNode* parent_node, |
+ TransformNode* target_node) { |
+ if (!parent_node) { |
+ node->data.to_screen = node->data.to_parent; |
+ node->data.ancestors_are_invertible = true; |
+ node->data.to_screen_is_animated = false; |
+ } else if (parent_node->data.flattens) { |
+ // Flattening is tricky. Once a layer is drawn into its render target, it |
+ // cannot escape, so we only need to consider transforms between the layer |
+ // and its target when flattening (i.e., its draw transform). To compute the |
+ // screen space transform when flattening is involved we combine three |
+ // transforms, A * B * C, where A is the screen space transform of the |
+ // target, B is the flattened draw transform of the layer's parent, and C is |
+ // the local transform. |
+ node->data.to_screen = target_node->data.to_screen; |
+ gfx::Transform flattened; |
+ ComputeTransform(parent_node->id, target_node->id, &flattened); |
+ flattened.FlattenTo2d(); |
+ node->data.to_screen.PreconcatTransform(flattened); |
+ node->data.to_screen.PreconcatTransform(node->data.to_parent); |
+ node->data.ancestors_are_invertible = |
+ parent_node->data.ancestors_are_invertible; |
+ } else { |
+ node->data.to_screen = parent_node->data.to_screen; |
+ node->data.to_screen.PreconcatTransform(node->data.to_parent); |
+ node->data.ancestors_are_invertible = |
+ parent_node->data.ancestors_are_invertible; |
+ } |
+ |
+ if (!node->data.to_screen.GetInverse(&node->data.from_screen)) |
+ node->data.ancestors_are_invertible = false; |
+} |
+ |
+void TransformTree::UpdateSublayerScale(TransformNode* node) { |
+ // The sublayer scale depends on the screen space transform, so update it too. |
+ node->data.sublayer_scale = |
+ node->data.needs_sublayer_scale |
+ ? MathUtil::ComputeTransform2dScaleComponents( |
+ node->data.to_screen, node->data.layer_scale_factor) |
+ : gfx::Vector2dF(1.0f, 1.0f); |
+} |
+ |
+void TransformTree::UpdateTargetSpaceTransform(TransformNode* node, |
+ TransformNode* target_node) { |
+ node->data.to_target.MakeIdentity(); |
+ if (node->data.needs_sublayer_scale) { |
+ node->data.to_target.Scale(node->data.sublayer_scale.x(), |
+ node->data.sublayer_scale.y()); |
+ } else { |
+ const bool target_is_root_surface = target_node->id == 1; |
+ // In order to include the root transform for the root surface, we walk up |
+ // to the root of the transform tree in ComputeTransform. |
+ int target_id = target_is_root_surface ? 0 : target_node->id; |
+ if (target_node) { |
+ node->data.to_target.Scale(target_node->data.sublayer_scale.x(), |
+ target_node->data.sublayer_scale.y()); |
+ } |
+ |
+ gfx::Transform unscaled_target_transform; |
+ ComputeTransform(node->id, target_id, &unscaled_target_transform); |
+ node->data.to_target.PreconcatTransform(unscaled_target_transform); |
+ } |
+ |
+ if (!node->data.to_target.GetInverse(&node->data.from_target)) |
+ node->data.ancestors_are_invertible = false; |
+} |
+ |
+void TransformTree::UpdateIsAnimated(TransformNode* node, |
+ TransformNode* parent_node) { |
+ if (parent_node) { |
+ node->data.to_screen_is_animated = |
+ node->data.is_animated || parent_node->data.to_screen_is_animated; |
+ } |
+} |
+ |
+void TransformTree::UpdateSnapping(TransformNode* node) { |
+ if (!node->data.scrolls || node->data.to_screen_is_animated || |
+ !node->data.to_target.IsScaleOrTranslation()) { |
+ return; |
+ } |
+ |
+ // Scroll snapping must be done in target space (the pixels we care about). |
+ // This means we effectively snap the target space transform. If TT is the |
+ // target space transform and TT' is TT with its translation components |
+ // rounded, then what we're after is the scroll delta X, where TT * X = TT'. |
+ // I.e., we want a transform that will realize our scroll snap. It follows |
+ // that X = TT^-1 * TT'. We cache TT and TT^-1 to make this more efficient. |
+ gfx::Transform rounded = node->data.to_target; |
+ rounded.RoundTranslationComponents(); |
+ gfx::Transform delta = node->data.from_target; |
+ delta *= rounded; |
+ gfx::Transform inverse_delta(gfx::Transform::kSkipInitialization); |
+ bool invertible_delta = delta.GetInverse(&inverse_delta); |
+ |
+ // The delta should be a translation, modulo floating point error, and should |
+ // therefore be invertible. |
+ DCHECK(invertible_delta); |
+ |
+ // Now that we have our scroll delta, we must apply it to each of our |
+ // combined, to/from matrices. |
+ node->data.to_parent.PreconcatTransform(delta); |
+ node->data.from_parent.ConcatTransform(inverse_delta); |
+ node->data.to_target.PreconcatTransform(delta); |
+ node->data.from_target.ConcatTransform(inverse_delta); |
+ node->data.to_screen.PreconcatTransform(delta); |
+ node->data.from_screen.ConcatTransform(inverse_delta); |
+} |
+ |
} // namespace cc |