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