[Android] A prototype of the interactive media notification.
[chromium-blink-merge.git] / content / browser / devtools / devtools_frame_trace_recorder.cc
blob9b67c1e17fde3cab71848ebce08687c970b37617
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 } // namespace
69 class DevToolsFrameTraceRecorderData
70 : public base::RefCounted<DevToolsFrameTraceRecorderData> {
71 public:
72 DevToolsFrameTraceRecorderData(const cc::CompositorFrameMetadata& metadata)
73 : metadata_(metadata), timestamp_(base::TraceTicks::Now()) {}
75 void FrameCaptured(const SkBitmap& bitmap, ReadbackResponse response) {
76 if (response != READBACK_SUCCESS)
77 return;
78 int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
79 if (current_frame_count >= kMaximumFrameDataCount)
80 return;
81 if (bitmap.drawsNothing())
82 return;
83 base::subtle::NoBarrier_AtomicIncrement(&frame_data_count, 1);
84 TRACE_EVENT_OBJECT_SNAPSHOT_WITH_ID_AND_TIMESTAMP(
85 TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), "Screenshot", 1,
86 timestamp_.ToInternalValue(),
87 scoped_refptr<base::trace_event::ConvertableToTraceFormat>(
88 new TraceableDevToolsScreenshot(bitmap)));
91 void CaptureFrame(RenderFrameHostImpl* host) {
92 RenderWidgetHostViewBase* view =
93 static_cast<RenderWidgetHostViewBase*>(host->GetView());
94 if (!view)
95 return;
96 int current_frame_count = base::subtle::NoBarrier_Load(&frame_data_count);
97 if (current_frame_count >= kMaximumFrameDataCount)
98 return;
99 float scale = metadata_.page_scale_factor;
100 float area = metadata_.scrollable_viewport_size.GetArea();
101 if (area * scale * scale > kFrameAreaLimit)
102 scale = sqrt(kFrameAreaLimit / area);
103 gfx::Size snapshot_size(gfx::ToRoundedSize(gfx::ScaleSize(
104 metadata_.scrollable_viewport_size, scale)));
105 view->CopyFromCompositingSurface(
106 gfx::Rect(), snapshot_size,
107 base::Bind(&DevToolsFrameTraceRecorderData::FrameCaptured, this),
108 kN32_SkColorType);
111 private:
112 friend class base::RefCounted<DevToolsFrameTraceRecorderData>;
113 ~DevToolsFrameTraceRecorderData() {}
115 cc::CompositorFrameMetadata metadata_;
116 base::TraceTicks timestamp_;
118 DISALLOW_COPY_AND_ASSIGN(DevToolsFrameTraceRecorderData);
121 DevToolsFrameTraceRecorder::DevToolsFrameTraceRecorder() { }
123 DevToolsFrameTraceRecorder::~DevToolsFrameTraceRecorder() { }
125 void DevToolsFrameTraceRecorder::OnSwapCompositorFrame(
126 RenderFrameHostImpl* host,
127 const cc::CompositorFrameMetadata& frame_metadata,
128 bool do_capture) {
129 if (!host)
130 return;
132 bool enabled;
133 TRACE_EVENT_CATEGORY_GROUP_ENABLED(
134 TRACE_DISABLED_BY_DEFAULT("devtools.screenshot"), &enabled);
135 if (!enabled || !do_capture) {
136 pending_frame_data_ = nullptr;
137 return;
140 bool is_new_trace;
141 TRACE_EVENT_IS_NEW_TRACE(&is_new_trace);
142 if (!is_new_trace && pending_frame_data_)
143 pending_frame_data_->CaptureFrame(host);
145 pending_frame_data_ = new DevToolsFrameTraceRecorderData(frame_metadata);
148 } // namespace content