1// Copyright 2012 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/picture_layer.h"
6
7#include "cc/layers/content_layer_client.h"
8#include "cc/layers/picture_layer_impl.h"
9#include "cc/trees/layer_tree_impl.h"
10#include "third_party/skia/include/core/SkPictureRecorder.h"
11#include "ui/gfx/rect_conversions.h"
12
13namespace cc {
14
15scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
16  return make_scoped_refptr(new PictureLayer(client));
17}
18
19PictureLayer::PictureLayer(ContentLayerClient* client)
20    : client_(client),
21      pile_(make_scoped_refptr(new PicturePile())),
22      instrumentation_object_tracker_(id()),
23      is_mask_(false),
24      update_source_frame_number_(-1),
25      can_use_lcd_text_last_frame_(can_use_lcd_text()) {
26}
27
28PictureLayer::~PictureLayer() {
29}
30
31bool PictureLayer::DrawsContent() const {
32  return Layer::DrawsContent() && client_;
33}
34
35scoped_ptr<LayerImpl> PictureLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
36  return PictureLayerImpl::Create(tree_impl, id()).PassAs<LayerImpl>();
37}
38
39void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
40  Layer::PushPropertiesTo(base_layer);
41  PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
42
43  if (layer_impl->bounds().IsEmpty()) {
44    // Update may not get called for an empty layer, so resize here instead.
45    // Using layer_impl because either bounds() or paint_properties().bounds
46    // may disagree and either one could have been pushed to layer_impl.
47    pile_->SetTilingRect(gfx::Rect());
48  } else if (update_source_frame_number_ ==
49             layer_tree_host()->source_frame_number()) {
50    // TODO(ernstm): This DCHECK is only valid as long as the pile's tiling_rect
51    // is identical to the layer_rect.
52    // If update called, then pile size must match bounds pushed to impl layer.
53    DCHECK_EQ(layer_impl->bounds().ToString(),
54              pile_->tiling_rect().size().ToString());
55  }
56
57  layer_impl->SetIsMask(is_mask_);
58
59  // Unlike other properties, invalidation must always be set on layer_impl.
60  // See PictureLayerImpl::PushPropertiesTo for more details.
61  layer_impl->invalidation_.Clear();
62  layer_impl->invalidation_.Swap(&pile_invalidation_);
63  layer_impl->pile_ = PicturePileImpl::CreateFromOther(pile_.get());
64}
65
66void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
67  Layer::SetLayerTreeHost(host);
68  if (host) {
69    pile_->SetMinContentsScale(host->settings().minimum_contents_scale);
70    pile_->SetTileGridSize(host->settings().default_tile_size);
71    pile_->set_slow_down_raster_scale_factor(
72        host->debug_state().slow_down_raster_scale_factor);
73    pile_->set_show_debug_picture_borders(
74        host->debug_state().show_picture_borders);
75  }
76}
77
78void PictureLayer::SetNeedsDisplayRect(const gfx::RectF& layer_rect) {
79  gfx::Rect rect = gfx::ToEnclosedRect(layer_rect);
80  if (!rect.IsEmpty()) {
81    // Clamp invalidation to the layer bounds.
82    rect.Intersect(gfx::Rect(bounds()));
83    pending_invalidation_.Union(rect);
84  }
85  Layer::SetNeedsDisplayRect(layer_rect);
86}
87
88bool PictureLayer::Update(ResourceUpdateQueue* queue,
89                          const OcclusionTracker<Layer>* occlusion) {
90  update_source_frame_number_ = layer_tree_host()->source_frame_number();
91  bool updated = Layer::Update(queue, occlusion);
92
93  UpdateCanUseLCDText();
94
95  gfx::Rect visible_layer_rect = gfx::ScaleToEnclosingRect(
96      visible_content_rect(), 1.f / contents_scale_x());
97
98  gfx::Rect layer_rect = gfx::Rect(paint_properties().bounds);
99
100  if (last_updated_visible_content_rect_ == visible_content_rect() &&
101      pile_->tiling_rect() == layer_rect && pending_invalidation_.IsEmpty()) {
102    // Only early out if the visible content rect of this layer hasn't changed.
103    return updated;
104  }
105
106  TRACE_EVENT1("cc", "PictureLayer::Update",
107               "source_frame_number",
108               layer_tree_host()->source_frame_number());
109  devtools_instrumentation::ScopedLayerTreeTask update_layer(
110      devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->id());
111
112  pile_->SetTilingRect(layer_rect);
113
114  // Calling paint in WebKit can sometimes cause invalidations, so save
115  // off the invalidation prior to calling update.
116  pending_invalidation_.Swap(&pile_invalidation_);
117  pending_invalidation_.Clear();
118
119  if (layer_tree_host()->settings().record_full_layer) {
120    // Workaround for http://crbug.com/235910 - to retain backwards compat
121    // the full page content must always be provided in the picture layer.
122    visible_layer_rect = gfx::Rect(bounds());
123  }
124
125  // UpdateAndExpandInvalidation will give us an invalidation that covers
126  // anything not explicitly recorded in this frame. We give this region
127  // to the impl side so that it drops tiles that may not have a recording
128  // for them.
129  DCHECK(client_);
130  updated |=
131      pile_->UpdateAndExpandInvalidation(client_,
132                                         &pile_invalidation_,
133                                         SafeOpaqueBackgroundColor(),
134                                         contents_opaque(),
135                                         client_->FillsBoundsCompletely(),
136                                         visible_layer_rect,
137                                         update_source_frame_number_,
138                                         RecordingMode(),
139                                         rendering_stats_instrumentation());
140  last_updated_visible_content_rect_ = visible_content_rect();
141
142  if (updated) {
143    SetNeedsPushProperties();
144  } else {
145    // If this invalidation did not affect the pile, then it can be cleared as
146    // an optimization.
147    pile_invalidation_.Clear();
148  }
149
150  return updated;
151}
152
153void PictureLayer::SetIsMask(bool is_mask) {
154  is_mask_ = is_mask;
155}
156
157Picture::RecordingMode PictureLayer::RecordingMode() const {
158  switch (layer_tree_host()->settings().recording_mode) {
159    case LayerTreeSettings::RecordNormally:
160      return Picture::RECORD_NORMALLY;
161    case LayerTreeSettings::RecordWithSkRecord:
162      return Picture::RECORD_WITH_SKRECORD;
163  }
164  NOTREACHED();
165  return Picture::RECORD_NORMALLY;
166}
167
168bool PictureLayer::SupportsLCDText() const {
169  return true;
170}
171
172void PictureLayer::UpdateCanUseLCDText() {
173  if (can_use_lcd_text_last_frame_ == can_use_lcd_text())
174    return;
175
176  can_use_lcd_text_last_frame_ = can_use_lcd_text();
177  if (client_)
178    client_->DidChangeLayerCanUseLCDText();
179}
180
181skia::RefPtr<SkPicture> PictureLayer::GetPicture() const {
182  // We could either flatten the PicturePile into a single SkPicture,
183  // or paint a fresh one depending on what we intend to do with the
184  // picture. For now we just paint a fresh one to get consistent results.
185  if (!DrawsContent())
186    return skia::RefPtr<SkPicture>();
187
188  int width = bounds().width();
189  int height = bounds().height();
190  gfx::RectF opaque;
191
192  SkPictureRecorder recorder;
193  SkCanvas* canvas = recorder.beginRecording(width, height, NULL, 0);
194  client_->PaintContents(canvas,
195                         gfx::Rect(width, height),
196                         &opaque,
197                         ContentLayerClient::GRAPHICS_CONTEXT_ENABLED);
198  skia::RefPtr<SkPicture> picture = skia::AdoptRef(recorder.endRecording());
199  return picture;
200}
201
202bool PictureLayer::IsSuitableForGpuRasterization() const {
203  return pile_->is_suitable_for_gpu_rasterization();
204}
205
206void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
207  benchmark->RunOnLayer(this);
208}
209
210}  // namespace cc
211