Roll src/third_party/WebKit eac3800:0237a66 (svn 202606:202607)
[chromium-blink-merge.git] / content / browser / devtools / devtools_frame_trace_recorder.cc
blobb024a08024798c37117f4717cef151102cb8304e
1 // Copyright (c) 2015 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.
5 #include "content/browser/devtools/devtools_frame_trace_recorder.h"
7 #include <string>
8 #include <vector>
10 #include "base/atomicops.h"
11 #include "base/base64.h"
12 #include "base/bind.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/trace_event/trace_event_impl.h"
15 #include "cc/output/compositor_frame_metadata.h"
16 #include "content/browser/frame_host/render_frame_host_impl.h"
17 #include "content/browser/renderer_host/render_widget_host_view_base.h"
18 #include "content/public/browser/readback_types.h"
19 #include "third_party/skia/include/core/SkBitmap.h"
20 #include "ui/gfx/codec/png_codec.h"
21 #include "ui/gfx/geometry/size.h"
22 #include "ui/gfx/geometry/size_conversions.h"
24 namespace content {
26 namespace {
28 static base::subtle::Atomic32 frame_data_count = 0;
29 static int kMaximumFrameDataCount = 150;
30 static size_t kFrameAreaLimit = 256000;
32 class TraceableDevToolsScreenshot
33 : public base::trace_event::ConvertableToTraceFormat {
34 public:
35 TraceableDevToolsScreenshot(const SkBitmap& bitmap) : frame_(bitmap) {}
37 void AppendAsTraceFormat(std::string* out) const override {
38 out->append("\"");
39 if (!frame_.drawsNothing()) {
40 std::vector<unsigned char> data;
41 SkAutoLockPixels lock_image(frame_);
42 bool encoded = gfx::PNGCodec::Encode(
43 reinterpret_cast<unsigned char*>(frame_.getAddr32(0, 0)),
44 gfx::PNGCodec::FORMAT_SkBitmap,
45 gfx::Size(frame_.width(), frame_.height()),
46 frame_.width() * frame_.bytesPerPixel(), false,
47 std::vector<gfx::PNGCodec::Comment>(), &data);
48 if (encoded) {
49 std::string encoded_data;
50 base::Base64Encode(
51 base::StringPiece(reinterpret_cast<char*>(&data[0]), data.size()),
52 &encoded_data);
53 out->append(encoded_data);
56 out->append("\"");
59 private:
60 ~TraceableDevToolsScreenshot() override {
61 base::subtle::NoBarrier_AtomicIncrement(&frame_data_count, -1);
64 SkBitmap frame_;
67 void FrameCaptured(base::TraceTicks timestamp, const SkBitmap& bitmap,
68 ReadbackResponse response) {
69 if (response != READBACK_SUCCESS)
70 return;
71 int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
72 if (current_frame_count >= kMaximumFrameDataCount)
73 return;
74 if (bitmap.drawsNothing())
75 return;
76 base::subtle::NoBarrier_AtomicIncrement(&frame_data_count, 1);
77 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(
78 TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), "Screenshot", 1,
79 timestamp.ToInternalValue(),
80 scoped_refptr<base::trace_event::ConvertableToTraceFormat>(
81 new TraceableDevToolsScreenshot(bitmap)));
84 void CaptureFrame(RenderFrameHostImpl* host,
85 const cc::CompositorFrameMetadata& metadata) {
86 RenderWidgetHostViewBase* view =
87 static_cast<RenderWidgetHostViewBase*>(host->GetView());
88 if (!view)
89 return;
90 int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
91 if (current_frame_count >= kMaximumFrameDataCount)
92 return;
93 float scale = metadata.page_scale_factor;
94 float area = metadata.scrollable_viewport_size.GetArea();
95 if (area * scale * scale > kFrameAreaLimit)
96 scale = sqrt(kFrameAreaLimit / area);
97 gfx::Size snapshot_size(gfx::ToRoundedSize(gfx::ScaleSize(
98 metadata.scrollable_viewport_size, scale)));
99 view->CopyFromCompositingSurface(
100 gfx::Rect(), snapshot_size,
101 base::Bind(FrameCaptured, base::TraceTicks::Now()),
102 kN32_SkColorType);
105 bool ScreenshotCategoryEnabled() {
106 bool enabled;
107 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
108 TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), &enabled);
109 return enabled;
112 } // namespace
114 DevToolsFrameTraceRecorder::DevToolsFrameTraceRecorder() { }
116 DevToolsFrameTraceRecorder::~DevToolsFrameTraceRecorder() { }
118 void DevToolsFrameTraceRecorder::OnSwapCompositorFrame(
119 RenderFrameHostImpl* host,
120 const cc::CompositorFrameMetadata& frame_metadata) {
121 if (!host || !ScreenshotCategoryEnabled())
122 return;
123 CaptureFrame(host, frame_metadata);
126 void DevToolsFrameTraceRecorder::OnSynchronousSwapCompositorFrame(
127 RenderFrameHostImpl* host,
128 const cc::CompositorFrameMetadata& frame_metadata) {
129 if (!host || !ScreenshotCategoryEnabled()) {
130 last_metadata_.reset();
131 return;
134 bool is_new_trace;
135 TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
136 if (!is_new_trace && last_metadata_)
137 CaptureFrame(host, *last_metadata_);
138 last_metadata_.reset(new cc::CompositorFrameMetadata(frame_metadata));
141 } // namespace content