Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(152)

Side by Side Diff: cc/trees/property_tree.cc

Issue 2251303003: Implement position: sticky updates on compositor (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Merge with master and add comments to WebLayerStickyPositionConstraint members. Created 4 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/trees/property_tree.h ('k') | cc/trees/property_tree_builder.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include <stddef.h> 5 #include <stddef.h>
6 6
7 #include <set> 7 #include <set>
8 #include <vector> 8 #include <vector>
9 9
10 #include "base/logging.h" 10 #include "base/logging.h"
11 #include "base/memory/ptr_util.h" 11 #include "base/memory/ptr_util.h"
12 #include "base/trace_event/trace_event_argument.h" 12 #include "base/trace_event/trace_event_argument.h"
13 #include "cc/animation/animation_host.h" 13 #include "cc/animation/animation_host.h"
14 #include "cc/layers/layer_impl.h" 14 #include "cc/layers/layer_impl.h"
15 #include "cc/output/copy_output_request.h" 15 #include "cc/output/copy_output_request.h"
16 #include "cc/proto/gfx_conversions.h"
16 #include "cc/proto/property_tree.pb.h" 17 #include "cc/proto/property_tree.pb.h"
17 #include "cc/proto/synced_property_conversions.h" 18 #include "cc/proto/synced_property_conversions.h"
18 #include "cc/trees/clip_node.h" 19 #include "cc/trees/clip_node.h"
19 #include "cc/trees/effect_node.h" 20 #include "cc/trees/effect_node.h"
20 #include "cc/trees/layer_tree_host_common.h" 21 #include "cc/trees/layer_tree_host_common.h"
21 #include "cc/trees/layer_tree_impl.h" 22 #include "cc/trees/layer_tree_impl.h"
22 #include "cc/trees/property_tree.h" 23 #include "cc/trees/property_tree.h"
23 #include "cc/trees/scroll_node.h" 24 #include "cc/trees/scroll_node.h"
24 #include "cc/trees/transform_node.h" 25 #include "cc/trees/transform_node.h"
25 #include "ui/gfx/geometry/vector2d_conversions.h" 26 #include "ui/gfx/geometry/vector2d_conversions.h"
26
27 namespace cc { 27 namespace cc {
28 28
29 template <typename T> 29 template <typename T>
30 PropertyTree<T>::PropertyTree() 30 PropertyTree<T>::PropertyTree()
31 : needs_update_(false) { 31 : needs_update_(false) {
32 nodes_.push_back(T()); 32 nodes_.push_back(T());
33 back()->id = kRootNodeId; 33 back()->id = kRootNodeId;
34 back()->parent_id = kInvalidNodeId; 34 back()->parent_id = kInvalidNodeId;
35 } 35 }
36 36
(...skipping 87 matching lines...) Expand 10 before | Expand all | Expand 10 after
124 value->EndDictionary(); 124 value->EndDictionary();
125 } 125 }
126 value->EndArray(); 126 value->EndArray();
127 } 127 }
128 128
129 template class PropertyTree<TransformNode>; 129 template class PropertyTree<TransformNode>;
130 template class PropertyTree<ClipNode>; 130 template class PropertyTree<ClipNode>;
131 template class PropertyTree<EffectNode>; 131 template class PropertyTree<EffectNode>;
132 template class PropertyTree<ScrollNode>; 132 template class PropertyTree<ScrollNode>;
133 133
134 void StickyPositionNodeData::ToProtobuf(
135 proto::StickyPositionNodeData* proto) const {
136 proto->set_scroll_ancestor(scroll_ancestor);
137 constraints.ToProtobuf(proto->mutable_constraints());
138 Vector2dFToProto(main_thread_offset, proto->mutable_main_thread_offset());
139 }
140
141 void StickyPositionNodeData::FromProtobuf(
142 const proto::StickyPositionNodeData& proto) {
143 scroll_ancestor = proto.scroll_ancestor();
144 constraints.FromProtobuf(proto.constraints());
145 main_thread_offset = ProtoToVector2dF(proto.main_thread_offset());
146 }
147
134 int TransformTree::Insert(const TransformNode& tree_node, int parent_id) { 148 int TransformTree::Insert(const TransformNode& tree_node, int parent_id) {
135 int node_id = PropertyTree<TransformNode>::Insert(tree_node, parent_id); 149 int node_id = PropertyTree<TransformNode>::Insert(tree_node, parent_id);
136 DCHECK_EQ(node_id, static_cast<int>(cached_data_.size())); 150 DCHECK_EQ(node_id, static_cast<int>(cached_data_.size()));
137 151
138 cached_data_.push_back(TransformCachedNodeData()); 152 cached_data_.push_back(TransformCachedNodeData());
139 return node_id; 153 return node_id;
140 } 154 }
141 155
142 void TransformTree::clear() { 156 void TransformTree::clear() {
143 PropertyTree<TransformNode>::clear(); 157 PropertyTree<TransformNode>::clear();
144 158
145 page_scale_factor_ = 1.f; 159 page_scale_factor_ = 1.f;
146 device_scale_factor_ = 1.f; 160 device_scale_factor_ = 1.f;
147 device_transform_scale_factor_ = 1.f; 161 device_transform_scale_factor_ = 1.f;
148 nodes_affected_by_inner_viewport_bounds_delta_.clear(); 162 nodes_affected_by_inner_viewport_bounds_delta_.clear();
149 nodes_affected_by_outer_viewport_bounds_delta_.clear(); 163 nodes_affected_by_outer_viewport_bounds_delta_.clear();
150 cached_data_.clear(); 164 cached_data_.clear();
151 cached_data_.push_back(TransformCachedNodeData()); 165 cached_data_.push_back(TransformCachedNodeData());
166 sticky_position_data_.clear();
152 167
153 #if DCHECK_IS_ON() 168 #if DCHECK_IS_ON()
154 TransformTree tree; 169 TransformTree tree;
155 // TODO(jaydasika) : Move tests that expect source_to_parent_updates_allowed 170 // TODO(jaydasika) : Move tests that expect source_to_parent_updates_allowed
156 // to be true on impl thread to main thread and set it to is_main_thread here. 171 // to be true on impl thread to main thread and set it to is_main_thread here.
157 tree.source_to_parent_updates_allowed_ = source_to_parent_updates_allowed_; 172 tree.source_to_parent_updates_allowed_ = source_to_parent_updates_allowed_;
158 DCHECK(tree == *this); 173 DCHECK(tree == *this);
159 #endif 174 #endif
160 } 175 }
161 176
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
243 node->transform_changed = false; 258 node->transform_changed = false;
244 } 259 }
245 } 260 }
246 261
247 void TransformTree::UpdateTransforms(int id) { 262 void TransformTree::UpdateTransforms(int id) {
248 TransformNode* node = Node(id); 263 TransformNode* node = Node(id);
249 TransformNode* parent_node = parent(node); 264 TransformNode* parent_node = parent(node);
250 TransformNode* target_node = Node(TargetId(id)); 265 TransformNode* target_node = Node(TargetId(id));
251 TransformNode* source_node = Node(node->source_node_id); 266 TransformNode* source_node = Node(node->source_node_id);
252 property_trees()->UpdateCachedNumber(); 267 property_trees()->UpdateCachedNumber();
253 if (node->needs_local_transform_update || NeedsSourceToParentUpdate(node)) 268 // TODO(flackr): Only dirty when scroll offset changes.
269 if (node->sticky_position_constraint_id >= 0 ||
270 node->needs_local_transform_update || NeedsSourceToParentUpdate(node)) {
254 UpdateLocalTransform(node); 271 UpdateLocalTransform(node);
255 else 272 } else {
256 UndoSnapping(node); 273 UndoSnapping(node);
274 }
257 UpdateScreenSpaceTransform(node, parent_node, target_node); 275 UpdateScreenSpaceTransform(node, parent_node, target_node);
258 UpdateSurfaceContentsScale(node); 276 UpdateSurfaceContentsScale(node);
259 UpdateAnimationProperties(node, parent_node); 277 UpdateAnimationProperties(node, parent_node);
260 UpdateSnapping(node); 278 UpdateSnapping(node);
261 UpdateTargetSpaceTransform(node, target_node); 279 UpdateTargetSpaceTransform(node, target_node);
262 UpdateNodeAndAncestorsHaveIntegerTranslations(node, parent_node); 280 UpdateNodeAndAncestorsHaveIntegerTranslations(node, parent_node);
263 UpdateTransformChanged(node, parent_node, source_node); 281 UpdateTransformChanged(node, parent_node, source_node);
264 UpdateNodeAndAncestorsAreAnimatedOrInvertible(node, parent_node); 282 UpdateNodeAndAncestorsAreAnimatedOrInvertible(node, parent_node);
265 } 283 }
266 284
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after
392 // from the destination to the source, with flattening, and then invert the 410 // from the destination to the source, with flattening, and then invert the
393 // result. 411 // result.
394 gfx::Transform dest_to_source; 412 gfx::Transform dest_to_source;
395 CombineTransformsBetween(dest_id, source_id, &dest_to_source); 413 CombineTransformsBetween(dest_id, source_id, &dest_to_source);
396 gfx::Transform source_to_dest; 414 gfx::Transform source_to_dest;
397 bool all_are_invertible = dest_to_source.GetInverse(&source_to_dest); 415 bool all_are_invertible = dest_to_source.GetInverse(&source_to_dest);
398 transform->PreconcatTransform(source_to_dest); 416 transform->PreconcatTransform(source_to_dest);
399 return all_are_invertible; 417 return all_are_invertible;
400 } 418 }
401 419
420 gfx::Vector2dF StickyPositionOffset(TransformTree* tree, TransformNode* node) {
421 if (node->sticky_position_constraint_id == -1)
422 return gfx::Vector2dF();
423 const StickyPositionNodeData* sticky_data =
424 tree->StickyPositionData(node->id);
425 const LayerStickyPositionConstraint& constraint = sticky_data->constraints;
426 ScrollNode* scroll_node =
427 tree->property_trees()->scroll_tree.Node(sticky_data->scroll_ancestor);
428 gfx::ScrollOffset scroll_offset =
429 tree->property_trees()->scroll_tree.current_scroll_offset(
430 scroll_node->owner_id);
431
432 gfx::RectF clip(gfx::PointF(scroll_offset.x(), scroll_offset.y()),
433 gfx::SizeF(scroll_node->scroll_clip_layer_bounds));
434 gfx::Vector2dF sticky_offset(
435 constraint.scroll_container_relative_sticky_box_rect.OffsetFromOrigin());
436 gfx::Vector2dF layer_offset(sticky_data->main_thread_offset);
437
438 // In each of the following cases, we measure the limit which is the point
439 // that the element should stick to, clamping on one side to 0 (because sticky
440 // only pushes elements in one direction). Then we clamp to how far we can
441 // push the element in that direction without being pushed outside of its
442 // containing block.
443 //
444 // Note: The order of applying the sticky constraints is applied such that
445 // left offset takes precedence over right offset, and top takes precedence
446 // over bottom offset.
447 if (constraint.is_anchored_right) {
448 float right_limit = clip.right() - constraint.right_offset;
449 float right_delta = std::min<float>(
450 0, right_limit -
451 constraint.scroll_container_relative_sticky_box_rect.right());
452 float available_space = std::min<float>(
453 0, constraint.scroll_container_relative_containing_block_rect.x() -
454 constraint.scroll_container_relative_sticky_box_rect.x());
455 if (right_delta < available_space)
456 right_delta = available_space;
457 sticky_offset.set_x(sticky_offset.x() + right_delta);
458 }
459 if (constraint.is_anchored_left) {
460 float left_limit = clip.x() + constraint.left_offset;
461 float left_delta = std::max<float>(
462 0,
463 left_limit - constraint.scroll_container_relative_sticky_box_rect.x());
464 float available_space = std::max<float>(
465 0, constraint.scroll_container_relative_containing_block_rect.right() -
466 constraint.scroll_container_relative_sticky_box_rect.right());
467 if (left_delta > available_space)
468 left_delta = available_space;
469 sticky_offset.set_x(sticky_offset.x() + left_delta);
470 }
471 if (constraint.is_anchored_bottom) {
472 float bottom_limit = clip.bottom() - constraint.bottom_offset;
473 float bottom_delta = std::min<float>(
474 0, bottom_limit -
475 constraint.scroll_container_relative_sticky_box_rect.bottom());
476 float available_space = std::min<float>(
477 0, constraint.scroll_container_relative_containing_block_rect.y() -
478 constraint.scroll_container_relative_sticky_box_rect.y());
479 if (bottom_delta < available_space)
480 bottom_delta = available_space;
481 sticky_offset.set_y(sticky_offset.y() + bottom_delta);
482 }
483 if (constraint.is_anchored_top) {
484 float top_limit = clip.y() + constraint.top_offset;
485 float top_delta = std::max<float>(
486 0,
487 top_limit - constraint.scroll_container_relative_sticky_box_rect.y());
488 float available_space = std::max<float>(
489 0, constraint.scroll_container_relative_containing_block_rect.bottom() -
490 constraint.scroll_container_relative_sticky_box_rect.bottom());
491 if (top_delta > available_space)
492 top_delta = available_space;
493 sticky_offset.set_y(sticky_offset.y() + top_delta);
494 }
495 return sticky_offset - layer_offset -
496 constraint.scroll_container_relative_sticky_box_rect
497 .OffsetFromOrigin();
498 }
499
402 void TransformTree::UpdateLocalTransform(TransformNode* node) { 500 void TransformTree::UpdateLocalTransform(TransformNode* node) {
403 gfx::Transform transform = node->post_local; 501 gfx::Transform transform = node->post_local;
404 if (NeedsSourceToParentUpdate(node)) { 502 if (NeedsSourceToParentUpdate(node)) {
405 gfx::Transform to_parent; 503 gfx::Transform to_parent;
406 ComputeTranslation(node->source_node_id, node->parent_id, &to_parent); 504 ComputeTranslation(node->source_node_id, node->parent_id, &to_parent);
407 gfx::Vector2dF unsnapping; 505 gfx::Vector2dF unsnapping;
408 TransformNode* current; 506 TransformNode* current;
409 TransformNode* parent_node; 507 TransformNode* parent_node;
410 for (current = Node(node->source_node_id); current->id > node->parent_id; 508 for (current = Node(node->source_node_id); current->id > node->parent_id;
411 current = parent(current)) { 509 current = parent(current)) {
(...skipping 29 matching lines...) Expand all
441 539
442 if (node->affected_by_inner_viewport_bounds_delta_y) 540 if (node->affected_by_inner_viewport_bounds_delta_y)
443 fixed_position_adjustment.set_y(inner_viewport_bounds_delta.y()); 541 fixed_position_adjustment.set_y(inner_viewport_bounds_delta.y());
444 else if (node->affected_by_outer_viewport_bounds_delta_y) 542 else if (node->affected_by_outer_viewport_bounds_delta_y)
445 fixed_position_adjustment.set_y(outer_viewport_bounds_delta.y()); 543 fixed_position_adjustment.set_y(outer_viewport_bounds_delta.y());
446 544
447 transform.Translate(node->source_to_parent.x() - node->scroll_offset.x() + 545 transform.Translate(node->source_to_parent.x() - node->scroll_offset.x() +
448 fixed_position_adjustment.x(), 546 fixed_position_adjustment.x(),
449 node->source_to_parent.y() - node->scroll_offset.y() + 547 node->source_to_parent.y() - node->scroll_offset.y() +
450 fixed_position_adjustment.y()); 548 fixed_position_adjustment.y());
549 transform.Translate(StickyPositionOffset(this, node));
451 transform.PreconcatTransform(node->local); 550 transform.PreconcatTransform(node->local);
452 transform.PreconcatTransform(node->pre_local); 551 transform.PreconcatTransform(node->pre_local);
552
453 node->set_to_parent(transform); 553 node->set_to_parent(transform);
454 node->needs_local_transform_update = false; 554 node->needs_local_transform_update = false;
455 } 555 }
456 556
457 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node, 557 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node,
458 TransformNode* parent_node, 558 TransformNode* parent_node,
459 TransformNode* target_node) { 559 TransformNode* target_node) {
460 if (!parent_node) { 560 if (!parent_node) {
461 SetToScreen(node->id, node->to_parent); 561 SetToScreen(node->id, node->to_parent);
462 node->ancestors_are_invertible = true; 562 node->ancestors_are_invertible = true;
(...skipping 289 matching lines...) Expand 10 before | Expand all | Expand 10 after
752 device_scale_factor_ == other.device_scale_factor() && 852 device_scale_factor_ == other.device_scale_factor() &&
753 device_transform_scale_factor_ == 853 device_transform_scale_factor_ ==
754 other.device_transform_scale_factor() && 854 other.device_transform_scale_factor() &&
755 nodes_affected_by_inner_viewport_bounds_delta_ == 855 nodes_affected_by_inner_viewport_bounds_delta_ ==
756 other.nodes_affected_by_inner_viewport_bounds_delta() && 856 other.nodes_affected_by_inner_viewport_bounds_delta() &&
757 nodes_affected_by_outer_viewport_bounds_delta_ == 857 nodes_affected_by_outer_viewport_bounds_delta_ ==
758 other.nodes_affected_by_outer_viewport_bounds_delta() && 858 other.nodes_affected_by_outer_viewport_bounds_delta() &&
759 cached_data_ == other.cached_data(); 859 cached_data_ == other.cached_data();
760 } 860 }
761 861
862 StickyPositionNodeData* TransformTree::StickyPositionData(int node_id) {
863 TransformNode* node = Node(node_id);
864 if (node->sticky_position_constraint_id == -1) {
865 node->sticky_position_constraint_id = sticky_position_data_.size();
866 sticky_position_data_.push_back(StickyPositionNodeData());
867 }
868 return &sticky_position_data_[node->sticky_position_constraint_id];
869 }
870
762 void TransformTree::ToProtobuf(proto::PropertyTree* proto) const { 871 void TransformTree::ToProtobuf(proto::PropertyTree* proto) const {
763 DCHECK(!proto->has_property_type()); 872 DCHECK(!proto->has_property_type());
764 proto->set_property_type(proto::PropertyTree::Transform); 873 proto->set_property_type(proto::PropertyTree::Transform);
765 874
766 PropertyTree::ToProtobuf(proto); 875 PropertyTree::ToProtobuf(proto);
767 proto::TransformTreeData* data = proto->mutable_transform_tree_data(); 876 proto::TransformTreeData* data = proto->mutable_transform_tree_data();
768 877
769 data->set_source_to_parent_updates_allowed(source_to_parent_updates_allowed_); 878 data->set_source_to_parent_updates_allowed(source_to_parent_updates_allowed_);
770 data->set_page_scale_factor(page_scale_factor_); 879 data->set_page_scale_factor(page_scale_factor_);
771 data->set_device_scale_factor(device_scale_factor_); 880 data->set_device_scale_factor(device_scale_factor_);
772 data->set_device_transform_scale_factor(device_transform_scale_factor_); 881 data->set_device_transform_scale_factor(device_transform_scale_factor_);
773 882
774 for (auto i : nodes_affected_by_inner_viewport_bounds_delta_) 883 for (auto i : nodes_affected_by_inner_viewport_bounds_delta_)
775 data->add_nodes_affected_by_inner_viewport_bounds_delta(i); 884 data->add_nodes_affected_by_inner_viewport_bounds_delta(i);
776 885
777 for (auto i : nodes_affected_by_outer_viewport_bounds_delta_) 886 for (auto i : nodes_affected_by_outer_viewport_bounds_delta_)
778 data->add_nodes_affected_by_outer_viewport_bounds_delta(i); 887 data->add_nodes_affected_by_outer_viewport_bounds_delta(i);
779 888
780 for (int i = 0; i < static_cast<int>(cached_data_.size()); ++i) 889 for (int i = 0; i < static_cast<int>(cached_data_.size()); ++i)
781 cached_data_[i].ToProtobuf(data->add_cached_data()); 890 cached_data_[i].ToProtobuf(data->add_cached_data());
891
892 for (int i = 0; i < static_cast<int>(sticky_position_data_.size()); ++i)
893 sticky_position_data_[i].ToProtobuf(data->add_sticky_position_data());
782 } 894 }
783 895
784 void TransformTree::FromProtobuf( 896 void TransformTree::FromProtobuf(
785 const proto::PropertyTree& proto, 897 const proto::PropertyTree& proto,
786 std::unordered_map<int, int>* node_id_to_index_map) { 898 std::unordered_map<int, int>* node_id_to_index_map) {
787 DCHECK(proto.has_property_type()); 899 DCHECK(proto.has_property_type());
788 DCHECK_EQ(proto.property_type(), proto::PropertyTree::Transform); 900 DCHECK_EQ(proto.property_type(), proto::PropertyTree::Transform);
789 901
790 PropertyTree::FromProtobuf(proto, node_id_to_index_map); 902 PropertyTree::FromProtobuf(proto, node_id_to_index_map);
791 const proto::TransformTreeData& data = proto.transform_tree_data(); 903 const proto::TransformTreeData& data = proto.transform_tree_data();
(...skipping 16 matching lines...) Expand all
808 nodes_affected_by_outer_viewport_bounds_delta_.push_back( 920 nodes_affected_by_outer_viewport_bounds_delta_.push_back(
809 data.nodes_affected_by_outer_viewport_bounds_delta(i)); 921 data.nodes_affected_by_outer_viewport_bounds_delta(i));
810 } 922 }
811 923
812 DCHECK_EQ(static_cast<int>(cached_data_.size()), 1); 924 DCHECK_EQ(static_cast<int>(cached_data_.size()), 1);
813 cached_data_.back().FromProtobuf(data.cached_data(0)); 925 cached_data_.back().FromProtobuf(data.cached_data(0));
814 for (int i = 1; i < data.cached_data_size(); ++i) { 926 for (int i = 1; i < data.cached_data_size(); ++i) {
815 cached_data_.push_back(TransformCachedNodeData()); 927 cached_data_.push_back(TransformCachedNodeData());
816 cached_data_.back().FromProtobuf(data.cached_data(i)); 928 cached_data_.back().FromProtobuf(data.cached_data(i));
817 } 929 }
930
931 DCHECK(static_cast<int>(sticky_position_data_.empty()));
932 for (int i = 0; i < data.sticky_position_data_size(); ++i) {
933 sticky_position_data_.push_back(StickyPositionNodeData());
934 sticky_position_data_.back().FromProtobuf(data.sticky_position_data(i));
935 }
818 } 936 }
819 937
820 EffectTree::EffectTree() {} 938 EffectTree::EffectTree() {}
821 939
822 EffectTree::~EffectTree() {} 940 EffectTree::~EffectTree() {}
823 941
824 void EffectTree::clear() { 942 void EffectTree::clear() {
825 PropertyTree<EffectNode>::clear(); 943 PropertyTree<EffectNode>::clear();
826 mask_replica_layer_ids_.clear(); 944 mask_replica_layer_ids_.clear();
827 945
(...skipping 1419 matching lines...) Expand 10 before | Expand all | Expand 10 after
2247 from_target.ConcatTransform(draw_transforms.from_target); 2365 from_target.ConcatTransform(draw_transforms.from_target);
2248 from_target.Scale(effect_node->surface_contents_scale.x(), 2366 from_target.Scale(effect_node->surface_contents_scale.x(),
2249 effect_node->surface_contents_scale.y()); 2367 effect_node->surface_contents_scale.y());
2250 DCHECK(from_target.ApproximatelyEqual(*transform) || 2368 DCHECK(from_target.ApproximatelyEqual(*transform) ||
2251 !draw_transforms.invertible); 2369 !draw_transforms.invertible);
2252 } 2370 }
2253 return success; 2371 return success;
2254 } 2372 }
2255 2373
2256 } // namespace cc 2374 } // namespace cc
OLDNEW
« no previous file with comments | « cc/trees/property_tree.h ('k') | cc/trees/property_tree_builder.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698