layer_impl.cc revision 3551c9c881056c480085172ff9840cab31610854
1// Copyright 2011 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cc/layers/layer_impl.h"
6
7#include "base/debug/trace_event.h"
8#include "base/strings/stringprintf.h"
9#include "cc/animation/animation_registrar.h"
10#include "cc/animation/scrollbar_animation_controller.h"
11#include "cc/animation/scrollbar_animation_controller_linear_fade.h"
12#include "cc/base/math_util.h"
13#include "cc/debug/debug_colors.h"
14#include "cc/debug/layer_tree_debug_state.h"
15#include "cc/debug/traced_value.h"
16#include "cc/input/layer_scroll_offset_delegate.h"
17#include "cc/layers/painted_scrollbar_layer_impl.h"
18#include "cc/layers/quad_sink.h"
19#include "cc/output/copy_output_request.h"
20#include "cc/quads/debug_border_draw_quad.h"
21#include "cc/trees/layer_tree_impl.h"
22#include "cc/trees/layer_tree_settings.h"
23#include "cc/trees/proxy.h"
24#include "ui/gfx/point_conversions.h"
25#include "ui/gfx/quad_f.h"
26#include "ui/gfx/rect_conversions.h"
27
28namespace cc {
29
30LayerImpl::LayerImpl(LayerTreeImpl* tree_impl, int id)
31    : parent_(NULL),
32      scroll_parent_(NULL),
33      clip_parent_(NULL),
34      mask_layer_id_(-1),
35      replica_layer_id_(-1),
36      layer_id_(id),
37      layer_tree_impl_(tree_impl),
38      anchor_point_(0.5f, 0.5f),
39      anchor_point_z_(0.f),
40      scroll_offset_delegate_(NULL),
41      scrollable_(false),
42      should_scroll_on_main_thread_(false),
43      have_wheel_event_handlers_(false),
44      background_color_(0),
45      stacking_order_changed_(false),
46      double_sided_(true),
47      layer_property_changed_(false),
48      layer_surface_property_changed_(false),
49      masks_to_bounds_(false),
50      contents_opaque_(false),
51      opacity_(1.0),
52      preserves_3d_(false),
53      use_parent_backface_visibility_(false),
54      draw_checkerboard_for_missing_tiles_(false),
55      draws_content_(false),
56      hide_layer_and_subtree_(false),
57      force_render_surface_(false),
58      is_container_for_fixed_position_layers_(false),
59      draw_depth_(0.f),
60      compositing_reasons_(kCompositingReasonUnknown),
61      current_draw_mode_(DRAW_MODE_NONE),
62      horizontal_scrollbar_layer_(NULL),
63      vertical_scrollbar_layer_(NULL) {
64  DCHECK_GT(layer_id_, 0);
65  DCHECK(layer_tree_impl_);
66  layer_tree_impl_->RegisterLayer(this);
67  AnimationRegistrar* registrar = layer_tree_impl_->animationRegistrar();
68  layer_animation_controller_ =
69      registrar->GetAnimationControllerForId(layer_id_);
70  layer_animation_controller_->AddValueObserver(this);
71}
72
73LayerImpl::~LayerImpl() {
74  DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_);
75
76  layer_tree_impl_->UnregisterLayer(this);
77  layer_animation_controller_->RemoveValueObserver(this);
78
79  if (scroll_children_) {
80    for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
81        it != scroll_children_->end(); ++it)
82      (*it)->scroll_parent_ = NULL;
83  }
84
85  if (scroll_parent_)
86    scroll_parent_->RemoveScrollChild(this);
87
88  if (clip_children_) {
89    for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
90        it != clip_children_->end(); ++it)
91      (*it)->clip_parent_ = NULL;
92  }
93
94  if (clip_parent_)
95    clip_parent_->RemoveClipChild(this);
96}
97
98void LayerImpl::AddChild(scoped_ptr<LayerImpl> child) {
99  child->set_parent(this);
100  DCHECK_EQ(layer_tree_impl(), child->layer_tree_impl());
101  children_.push_back(child.Pass());
102  layer_tree_impl()->set_needs_update_draw_properties();
103}
104
105scoped_ptr<LayerImpl> LayerImpl::RemoveChild(LayerImpl* child) {
106  for (OwnedLayerImplList::iterator it = children_.begin();
107       it != children_.end();
108       ++it) {
109    if (*it == child) {
110      scoped_ptr<LayerImpl> ret = children_.take(it);
111      children_.erase(it);
112      layer_tree_impl()->set_needs_update_draw_properties();
113      return ret.Pass();
114    }
115  }
116  return scoped_ptr<LayerImpl>();
117}
118
119void LayerImpl::ClearChildList() {
120  if (children_.empty())
121    return;
122
123  children_.clear();
124  layer_tree_impl()->set_needs_update_draw_properties();
125}
126
127bool LayerImpl::HasAncestor(const LayerImpl* ancestor) const {
128  if (!ancestor)
129    return false;
130
131  for (const LayerImpl* layer = this; layer; layer = layer->parent()) {
132    if (layer == ancestor)
133      return true;
134  }
135
136  return false;
137}
138
139void LayerImpl::SetScrollParent(LayerImpl* parent) {
140  if (scroll_parent_ == parent)
141    return;
142
143  if (scroll_parent_)
144    scroll_parent_->RemoveScrollChild(this);
145
146  scroll_parent_ = parent;
147}
148
149void LayerImpl::SetScrollChildren(std::set<LayerImpl*>* children) {
150  if (scroll_children_.get() == children)
151    return;
152  scroll_children_.reset(children);
153}
154
155void LayerImpl::RemoveScrollChild(LayerImpl* child) {
156  DCHECK(scroll_children_);
157  scroll_children_->erase(child);
158  if (scroll_children_->empty())
159    scroll_children_.reset();
160}
161
162void LayerImpl::SetClipParent(LayerImpl* ancestor) {
163  if (clip_parent_ == ancestor)
164    return;
165
166  if (clip_parent_)
167    clip_parent_->RemoveClipChild(this);
168
169  clip_parent_ = ancestor;
170}
171
172void LayerImpl::SetClipChildren(std::set<LayerImpl*>* children) {
173  if (clip_children_.get() == children)
174    return;
175  clip_children_.reset(children);
176}
177
178void LayerImpl::RemoveClipChild(LayerImpl* child) {
179  DCHECK(clip_children_);
180  clip_children_->erase(child);
181  if (clip_children_->empty())
182    clip_children_.reset();
183}
184
185void LayerImpl::PassCopyRequests(ScopedPtrVector<CopyOutputRequest>* requests) {
186  if (requests->empty())
187    return;
188
189  bool was_empty = copy_requests_.empty();
190  copy_requests_.insert_and_take(copy_requests_.end(), *requests);
191  requests->clear();
192
193  if (was_empty && layer_tree_impl()->IsActiveTree())
194    layer_tree_impl()->AddLayerWithCopyOutputRequest(this);
195  NoteLayerPropertyChangedForSubtree();
196}
197
198void LayerImpl::TakeCopyRequestsAndTransformToTarget(
199    ScopedPtrVector<CopyOutputRequest>* requests) {
200  if (copy_requests_.empty())
201    return;
202
203  size_t first_inserted_request = requests->size();
204  requests->insert_and_take(requests->end(), copy_requests_);
205  copy_requests_.clear();
206
207  for (size_t i = first_inserted_request; i < requests->size(); ++i) {
208    CopyOutputRequest* request = requests->at(i);
209    if (!request->has_area())
210      continue;
211
212    gfx::Rect request_in_layer_space = request->area();
213    gfx::Rect request_in_content_space =
214        LayerRectToContentRect(request_in_layer_space);
215    request->set_area(
216        MathUtil::MapClippedRect(draw_properties_.target_space_transform,
217                                 request_in_content_space));
218  }
219
220  if (layer_tree_impl()->IsActiveTree())
221    layer_tree_impl()->RemoveLayerWithCopyOutputRequest(this);
222}
223
224void LayerImpl::CreateRenderSurface() {
225  DCHECK(!draw_properties_.render_surface);
226  draw_properties_.render_surface =
227      make_scoped_ptr(new RenderSurfaceImpl(this));
228  draw_properties_.render_target = this;
229}
230
231void LayerImpl::ClearRenderSurface() {
232  draw_properties_.render_surface.reset();
233}
234
235scoped_ptr<SharedQuadState> LayerImpl::CreateSharedQuadState() const {
236  scoped_ptr<SharedQuadState> state = SharedQuadState::Create();
237  state->SetAll(draw_properties_.target_space_transform,
238                draw_properties_.content_bounds,
239                draw_properties_.visible_content_rect,
240                draw_properties_.clip_rect,
241                draw_properties_.is_clipped,
242                draw_properties_.opacity);
243  return state.Pass();
244}
245
246bool LayerImpl::WillDraw(DrawMode draw_mode,
247                         ResourceProvider* resource_provider) {
248  // WillDraw/DidDraw must be matched.
249  DCHECK_NE(DRAW_MODE_NONE, draw_mode);
250  DCHECK_EQ(DRAW_MODE_NONE, current_draw_mode_);
251  current_draw_mode_ = draw_mode;
252  return true;
253}
254
255void LayerImpl::DidDraw(ResourceProvider* resource_provider) {
256  DCHECK_NE(DRAW_MODE_NONE, current_draw_mode_);
257  current_draw_mode_ = DRAW_MODE_NONE;
258}
259
260bool LayerImpl::ShowDebugBorders() const {
261  return layer_tree_impl()->debug_state().show_debug_borders;
262}
263
264void LayerImpl::GetDebugBorderProperties(SkColor* color, float* width) const {
265  if (draws_content_) {
266    *color = DebugColors::ContentLayerBorderColor();
267    *width = DebugColors::ContentLayerBorderWidth(layer_tree_impl());
268    return;
269  }
270
271  if (masks_to_bounds_) {
272    *color = DebugColors::MaskingLayerBorderColor();
273    *width = DebugColors::MaskingLayerBorderWidth(layer_tree_impl());
274    return;
275  }
276
277  *color = DebugColors::ContainerLayerBorderColor();
278  *width = DebugColors::ContainerLayerBorderWidth(layer_tree_impl());
279}
280
281void LayerImpl::AppendDebugBorderQuad(
282    QuadSink* quad_sink,
283    const SharedQuadState* shared_quad_state,
284    AppendQuadsData* append_quads_data) const {
285  SkColor color;
286  float width;
287  GetDebugBorderProperties(&color, &width);
288  AppendDebugBorderQuad(
289      quad_sink, shared_quad_state, append_quads_data, color, width);
290}
291
292void LayerImpl::AppendDebugBorderQuad(QuadSink* quad_sink,
293                                      const SharedQuadState* shared_quad_state,
294                                      AppendQuadsData* append_quads_data,
295                                      SkColor color,
296                                      float width) const {
297  if (!ShowDebugBorders())
298    return;
299
300  gfx::Rect content_rect(content_bounds());
301  scoped_ptr<DebugBorderDrawQuad> debug_border_quad =
302      DebugBorderDrawQuad::Create();
303  debug_border_quad->SetNew(shared_quad_state, content_rect, color, width);
304  quad_sink->Append(debug_border_quad.PassAs<DrawQuad>(), append_quads_data);
305}
306
307bool LayerImpl::HasDelegatedContent() const {
308  return false;
309}
310
311bool LayerImpl::HasContributingDelegatedRenderPasses() const {
312  return false;
313}
314
315RenderPass::Id LayerImpl::FirstContributingRenderPassId() const {
316  return RenderPass::Id(0, 0);
317}
318
319RenderPass::Id LayerImpl::NextContributingRenderPassId(RenderPass::Id id)
320    const {
321  return RenderPass::Id(0, 0);
322}
323
324ResourceProvider::ResourceId LayerImpl::ContentsResourceId() const {
325  NOTREACHED();
326  return 0;
327}
328
329void LayerImpl::SetSentScrollDelta(gfx::Vector2d sent_scroll_delta) {
330  // Pending tree never has sent scroll deltas
331  DCHECK(layer_tree_impl()->IsActiveTree());
332
333  if (sent_scroll_delta_ == sent_scroll_delta)
334    return;
335
336  sent_scroll_delta_ = sent_scroll_delta;
337}
338
339gfx::Vector2dF LayerImpl::ScrollBy(gfx::Vector2dF scroll) {
340  DCHECK(scrollable());
341
342  gfx::Vector2dF min_delta = -scroll_offset_;
343  gfx::Vector2dF max_delta = max_scroll_offset_ - scroll_offset_;
344  // Clamp new_delta so that position + delta stays within scroll bounds.
345  gfx::Vector2dF new_delta = (ScrollDelta() + scroll);
346  new_delta.SetToMax(min_delta);
347  new_delta.SetToMin(max_delta);
348  gfx::Vector2dF unscrolled = ScrollDelta() + scroll - new_delta;
349  SetScrollDelta(new_delta);
350  return unscrolled;
351}
352
353void LayerImpl::ApplySentScrollDeltasFromAbortedCommit() {
354  // Pending tree never has sent scroll deltas
355  DCHECK(layer_tree_impl()->IsActiveTree());
356
357  // Apply sent scroll deltas to scroll position / scroll delta as if the
358  // main thread had applied them and then committed those values.
359  //
360  // This function should not change the total scroll offset; it just shifts
361  // some of the scroll delta to the scroll offset.  Therefore, adjust these
362  // variables directly rather than calling the scroll offset delegate to
363  // avoid sending it multiple spurious calls.
364  //
365  // Because of the way scroll delta is calculated with a delegate, this will
366  // leave the total scroll offset unchanged on this layer regardless of
367  // whether a delegate is being used.
368  scroll_offset_ += sent_scroll_delta_;
369  scroll_delta_ -= sent_scroll_delta_;
370  sent_scroll_delta_ = gfx::Vector2d();
371}
372
373void LayerImpl::ApplyScrollDeltasSinceBeginFrame() {
374  // Only the pending tree can have missing scrolls.
375  DCHECK(layer_tree_impl()->IsPendingTree());
376  if (!scrollable())
377    return;
378
379  // Pending tree should never have sent scroll deltas.
380  DCHECK(sent_scroll_delta().IsZero());
381
382  LayerImpl* active_twin = layer_tree_impl()->FindActiveTreeLayerById(id());
383  if (active_twin) {
384    // Scrolls that happens after begin frame (where the sent scroll delta
385    // comes from) and commit need to be applied to the pending tree
386    // so that it is up to date with the total scroll.
387    SetScrollDelta(active_twin->ScrollDelta() -
388                   active_twin->sent_scroll_delta());
389  }
390}
391
392InputHandler::ScrollStatus LayerImpl::TryScroll(
393    gfx::PointF screen_space_point,
394    InputHandler::ScrollInputType type) const {
395  if (should_scroll_on_main_thread()) {
396    TRACE_EVENT0("cc", "LayerImpl::TryScroll: Failed ShouldScrollOnMainThread");
397    return InputHandler::ScrollOnMainThread;
398  }
399
400  if (!screen_space_transform().IsInvertible()) {
401    TRACE_EVENT0("cc", "LayerImpl::TryScroll: Ignored NonInvertibleTransform");
402    return InputHandler::ScrollIgnored;
403  }
404
405  if (!non_fast_scrollable_region().IsEmpty()) {
406    bool clipped = false;
407    gfx::Transform inverse_screen_space_transform(
408        gfx::Transform::kSkipInitialization);
409    if (!screen_space_transform().GetInverse(&inverse_screen_space_transform)) {
410      // TODO(shawnsingh): We shouldn't be applying a projection if screen space
411      // transform is uninvertible here. Perhaps we should be returning
412      // ScrollOnMainThread in this case?
413    }
414
415    gfx::PointF hit_test_point_in_content_space =
416        MathUtil::ProjectPoint(inverse_screen_space_transform,
417                               screen_space_point,
418                               &clipped);
419    gfx::PointF hit_test_point_in_layer_space =
420        gfx::ScalePoint(hit_test_point_in_content_space,
421                        1.f / contents_scale_x(),
422                        1.f / contents_scale_y());
423    if (!clipped &&
424        non_fast_scrollable_region().Contains(
425            gfx::ToRoundedPoint(hit_test_point_in_layer_space))) {
426      TRACE_EVENT0("cc",
427                   "LayerImpl::tryScroll: Failed NonFastScrollableRegion");
428      return InputHandler::ScrollOnMainThread;
429    }
430  }
431
432  if (type == InputHandler::Wheel && have_wheel_event_handlers()) {
433    TRACE_EVENT0("cc", "LayerImpl::tryScroll: Failed WheelEventHandlers");
434    return InputHandler::ScrollOnMainThread;
435  }
436
437  if (!scrollable()) {
438    TRACE_EVENT0("cc", "LayerImpl::tryScroll: Ignored not scrollable");
439    return InputHandler::ScrollIgnored;
440  }
441
442  if (max_scroll_offset_.x() <= 0 && max_scroll_offset_.y() <= 0) {
443    TRACE_EVENT0("cc",
444                 "LayerImpl::tryScroll: Ignored. Technically scrollable,"
445                 " but has no affordance in either direction.");
446    return InputHandler::ScrollIgnored;
447  }
448
449  return InputHandler::ScrollStarted;
450}
451
452bool LayerImpl::DrawCheckerboardForMissingTiles() const {
453  return draw_checkerboard_for_missing_tiles_ &&
454      !layer_tree_impl()->settings().background_color_instead_of_checkerboard;
455}
456
457gfx::Rect LayerImpl::LayerRectToContentRect(
458    const gfx::RectF& layer_rect) const {
459  gfx::RectF content_rect =
460      gfx::ScaleRect(layer_rect, contents_scale_x(), contents_scale_y());
461  // Intersect with content rect to avoid the extra pixel because for some
462  // values x and y, ceil((x / y) * y) may be x + 1.
463  content_rect.Intersect(gfx::Rect(content_bounds()));
464  return gfx::ToEnclosingRect(content_rect);
465}
466
467skia::RefPtr<SkPicture> LayerImpl::GetPicture() {
468  return skia::RefPtr<SkPicture>();
469}
470
471bool LayerImpl::CanClipSelf() const {
472  return false;
473}
474
475bool LayerImpl::AreVisibleResourcesReady() const {
476  return true;
477}
478
479scoped_ptr<LayerImpl> LayerImpl::CreateLayerImpl(LayerTreeImpl* tree_impl) {
480  return LayerImpl::Create(tree_impl, layer_id_);
481}
482
483void LayerImpl::PushPropertiesTo(LayerImpl* layer) {
484  layer->SetAnchorPoint(anchor_point_);
485  layer->SetAnchorPointZ(anchor_point_z_);
486  layer->SetBackgroundColor(background_color_);
487  layer->SetBounds(bounds_);
488  layer->SetContentBounds(content_bounds());
489  layer->SetContentsScale(contents_scale_x(), contents_scale_y());
490  layer->SetDebugName(debug_name_);
491  layer->SetCompositingReasons(compositing_reasons_);
492  layer->SetDoubleSided(double_sided_);
493  layer->SetDrawCheckerboardForMissingTiles(
494      draw_checkerboard_for_missing_tiles_);
495  layer->SetForceRenderSurface(force_render_surface_);
496  layer->SetDrawsContent(DrawsContent());
497  layer->SetHideLayerAndSubtree(hide_layer_and_subtree_);
498  layer->SetFilters(filters());
499  layer->SetFilter(filter());
500  layer->SetBackgroundFilters(background_filters());
501  layer->SetMasksToBounds(masks_to_bounds_);
502  layer->SetShouldScrollOnMainThread(should_scroll_on_main_thread_);
503  layer->SetHaveWheelEventHandlers(have_wheel_event_handlers_);
504  layer->SetNonFastScrollableRegion(non_fast_scrollable_region_);
505  layer->SetTouchEventHandlerRegion(touch_event_handler_region_);
506  layer->SetContentsOpaque(contents_opaque_);
507  layer->SetOpacity(opacity_);
508  layer->SetPosition(position_);
509  layer->SetIsContainerForFixedPositionLayers(
510      is_container_for_fixed_position_layers_);
511  layer->SetFixedContainerSizeDelta(fixed_container_size_delta_);
512  layer->SetPositionConstraint(position_constraint_);
513  layer->SetPreserves3d(preserves_3d());
514  layer->SetUseParentBackfaceVisibility(use_parent_backface_visibility_);
515  layer->SetSublayerTransform(sublayer_transform_);
516  layer->SetTransform(transform_);
517
518  layer->SetScrollable(scrollable_);
519  layer->SetScrollOffset(scroll_offset_);
520  layer->SetMaxScrollOffset(max_scroll_offset_);
521
522  LayerImpl* scroll_parent = NULL;
523  if (scroll_parent_)
524    scroll_parent = layer->layer_tree_impl()->LayerById(scroll_parent_->id());
525
526  layer->SetScrollParent(scroll_parent);
527  if (scroll_children_) {
528    std::set<LayerImpl*>* scroll_children = new std::set<LayerImpl*>;
529    for (std::set<LayerImpl*>::iterator it = scroll_children_->begin();
530        it != scroll_children_->end(); ++it)
531      scroll_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
532    layer->SetScrollChildren(scroll_children);
533  }
534
535  LayerImpl* clip_parent = NULL;
536  if (clip_parent_) {
537    clip_parent = layer->layer_tree_impl()->LayerById(
538        clip_parent_->id());
539  }
540
541  layer->SetClipParent(clip_parent);
542  if (clip_children_) {
543    std::set<LayerImpl*>* clip_children = new std::set<LayerImpl*>;
544    for (std::set<LayerImpl*>::iterator it = clip_children_->begin();
545        it != clip_children_->end(); ++it)
546      clip_children->insert(layer->layer_tree_impl()->LayerById((*it)->id()));
547    layer->SetClipChildren(clip_children);
548  }
549
550  layer->PassCopyRequests(&copy_requests_);
551
552  // If the main thread commits multiple times before the impl thread actually
553  // draws, then damage tracking will become incorrect if we simply clobber the
554  // update_rect here. The LayerImpl's update_rect needs to accumulate (i.e.
555  // union) any update changes that have occurred on the main thread.
556  update_rect_.Union(layer->update_rect());
557  layer->set_update_rect(update_rect_);
558
559  layer->SetScrollDelta(layer->ScrollDelta() - layer->sent_scroll_delta());
560  layer->SetSentScrollDelta(gfx::Vector2d());
561
562  layer->SetStackingOrderChanged(stacking_order_changed_);
563
564  // Reset any state that should be cleared for the next update.
565  stacking_order_changed_ = false;
566  update_rect_ = gfx::RectF();
567}
568
569base::DictionaryValue* LayerImpl::LayerTreeAsJson() const {
570  base::DictionaryValue* result = new base::DictionaryValue;
571  result->SetString("LayerType", LayerTypeAsString());
572
573  base::ListValue* list = new base::ListValue;
574  list->AppendInteger(bounds().width());
575  list->AppendInteger(bounds().height());
576  result->Set("Bounds", list);
577
578  list = new base::ListValue;
579  list->AppendDouble(position_.x());
580  list->AppendDouble(position_.y());
581  result->Set("Position", list);
582
583  const gfx::Transform& gfx_transform = draw_properties_.target_space_transform;
584  double transform[16];
585  gfx_transform.matrix().asColMajord(transform);
586  list = new base::ListValue;
587  for (int i = 0; i < 16; ++i)
588    list->AppendDouble(transform[i]);
589  result->Set("DrawTransform", list);
590
591  result->SetBoolean("DrawsContent", draws_content_);
592  result->SetDouble("Opacity", opacity());
593  result->SetBoolean("ContentsOpaque", contents_opaque_);
594
595  if (scrollable_)
596    result->SetBoolean("Scrollable", scrollable_);
597
598  list = new base::ListValue;
599  for (size_t i = 0; i < children_.size(); ++i)
600    list->Append(children_[i]->LayerTreeAsJson());
601  result->Set("Children", list);
602
603  return result;
604}
605
606void LayerImpl::SetStackingOrderChanged(bool stacking_order_changed) {
607  if (stacking_order_changed) {
608    stacking_order_changed_ = true;
609    NoteLayerPropertyChangedForSubtree();
610  }
611}
612
613bool LayerImpl::LayerSurfacePropertyChanged() const {
614  if (layer_surface_property_changed_)
615    return true;
616
617  // If this layer's surface property hasn't changed, we want to see if
618  // some layer above us has changed this property. This is done for the
619  // case when such parent layer does not draw content, and therefore will
620  // not be traversed by the damage tracker. We need to make sure that
621  // property change on such layer will be caught by its descendants.
622  LayerImpl* current = this->parent_;
623  while (current && !current->draw_properties_.render_surface) {
624    if (current->layer_surface_property_changed_)
625      return true;
626    current = current->parent_;
627  }
628
629  return false;
630}
631
632void LayerImpl::NoteLayerSurfacePropertyChanged() {
633  layer_surface_property_changed_ = true;
634  layer_tree_impl()->set_needs_update_draw_properties();
635}
636
637void LayerImpl::NoteLayerPropertyChanged() {
638  layer_property_changed_ = true;
639  layer_tree_impl()->set_needs_update_draw_properties();
640}
641
642void LayerImpl::NoteLayerPropertyChangedForSubtree() {
643  NoteLayerPropertyChanged();
644  NoteLayerPropertyChangedForDescendants();
645}
646
647void LayerImpl::NoteLayerPropertyChangedForDescendants() {
648  layer_tree_impl()->set_needs_update_draw_properties();
649  for (size_t i = 0; i < children_.size(); ++i)
650    children_[i]->NoteLayerPropertyChangedForSubtree();
651}
652
653const char* LayerImpl::LayerTypeAsString() const {
654  return "cc::LayerImpl";
655}
656
657void LayerImpl::ResetAllChangeTrackingForSubtree() {
658  layer_property_changed_ = false;
659  layer_surface_property_changed_ = false;
660
661  update_rect_ = gfx::RectF();
662
663  if (draw_properties_.render_surface)
664    draw_properties_.render_surface->ResetPropertyChangedFlag();
665
666  if (mask_layer_)
667    mask_layer_->ResetAllChangeTrackingForSubtree();
668
669  if (replica_layer_) {
670    // This also resets the replica mask, if it exists.
671    replica_layer_->ResetAllChangeTrackingForSubtree();
672  }
673
674  for (size_t i = 0; i < children_.size(); ++i)
675    children_[i]->ResetAllChangeTrackingForSubtree();
676}
677
678bool LayerImpl::LayerIsAlwaysDamaged() const {
679  return false;
680}
681
682void LayerImpl::OnOpacityAnimated(float opacity) {
683  SetOpacity(opacity);
684}
685
686void LayerImpl::OnTransformAnimated(const gfx::Transform& transform) {
687  SetTransform(transform);
688}
689
690bool LayerImpl::IsActive() const {
691  return layer_tree_impl_->IsActiveTree();
692}
693
694void LayerImpl::SetBounds(gfx::Size bounds) {
695  if (bounds_ == bounds)
696    return;
697
698  bounds_ = bounds;
699
700  if (masks_to_bounds())
701    NoteLayerPropertyChangedForSubtree();
702  else
703    NoteLayerPropertyChanged();
704}
705
706void LayerImpl::SetMaskLayer(scoped_ptr<LayerImpl> mask_layer) {
707  int new_layer_id = mask_layer ? mask_layer->id() : -1;
708
709  if (mask_layer) {
710    DCHECK_EQ(layer_tree_impl(), mask_layer->layer_tree_impl());
711    DCHECK_NE(new_layer_id, mask_layer_id_);
712  } else if (new_layer_id == mask_layer_id_) {
713    return;
714  }
715
716  mask_layer_ = mask_layer.Pass();
717  mask_layer_id_ = new_layer_id;
718  if (mask_layer_)
719    mask_layer_->set_parent(this);
720  NoteLayerPropertyChangedForSubtree();
721}
722
723scoped_ptr<LayerImpl> LayerImpl::TakeMaskLayer() {
724  mask_layer_id_ = -1;
725  return mask_layer_.Pass();
726}
727
728void LayerImpl::SetReplicaLayer(scoped_ptr<LayerImpl> replica_layer) {
729  int new_layer_id = replica_layer ? replica_layer->id() : -1;
730
731  if (replica_layer) {
732    DCHECK_EQ(layer_tree_impl(), replica_layer->layer_tree_impl());
733    DCHECK_NE(new_layer_id, replica_layer_id_);
734  } else if (new_layer_id == replica_layer_id_) {
735    return;
736  }
737
738  replica_layer_ = replica_layer.Pass();
739  replica_layer_id_ = new_layer_id;
740  if (replica_layer_)
741    replica_layer_->set_parent(this);
742  NoteLayerPropertyChangedForSubtree();
743}
744
745scoped_ptr<LayerImpl> LayerImpl::TakeReplicaLayer() {
746  replica_layer_id_ = -1;
747  return replica_layer_.Pass();
748}
749
750PaintedScrollbarLayerImpl* LayerImpl::ToScrollbarLayer() {
751  return NULL;
752}
753
754void LayerImpl::SetDrawsContent(bool draws_content) {
755  if (draws_content_ == draws_content)
756    return;
757
758  draws_content_ = draws_content;
759  NoteLayerPropertyChanged();
760}
761
762void LayerImpl::SetHideLayerAndSubtree(bool hide) {
763  if (hide_layer_and_subtree_ == hide)
764    return;
765
766  hide_layer_and_subtree_ = hide;
767  NoteLayerPropertyChangedForSubtree();
768}
769
770void LayerImpl::SetAnchorPoint(gfx::PointF anchor_point) {
771  if (anchor_point_ == anchor_point)
772    return;
773
774  anchor_point_ = anchor_point;
775  NoteLayerPropertyChangedForSubtree();
776}
777
778void LayerImpl::SetAnchorPointZ(float anchor_point_z) {
779  if (anchor_point_z_ == anchor_point_z)
780    return;
781
782  anchor_point_z_ = anchor_point_z;
783  NoteLayerPropertyChangedForSubtree();
784}
785
786void LayerImpl::SetBackgroundColor(SkColor background_color) {
787  if (background_color_ == background_color)
788    return;
789
790  background_color_ = background_color;
791  NoteLayerPropertyChanged();
792}
793
794SkColor LayerImpl::SafeOpaqueBackgroundColor() const {
795  SkColor color = background_color();
796  if (SkColorGetA(color) == 255 && !contents_opaque()) {
797    color = SK_ColorTRANSPARENT;
798  } else if (SkColorGetA(color) != 255 && contents_opaque()) {
799    for (const LayerImpl* layer = parent(); layer;
800         layer = layer->parent()) {
801      color = layer->background_color();
802      if (SkColorGetA(color) == 255)
803        break;
804    }
805    if (SkColorGetA(color) != 255)
806      color = layer_tree_impl()->background_color();
807    if (SkColorGetA(color) != 255)
808      color = SkColorSetA(color, 255);
809  }
810  return color;
811}
812
813void LayerImpl::SetFilters(const FilterOperations& filters) {
814  if (filters_ == filters)
815    return;
816
817  DCHECK(!filter_);
818  filters_ = filters;
819  NoteLayerPropertyChangedForSubtree();
820}
821
822void LayerImpl::SetBackgroundFilters(
823    const FilterOperations& filters) {
824  if (background_filters_ == filters)
825    return;
826
827  background_filters_ = filters;
828  NoteLayerPropertyChanged();
829}
830
831void LayerImpl::SetFilter(const skia::RefPtr<SkImageFilter>& filter) {
832  if (filter_.get() == filter.get())
833    return;
834
835  DCHECK(filters_.IsEmpty());
836  filter_ = filter;
837  NoteLayerPropertyChangedForSubtree();
838}
839
840void LayerImpl::SetMasksToBounds(bool masks_to_bounds) {
841  if (masks_to_bounds_ == masks_to_bounds)
842    return;
843
844  masks_to_bounds_ = masks_to_bounds;
845  NoteLayerPropertyChangedForSubtree();
846}
847
848void LayerImpl::SetContentsOpaque(bool opaque) {
849  if (contents_opaque_ == opaque)
850    return;
851
852  contents_opaque_ = opaque;
853  NoteLayerPropertyChangedForSubtree();
854}
855
856void LayerImpl::SetOpacity(float opacity) {
857  if (opacity_ == opacity)
858    return;
859
860  opacity_ = opacity;
861  NoteLayerSurfacePropertyChanged();
862}
863
864bool LayerImpl::OpacityIsAnimating() const {
865  return layer_animation_controller_->IsAnimatingProperty(Animation::Opacity);
866}
867
868bool LayerImpl::OpacityIsAnimatingOnImplOnly() const {
869  Animation* opacity_animation =
870      layer_animation_controller_->GetAnimation(Animation::Opacity);
871  return opacity_animation && opacity_animation->is_impl_only();
872}
873
874void LayerImpl::SetPosition(gfx::PointF position) {
875  if (position_ == position)
876    return;
877
878  position_ = position;
879  NoteLayerPropertyChangedForSubtree();
880}
881
882void LayerImpl::SetPreserves3d(bool preserves3_d) {
883  if (preserves_3d_ == preserves3_d)
884    return;
885
886  preserves_3d_ = preserves3_d;
887  NoteLayerPropertyChangedForSubtree();
888}
889
890void LayerImpl::SetSublayerTransform(const gfx::Transform& sublayer_transform) {
891  if (sublayer_transform_ == sublayer_transform)
892    return;
893
894  sublayer_transform_ = sublayer_transform;
895  // Sublayer transform does not affect the current layer; it affects only its
896  // children.
897  NoteLayerPropertyChangedForDescendants();
898}
899
900void LayerImpl::SetTransform(const gfx::Transform& transform) {
901  if (transform_ == transform)
902    return;
903
904  transform_ = transform;
905  NoteLayerSurfacePropertyChanged();
906}
907
908bool LayerImpl::TransformIsAnimating() const {
909  return layer_animation_controller_->IsAnimatingProperty(Animation::Transform);
910}
911
912bool LayerImpl::TransformIsAnimatingOnImplOnly() const {
913  Animation* transform_animation =
914      layer_animation_controller_->GetAnimation(Animation::Transform);
915  return transform_animation && transform_animation->is_impl_only();
916}
917
918void LayerImpl::SetContentBounds(gfx::Size content_bounds) {
919  if (this->content_bounds() == content_bounds)
920    return;
921
922  draw_properties_.content_bounds = content_bounds;
923  NoteLayerPropertyChanged();
924}
925
926void LayerImpl::SetContentsScale(float contents_scale_x,
927                                 float contents_scale_y) {
928  if (this->contents_scale_x() == contents_scale_x &&
929      this->contents_scale_y() == contents_scale_y)
930    return;
931
932  draw_properties_.contents_scale_x = contents_scale_x;
933  draw_properties_.contents_scale_y = contents_scale_y;
934  NoteLayerPropertyChanged();
935}
936
937void LayerImpl::CalculateContentsScale(
938    float ideal_contents_scale,
939    float device_scale_factor,
940    float page_scale_factor,
941    bool animating_transform_to_screen,
942    float* contents_scale_x,
943    float* contents_scale_y,
944    gfx::Size* content_bounds) {
945  // Base LayerImpl has all of its content scales and content bounds pushed
946  // from its Layer during commit and just reuses those values as-is.
947  *contents_scale_x = this->contents_scale_x();
948  *contents_scale_y = this->contents_scale_y();
949  *content_bounds = this->content_bounds();
950}
951
952void LayerImpl::UpdateScrollbarPositions() {
953  gfx::Vector2dF current_offset = scroll_offset_ + ScrollDelta();
954
955  gfx::RectF viewport(PointAtOffsetFromOrigin(current_offset), bounds_);
956  gfx::SizeF scrollable_size(max_scroll_offset_.x() + bounds_.width(),
957                             max_scroll_offset_.y() + bounds_.height());
958  if (horizontal_scrollbar_layer_) {
959    horizontal_scrollbar_layer_->SetCurrentPos(current_offset.x());
960    horizontal_scrollbar_layer_->SetMaximum(max_scroll_offset_.x());
961    horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(
962        viewport.width() / scrollable_size.width());
963  }
964  if (vertical_scrollbar_layer_) {
965    vertical_scrollbar_layer_->SetCurrentPos(current_offset.y());
966    vertical_scrollbar_layer_->SetMaximum(max_scroll_offset_.y());
967    vertical_scrollbar_layer_->SetVisibleToTotalLengthRatio(
968        viewport.height() / scrollable_size.height());
969  }
970
971  if (current_offset == last_scroll_offset_)
972    return;
973  last_scroll_offset_ = current_offset;
974
975  if (scrollbar_animation_controller_ &&
976      !scrollbar_animation_controller_->IsScrollGestureInProgress()) {
977    scrollbar_animation_controller_->DidProgrammaticallyUpdateScroll(
978        layer_tree_impl_->CurrentPhysicalTimeTicks());
979  }
980
981  // Get the current_offset_.y() value for a sanity-check on scrolling
982  // benchmark metrics. Specifically, we want to make sure
983  // BasicMouseWheelSmoothScrollGesture has proper scroll curves.
984  if (layer_tree_impl()->IsActiveTree()) {
985    TRACE_COUNTER_ID1("gpu", "scroll_offset_y", this->id(), current_offset.y());
986  }
987}
988
989void LayerImpl::SetScrollOffsetDelegate(
990    LayerScrollOffsetDelegate* scroll_offset_delegate) {
991  if (!scroll_offset_delegate && scroll_offset_delegate_) {
992    scroll_delta_ =
993        scroll_offset_delegate_->GetTotalScrollOffset() - scroll_offset_;
994  }
995  gfx::Vector2dF total_offset = TotalScrollOffset();
996  scroll_offset_delegate_ = scroll_offset_delegate;
997  if (scroll_offset_delegate_)
998    scroll_offset_delegate_->SetTotalScrollOffset(total_offset);
999}
1000
1001void LayerImpl::SetScrollOffset(gfx::Vector2d scroll_offset) {
1002  if (scroll_offset_ == scroll_offset)
1003    return;
1004
1005  scroll_offset_ = scroll_offset;
1006
1007  if (scroll_offset_delegate_)
1008    scroll_offset_delegate_->SetTotalScrollOffset(TotalScrollOffset());
1009
1010  NoteLayerPropertyChangedForSubtree();
1011  UpdateScrollbarPositions();
1012}
1013
1014gfx::Vector2dF LayerImpl::ScrollDelta() const {
1015  if (scroll_offset_delegate_)
1016    return scroll_offset_delegate_->GetTotalScrollOffset() - scroll_offset_;
1017  return scroll_delta_;
1018}
1019
1020void LayerImpl::SetScrollDelta(gfx::Vector2dF scroll_delta) {
1021  if (ScrollDelta() == scroll_delta)
1022    return;
1023
1024  if (layer_tree_impl()->IsActiveTree()) {
1025    LayerImpl* pending_twin = layer_tree_impl()->FindPendingTreeLayerById(id());
1026    if (pending_twin) {
1027      // The pending twin can't mirror the scroll delta of the active
1028      // layer.  Although the delta - sent scroll delta difference is
1029      // identical for both twins, the sent scroll delta for the pending
1030      // layer is zero, as anything that has been sent has been baked
1031      // into the layer's position/scroll offset as a part of commit.
1032      DCHECK(pending_twin->sent_scroll_delta().IsZero());
1033      pending_twin->SetScrollDelta(scroll_delta - sent_scroll_delta());
1034    }
1035  }
1036
1037  if (scroll_offset_delegate_) {
1038    scroll_offset_delegate_->SetTotalScrollOffset(
1039        scroll_offset_ + scroll_delta);
1040  } else {
1041    scroll_delta_ = scroll_delta;
1042  }
1043
1044  NoteLayerPropertyChangedForSubtree();
1045  UpdateScrollbarPositions();
1046}
1047
1048gfx::Vector2dF LayerImpl::TotalScrollOffset() const {
1049  return scroll_offset_ + ScrollDelta();
1050}
1051
1052void LayerImpl::SetDoubleSided(bool double_sided) {
1053  if (double_sided_ == double_sided)
1054    return;
1055
1056  double_sided_ = double_sided;
1057  NoteLayerPropertyChangedForSubtree();
1058}
1059
1060Region LayerImpl::VisibleContentOpaqueRegion() const {
1061  if (contents_opaque())
1062    return visible_content_rect();
1063  return Region();
1064}
1065
1066void LayerImpl::DidBeginTracing() {}
1067
1068void LayerImpl::DidLoseOutputSurface() {}
1069
1070void LayerImpl::SetMaxScrollOffset(gfx::Vector2d max_scroll_offset) {
1071  if (max_scroll_offset_ == max_scroll_offset)
1072    return;
1073  max_scroll_offset_ = max_scroll_offset;
1074
1075  layer_tree_impl()->set_needs_update_draw_properties();
1076  UpdateScrollbarPositions();
1077}
1078
1079void LayerImpl::SetScrollbarOpacity(float opacity) {
1080  if (horizontal_scrollbar_layer_)
1081    horizontal_scrollbar_layer_->SetOpacity(opacity);
1082  if (vertical_scrollbar_layer_)
1083    vertical_scrollbar_layer_->SetOpacity(opacity);
1084}
1085
1086void LayerImpl::DidBecomeActive() {
1087  if (!layer_tree_impl_->settings().use_linear_fade_scrollbar_animator)
1088    return;
1089
1090  bool need_scrollbar_animation_controller = horizontal_scrollbar_layer_ ||
1091                                             vertical_scrollbar_layer_;
1092  if (need_scrollbar_animation_controller) {
1093    if (!scrollbar_animation_controller_) {
1094      base::TimeDelta fadeout_delay = base::TimeDelta::FromMilliseconds(
1095          layer_tree_impl_->settings().scrollbar_linear_fade_delay_ms);
1096      base::TimeDelta fadeout_length = base::TimeDelta::FromMilliseconds(
1097          layer_tree_impl_->settings().scrollbar_linear_fade_length_ms);
1098      scrollbar_animation_controller_ =
1099          ScrollbarAnimationControllerLinearFade::Create(
1100              this, fadeout_delay, fadeout_length)
1101              .PassAs<ScrollbarAnimationController>();
1102    }
1103  } else {
1104    scrollbar_animation_controller_.reset();
1105  }
1106}
1107void LayerImpl::SetHorizontalScrollbarLayer(
1108    PaintedScrollbarLayerImpl* scrollbar_layer) {
1109  horizontal_scrollbar_layer_ = scrollbar_layer;
1110  if (horizontal_scrollbar_layer_)
1111    horizontal_scrollbar_layer_->set_scroll_layer_id(id());
1112}
1113
1114void LayerImpl::SetVerticalScrollbarLayer(
1115    PaintedScrollbarLayerImpl* scrollbar_layer) {
1116  vertical_scrollbar_layer_ = scrollbar_layer;
1117  if (vertical_scrollbar_layer_)
1118    vertical_scrollbar_layer_->set_scroll_layer_id(id());
1119}
1120
1121static scoped_ptr<base::Value>
1122CompositingReasonsAsValue(CompositingReasons reasons) {
1123  scoped_ptr<base::ListValue> reason_list(new base::ListValue());
1124
1125  if (reasons == kCompositingReasonUnknown) {
1126    reason_list->AppendString("No reasons given");
1127    return reason_list.PassAs<base::Value>();
1128  }
1129
1130  if (reasons & kCompositingReason3DTransform)
1131    reason_list->AppendString("Has a 3d Transform");
1132
1133  if (reasons & kCompositingReasonVideo)
1134    reason_list->AppendString("Is accelerated video");
1135
1136  if (reasons & kCompositingReasonCanvas)
1137    reason_list->AppendString("Is accelerated canvas");
1138
1139  if (reasons & kCompositingReasonPlugin)
1140    reason_list->AppendString("Is accelerated plugin");
1141
1142  if (reasons & kCompositingReasonIFrame)
1143    reason_list->AppendString("Is accelerated iframe");
1144
1145  if (reasons & kCompositingReasonBackfaceVisibilityHidden)
1146    reason_list->AppendString("Has backface-visibility: hidden");
1147
1148  if (reasons & kCompositingReasonAnimation)
1149    reason_list->AppendString("Has accelerated animation or transition");
1150
1151  if (reasons & kCompositingReasonFilters)
1152    reason_list->AppendString("Has accelerated filters");
1153
1154  if (reasons & kCompositingReasonPositionFixed)
1155    reason_list->AppendString("Is fixed position");
1156
1157  if (reasons & kCompositingReasonPositionSticky)
1158    reason_list->AppendString("Is sticky position");
1159
1160  if (reasons & kCompositingReasonOverflowScrollingTouch)
1161    reason_list->AppendString("Is a scrollable overflow element");
1162
1163  if (reasons & kCompositingReasonBlending)
1164    reason_list->AppendString("Has a blend mode");
1165
1166  if (reasons & kCompositingReasonAssumedOverlap)
1167    reason_list->AppendString("Might overlap a composited animation");
1168
1169  if (reasons & kCompositingReasonOverlap)
1170    reason_list->AppendString("Overlaps other composited content");
1171
1172  if (reasons & kCompositingReasonNegativeZIndexChildren) {
1173    reason_list->AppendString("Might overlap negative z-index "
1174                              "composited content");
1175  }
1176
1177  if (reasons & kCompositingReasonTransformWithCompositedDescendants) {
1178    reason_list->AppendString("Has transform needed by a "
1179                              "composited descendant");
1180  }
1181
1182  if (reasons & kCompositingReasonOpacityWithCompositedDescendants)
1183    reason_list->AppendString("Has opacity needed by a composited descendant");
1184
1185  if (reasons & kCompositingReasonMaskWithCompositedDescendants)
1186    reason_list->AppendString("Has a mask needed by a composited descendant");
1187
1188  if (reasons & kCompositingReasonReflectionWithCompositedDescendants)
1189    reason_list->AppendString("Has a reflection with a composited descendant");
1190
1191  if (reasons & kCompositingReasonFilterWithCompositedDescendants)
1192    reason_list->AppendString("Has filter effect with a composited descendant");
1193
1194  if (reasons & kCompositingReasonBlendingWithCompositedDescendants)
1195    reason_list->AppendString("Has a blend mode with a composited descendant");
1196
1197  if (reasons & kCompositingReasonClipsCompositingDescendants)
1198    reason_list->AppendString("Clips a composited descendant");
1199
1200  if (reasons & kCompositingReasonPerspective) {
1201    reason_list->AppendString("Has a perspective transform needed by a "
1202                              "composited 3d descendant");
1203  }
1204
1205  if (reasons & kCompositingReasonPreserve3D) {
1206    reason_list->AppendString("Has preserves-3d style with composited "
1207                              "3d descendant");
1208  }
1209
1210  if (reasons & kCompositingReasonReflectionOfCompositedParent)
1211    reason_list->AppendString("Is the reflection of a composited layer");
1212
1213  if (reasons & kCompositingReasonRoot)
1214    reason_list->AppendString("Is the root");
1215
1216  if (reasons & kCompositingReasonLayerForClip)
1217    reason_list->AppendString("Convenience layer, to clip subtree");
1218
1219  if (reasons & kCompositingReasonLayerForScrollbar)
1220    reason_list->AppendString("Convenience layer for rendering scrollbar");
1221
1222  if (reasons & kCompositingReasonLayerForScrollingContainer)
1223    reason_list->AppendString("Convenience layer, the scrolling container");
1224
1225  if (reasons & kCompositingReasonLayerForForeground) {
1226    reason_list->AppendString("Convenience layer, foreground when main layer "
1227                              "has negative z-index composited content");
1228  }
1229
1230  if (reasons & kCompositingReasonLayerForBackground) {
1231    reason_list->AppendString("Convenience layer, background when main layer "
1232                              "has a composited background");
1233  }
1234
1235  if (reasons & kCompositingReasonLayerForMask)
1236    reason_list->AppendString("Is a mask layer");
1237
1238  if (reasons & kCompositingReasonOverflowScrollingParent)
1239    reason_list->AppendString("Scroll parent is not an ancestor");
1240
1241  if (reasons & kCompositingReasonOutOfFlowClipping)
1242    reason_list->AppendString("Has clipping ancestor");
1243
1244  return reason_list.PassAs<base::Value>();
1245}
1246
1247void LayerImpl::AsValueInto(base::DictionaryValue* state) const {
1248  TracedValue::MakeDictIntoImplicitSnapshot(state, LayerTypeAsString(), this);
1249  state->SetInteger("layer_id", id());
1250  state->SetString("layer_name", debug_name());
1251  state->Set("bounds", MathUtil::AsValue(bounds()).release());
1252  state->SetInteger("draws_content", DrawsContent());
1253  state->SetInteger("gpu_memory_usage", GPUMemoryUsageInBytes());
1254  state->Set("compositing_reasons",
1255             CompositingReasonsAsValue(compositing_reasons_).release());
1256
1257  bool clipped;
1258  gfx::QuadF layer_quad = MathUtil::MapQuad(
1259      screen_space_transform(),
1260      gfx::QuadF(gfx::Rect(content_bounds())),
1261      &clipped);
1262  state->Set("layer_quad", MathUtil::AsValue(layer_quad).release());
1263
1264
1265  scoped_ptr<base::ListValue> children_list(new base::ListValue());
1266  for (size_t i = 0; i < children_.size(); ++i)
1267    children_list->Append(children_[i]->AsValue().release());
1268  state->Set("children", children_list.release());
1269  if (mask_layer_)
1270    state->Set("mask_layer", mask_layer_->AsValue().release());
1271  if (replica_layer_)
1272    state->Set("replica_layer", replica_layer_->AsValue().release());
1273
1274  if (scroll_parent_)
1275    state->SetInteger("scroll_parent", scroll_parent_->id());
1276
1277  if (clip_parent_)
1278    state->SetInteger("clip_parent", clip_parent_->id());
1279}
1280
1281size_t LayerImpl::GPUMemoryUsageInBytes() const { return 0; }
1282
1283scoped_ptr<base::Value> LayerImpl::AsValue() const {
1284  scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
1285  AsValueInto(state.get());
1286  return state.PassAs<base::Value>();
1287}
1288
1289}  // namespace cc
1290