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 <memory>
8 #include <utility>
9 
10 #include "base/auto_reset.h"
11 #include "base/debug/crash_logging.h"
12 #include "base/debug/dump_without_crashing.h"
13 #include "base/trace_event/trace_event.h"
14 #include "cc/layers/content_layer_client.h"
15 #include "cc/layers/picture_layer_impl.h"
16 #include "cc/layers/recording_source.h"
17 #include "cc/paint/paint_record.h"
18 #include "cc/trees/layer_tree_host.h"
19 #include "cc/trees/layer_tree_impl.h"
20 #include "cc/trees/transform_node.h"
21 #include "third_party/skia/include/core/SkPictureRecorder.h"
22 #include "ui/gfx/geometry/rect_conversions.h"
23 
24 namespace cc {
25 
26 PictureLayer::PictureLayerInputs::PictureLayerInputs() = default;
27 
28 PictureLayer::PictureLayerInputs::~PictureLayerInputs() = default;
29 
Create(ContentLayerClient * client)30 scoped_refptr<PictureLayer> PictureLayer::Create(ContentLayerClient* client) {
31   return base::WrapRefCounted(new PictureLayer(client));
32 }
33 
PictureLayer(ContentLayerClient * client)34 PictureLayer::PictureLayer(ContentLayerClient* client)
35     : instrumentation_object_tracker_(id()), update_source_frame_number_(-1) {
36   picture_layer_inputs_.client = client;
37 }
38 
PictureLayer(ContentLayerClient * client,std::unique_ptr<RecordingSource> source)39 PictureLayer::PictureLayer(ContentLayerClient* client,
40                            std::unique_ptr<RecordingSource> source)
41     : PictureLayer(client) {
42   recording_source_ = std::move(source);
43 }
44 
45 PictureLayer::~PictureLayer() = default;
46 
CreateLayerImpl(LayerTreeImpl * tree_impl)47 std::unique_ptr<LayerImpl> PictureLayer::CreateLayerImpl(
48     LayerTreeImpl* tree_impl) {
49   return PictureLayerImpl::Create(tree_impl, id());
50 }
51 
PushPropertiesTo(LayerImpl * base_layer)52 void PictureLayer::PushPropertiesTo(LayerImpl* base_layer) {
53   // TODO(enne): http://crbug.com/918126 debugging
54   CHECK(this);
55 
56   PictureLayerImpl* layer_impl = static_cast<PictureLayerImpl*>(base_layer);
57 
58   Layer::PushPropertiesTo(base_layer);
59   TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
60                "PictureLayer::PushPropertiesTo");
61   DropRecordingSourceContentIfInvalid();
62 
63   layer_impl->SetNearestNeighbor(picture_layer_inputs_.nearest_neighbor);
64   layer_impl->set_gpu_raster_max_texture_size(
65       layer_tree_host()->device_viewport_rect().size());
66   layer_impl->SetIsBackdropFilterMask(is_backdrop_filter_mask());
67   layer_impl->SetDirectlyCompositedImageSize(
68       picture_layer_inputs_.directly_composited_image_size);
69 
70   // TODO(enne): http://crbug.com/918126 debugging
71   CHECK(this);
72   if (!recording_source_) {
73     bool valid_host = layer_tree_host();
74     bool has_parent = parent();
75     bool parent_has_host = parent() && parent()->layer_tree_host();
76 
77     auto str = base::StringPrintf("vh: %d, hp: %d, phh: %d", valid_host,
78                                   has_parent, parent_has_host);
79     static auto* crash_key = base::debug::AllocateCrashKeyString(
80         "issue918126", base::debug::CrashKeySize::Size32);
81     base::debug::SetCrashKeyString(crash_key, str);
82     base::debug::DumpWithoutCrashing();
83   }
84 
85   layer_impl->UpdateRasterSource(recording_source_->CreateRasterSource(),
86                                  &last_updated_invalidation_, nullptr, nullptr);
87   DCHECK(last_updated_invalidation_.IsEmpty());
88 }
89 
SetLayerTreeHost(LayerTreeHost * host)90 void PictureLayer::SetLayerTreeHost(LayerTreeHost* host) {
91   Layer::SetLayerTreeHost(host);
92 
93   if (!host)
94     return;
95 
96   if (!recording_source_)
97     recording_source_.reset(new RecordingSource);
98   recording_source_->SetSlowdownRasterScaleFactor(
99       host->GetDebugState().slow_down_raster_scale_factor);
100 
101   // Source frame numbers are relative the LayerTreeHost, so this needs
102   // to be reset.
103   update_source_frame_number_ = -1;
104 }
105 
SetNeedsDisplayRect(const gfx::Rect & layer_rect)106 void PictureLayer::SetNeedsDisplayRect(const gfx::Rect& layer_rect) {
107   DCHECK(!layer_tree_host() || !layer_tree_host()->in_paint_layer_contents());
108   if (recording_source_)
109     recording_source_->SetNeedsDisplayRect(layer_rect);
110   Layer::SetNeedsDisplayRect(layer_rect);
111 }
112 
Update()113 bool PictureLayer::Update() {
114   update_source_frame_number_ = layer_tree_host()->SourceFrameNumber();
115   bool updated = Layer::Update();
116 
117   gfx::Size layer_size = bounds();
118 
119   recording_source_->SetBackgroundColor(SafeOpaqueBackgroundColor());
120   recording_source_->SetRequiresClear(
121       !contents_opaque() &&
122       !picture_layer_inputs_.client->FillsBoundsCompletely());
123 
124   TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "PictureLayer::Update",
125                "source_frame_number", layer_tree_host()->SourceFrameNumber());
126   devtools_instrumentation::ScopedLayerTreeTask update_layer(
127       devtools_instrumentation::kUpdateLayer, id(), layer_tree_host()->GetId());
128 
129   // UpdateAndExpandInvalidation will give us an invalidation that covers
130   // anything not explicitly recorded in this frame. We give this region
131   // to the impl side so that it drops tiles that may not have a recording
132   // for them.
133   DCHECK(picture_layer_inputs_.client);
134 
135   auto recorded_viewport = picture_layer_inputs_.client->PaintableRegion();
136 
137   updated |= recording_source_->UpdateAndExpandInvalidation(
138       &last_updated_invalidation_, layer_size, recorded_viewport);
139 
140   if (updated) {
141     {
142       auto old_display_list = std::move(picture_layer_inputs_.display_list);
143       picture_layer_inputs_.display_list =
144           picture_layer_inputs_.client->PaintContentsToDisplayList();
145       if (old_display_list &&
146           picture_layer_inputs_.display_list
147               ->NeedsAdditionalInvalidationForLCDText(*old_display_list)) {
148         last_updated_invalidation_ = gfx::Rect(bounds());
149       }
150     }
151 
152     // Clear out previous directly composited image state - if the layer
153     // qualifies we'll set up the state below.
154     picture_layer_inputs_.directly_composited_image_size = base::nullopt;
155     picture_layer_inputs_.nearest_neighbor = false;
156     base::Optional<DisplayItemList::DirectlyCompositedImageResult> result =
157         picture_layer_inputs_.display_list->GetDirectlyCompositedImageResult(
158             bounds());
159     if (result) {
160       // Directly composited images are not guaranteed to fully cover every
161       // pixel in the layer due to ceiling when calculating the tile content
162       // rect from the layer bounds.
163       recording_source_->SetRequiresClear(true);
164       picture_layer_inputs_.directly_composited_image_size =
165           result->intrinsic_image_size;
166       picture_layer_inputs_.nearest_neighbor = result->nearest_neighbor;
167     }
168 
169     recording_source_->UpdateDisplayItemList(
170         picture_layer_inputs_.display_list,
171         layer_tree_host()->recording_scale_factor());
172 
173     SetNeedsPushProperties();
174     IncreasePaintCount();
175   } else {
176     // If this invalidation did not affect the recording source, then it can be
177     // cleared as an optimization.
178     last_updated_invalidation_.Clear();
179   }
180 
181   return updated;
182 }
183 
GetPicture() const184 sk_sp<SkPicture> PictureLayer::GetPicture() const {
185   if (!DrawsContent() || bounds().IsEmpty())
186     return nullptr;
187 
188   scoped_refptr<DisplayItemList> display_list =
189       picture_layer_inputs_.client->PaintContentsToDisplayList();
190   SkPictureRecorder recorder;
191   SkCanvas* canvas =
192       recorder.beginRecording(bounds().width(), bounds().height());
193   canvas->clear(SK_ColorTRANSPARENT);
194   display_list->Raster(canvas);
195   return recorder.finishRecordingAsPicture();
196 }
197 
ClearClient()198 void PictureLayer::ClearClient() {
199   picture_layer_inputs_.client = nullptr;
200   UpdateDrawsContent(HasDrawableContent());
201 }
202 
SetNearestNeighbor(bool nearest_neighbor)203 void PictureLayer::SetNearestNeighbor(bool nearest_neighbor) {
204   if (picture_layer_inputs_.nearest_neighbor == nearest_neighbor)
205     return;
206 
207   picture_layer_inputs_.nearest_neighbor = nearest_neighbor;
208   SetNeedsCommit();
209 }
210 
HasDrawableContent() const211 bool PictureLayer::HasDrawableContent() const {
212   return picture_layer_inputs_.client && Layer::HasDrawableContent();
213 }
214 
SetIsBackdropFilterMask(bool is_backdrop_filter_mask)215 void PictureLayer::SetIsBackdropFilterMask(bool is_backdrop_filter_mask) {
216   if (picture_layer_inputs_.is_backdrop_filter_mask == is_backdrop_filter_mask)
217     return;
218 
219   picture_layer_inputs_.is_backdrop_filter_mask = is_backdrop_filter_mask;
220   SetNeedsCommit();
221 }
222 
RunMicroBenchmark(MicroBenchmark * benchmark)223 void PictureLayer::RunMicroBenchmark(MicroBenchmark* benchmark) {
224   benchmark->RunOnLayer(this);
225 }
226 
CaptureContent(const gfx::Rect & rect,std::vector<NodeInfo> * content)227 void PictureLayer::CaptureContent(const gfx::Rect& rect,
228                                   std::vector<NodeInfo>* content) {
229   if (!DrawsContent())
230     return;
231 
232   const DisplayItemList* display_item_list = GetDisplayItemList();
233   if (!display_item_list)
234     return;
235 
236   // We could run into this situation as CaptureContent could start at any time.
237   if (transform_tree_index() == TransformTree::kInvalidNodeId)
238     return;
239 
240   gfx::Transform inverse_screen_space_transform;
241   if (!ScreenSpaceTransform().GetInverse(&inverse_screen_space_transform))
242     return;
243   gfx::Rect transformed = MathUtil::ProjectEnclosingClippedRect(
244       inverse_screen_space_transform, rect);
245 
246   transformed.Intersect(gfx::Rect(bounds()));
247   if (transformed.IsEmpty())
248     return;
249 
250   display_item_list->CaptureContent(transformed, content);
251   if (auto* outer_viewport_layer = layer_tree_host()->LayerByElementId(
252           layer_tree_host()->OuterViewportScrollElementId())) {
253     if (transform_tree_index() == outer_viewport_layer->transform_tree_index())
254       return;
255     gfx::Transform inverse_outer_screen_space_transform;
256     if (!outer_viewport_layer->ScreenSpaceTransform().GetInverse(
257             &inverse_outer_screen_space_transform)) {
258       return;
259     }
260     gfx::Transform combined_transform{ScreenSpaceTransform(),
261                                       inverse_outer_screen_space_transform};
262     for (auto& i : *content) {
263       i.visual_rect = MathUtil::ProjectEnclosingClippedRect(combined_transform,
264                                                             i.visual_rect);
265     }
266   }
267 }
268 
DropRecordingSourceContentIfInvalid()269 void PictureLayer::DropRecordingSourceContentIfInvalid() {
270   int source_frame_number = layer_tree_host()->SourceFrameNumber();
271   gfx::Size recording_source_bounds = recording_source_->GetSize();
272 
273   gfx::Size layer_bounds = bounds();
274 
275   // If update called, then recording source size must match bounds pushed to
276   // impl layer.
277   DCHECK(update_source_frame_number_ != source_frame_number ||
278          layer_bounds == recording_source_bounds)
279       << " bounds " << layer_bounds.ToString() << " recording source "
280       << recording_source_bounds.ToString();
281 
282   if (update_source_frame_number_ != source_frame_number &&
283       recording_source_bounds != layer_bounds) {
284     // Update may not get called for the layer (if it's not in the viewport
285     // for example), even though it has resized making the recording source no
286     // longer valid. In this case just destroy the recording source.
287     recording_source_->SetEmptyBounds();
288     picture_layer_inputs_.display_list = nullptr;
289   }
290 }
291 
GetDisplayItemList()292 const DisplayItemList* PictureLayer::GetDisplayItemList() {
293   return picture_layer_inputs_.display_list.get();
294 }
295 
296 }  // namespace cc
297