| 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
|
|
|