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