summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cc/cc.gyp1
-rw-r--r--cc/proto/BUILD.gn1
-rw-r--r--cc/proto/gfx_conversions_unittest.cc74
-rw-r--r--cc/proto/property_tree.proto148
-rw-r--r--cc/trees/property_tree.cc464
-rw-r--r--cc/trees/property_tree.h76
-rw-r--r--cc/trees/property_tree_unittest.cc1491
7 files changed, 1694 insertions, 561 deletions
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 8205cb7..4fd6b04 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -594,6 +594,7 @@
'proto/point.proto',
'proto/point3f.proto',
'proto/pointf.proto',
+ 'proto/property_tree.proto',
'proto/rect.proto',
'proto/rectf.proto',
'proto/region.proto',
diff --git a/cc/proto/BUILD.gn b/cc/proto/BUILD.gn
index 07258a6..884045f 100644
--- a/cc/proto/BUILD.gn
+++ b/cc/proto/BUILD.gn
@@ -36,6 +36,7 @@ proto_library("proto_internal") {
"point.proto",
"point3f.proto",
"pointf.proto",
+ "property_tree.proto",
"rect.proto",
"rectf.proto",
"region.proto",
diff --git a/cc/proto/gfx_conversions_unittest.cc b/cc/proto/gfx_conversions_unittest.cc
index 6affc1c..cf46be8 100644
--- a/cc/proto/gfx_conversions_unittest.cc
+++ b/cc/proto/gfx_conversions_unittest.cc
@@ -194,29 +194,79 @@ TEST(GfxProtoConversionsTest, SerializeDeserializeTransform) {
}
TEST(GfxProtoConversionsTest, SerializeDeserializeVector2dF) {
- const gfx::Vector2dF vector(5.1f, 10.2f);
+ // Test Case 1
+ const gfx::Vector2dF vector1(5.1f, 10.2f);
// Test Vector2dFToProto
- proto::Vector2dF proto;
- Vector2dFToProto(vector, &proto);
- EXPECT_EQ(vector.x(), proto.x());
- EXPECT_EQ(vector.y(), proto.y());
+ proto::Vector2dF proto1;
+ Vector2dFToProto(vector1, &proto1);
+ EXPECT_EQ(vector1.x(), proto1.x());
+ EXPECT_EQ(vector1.y(), proto1.y());
// Test ProtoToVector2dF
- EXPECT_EQ(vector, ProtoToVector2dF(proto));
+ EXPECT_EQ(vector1, ProtoToVector2dF(proto1));
+
+ // Test Case 2
+ const gfx::Vector2dF vector2(-3.1f, 0.2f);
+
+ // Test Vector2dFToProto
+ proto::Vector2dF proto2;
+ Vector2dFToProto(vector2, &proto2);
+ EXPECT_EQ(vector2.x(), proto2.x());
+ EXPECT_EQ(vector2.y(), proto2.y());
+
+ // Test ProtoToVector2dF
+ EXPECT_EQ(vector2, ProtoToVector2dF(proto2));
+
+ // Test Case 3
+ const gfx::Vector2dF vector3(2.0f, -1.5f);
+
+ // Test Vector2dFToProto
+ proto::Vector2dF proto3;
+ Vector2dFToProto(vector3, &proto3);
+ EXPECT_EQ(vector3.x(), proto3.x());
+ EXPECT_EQ(vector3.y(), proto3.y());
+
+ // Test ProtoToVector2dF
+ EXPECT_EQ(vector3, ProtoToVector2dF(proto3));
}
TEST(GfxProtoConversionsTest, SerializeDeserializeScrollOffset) {
- const gfx::ScrollOffset scroll_offset(5.1f, 10.2f);
+ // Test Case 1
+ const gfx::ScrollOffset scroll_offset1(5.1f, 10.2f);
+
+ // Test ScrollOffsetToProto
+ proto::ScrollOffset proto1;
+ ScrollOffsetToProto(scroll_offset1, &proto1);
+ EXPECT_EQ(scroll_offset1.x(), proto1.x());
+ EXPECT_EQ(scroll_offset1.y(), proto1.y());
+
+ // Test ProtoToScrollOffset
+ EXPECT_EQ(scroll_offset1, ProtoToScrollOffset(proto1));
+
+ // Test Case 2
+ const gfx::ScrollOffset scroll_offset2(-0.1f, 0.2f);
+
+ // Test ScrollOffsetToProto
+ proto::ScrollOffset proto2;
+ ScrollOffsetToProto(scroll_offset2, &proto2);
+ EXPECT_EQ(scroll_offset2.x(), proto2.x());
+ EXPECT_EQ(scroll_offset2.y(), proto2.y());
+
+ // Test ProtoToScrollOffset
+ EXPECT_EQ(scroll_offset2, ProtoToScrollOffset(proto2));
+
+ // Test Case 3
+ const gfx::ScrollOffset scroll_offset3(4.0f, -3.2f);
// Test ScrollOffsetToProto
- proto::ScrollOffset proto;
- ScrollOffsetToProto(scroll_offset, &proto);
- EXPECT_EQ(scroll_offset.x(), proto.x());
- EXPECT_EQ(scroll_offset.y(), proto.y());
+ proto::ScrollOffset proto3;
+ ScrollOffsetToProto(scroll_offset3, &proto3);
+ EXPECT_EQ(scroll_offset3.x(), proto3.x());
+ EXPECT_EQ(scroll_offset3.y(), proto3.y());
// Test ProtoToScrollOffset
- EXPECT_EQ(scroll_offset, ProtoToScrollOffset(proto));
+ EXPECT_EQ(scroll_offset3, ProtoToScrollOffset(proto3));
}
} // namespace
diff --git a/cc/proto/property_tree.proto b/cc/proto/property_tree.proto
new file mode 100644
index 0000000..6bf2a7f
--- /dev/null
+++ b/cc/proto/property_tree.proto
@@ -0,0 +1,148 @@
+// Copyright 2015 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.
+
+syntax = "proto2";
+
+import "rectf.proto";
+import "scroll_offset.proto";
+import "transform.proto";
+import "vector2df.proto";
+
+option optimize_for = LITE_RUNTIME;
+
+package cc.proto;
+
+// The messages declared in this file correspond to the classes declared in
+// cc/trees/property_tree.h
+
+// Proto for struct TransformNodeData.
+message TranformNodeData {
+ optional Transform pre_local = 1;
+ optional Transform local = 2;
+ optional Transform post_local = 3;
+ optional Transform to_parent = 4;
+ optional Transform to_target = 5;
+ optional Transform from_target = 6;
+ optional Transform to_screen = 7;
+ optional Transform from_screen = 8;
+
+ optional int64 target_id = 9;
+ optional int64 content_target_id = 10;
+ optional int64 source_node_id = 11;
+ optional bool needs_local_transform_update = 12;
+ optional bool is_invertible = 13;
+ optional bool ancestors_are_invertible = 14;
+ optional bool is_animated = 15;
+ optional bool to_screen_is_animated = 16;
+ optional bool has_only_translation_animations = 17;
+ optional bool to_screen_has_scale_animation = 18;
+ optional bool flattens_inherited_transform = 19;
+ optional bool node_and_ancestors_are_flat = 20;
+ optional bool node_and_ancestors_have_only_integer_translation = 21;
+ optional bool scrolls = 22;
+ optional bool needs_sublayer_scale = 23;
+ optional bool affected_by_inner_viewport_bounds_delta_x = 24;
+ optional bool affected_by_inner_viewport_bounds_delta_y = 25;
+ optional bool affected_by_outer_viewport_bounds_delta_x = 26;
+ optional bool affected_by_outer_viewport_bounds_delta_y = 27;
+ optional bool in_subtree_of_page_scale_layer = 28;
+ optional float post_local_scale_factor = 29;
+ optional float local_maximum_animation_target_scale = 30;
+ optional float local_starting_animation_scale = 31;
+ optional float combined_maximum_animation_target_scale = 32;
+ optional float combined_starting_animation_scale = 33;
+
+ optional Vector2dF sublayer_scale = 34;
+ optional ScrollOffset scroll_offset = 35;
+ optional Vector2dF scroll_snap = 36;
+ optional Vector2dF source_offset = 37;
+ optional Vector2dF source_to_parent = 38;
+}
+
+// Proto for struct ClipNodeData.
+message ClipNodeData {
+ optional RectF clip = 1;
+ optional RectF combined_clip_in_target_space = 2;
+ optional RectF clip_in_target_space = 3;
+
+ optional int64 transform_id = 4;
+ optional int64 target_id = 5;
+ optional bool applies_local_clip = 6;
+ optional bool layer_clipping_uses_only_local_clip = 7;
+ optional bool target_is_clipped = 8;
+ optional bool layers_are_clipped = 9;
+ optional bool layers_are_clipped_when_surfaces_disabled = 10;
+ optional bool resets_clip = 11;
+}
+
+// Proto for struct EffectNodeData.
+message EffectNodeData {
+ optional float opacity = 1;
+ optional float screen_space_opacity = 2;
+ optional bool has_render_surface = 3;
+ optional int64 transform_id = 4;
+ optional int64 clip_id = 5;
+}
+
+// This defines the proto used for all types of struct TreeNode.
+message TreeNode {
+ // The following fields are the base TreeNode properties. This list
+ // corresponds to the data members from struct TreeNode.
+ optional int64 id = 1;
+ optional int64 parent_id = 2;
+ optional int64 owner_id = 3;
+
+ // The following fields correspond to the possible values for TreeNode::data.
+ // Only one of these fields should be set, based on the type of property tree
+ // this node belongs to.
+ optional TranformNodeData transform_node_data = 1000;
+ optional ClipNodeData clip_node_data = 1001;
+ optional EffectNodeData effect_node_data = 1002;
+}
+
+// This defines the proto used for all property trees. PropertyType denotes the
+// type of this tree.
+message PropertyTree {
+ enum PropertyType {
+ Transform = 1;
+ Clip = 2;
+ Effect = 3;
+ }
+
+ // The following fields are the base PropertyTree properties. This list
+ // corresponds to the data members from class PropertyTree.
+ optional PropertyType property_type = 1;
+ repeated TreeNode nodes = 2;
+ optional bool needs_update = 3;
+
+ // The following fields denote the data members for each subclass of
+ // PropertyTree. Only one of these fields should be set, depending on the type
+ // of this property tree.
+ optional TransformTreeData transform_tree_data = 1000;
+}
+
+// Proto for data members of class TransformTree.
+message TransformTreeData {
+ optional bool source_to_parent_updates_allowed = 1;
+ optional float page_scale_factor = 2;
+ optional float device_scale_factor = 3;
+ optional float device_transform_scale_factor = 4;
+ optional Vector2dF inner_viewport_bounds_delta = 5;
+ optional Vector2dF outer_viewport_bounds_delta = 6;
+ repeated int64 nodes_affected_by_inner_viewport_bounds_delta = 7
+ [packed = true];
+ repeated int64 nodes_affected_by_outer_viewport_bounds_delta = 8
+ [packed = true];
+}
+
+// Proto for class PropertyTrees.
+message PropertyTrees {
+ optional PropertyTree transform_tree = 1;
+ optional PropertyTree effect_tree = 2;
+ optional PropertyTree clip_tree = 3;
+
+ optional bool needs_rebuild = 4;
+ optional bool non_root_surfaces_enabled = 5;
+ optional int64 sequence_number = 6;
+} \ No newline at end of file
diff --git a/cc/trees/property_tree.cc b/cc/trees/property_tree.cc
index 570a687..a6b72e6 100644
--- a/cc/trees/property_tree.cc
+++ b/cc/trees/property_tree.cc
@@ -7,11 +7,42 @@
#include "base/logging.h"
#include "cc/base/math_util.h"
+#include "cc/proto/gfx_conversions.h"
+#include "cc/proto/property_tree.pb.h"
+#include "cc/proto/scroll_offset.pb.h"
+#include "cc/proto/transform.pb.h"
+#include "cc/proto/vector2df.pb.h"
#include "cc/trees/property_tree.h"
namespace cc {
template <typename T>
+bool TreeNode<T>::operator==(const TreeNode<T>& other) const {
+ return id == other.id && parent_id == other.parent_id &&
+ owner_id == other.owner_id && data == other.data;
+}
+
+template <typename T>
+void TreeNode<T>::ToProtobuf(proto::TreeNode* proto) const {
+ proto->set_id(id);
+ proto->set_parent_id(parent_id);
+ proto->set_owner_id(owner_id);
+ data.ToProtobuf(proto);
+}
+
+template <typename T>
+void TreeNode<T>::FromProtobuf(const proto::TreeNode& proto) {
+ id = proto.id();
+ parent_id = proto.parent_id();
+ owner_id = proto.owner_id();
+ data.FromProtobuf(proto);
+}
+
+template struct TreeNode<TransformNodeData>;
+template struct TreeNode<ClipNodeData>;
+template struct TreeNode<EffectNodeData>;
+
+template <typename T>
PropertyTree<T>::PropertyTree()
: needs_update_(false) {
nodes_.push_back(T());
@@ -50,6 +81,38 @@ void PropertyTree<T>::clear() {
back()->parent_id = -1;
}
+template <typename T>
+bool PropertyTree<T>::operator==(const PropertyTree<T>& other) const {
+ return nodes_ == other.nodes() && needs_update_ == other.needs_update();
+}
+
+template <typename T>
+void PropertyTree<T>::ToProtobuf(proto::PropertyTree* proto) const {
+ DCHECK_EQ(0, proto->nodes_size());
+ for (const auto& node : nodes_)
+ node.ToProtobuf(proto->add_nodes());
+ proto->set_needs_update(needs_update_);
+}
+
+template <typename T>
+void PropertyTree<T>::FromProtobuf(const proto::PropertyTree& proto) {
+ // Verify that the property tree is empty.
+ DCHECK_EQ(static_cast<int>(nodes_.size()), 1);
+ DCHECK_EQ(back()->id, 0);
+ DCHECK_EQ(back()->parent_id, -1);
+
+ // Add the first node.
+ DCHECK_GT(proto.nodes_size(), 0);
+ nodes_.back().FromProtobuf(proto.nodes(0));
+
+ for (int i = 1; i < proto.nodes_size(); ++i) {
+ nodes_.push_back(T());
+ nodes_.back().FromProtobuf(proto.nodes(i));
+ }
+
+ needs_update_ = proto.needs_update();
+}
+
template class PropertyTree<TransformNode>;
template class PropertyTree<ClipNode>;
template class PropertyTree<EffectNode>;
@@ -84,6 +147,54 @@ TransformNodeData::TransformNodeData()
TransformNodeData::~TransformNodeData() {
}
+bool TransformNodeData::operator==(const TransformNodeData& other) const {
+ return pre_local == other.pre_local && local == other.local &&
+ post_local == other.post_local && to_parent == other.to_parent &&
+ to_target == other.to_target && from_target == other.from_target &&
+ to_screen == other.to_screen && from_screen == other.from_screen &&
+ target_id == other.target_id &&
+ content_target_id == other.content_target_id &&
+ source_node_id == other.source_node_id &&
+ needs_local_transform_update == other.needs_local_transform_update &&
+ is_invertible == other.is_invertible &&
+ ancestors_are_invertible == other.ancestors_are_invertible &&
+ is_animated == other.is_animated &&
+ to_screen_is_animated == other.to_screen_is_animated &&
+ has_only_translation_animations ==
+ other.has_only_translation_animations &&
+ to_screen_has_scale_animation == other.to_screen_has_scale_animation &&
+ flattens_inherited_transform == other.flattens_inherited_transform &&
+ node_and_ancestors_are_flat == other.node_and_ancestors_are_flat &&
+ node_and_ancestors_have_only_integer_translation ==
+ other.node_and_ancestors_have_only_integer_translation &&
+ scrolls == other.scrolls &&
+ needs_sublayer_scale == other.needs_sublayer_scale &&
+ affected_by_inner_viewport_bounds_delta_x ==
+ other.affected_by_inner_viewport_bounds_delta_x &&
+ affected_by_inner_viewport_bounds_delta_y ==
+ other.affected_by_inner_viewport_bounds_delta_y &&
+ affected_by_outer_viewport_bounds_delta_x ==
+ other.affected_by_outer_viewport_bounds_delta_x &&
+ affected_by_outer_viewport_bounds_delta_y ==
+ other.affected_by_outer_viewport_bounds_delta_y &&
+ in_subtree_of_page_scale_layer ==
+ other.in_subtree_of_page_scale_layer &&
+ post_local_scale_factor == other.post_local_scale_factor &&
+ local_maximum_animation_target_scale ==
+ other.local_maximum_animation_target_scale &&
+ local_starting_animation_scale ==
+ other.local_starting_animation_scale &&
+ combined_maximum_animation_target_scale ==
+ other.combined_maximum_animation_target_scale &&
+ combined_starting_animation_scale ==
+ other.combined_starting_animation_scale &&
+ sublayer_scale == other.sublayer_scale &&
+ scroll_offset == other.scroll_offset &&
+ scroll_snap == other.scroll_snap &&
+ source_offset == other.source_offset &&
+ source_to_parent == other.source_to_parent;
+}
+
void TransformNodeData::update_pre_local_transform(
const gfx::Point3F& transform_origin) {
pre_local.MakeIdentity();
@@ -102,6 +213,133 @@ void TransformNodeData::update_post_local_transform(
transform_origin.z());
}
+void TransformNodeData::ToProtobuf(proto::TreeNode* proto) const {
+ DCHECK(!proto->has_transform_node_data());
+ proto::TranformNodeData* data = proto->mutable_transform_node_data();
+
+ TransformToProto(pre_local, data->mutable_pre_local());
+ TransformToProto(local, data->mutable_local());
+ TransformToProto(post_local, data->mutable_post_local());
+
+ TransformToProto(to_parent, data->mutable_to_parent());
+
+ TransformToProto(to_target, data->mutable_to_target());
+ TransformToProto(from_target, data->mutable_from_target());
+
+ TransformToProto(to_screen, data->mutable_to_screen());
+ TransformToProto(from_screen, data->mutable_from_screen());
+
+ data->set_target_id(target_id);
+ data->set_content_target_id(content_target_id);
+ data->set_source_node_id(source_node_id);
+
+ data->set_needs_local_transform_update(needs_local_transform_update);
+
+ data->set_is_invertible(is_invertible);
+ data->set_ancestors_are_invertible(ancestors_are_invertible);
+
+ data->set_is_animated(is_animated);
+ data->set_to_screen_is_animated(to_screen_is_animated);
+ data->set_has_only_translation_animations(has_only_translation_animations);
+ data->set_to_screen_has_scale_animation(to_screen_has_scale_animation);
+
+ data->set_flattens_inherited_transform(flattens_inherited_transform);
+ data->set_node_and_ancestors_are_flat(node_and_ancestors_are_flat);
+
+ data->set_node_and_ancestors_have_only_integer_translation(
+ node_and_ancestors_have_only_integer_translation);
+ data->set_scrolls(scrolls);
+ data->set_needs_sublayer_scale(needs_sublayer_scale);
+
+ data->set_affected_by_inner_viewport_bounds_delta_x(
+ affected_by_inner_viewport_bounds_delta_x);
+ data->set_affected_by_inner_viewport_bounds_delta_y(
+ affected_by_inner_viewport_bounds_delta_y);
+ data->set_affected_by_outer_viewport_bounds_delta_x(
+ affected_by_outer_viewport_bounds_delta_x);
+ data->set_affected_by_outer_viewport_bounds_delta_y(
+ affected_by_outer_viewport_bounds_delta_y);
+
+ data->set_in_subtree_of_page_scale_layer(in_subtree_of_page_scale_layer);
+ data->set_post_local_scale_factor(post_local_scale_factor);
+ data->set_local_maximum_animation_target_scale(
+ local_maximum_animation_target_scale);
+ data->set_local_starting_animation_scale(local_starting_animation_scale);
+ data->set_combined_maximum_animation_target_scale(
+ combined_maximum_animation_target_scale);
+ data->set_combined_starting_animation_scale(
+ combined_starting_animation_scale);
+
+ Vector2dFToProto(sublayer_scale, data->mutable_sublayer_scale());
+ ScrollOffsetToProto(scroll_offset, data->mutable_scroll_offset());
+ Vector2dFToProto(scroll_snap, data->mutable_scroll_snap());
+ Vector2dFToProto(source_offset, data->mutable_source_offset());
+ Vector2dFToProto(source_to_parent, data->mutable_source_to_parent());
+}
+
+void TransformNodeData::FromProtobuf(const proto::TreeNode& proto) {
+ DCHECK(proto.has_transform_node_data());
+ const proto::TranformNodeData& data = proto.transform_node_data();
+
+ pre_local = ProtoToTransform(data.pre_local());
+ local = ProtoToTransform(data.local());
+ post_local = ProtoToTransform(data.post_local());
+
+ to_parent = ProtoToTransform(data.to_parent());
+
+ to_target = ProtoToTransform(data.to_target());
+ from_target = ProtoToTransform(data.from_target());
+
+ to_screen = ProtoToTransform(data.to_screen());
+ from_screen = ProtoToTransform(data.from_screen());
+
+ target_id = data.target_id();
+ content_target_id = data.content_target_id();
+ source_node_id = data.source_node_id();
+
+ needs_local_transform_update = data.needs_local_transform_update();
+
+ is_invertible = data.is_invertible();
+ ancestors_are_invertible = data.ancestors_are_invertible();
+
+ is_animated = data.is_animated();
+ to_screen_is_animated = data.to_screen_is_animated();
+ has_only_translation_animations = data.has_only_translation_animations();
+ to_screen_has_scale_animation = data.to_screen_has_scale_animation();
+
+ flattens_inherited_transform = data.flattens_inherited_transform();
+ node_and_ancestors_are_flat = data.node_and_ancestors_are_flat();
+
+ node_and_ancestors_have_only_integer_translation =
+ data.node_and_ancestors_have_only_integer_translation();
+ scrolls = data.scrolls();
+ needs_sublayer_scale = data.needs_sublayer_scale();
+
+ affected_by_inner_viewport_bounds_delta_x =
+ data.affected_by_inner_viewport_bounds_delta_x();
+ affected_by_inner_viewport_bounds_delta_y =
+ data.affected_by_inner_viewport_bounds_delta_y();
+ affected_by_outer_viewport_bounds_delta_x =
+ data.affected_by_outer_viewport_bounds_delta_x();
+ affected_by_outer_viewport_bounds_delta_y =
+ data.affected_by_outer_viewport_bounds_delta_y();
+
+ in_subtree_of_page_scale_layer = data.in_subtree_of_page_scale_layer();
+ post_local_scale_factor = data.post_local_scale_factor();
+ local_maximum_animation_target_scale =
+ data.local_maximum_animation_target_scale();
+ local_starting_animation_scale = data.local_starting_animation_scale();
+ combined_maximum_animation_target_scale =
+ data.combined_maximum_animation_target_scale();
+ combined_starting_animation_scale = data.combined_starting_animation_scale();
+
+ sublayer_scale = ProtoToVector2dF(data.sublayer_scale());
+ scroll_offset = ProtoToScrollOffset(data.scroll_offset());
+ scroll_snap = ProtoToVector2dF(data.scroll_snap());
+ source_offset = ProtoToVector2dF(data.source_offset());
+ source_to_parent = ProtoToVector2dF(data.source_to_parent());
+}
+
ClipNodeData::ClipNodeData()
: transform_id(-1),
target_id(-1),
@@ -112,6 +350,63 @@ ClipNodeData::ClipNodeData()
layers_are_clipped_when_surfaces_disabled(false),
resets_clip(false) {}
+bool ClipNodeData::operator==(const ClipNodeData& other) const {
+ return clip == other.clip &&
+ combined_clip_in_target_space == other.combined_clip_in_target_space &&
+ clip_in_target_space == other.clip_in_target_space &&
+ transform_id == other.transform_id && target_id == other.target_id &&
+ applies_local_clip == other.applies_local_clip &&
+ layer_clipping_uses_only_local_clip ==
+ other.layer_clipping_uses_only_local_clip &&
+ target_is_clipped == other.target_is_clipped &&
+ layers_are_clipped == other.layers_are_clipped &&
+ layers_are_clipped_when_surfaces_disabled ==
+ other.layers_are_clipped_when_surfaces_disabled &&
+ resets_clip == other.resets_clip;
+}
+
+void ClipNodeData::ToProtobuf(proto::TreeNode* proto) const {
+ DCHECK(!proto->has_clip_node_data());
+ proto::ClipNodeData* data = proto->mutable_clip_node_data();
+
+ RectFToProto(clip, data->mutable_clip());
+ RectFToProto(combined_clip_in_target_space,
+ data->mutable_combined_clip_in_target_space());
+ RectFToProto(clip_in_target_space, data->mutable_clip_in_target_space());
+
+ data->set_transform_id(transform_id);
+ data->set_target_id(target_id);
+ data->set_applies_local_clip(applies_local_clip);
+ data->set_layer_clipping_uses_only_local_clip(
+ layer_clipping_uses_only_local_clip);
+ data->set_target_is_clipped(target_is_clipped);
+ data->set_layers_are_clipped(layers_are_clipped);
+ data->set_layers_are_clipped_when_surfaces_disabled(
+ layers_are_clipped_when_surfaces_disabled);
+ data->set_resets_clip(resets_clip);
+}
+
+void ClipNodeData::FromProtobuf(const proto::TreeNode& proto) {
+ DCHECK(proto.has_clip_node_data());
+ const proto::ClipNodeData& data = proto.clip_node_data();
+
+ clip = ProtoToRectF(data.clip());
+ combined_clip_in_target_space =
+ ProtoToRectF(data.combined_clip_in_target_space());
+ clip_in_target_space = ProtoToRectF(data.clip_in_target_space());
+
+ transform_id = data.transform_id();
+ target_id = data.target_id();
+ applies_local_clip = data.applies_local_clip();
+ layer_clipping_uses_only_local_clip =
+ data.layer_clipping_uses_only_local_clip();
+ target_is_clipped = data.target_is_clipped();
+ layers_are_clipped = data.layers_are_clipped();
+ layers_are_clipped_when_surfaces_disabled =
+ data.layers_are_clipped_when_surfaces_disabled();
+ resets_clip = data.resets_clip();
+}
+
EffectNodeData::EffectNodeData()
: opacity(1.f),
screen_space_opacity(1.f),
@@ -119,6 +414,34 @@ EffectNodeData::EffectNodeData()
transform_id(0),
clip_id(0) {}
+bool EffectNodeData::operator==(const EffectNodeData& other) const {
+ return opacity == other.opacity &&
+ screen_space_opacity == other.screen_space_opacity &&
+ has_render_surface == other.has_render_surface &&
+ transform_id == other.transform_id && clip_id == other.clip_id;
+}
+
+void EffectNodeData::ToProtobuf(proto::TreeNode* proto) const {
+ DCHECK(!proto->has_effect_node_data());
+ proto::EffectNodeData* data = proto->mutable_effect_node_data();
+ data->set_opacity(opacity);
+ data->set_screen_space_opacity(screen_space_opacity);
+ data->set_has_render_surface(has_render_surface);
+ data->set_transform_id(transform_id);
+ data->set_clip_id(clip_id);
+}
+
+void EffectNodeData::FromProtobuf(const proto::TreeNode& proto) {
+ DCHECK(proto.has_effect_node_data());
+ const proto::EffectNodeData& data = proto.effect_node_data();
+
+ opacity = data.opacity();
+ screen_space_opacity = data.screen_space_opacity();
+ has_render_surface = data.has_render_surface();
+ transform_id = data.transform_id();
+ clip_id = data.clip_id();
+}
+
void TransformTree::clear() {
PropertyTree<TransformNode>::clear();
@@ -624,6 +947,78 @@ bool TransformTree::HasNodesAffectedByOuterViewportBoundsDelta() const {
return !nodes_affected_by_outer_viewport_bounds_delta_.empty();
}
+bool TransformTree::operator==(const TransformTree& other) const {
+ return PropertyTree::operator==(other) &&
+ source_to_parent_updates_allowed_ ==
+ other.source_to_parent_updates_allowed() &&
+ page_scale_factor_ == other.page_scale_factor() &&
+ device_scale_factor_ == other.device_scale_factor() &&
+ device_transform_scale_factor_ ==
+ other.device_transform_scale_factor() &&
+ inner_viewport_bounds_delta_ == other.inner_viewport_bounds_delta() &&
+ outer_viewport_bounds_delta_ == other.outer_viewport_bounds_delta() &&
+ nodes_affected_by_inner_viewport_bounds_delta_ ==
+ other.nodes_affected_by_inner_viewport_bounds_delta() &&
+ nodes_affected_by_outer_viewport_bounds_delta_ ==
+ other.nodes_affected_by_outer_viewport_bounds_delta();
+}
+
+void TransformTree::ToProtobuf(proto::PropertyTree* proto) const {
+ DCHECK(!proto->has_property_type());
+ proto->set_property_type(proto::PropertyTree::Transform);
+
+ PropertyTree::ToProtobuf(proto);
+ proto::TransformTreeData* data = proto->mutable_transform_tree_data();
+
+ data->set_source_to_parent_updates_allowed(source_to_parent_updates_allowed_);
+ data->set_page_scale_factor(page_scale_factor_);
+ data->set_device_scale_factor(device_scale_factor_);
+ data->set_device_transform_scale_factor(device_transform_scale_factor_);
+
+ Vector2dFToProto(inner_viewport_bounds_delta_,
+ data->mutable_inner_viewport_bounds_delta());
+ Vector2dFToProto(outer_viewport_bounds_delta_,
+ data->mutable_outer_viewport_bounds_delta());
+
+ for (auto i : nodes_affected_by_inner_viewport_bounds_delta_)
+ data->add_nodes_affected_by_inner_viewport_bounds_delta(i);
+
+ for (auto i : nodes_affected_by_outer_viewport_bounds_delta_)
+ data->add_nodes_affected_by_outer_viewport_bounds_delta(i);
+}
+
+void TransformTree::FromProtobuf(const proto::PropertyTree& proto) {
+ DCHECK(proto.has_property_type());
+ DCHECK_EQ(proto.property_type(), proto::PropertyTree::Transform);
+
+ PropertyTree::FromProtobuf(proto);
+ const proto::TransformTreeData& data = proto.transform_tree_data();
+
+ source_to_parent_updates_allowed_ = data.source_to_parent_updates_allowed();
+ page_scale_factor_ = data.page_scale_factor();
+ device_scale_factor_ = data.device_scale_factor();
+ device_transform_scale_factor_ = data.device_transform_scale_factor();
+
+ inner_viewport_bounds_delta_ =
+ ProtoToVector2dF(data.inner_viewport_bounds_delta());
+ outer_viewport_bounds_delta_ =
+ ProtoToVector2dF(data.outer_viewport_bounds_delta());
+
+ DCHECK(nodes_affected_by_inner_viewport_bounds_delta_.empty());
+ for (int i = 0; i < data.nodes_affected_by_inner_viewport_bounds_delta_size();
+ ++i) {
+ nodes_affected_by_inner_viewport_bounds_delta_.push_back(
+ data.nodes_affected_by_inner_viewport_bounds_delta(i));
+ }
+
+ DCHECK(nodes_affected_by_outer_viewport_bounds_delta_.empty());
+ for (int i = 0; i < data.nodes_affected_by_outer_viewport_bounds_delta_size();
+ ++i) {
+ nodes_affected_by_outer_viewport_bounds_delta_.push_back(
+ data.nodes_affected_by_outer_viewport_bounds_delta(i));
+ }
+}
+
void EffectTree::UpdateOpacities(int id) {
EffectNode* node = Node(id);
node->data.screen_space_opacity = node->data.opacity;
@@ -660,9 +1055,78 @@ gfx::RectF ClipTree::ViewportClip() {
return Node(1)->data.clip;
}
+bool ClipTree::operator==(const ClipTree& other) const {
+ return PropertyTree::operator==(other);
+}
+
+void ClipTree::ToProtobuf(proto::PropertyTree* proto) const {
+ DCHECK(!proto->has_property_type());
+ proto->set_property_type(proto::PropertyTree::Clip);
+
+ PropertyTree::ToProtobuf(proto);
+}
+
+void ClipTree::FromProtobuf(const proto::PropertyTree& proto) {
+ DCHECK(proto.has_property_type());
+ DCHECK_EQ(proto.property_type(), proto::PropertyTree::Clip);
+
+ PropertyTree::FromProtobuf(proto);
+}
+
+bool EffectTree::operator==(const EffectTree& other) const {
+ return PropertyTree::operator==(other);
+}
+
+void EffectTree::ToProtobuf(proto::PropertyTree* proto) const {
+ DCHECK(!proto->has_property_type());
+ proto->set_property_type(proto::PropertyTree::Effect);
+
+ PropertyTree::ToProtobuf(proto);
+}
+
+void EffectTree::FromProtobuf(const proto::PropertyTree& proto) {
+ DCHECK(proto.has_property_type());
+ DCHECK_EQ(proto.property_type(), proto::PropertyTree::Effect);
+
+ PropertyTree::FromProtobuf(proto);
+}
+
PropertyTrees::PropertyTrees()
: needs_rebuild(true),
non_root_surfaces_enabled(true),
sequence_number(0) {}
+bool PropertyTrees::operator==(const PropertyTrees& other) const {
+ return transform_tree == other.transform_tree &&
+ effect_tree == other.effect_tree && clip_tree == other.clip_tree &&
+ needs_rebuild == other.needs_rebuild &&
+ non_root_surfaces_enabled == other.non_root_surfaces_enabled &&
+ sequence_number == other.sequence_number;
+}
+
+void PropertyTrees::ToProtobuf(proto::PropertyTrees* proto) const {
+ // TODO(khushalsagar): Add support for sending diffs when serializaing
+ // property trees. See crbug/555370.
+ transform_tree.ToProtobuf(proto->mutable_transform_tree());
+ effect_tree.ToProtobuf(proto->mutable_effect_tree());
+ clip_tree.ToProtobuf(proto->mutable_clip_tree());
+ proto->set_needs_rebuild(needs_rebuild);
+ proto->set_non_root_surfaces_enabled(non_root_surfaces_enabled);
+
+ // TODO(khushalsagar): Consider using the sequence number to decide if
+ // property trees need to be serialized again for a commit. See crbug/555370.
+ proto->set_sequence_number(sequence_number);
+}
+
+// static
+void PropertyTrees::FromProtobuf(const proto::PropertyTrees& proto) {
+ transform_tree.FromProtobuf(proto.transform_tree());
+ effect_tree.FromProtobuf(proto.effect_tree());
+ clip_tree.FromProtobuf(proto.clip_tree());
+
+ needs_rebuild = proto.needs_rebuild();
+ non_root_surfaces_enabled = proto.non_root_surfaces_enabled();
+ sequence_number = proto.sequence_number();
+}
+
} // namespace cc
diff --git a/cc/trees/property_tree.h b/cc/trees/property_tree.h
index 6f26ef6..4fbcc43 100644
--- a/cc/trees/property_tree.h
+++ b/cc/trees/property_tree.h
@@ -15,6 +15,23 @@
namespace cc {
+namespace proto {
+class ClipNodeData;
+class EffectNodeData;
+class PropertyTree;
+class PropertyTrees;
+class TranformNodeData;
+class TransformTreeData;
+class TreeNode;
+}
+
+// ------------------------------*IMPORTANT*---------------------------------
+// Each class declared here has a corresponding proto defined in
+// cc/proto/property_tree.proto. When making any changes to a class structure
+// including addition/deletion/updation of a field, please also make the
+// change to its proto and the ToProtobuf and FromProtobuf methods for that
+// class.
+
template <typename T>
struct CC_EXPORT TreeNode {
TreeNode() : id(-1), parent_id(-1), owner_id(-1), data() {}
@@ -22,6 +39,11 @@ struct CC_EXPORT TreeNode {
int parent_id;
int owner_id;
T data;
+
+ bool operator==(const TreeNode<T>& other) const;
+
+ void ToProtobuf(proto::TreeNode* proto) const;
+ void FromProtobuf(const proto::TreeNode& proto);
};
struct CC_EXPORT TransformNodeData {
@@ -141,6 +163,8 @@ struct CC_EXPORT TransformNodeData {
gfx::Vector2dF source_offset;
gfx::Vector2dF source_to_parent;
+ bool operator==(const TransformNodeData& other) const;
+
void set_to_parent(const gfx::Transform& transform) {
to_parent = transform;
is_invertible = to_parent.IsInvertible();
@@ -150,6 +174,9 @@ struct CC_EXPORT TransformNodeData {
void update_post_local_transform(const gfx::PointF& position,
const gfx::Point3F& transform_origin);
+
+ void ToProtobuf(proto::TreeNode* proto) const;
+ void FromProtobuf(const proto::TreeNode& proto);
};
typedef TreeNode<TransformNodeData> TransformNode;
@@ -198,6 +225,11 @@ struct CC_EXPORT ClipNodeData {
// Nodes that correspond to unclipped surfaces disregard ancestor clips.
bool resets_clip : 1;
+
+ bool operator==(const ClipNodeData& other) const;
+
+ void ToProtobuf(proto::TreeNode* proto) const;
+ void FromProtobuf(const proto::TreeNode& proto);
};
typedef TreeNode<ClipNodeData> ClipNode;
@@ -211,6 +243,11 @@ struct CC_EXPORT EffectNodeData {
bool has_render_surface;
int transform_id;
int clip_id;
+
+ bool operator==(const EffectNodeData& other) const;
+
+ void ToProtobuf(proto::TreeNode* proto) const;
+ void FromProtobuf(const proto::TreeNode& proto);
};
typedef TreeNode<EffectNodeData> EffectNode;
@@ -221,6 +258,8 @@ class CC_EXPORT PropertyTree {
PropertyTree();
virtual ~PropertyTree();
+ bool operator==(const PropertyTree<T>& other) const;
+
int Insert(const T& tree_node, int parent_id);
T* Node(int i) {
@@ -248,8 +287,13 @@ class CC_EXPORT PropertyTree {
void set_needs_update(bool needs_update) { needs_update_ = needs_update; }
bool needs_update() const { return needs_update_; }
+ const std::vector<T>& nodes() const { return nodes_; }
+
int next_available_id() const { return static_cast<int>(size()); }
+ void ToProtobuf(proto::PropertyTree* proto) const;
+ void FromProtobuf(const proto::PropertyTree& proto);
+
private:
// Copy and assign are permitted. This is how we do tree sync.
std::vector<T> nodes_;
@@ -262,6 +306,8 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
TransformTree();
~TransformTree() override;
+ bool operator==(const TransformTree& other) const;
+
void clear() override;
// Computes the change of basis transform from node |source_id| to |dest_id|.
@@ -331,6 +377,9 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
void SetDeviceTransform(const gfx::Transform& transform,
gfx::PointF root_position);
void SetDeviceTransformScaleFactor(const gfx::Transform& transform);
+ float device_transform_scale_factor() const {
+ return device_transform_scale_factor_;
+ }
void SetInnerViewportBoundsDelta(gfx::Vector2dF bounds_delta);
gfx::Vector2dF inner_viewport_bounds_delta() const {
@@ -348,6 +397,18 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
bool HasNodesAffectedByInnerViewportBoundsDelta() const;
bool HasNodesAffectedByOuterViewportBoundsDelta() const;
+ const std::vector<int>& nodes_affected_by_inner_viewport_bounds_delta()
+ const {
+ return nodes_affected_by_inner_viewport_bounds_delta_;
+ }
+ const std::vector<int>& nodes_affected_by_outer_viewport_bounds_delta()
+ const {
+ return nodes_affected_by_outer_viewport_bounds_delta_;
+ }
+
+ void ToProtobuf(proto::PropertyTree* proto) const;
+ void FromProtobuf(const proto::PropertyTree& proto);
+
private:
// Returns true iff the node at |desc_id| is a descendant of the node at
// |anc_id|.
@@ -398,19 +459,34 @@ class CC_EXPORT TransformTree final : public PropertyTree<TransformNode> {
class CC_EXPORT ClipTree final : public PropertyTree<ClipNode> {
public:
+ bool operator==(const ClipTree& other) const;
+
void SetViewportClip(gfx::RectF viewport_rect);
gfx::RectF ViewportClip();
+
+ void ToProtobuf(proto::PropertyTree* proto) const;
+ void FromProtobuf(const proto::PropertyTree& proto);
};
class CC_EXPORT EffectTree final : public PropertyTree<EffectNode> {
public:
+ bool operator==(const EffectTree& other) const;
+
void UpdateOpacities(int id);
+
+ void ToProtobuf(proto::PropertyTree* proto) const;
+ void FromProtobuf(const proto::PropertyTree& proto);
};
class CC_EXPORT PropertyTrees final {
public:
PropertyTrees();
+ bool operator==(const PropertyTrees& other) const;
+
+ void ToProtobuf(proto::PropertyTrees* proto) const;
+ void FromProtobuf(const proto::PropertyTrees& proto);
+
TransformTree transform_tree;
EffectTree effect_tree;
ClipTree clip_tree;
diff --git a/cc/trees/property_tree_unittest.cc b/cc/trees/property_tree_unittest.cc
index e72a9ad..e9b8c2d 100644
--- a/cc/trees/property_tree_unittest.cc
+++ b/cc/trees/property_tree_unittest.cc
@@ -4,584 +4,977 @@
#include "cc/trees/property_tree.h"
+#include "cc/proto/property_tree.pb.h"
#include "cc/test/geometry_test_utils.h"
#include "cc/trees/draw_property_utils.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace cc {
-
-TEST(PropertyTreeTest, ComputeTransformRoot) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.local.Translate(2, 2);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- gfx::Transform expected;
- gfx::Transform transform;
- bool success = tree.ComputeTransform(0, 0, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.Translate(2, 2);
- success = tree.ComputeTransform(0, -1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(-2, -2);
- success = tree.ComputeTransform(-1, 0, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+namespace {
+
+TEST(PropertyTreeSerializationTest, TransformNodeDataSerialization) {
+ TransformNodeData original;
+ original.pre_local.Translate3d(1.f, 2.f, 3.f);
+ original.local.Translate3d(3.f, 1.f, 5.f);
+ original.post_local.Translate3d(1.f, 8.f, 3.f);
+ original.to_parent.Translate3d(3.2f, 2.f, 3.f);
+ original.to_target.Translate3d(2.6f, 2.f, 3.f);
+ original.from_target.Translate3d(4.3f, 2.f, 3.f);
+ original.to_screen.Translate3d(7.2f, 2.f, 4.5f);
+ original.from_screen.Translate3d(2.f, 2.f, 7.f);
+ original.target_id = 3;
+ original.content_target_id = 4;
+ original.source_node_id = 5;
+ original.needs_local_transform_update = false;
+ original.is_invertible = false;
+ original.ancestors_are_invertible = false;
+ original.is_animated = false;
+ original.to_screen_is_animated = false;
+ original.has_only_translation_animations = false;
+ original.to_screen_has_scale_animation = false;
+ original.flattens_inherited_transform = false;
+ original.node_and_ancestors_are_flat = false;
+ original.node_and_ancestors_have_only_integer_translation = false;
+ original.scrolls = false;
+ original.needs_sublayer_scale = false;
+ original.affected_by_inner_viewport_bounds_delta_x = false;
+ original.affected_by_inner_viewport_bounds_delta_y = false;
+ original.affected_by_outer_viewport_bounds_delta_x = false;
+ original.affected_by_outer_viewport_bounds_delta_y = false;
+ original.in_subtree_of_page_scale_layer = false;
+ original.post_local_scale_factor = 0.5f;
+ original.local_maximum_animation_target_scale = 0.6f;
+ original.local_starting_animation_scale = 0.7f;
+ original.combined_maximum_animation_target_scale = 0.8f;
+ original.combined_starting_animation_scale = 0.9f;
+ original.sublayer_scale = gfx::Vector2dF(0.5f, 0.5f);
+ original.scroll_offset = gfx::ScrollOffset(1.5f, 1.5f);
+ original.scroll_snap = gfx::Vector2dF(0.4f, 0.4f);
+ original.source_offset = gfx::Vector2dF(2.5f, 2.4f);
+ original.source_to_parent = gfx::Vector2dF(3.2f, 3.2f);
+
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ TransformNodeData result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, ComputeTransformChild) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.local.Translate(2, 2);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode child;
- child.data.local.Translate(3, 3);
- child.data.target_id = 0;
- child.data.source_node_id = 0;
-
- tree.Insert(child, 0);
- tree.UpdateTransforms(1);
-
- gfx::Transform expected;
- gfx::Transform transform;
-
- expected.Translate(3, 3);
- bool success = tree.ComputeTransform(1, 0, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(-3, -3);
- success = tree.ComputeTransform(0, 1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(5, 5);
- success = tree.ComputeTransform(1, -1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(-5, -5);
- success = tree.ComputeTransform(-1, 1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-}
+TEST(PropertyTreeSerializationTest, TransformNodeSerialization) {
+ TransformNode original;
+ original.id = 3;
+ original.parent_id = 2;
+ original.owner_id = 4;
-TEST(PropertyTreeTest, ComputeTransformSibling) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.local.Translate(2, 2);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode child;
- child.data.local.Translate(3, 3);
- child.data.source_node_id = 0;
- child.data.target_id = 0;
-
- TransformNode sibling;
- sibling.data.local.Translate(7, 7);
- sibling.data.source_node_id = 0;
- sibling.data.target_id = 0;
-
- tree.Insert(child, 0);
- tree.Insert(sibling, 0);
-
- tree.UpdateTransforms(1);
- tree.UpdateTransforms(2);
-
- gfx::Transform expected;
- gfx::Transform transform;
-
- expected.Translate(4, 4);
- bool success = tree.ComputeTransform(2, 1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(-4, -4);
- success = tree.ComputeTransform(1, 2, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-}
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ TransformNode result;
+ result.FromProtobuf(proto);
-TEST(PropertyTreeTest, ComputeTransformSiblingSingularAncestor) {
- // In this test, we have the following tree:
- // root
- // + singular
- // + child
- // + sibling
- // Since the lowest common ancestor of |child| and |sibling| has a singular
- // transform, we cannot use screen space transforms to compute change of basis
- // transforms between these nodes.
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.local.Translate(2, 2);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode singular;
- singular.data.local.matrix().set(2, 2, 0.0);
- singular.data.source_node_id = 0;
- singular.data.target_id = 0;
-
- TransformNode child;
- child.data.local.Translate(3, 3);
- child.data.source_node_id = 1;
- child.data.target_id = 0;
-
- TransformNode sibling;
- sibling.data.local.Translate(7, 7);
- sibling.data.source_node_id = 1;
- sibling.data.target_id = 0;
-
- tree.Insert(singular, 0);
- tree.Insert(child, 1);
- tree.Insert(sibling, 1);
-
- tree.UpdateTransforms(1);
- tree.UpdateTransforms(2);
- tree.UpdateTransforms(3);
-
- gfx::Transform expected;
- gfx::Transform transform;
-
- expected.Translate(4, 4);
- bool success = tree.ComputeTransform(3, 2, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- transform.MakeIdentity();
- expected.MakeIdentity();
- expected.Translate(-4, -4);
- success = tree.ComputeTransform(2, 3, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, TransformsWithFlattening) {
- TransformTree tree;
-
- int grand_parent = tree.Insert(TransformNode(), 0);
- tree.Node(grand_parent)->data.content_target_id = grand_parent;
- tree.Node(grand_parent)->data.target_id = grand_parent;
- tree.Node(grand_parent)->data.source_node_id = 0;
-
- gfx::Transform rotation_about_x;
- rotation_about_x.RotateAboutXAxis(15);
-
- int parent = tree.Insert(TransformNode(), grand_parent);
- tree.Node(parent)->data.needs_sublayer_scale = true;
- tree.Node(parent)->data.target_id = grand_parent;
- tree.Node(parent)->data.content_target_id = parent;
- tree.Node(parent)->data.source_node_id = grand_parent;
- tree.Node(parent)->data.local = rotation_about_x;
-
- int child = tree.Insert(TransformNode(), parent);
- tree.Node(child)->data.target_id = parent;
- tree.Node(child)->data.content_target_id = parent;
- tree.Node(child)->data.source_node_id = parent;
- tree.Node(child)->data.flattens_inherited_transform = true;
- tree.Node(child)->data.local = rotation_about_x;
-
- int grand_child = tree.Insert(TransformNode(), child);
- tree.Node(grand_child)->data.target_id = parent;
- tree.Node(grand_child)->data.content_target_id = parent;
- tree.Node(grand_child)->data.source_node_id = child;
- tree.Node(grand_child)->data.flattens_inherited_transform = true;
- tree.Node(grand_child)->data.local = rotation_about_x;
-
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
-
- gfx::Transform flattened_rotation_about_x = rotation_about_x;
- flattened_rotation_about_x.FlattenTo2d();
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x,
- tree.Node(child)->data.to_target);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x * rotation_about_x,
- tree.Node(child)->data.to_screen);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x * rotation_about_x,
- tree.Node(grand_child)->data.to_target);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x *
- flattened_rotation_about_x *
- rotation_about_x,
- tree.Node(grand_child)->data.to_screen);
-
- gfx::Transform grand_child_to_child;
- bool success =
- tree.ComputeTransform(grand_child, child, &grand_child_to_child);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
-
- // Remove flattening at grand_child, and recompute transforms.
- tree.Node(grand_child)->data.flattens_inherited_transform = false;
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x * rotation_about_x,
- tree.Node(grand_child)->data.to_target);
-
- EXPECT_TRANSFORMATION_MATRIX_EQ(
- flattened_rotation_about_x * rotation_about_x * rotation_about_x,
- tree.Node(grand_child)->data.to_screen);
-
- success = tree.ComputeTransform(grand_child, child, &grand_child_to_child);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
+TEST(PropertyTreeSerializationTest, TransformTreeSerialization) {
+ TransformTree original;
+ TransformNode& root = *original.Node(0);
+ root.data.target_id = 3;
+ root.data.content_target_id = 4;
+ TransformNode second;
+ second.data.local.Translate3d(2.f, 2.f, 0.f);
+ second.data.source_node_id = 0;
+ second.data.target_id = 0;
+ TransformNode third;
+ third.data.scrolls = true;
+ third.data.source_node_id = 1;
+ third.data.target_id = 0;
+
+ original.Insert(second, 0);
+ original.Insert(third, 1);
+ original.set_needs_update(true);
+
+ original.set_page_scale_factor(0.5f);
+ original.set_device_scale_factor(0.6f);
+ gfx::Transform transform =
+ gfx::Transform(1.05f, 2.15f, 3.14f, 4.13f, 5.12f, 6.11f, 7.1f, 8.9f, 9.8f,
+ 10.7f, 11.6f, 12.5f, 13.4f, 14.3f, 15.2f, 16.1f);
+ original.SetDeviceTransformScaleFactor(transform);
+ original.SetInnerViewportBoundsDelta(gfx::Vector2dF(0.4f, 0.6f));
+ original.SetOuterViewportBoundsDelta(gfx::Vector2dF(0.5f, 0.7f));
+ original.AddNodeAffectedByInnerViewportBoundsDelta(0);
+ original.AddNodeAffectedByOuterViewportBoundsDelta(1);
+
+ proto::PropertyTree proto;
+ original.ToProtobuf(&proto);
+ TransformTree result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, MultiplicationOrder) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.local.Translate(2, 2);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode child;
- child.data.local.Scale(2, 2);
- child.data.target_id = 0;
- child.data.source_node_id = 0;
-
- tree.Insert(child, 0);
- tree.UpdateTransforms(1);
-
- gfx::Transform expected;
- expected.Translate(2, 2);
- expected.Scale(2, 2);
-
- gfx::Transform transform;
- gfx::Transform inverse;
-
- bool success = tree.ComputeTransform(1, -1, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- success = tree.ComputeTransform(-1, 1, &inverse);
- EXPECT_TRUE(success);
-
- transform = transform * inverse;
- expected.MakeIdentity();
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+TEST(PropertyTreeSerializationTest, ClipNodeDataSerialization) {
+ ClipNodeData original;
+ original.clip = gfx::RectF(0.5f, 0.5f);
+ original.combined_clip_in_target_space = gfx::RectF(0.6f, 0.6f);
+ original.clip_in_target_space = gfx::RectF(0.7f, 0.7f);
+ original.transform_id = 2;
+ original.target_id = 3;
+ original.applies_local_clip = false;
+ original.layer_clipping_uses_only_local_clip = false;
+ original.target_is_clipped = false;
+ original.layers_are_clipped = false;
+ original.layers_are_clipped_when_surfaces_disabled = false;
+ original.resets_clip = false;
+
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ ClipNodeData result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, ComputeTransformWithUninvertibleTransform) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode child;
- child.data.local.Scale(0, 0);
- child.data.target_id = 0;
- child.data.source_node_id = 0;
-
- tree.Insert(child, 0);
- tree.UpdateTransforms(1);
-
- gfx::Transform expected;
- expected.Scale(0, 0);
+TEST(PropertyTreeSerializationTest, ClipNodeSerialization) {
+ ClipNode original;
+ original.id = 3;
+ original.parent_id = 2;
+ original.owner_id = 4;
- gfx::Transform transform;
- gfx::Transform inverse;
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ ClipNode result;
+ result.FromProtobuf(proto);
- bool success = tree.ComputeTransform(1, 0, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
-
- // To compute this would require inverting the 0 matrix, so we cannot
- // succeed.
- success = tree.ComputeTransform(0, 1, &inverse);
- EXPECT_FALSE(success);
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, ComputeTransformWithSublayerScale) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode grand_parent;
- grand_parent.data.local.Scale(2.f, 2.f);
- grand_parent.data.target_id = 0;
- grand_parent.data.source_node_id = 0;
- grand_parent.data.needs_sublayer_scale = true;
- int grand_parent_id = tree.Insert(grand_parent, 0);
- tree.UpdateTransforms(grand_parent_id);
-
- TransformNode parent;
- parent.data.local.Translate(15.f, 15.f);
- parent.data.target_id = grand_parent_id;
- parent.data.source_node_id = grand_parent_id;
- int parent_id = tree.Insert(parent, grand_parent_id);
- tree.UpdateTransforms(parent_id);
-
- TransformNode child;
- child.data.local.Scale(3.f, 3.f);
- child.data.target_id = grand_parent_id;
- child.data.source_node_id = parent_id;
- int child_id = tree.Insert(child, parent_id);
- tree.UpdateTransforms(child_id);
-
- TransformNode grand_child;
- grand_child.data.local.Scale(5.f, 5.f);
- grand_child.data.target_id = grand_parent_id;
- grand_child.data.source_node_id = child_id;
- grand_child.data.needs_sublayer_scale = true;
- int grand_child_id = tree.Insert(grand_child, child_id);
- tree.UpdateTransforms(grand_child_id);
-
- EXPECT_EQ(gfx::Vector2dF(2.f, 2.f),
- tree.Node(grand_parent_id)->data.sublayer_scale);
- EXPECT_EQ(gfx::Vector2dF(30.f, 30.f),
- tree.Node(grand_child_id)->data.sublayer_scale);
-
- // Compute transform from grand_parent to grand_child.
- gfx::Transform expected_transform_without_sublayer_scale;
- expected_transform_without_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
- expected_transform_without_sublayer_scale.Translate(-15.f, -15.f);
-
- gfx::Transform expected_transform_with_dest_sublayer_scale;
- expected_transform_with_dest_sublayer_scale.Scale(30.f, 30.f);
- expected_transform_with_dest_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
- expected_transform_with_dest_sublayer_scale.Translate(-15.f, -15.f);
-
- gfx::Transform expected_transform_with_source_sublayer_scale;
- expected_transform_with_source_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
- expected_transform_with_source_sublayer_scale.Translate(-15.f, -15.f);
- expected_transform_with_source_sublayer_scale.Scale(0.5f, 0.5f);
-
- gfx::Transform transform;
- bool success =
- tree.ComputeTransform(grand_parent_id, grand_child_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
- transform);
-
- success = tree.ComputeTransformWithDestinationSublayerScale(
- grand_parent_id, grand_child_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
- transform);
-
- success = tree.ComputeTransformWithSourceSublayerScale(
- grand_parent_id, grand_child_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale,
- transform);
-
- // Now compute transform from grand_child to grand_parent.
- expected_transform_without_sublayer_scale.MakeIdentity();
- expected_transform_without_sublayer_scale.Translate(15.f, 15.f);
- expected_transform_without_sublayer_scale.Scale(15.f, 15.f);
-
- expected_transform_with_dest_sublayer_scale.MakeIdentity();
- expected_transform_with_dest_sublayer_scale.Scale(2.f, 2.f);
- expected_transform_with_dest_sublayer_scale.Translate(15.f, 15.f);
- expected_transform_with_dest_sublayer_scale.Scale(15.f, 15.f);
-
- expected_transform_with_source_sublayer_scale.MakeIdentity();
- expected_transform_with_source_sublayer_scale.Translate(15.f, 15.f);
- expected_transform_with_source_sublayer_scale.Scale(15.f, 15.f);
- expected_transform_with_source_sublayer_scale.Scale(1.f / 30.f, 1.f / 30.f);
-
- success = tree.ComputeTransform(grand_child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
- transform);
-
- success = tree.ComputeTransformWithDestinationSublayerScale(
- grand_child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
- transform);
-
- success = tree.ComputeTransformWithSourceSublayerScale(
- grand_child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_source_sublayer_scale,
- transform);
+TEST(PropertyTreeSerializationTest, ClipTreeSerialization) {
+ ClipTree original;
+ ClipNode& root = *original.Node(0);
+ root.data.transform_id = 2;
+ root.data.target_id = 1;
+ ClipNode second;
+ second.data.transform_id = 4;
+ second.data.applies_local_clip = true;
+ ClipNode third;
+ third.data.target_id = 3;
+ third.data.target_is_clipped = false;
+
+ original.Insert(second, 0);
+ original.Insert(third, 1);
+ original.set_needs_update(true);
+
+ proto::PropertyTree proto;
+ original.ToProtobuf(&proto);
+ ClipTree result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, ComputeTransformToTargetWithZeroSublayerScale) {
- TransformTree tree;
- TransformNode& root = *tree.Node(0);
- root.data.target_id = 0;
- tree.UpdateTransforms(0);
-
- TransformNode grand_parent;
- grand_parent.data.local.Scale(2.f, 0.f);
- grand_parent.data.target_id = 0;
- grand_parent.data.source_node_id = 0;
- grand_parent.data.needs_sublayer_scale = true;
- int grand_parent_id = tree.Insert(grand_parent, 0);
- tree.Node(grand_parent_id)->data.content_target_id = grand_parent_id;
- tree.UpdateTransforms(grand_parent_id);
-
- TransformNode parent;
- parent.data.local.Translate(1.f, 1.f);
- parent.data.target_id = grand_parent_id;
- parent.data.content_target_id = grand_parent_id;
- parent.data.source_node_id = grand_parent_id;
- int parent_id = tree.Insert(parent, grand_parent_id);
- tree.UpdateTransforms(parent_id);
-
- TransformNode child;
- child.data.local.Translate(3.f, 4.f);
- child.data.target_id = grand_parent_id;
- child.data.content_target_id = grand_parent_id;
- child.data.source_node_id = parent_id;
- int child_id = tree.Insert(child, parent_id);
- tree.UpdateTransforms(child_id);
-
- gfx::Transform expected_transform;
- expected_transform.Translate(4.f, 5.f);
-
- gfx::Transform transform;
- bool success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
-
- tree.Node(grand_parent_id)->data.local.MakeIdentity();
- tree.Node(grand_parent_id)->data.local.Scale(0.f, 2.f);
- tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
- tree.set_needs_update(true);
-
- ComputeTransforms(&tree);
-
- success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
-
- tree.Node(grand_parent_id)->data.local.MakeIdentity();
- tree.Node(grand_parent_id)->data.local.Scale(0.f, 0.f);
- tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
- tree.set_needs_update(true);
-
- ComputeTransforms(&tree);
-
- success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
-}
+TEST(PropertyTreeSerializationTest, EffectNodeDataSerialization) {
+ EffectNodeData original;
+ original.opacity = 0.5f;
+ original.screen_space_opacity = 0.6f;
+ original.has_render_surface = false;
+ original.transform_id = 2;
+ original.clip_id = 3;
-TEST(PropertyTreeTest, FlatteningWhenDestinationHasOnlyFlatAncestors) {
- // This tests that flattening is performed correctly when
- // destination and its ancestors are flat, but there are 3d transforms
- // and flattening between the source and destination.
- TransformTree tree;
-
- int parent = tree.Insert(TransformNode(), 0);
- tree.Node(parent)->data.content_target_id = parent;
- tree.Node(parent)->data.target_id = parent;
- tree.Node(parent)->data.source_node_id = 0;
- tree.Node(parent)->data.local.Translate(2, 2);
-
- gfx::Transform rotation_about_x;
- rotation_about_x.RotateAboutXAxis(15);
-
- int child = tree.Insert(TransformNode(), parent);
- tree.Node(child)->data.content_target_id = child;
- tree.Node(child)->data.target_id = child;
- tree.Node(child)->data.source_node_id = parent;
- tree.Node(child)->data.local = rotation_about_x;
-
-
- int grand_child = tree.Insert(TransformNode(), child);
- tree.Node(grand_child)->data.content_target_id = grand_child;
- tree.Node(grand_child)->data.target_id = grand_child;
- tree.Node(grand_child)->data.source_node_id = child;
- tree.Node(grand_child)->data.flattens_inherited_transform = true;
-
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
-
- gfx::Transform flattened_rotation_about_x = rotation_about_x;
- flattened_rotation_about_x.FlattenTo2d();
-
- gfx::Transform grand_child_to_parent;
- bool success =
- tree.ComputeTransform(grand_child, parent, &grand_child_to_parent);
- EXPECT_TRUE(success);
- EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x,
- grand_child_to_parent);
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ EffectNodeData result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, ScreenSpaceOpacityUpdateTest) {
- // This tests that screen space opacity is updated for the subtree when
- // opacity of a node changes.
- EffectTree tree;
+TEST(PropertyTreeSerializationTest, EffectNodeSerialization) {
+ EffectNode original;
+ original.id = 3;
+ original.parent_id = 2;
+ original.owner_id = 4;
- int parent = tree.Insert(EffectNode(), 0);
- int child = tree.Insert(EffectNode(), parent);
+ proto::TreeNode proto;
+ original.ToProtobuf(&proto);
+ EffectNode result;
+ result.FromProtobuf(proto);
- EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 1.f);
- tree.Node(parent)->data.opacity = 0.5f;
- tree.set_needs_update(true);
- ComputeOpacities(&tree);
- EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.5f);
+ EXPECT_EQ(original, result);
+}
- tree.Node(child)->data.opacity = 0.5f;
- tree.set_needs_update(true);
- ComputeOpacities(&tree);
- EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.25f);
+TEST(PropertyTreeSerializationTest, EffectTreeSerialization) {
+ EffectTree original;
+ EffectNode& root = *original.Node(0);
+ root.data.transform_id = 2;
+ root.data.clip_id = 1;
+ EffectNode second;
+ second.data.transform_id = 4;
+ second.data.opacity = true;
+ EffectNode third;
+ third.data.clip_id = 3;
+ third.data.has_render_surface = false;
+
+ original.Insert(second, 0);
+ original.Insert(third, 1);
+ original.set_needs_update(true);
+
+ proto::PropertyTree proto;
+ original.ToProtobuf(&proto);
+ EffectTree result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
-TEST(PropertyTreeTest, NonIntegerTranslationTest) {
- // This tests that when a node has non-integer translation, the information
- // is propagated to the subtree.
- TransformTree tree;
-
- int parent = tree.Insert(TransformNode(), 0);
- tree.Node(parent)->data.target_id = parent;
- tree.Node(parent)->data.local.Translate(1.5f, 1.5f);
-
- int child = tree.Insert(TransformNode(), parent);
- tree.Node(child)->data.target_id = parent;
- tree.Node(child)->data.local.Translate(1, 1);
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
- EXPECT_FALSE(
- tree.Node(parent)->data.node_and_ancestors_have_only_integer_translation);
- EXPECT_FALSE(
- tree.Node(child)->data.node_and_ancestors_have_only_integer_translation);
-
- tree.Node(parent)->data.local.Translate(0.5f, 0.5f);
- tree.Node(child)->data.local.Translate(0.5f, 0.5f);
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
- EXPECT_TRUE(
- tree.Node(parent)->data.node_and_ancestors_have_only_integer_translation);
- EXPECT_FALSE(
- tree.Node(child)->data.node_and_ancestors_have_only_integer_translation);
-
- tree.Node(child)->data.local.Translate(0.5f, 0.5f);
- tree.Node(child)->data.target_id = child;
- tree.set_needs_update(true);
- ComputeTransforms(&tree);
- EXPECT_TRUE(
- tree.Node(parent)->data.node_and_ancestors_have_only_integer_translation);
- EXPECT_TRUE(
- tree.Node(child)->data.node_and_ancestors_have_only_integer_translation);
+TEST(PropertyTreeSerializationTest, PropertyTrees) {
+ PropertyTrees original;
+ original.transform_tree.Insert(TransformNode(), 0);
+ original.transform_tree.Insert(TransformNode(), 1);
+ original.clip_tree.Insert(ClipNode(), 0);
+ original.clip_tree.Insert(ClipNode(), 1);
+ original.effect_tree.Insert(EffectNode(), 0);
+ original.effect_tree.Insert(EffectNode(), 1);
+ original.needs_rebuild = false;
+ original.non_root_surfaces_enabled = false;
+ original.sequence_number = 3;
+
+ proto::PropertyTrees proto;
+ original.ToProtobuf(&proto);
+ PropertyTrees result;
+ result.FromProtobuf(proto);
+
+ EXPECT_EQ(original, result);
}
+class PropertyTreeTest : public testing::Test {
+ public:
+ PropertyTreeTest() : test_serialization_(false) {}
+
+ protected:
+ void RunTest(bool test_serialization) {
+ test_serialization_ = test_serialization;
+ StartTest();
+ }
+
+ virtual void StartTest() = 0;
+
+ TransformTree TransformTreeForTest(const TransformTree& transform_tree) {
+ if (!test_serialization_) {
+ return transform_tree;
+ }
+ TransformTree new_tree;
+ proto::PropertyTree proto;
+ transform_tree.ToProtobuf(&proto);
+ new_tree.FromProtobuf(proto);
+
+ EXPECT_EQ(transform_tree, new_tree);
+ return new_tree;
+ }
+
+ EffectTree EffectTreeForTest(const EffectTree& effect_tree) {
+ if (!test_serialization_) {
+ return effect_tree;
+ }
+ EffectTree new_tree;
+ proto::PropertyTree proto;
+ effect_tree.ToProtobuf(&proto);
+ new_tree.FromProtobuf(proto);
+
+ EXPECT_EQ(effect_tree, new_tree);
+ return new_tree;
+ }
+
+ private:
+ bool test_serialization_;
+};
+
+#define DIRECT_PROPERTY_TREE_TEST_F(TEST_FIXTURE_NAME) \
+ TEST_F(TEST_FIXTURE_NAME, RunDirect) { RunTest(false); }
+
+#define SERIALIZED_PROPERTY_TREE_TEST_F(TEST_FIXTURE_NAME) \
+ TEST_F(TEST_FIXTURE_NAME, RunSerialized) { RunTest(true); }
+
+#define DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(TEST_FIXTURE_NAME) \
+ DIRECT_PROPERTY_TREE_TEST_F(TEST_FIXTURE_NAME); \
+ SERIALIZED_PROPERTY_TREE_TEST_F(TEST_FIXTURE_NAME)
+
+class PropertyTreeTestComputeTransformRoot : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(0);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+ bool success = tree.ComputeTransform(0, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.Translate(2, 2);
+ success = tree.ComputeTransform(0, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-2, -2);
+ success = tree.ComputeTransform(-1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformRoot);
+
+class PropertyTreeTestComputeTransformChild : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(3, 3);
+ bool success = tree.ComputeTransform(1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-3, -3);
+ success = tree.ComputeTransform(0, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(5, 5);
+ success = tree.ComputeTransform(1, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-5, -5);
+ success = tree.ComputeTransform(-1, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformChild);
+
+class PropertyTreeTestComputeTransformSibling : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.source_node_id = 0;
+ child.data.target_id = 0;
+
+ TransformNode sibling;
+ sibling.data.local.Translate(7, 7);
+ sibling.data.source_node_id = 0;
+ sibling.data.target_id = 0;
+
+ tree.Insert(child, 0);
+ tree.Insert(sibling, 0);
+
+ tree = TransformTreeForTest(tree);
+
+ tree.UpdateTransforms(1);
+ tree.UpdateTransforms(2);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(4, 4);
+ bool success = tree.ComputeTransform(2, 1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-4, -4);
+ success = tree.ComputeTransform(1, 2, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformSibling);
+
+class PropertyTreeTestComputeTransformSiblingSingularAncestor
+ : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ // In this test, we have the following tree:
+ // root
+ // + singular
+ // + child
+ // + sibling
+ // Since the lowest common ancestor of |child| and |sibling| has a singular
+ // transform, we cannot use screen space transforms to compute change of
+ // basis
+ // transforms between these nodes.
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode singular;
+ singular.data.local.matrix().set(2, 2, 0.0);
+ singular.data.source_node_id = 0;
+ singular.data.target_id = 0;
+
+ TransformNode child;
+ child.data.local.Translate(3, 3);
+ child.data.source_node_id = 1;
+ child.data.target_id = 0;
+
+ TransformNode sibling;
+ sibling.data.local.Translate(7, 7);
+ sibling.data.source_node_id = 1;
+ sibling.data.target_id = 0;
+
+ tree.Insert(singular, 0);
+ tree.Insert(child, 1);
+ tree.Insert(sibling, 1);
+
+ tree = TransformTreeForTest(tree);
+
+ tree.UpdateTransforms(1);
+ tree.UpdateTransforms(2);
+ tree.UpdateTransforms(3);
+
+ gfx::Transform expected;
+ gfx::Transform transform;
+
+ expected.Translate(4, 4);
+ bool success = tree.ComputeTransform(3, 2, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ transform.MakeIdentity();
+ expected.MakeIdentity();
+ expected.Translate(-4, -4);
+ success = tree.ComputeTransform(2, 3, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformSiblingSingularAncestor);
+
+class PropertyTreeTestTransformsWithFlattening : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+
+ int grand_parent = tree.Insert(TransformNode(), 0);
+ tree.Node(grand_parent)->data.content_target_id = grand_parent;
+ tree.Node(grand_parent)->data.target_id = grand_parent;
+ tree.Node(grand_parent)->data.source_node_id = 0;
+
+ gfx::Transform rotation_about_x;
+ rotation_about_x.RotateAboutXAxis(15);
+
+ int parent = tree.Insert(TransformNode(), grand_parent);
+ tree.Node(parent)->data.needs_sublayer_scale = true;
+ tree.Node(parent)->data.target_id = grand_parent;
+ tree.Node(parent)->data.content_target_id = parent;
+ tree.Node(parent)->data.source_node_id = grand_parent;
+ tree.Node(parent)->data.local = rotation_about_x;
+
+ int child = tree.Insert(TransformNode(), parent);
+ tree.Node(child)->data.target_id = parent;
+ tree.Node(child)->data.content_target_id = parent;
+ tree.Node(child)->data.source_node_id = parent;
+ tree.Node(child)->data.flattens_inherited_transform = true;
+ tree.Node(child)->data.local = rotation_about_x;
+
+ int grand_child = tree.Insert(TransformNode(), child);
+ tree.Node(grand_child)->data.target_id = parent;
+ tree.Node(grand_child)->data.content_target_id = parent;
+ tree.Node(grand_child)->data.source_node_id = child;
+ tree.Node(grand_child)->data.flattens_inherited_transform = true;
+ tree.Node(grand_child)->data.local = rotation_about_x;
+
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+
+ gfx::Transform flattened_rotation_about_x = rotation_about_x;
+ flattened_rotation_about_x.FlattenTo2d();
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x,
+ tree.Node(child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ flattened_rotation_about_x * rotation_about_x,
+ tree.Node(child)->data.to_screen);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ flattened_rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x *
+ flattened_rotation_about_x *
+ rotation_about_x,
+ tree.Node(grand_child)->data.to_screen);
+
+ gfx::Transform grand_child_to_child;
+ bool success =
+ tree.ComputeTransform(grand_child, child, &grand_child_to_child);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
+
+ // Remove flattening at grand_child, and recompute transforms.
+ tree.Node(grand_child)->data.flattens_inherited_transform = false;
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_target);
+
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ flattened_rotation_about_x * rotation_about_x * rotation_about_x,
+ tree.Node(grand_child)->data.to_screen);
+
+ success = tree.ComputeTransform(grand_child, child, &grand_child_to_child);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(rotation_about_x, grand_child_to_child);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestTransformsWithFlattening);
+
+class PropertyTreeTestMultiplicationOrder : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.local.Translate(2, 2);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Scale(2, 2);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ expected.Translate(2, 2);
+ expected.Scale(2, 2);
+
+ gfx::Transform transform;
+ gfx::Transform inverse;
+
+ bool success = tree.ComputeTransform(1, -1, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ success = tree.ComputeTransform(-1, 1, &inverse);
+ EXPECT_TRUE(success);
+
+ transform = transform * inverse;
+ expected.MakeIdentity();
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(PropertyTreeTestMultiplicationOrder);
+
+class PropertyTreeTestComputeTransformWithUninvertibleTransform
+ : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode child;
+ child.data.local.Scale(0, 0);
+ child.data.target_id = 0;
+ child.data.source_node_id = 0;
+
+ tree.Insert(child, 0);
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(1);
+
+ gfx::Transform expected;
+ expected.Scale(0, 0);
+
+ gfx::Transform transform;
+ gfx::Transform inverse;
+
+ bool success = tree.ComputeTransform(1, 0, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected, transform);
+
+ // To compute this would require inverting the 0 matrix, so we cannot
+ // succeed.
+ success = tree.ComputeTransform(0, 1, &inverse);
+ EXPECT_FALSE(success);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformWithUninvertibleTransform);
+
+class PropertyTreeTestComputeTransformWithSublayerScale
+ : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode grand_parent;
+ grand_parent.data.local.Scale(2.f, 2.f);
+ grand_parent.data.target_id = 0;
+ grand_parent.data.source_node_id = 0;
+ grand_parent.data.needs_sublayer_scale = true;
+ int grand_parent_id = tree.Insert(grand_parent, 0);
+ tree.UpdateTransforms(grand_parent_id);
+
+ TransformNode parent;
+ parent.data.local.Translate(15.f, 15.f);
+ parent.data.target_id = grand_parent_id;
+ parent.data.source_node_id = grand_parent_id;
+ int parent_id = tree.Insert(parent, grand_parent_id);
+ tree.UpdateTransforms(parent_id);
+
+ TransformNode child;
+ child.data.local.Scale(3.f, 3.f);
+ child.data.target_id = grand_parent_id;
+ child.data.source_node_id = parent_id;
+ int child_id = tree.Insert(child, parent_id);
+ tree.UpdateTransforms(child_id);
+
+ TransformNode grand_child;
+ grand_child.data.local.Scale(5.f, 5.f);
+ grand_child.data.target_id = grand_parent_id;
+ grand_child.data.source_node_id = child_id;
+ grand_child.data.needs_sublayer_scale = true;
+ int grand_child_id = tree.Insert(grand_child, child_id);
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(grand_child_id);
+
+ EXPECT_EQ(gfx::Vector2dF(2.f, 2.f),
+ tree.Node(grand_parent_id)->data.sublayer_scale);
+ EXPECT_EQ(gfx::Vector2dF(30.f, 30.f),
+ tree.Node(grand_child_id)->data.sublayer_scale);
+
+ // Compute transform from grand_parent to grand_child.
+ gfx::Transform expected_transform_without_sublayer_scale;
+ expected_transform_without_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_without_sublayer_scale.Translate(-15.f, -15.f);
+
+ gfx::Transform expected_transform_with_dest_sublayer_scale;
+ expected_transform_with_dest_sublayer_scale.Scale(30.f, 30.f);
+ expected_transform_with_dest_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_with_dest_sublayer_scale.Translate(-15.f, -15.f);
+
+ gfx::Transform expected_transform_with_source_sublayer_scale;
+ expected_transform_with_source_sublayer_scale.Scale(1.f / 15.f, 1.f / 15.f);
+ expected_transform_with_source_sublayer_scale.Translate(-15.f, -15.f);
+ expected_transform_with_source_sublayer_scale.Scale(0.5f, 0.5f);
+
+ gfx::Transform transform;
+ bool success =
+ tree.ComputeTransform(grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithDestinationSublayerScale(
+ grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithSourceSublayerScale(
+ grand_parent_id, grand_child_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ expected_transform_with_source_sublayer_scale, transform);
+
+ // Now compute transform from grand_child to grand_parent.
+ expected_transform_without_sublayer_scale.MakeIdentity();
+ expected_transform_without_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_without_sublayer_scale.Scale(15.f, 15.f);
+
+ expected_transform_with_dest_sublayer_scale.MakeIdentity();
+ expected_transform_with_dest_sublayer_scale.Scale(2.f, 2.f);
+ expected_transform_with_dest_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_with_dest_sublayer_scale.Scale(15.f, 15.f);
+
+ expected_transform_with_source_sublayer_scale.MakeIdentity();
+ expected_transform_with_source_sublayer_scale.Translate(15.f, 15.f);
+ expected_transform_with_source_sublayer_scale.Scale(15.f, 15.f);
+ expected_transform_with_source_sublayer_scale.Scale(1.f / 30.f, 1.f / 30.f);
+
+ success =
+ tree.ComputeTransform(grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_without_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithDestinationSublayerScale(
+ grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform_with_dest_sublayer_scale,
+ transform);
+
+ success = tree.ComputeTransformWithSourceSublayerScale(
+ grand_child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(
+ expected_transform_with_source_sublayer_scale, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformWithSublayerScale);
+
+class PropertyTreeTestComputeTransformToTargetWithZeroSublayerScale
+ : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ TransformTree tree;
+ TransformNode& root = *tree.Node(0);
+ root.data.target_id = 0;
+ tree.UpdateTransforms(0);
+
+ TransformNode grand_parent;
+ grand_parent.data.local.Scale(2.f, 0.f);
+ grand_parent.data.target_id = 0;
+ grand_parent.data.source_node_id = 0;
+ grand_parent.data.needs_sublayer_scale = true;
+ int grand_parent_id = tree.Insert(grand_parent, 0);
+ tree.Node(grand_parent_id)->data.content_target_id = grand_parent_id;
+ tree.UpdateTransforms(grand_parent_id);
+
+ TransformNode parent;
+ parent.data.local.Translate(1.f, 1.f);
+ parent.data.target_id = grand_parent_id;
+ parent.data.content_target_id = grand_parent_id;
+ parent.data.source_node_id = grand_parent_id;
+ int parent_id = tree.Insert(parent, grand_parent_id);
+ tree.UpdateTransforms(parent_id);
+
+ TransformNode child;
+ child.data.local.Translate(3.f, 4.f);
+ child.data.target_id = grand_parent_id;
+ child.data.content_target_id = grand_parent_id;
+ child.data.source_node_id = parent_id;
+ int child_id = tree.Insert(child, parent_id);
+ tree = TransformTreeForTest(tree);
+ tree.UpdateTransforms(child_id);
+
+ gfx::Transform expected_transform;
+ expected_transform.Translate(4.f, 5.f);
+
+ gfx::Transform transform;
+ bool success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
+
+ tree.Node(grand_parent_id)->data.local.MakeIdentity();
+ tree.Node(grand_parent_id)->data.local.Scale(0.f, 2.f);
+ tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+
+ ComputeTransforms(&tree);
+
+ success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
+
+ tree.Node(grand_parent_id)->data.local.MakeIdentity();
+ tree.Node(grand_parent_id)->data.local.Scale(0.f, 0.f);
+ tree.Node(grand_parent_id)->data.needs_local_transform_update = true;
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+
+ ComputeTransforms(&tree);
+
+ success = tree.ComputeTransform(child_id, grand_parent_id, &transform);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(expected_transform, transform);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestComputeTransformToTargetWithZeroSublayerScale);
+
+class PropertyTreeTestFlatteningWhenDestinationHasOnlyFlatAncestors
+ : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ // This tests that flattening is performed correctly when
+ // destination and its ancestors are flat, but there are 3d transforms
+ // and flattening between the source and destination.
+ TransformTree tree;
+
+ int parent = tree.Insert(TransformNode(), 0);
+ tree.Node(parent)->data.content_target_id = parent;
+ tree.Node(parent)->data.target_id = parent;
+ tree.Node(parent)->data.source_node_id = 0;
+ tree.Node(parent)->data.local.Translate(2, 2);
+
+ gfx::Transform rotation_about_x;
+ rotation_about_x.RotateAboutXAxis(15);
+
+ int child = tree.Insert(TransformNode(), parent);
+ tree.Node(child)->data.content_target_id = child;
+ tree.Node(child)->data.target_id = child;
+ tree.Node(child)->data.source_node_id = parent;
+ tree.Node(child)->data.local = rotation_about_x;
+
+ int grand_child = tree.Insert(TransformNode(), child);
+ tree.Node(grand_child)->data.content_target_id = grand_child;
+ tree.Node(grand_child)->data.target_id = grand_child;
+ tree.Node(grand_child)->data.source_node_id = child;
+ tree.Node(grand_child)->data.flattens_inherited_transform = true;
+
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+
+ gfx::Transform flattened_rotation_about_x = rotation_about_x;
+ flattened_rotation_about_x.FlattenTo2d();
+
+ gfx::Transform grand_child_to_parent;
+ bool success =
+ tree.ComputeTransform(grand_child, parent, &grand_child_to_parent);
+ EXPECT_TRUE(success);
+ EXPECT_TRANSFORMATION_MATRIX_EQ(flattened_rotation_about_x,
+ grand_child_to_parent);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestFlatteningWhenDestinationHasOnlyFlatAncestors);
+
+class PropertyTreeTestScreenSpaceOpacityUpdateTest : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ // This tests that screen space opacity is updated for the subtree when
+ // opacity of a node changes.
+ EffectTree tree;
+
+ int parent = tree.Insert(EffectNode(), 0);
+ int child = tree.Insert(EffectNode(), parent);
+ tree = EffectTreeForTest(tree);
+
+ EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 1.f);
+ tree.Node(parent)->data.opacity = 0.5f;
+ tree.set_needs_update(true);
+ tree = EffectTreeForTest(tree);
+ ComputeOpacities(&tree);
+ EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.5f);
+
+ tree.Node(child)->data.opacity = 0.5f;
+ tree.set_needs_update(true);
+ tree = EffectTreeForTest(tree);
+ ComputeOpacities(&tree);
+ EXPECT_EQ(tree.Node(child)->data.screen_space_opacity, 0.25f);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestScreenSpaceOpacityUpdateTest);
+
+class PropertyTreeTestNonIntegerTranslationTest : public PropertyTreeTest {
+ protected:
+ void StartTest() override {
+ // This tests that when a node has non-integer translation, the information
+ // is propagated to the subtree.
+ TransformTree tree;
+
+ int parent = tree.Insert(TransformNode(), 0);
+ tree.Node(parent)->data.target_id = parent;
+ tree.Node(parent)->data.local.Translate(1.5f, 1.5f);
+
+ int child = tree.Insert(TransformNode(), parent);
+ tree.Node(child)->data.target_id = parent;
+ tree.Node(child)->data.local.Translate(1, 1);
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+ EXPECT_FALSE(tree.Node(parent)
+ ->data.node_and_ancestors_have_only_integer_translation);
+ EXPECT_FALSE(tree.Node(child)
+ ->data.node_and_ancestors_have_only_integer_translation);
+
+ tree.Node(parent)->data.local.Translate(0.5f, 0.5f);
+ tree.Node(child)->data.local.Translate(0.5f, 0.5f);
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+ EXPECT_TRUE(tree.Node(parent)
+ ->data.node_and_ancestors_have_only_integer_translation);
+ EXPECT_FALSE(tree.Node(child)
+ ->data.node_and_ancestors_have_only_integer_translation);
+
+ tree.Node(child)->data.local.Translate(0.5f, 0.5f);
+ tree.Node(child)->data.target_id = child;
+ tree.set_needs_update(true);
+ tree = TransformTreeForTest(tree);
+ ComputeTransforms(&tree);
+ EXPECT_TRUE(tree.Node(parent)
+ ->data.node_and_ancestors_have_only_integer_translation);
+ EXPECT_TRUE(tree.Node(child)
+ ->data.node_and_ancestors_have_only_integer_translation);
+ }
+};
+
+DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F(
+ PropertyTreeTestNonIntegerTranslationTest);
+
+#undef DIRECT_AND_SERIALIZED_PROPERTY_TREE_TEST_F
+#undef SERIALIZED_PROPERTY_TREE_TEST_F
+#undef DIRECT_PROPERTY_TREE_TEST_F
+
+} // namespace
} // namespace cc