1 // Copyright 2013 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 "extensions/browser/api/capture_web_contents_function.h"
7 #include "base/base64.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/public/browser/render_widget_host.h"
10 #include "content/public/browser/render_widget_host_view.h"
11 #include "content/public/browser/web_contents.h"
12 #include "extensions/browser/extension_function.h"
13 #include "extensions/common/constants.h"
14 #include "ui/gfx/codec/jpeg_codec.h"
15 #include "ui/gfx/codec/png_codec.h"
16 #include "ui/gfx/display.h"
17 #include "ui/gfx/geometry/size_conversions.h"
18 #include "ui/gfx/screen.h"
20 using content::RenderWidgetHost
;
21 using content::RenderWidgetHostView
;
22 using content::WebContents
;
24 namespace extensions
{
26 using core_api::extension_types::ImageDetails
;
28 bool CaptureWebContentsFunction::HasPermission() {
32 bool CaptureWebContentsFunction::RunAsync() {
33 EXTENSION_FUNCTION_VALIDATE(args_
);
35 context_id_
= extension_misc::kCurrentWindowId
;
36 args_
->GetInteger(0, &context_id_
);
38 scoped_ptr
<ImageDetails
> image_details
;
39 if (args_
->GetSize() > 1) {
40 base::Value
* spec
= NULL
;
41 EXTENSION_FUNCTION_VALIDATE(args_
->Get(1, &spec
) && spec
);
42 image_details
= ImageDetails::FromValue(*spec
);
45 if (!IsScreenshotEnabled())
48 WebContents
* contents
= GetWebContentsForID(context_id_
);
52 // The default format and quality setting used when encoding jpegs.
53 const core_api::extension_types::ImageFormat kDefaultFormat
=
54 core_api::extension_types::IMAGE_FORMAT_JPEG
;
55 const int kDefaultQuality
= 90;
57 image_format_
= kDefaultFormat
;
58 image_quality_
= kDefaultQuality
;
61 if (image_details
->format
!=
62 core_api::extension_types::IMAGE_FORMAT_NONE
)
63 image_format_
= image_details
->format
;
64 if (image_details
->quality
.get())
65 image_quality_
= *image_details
->quality
;
68 // TODO(miu): Account for fullscreen render widget? http://crbug.com/419878
69 RenderWidgetHostView
* const view
= contents
->GetRenderWidgetHostView();
70 RenderWidgetHost
* const host
= view
? view
->GetRenderWidgetHost() : nullptr;
72 OnCaptureFailure(FAILURE_REASON_VIEW_INVISIBLE
);
76 // By default, the requested bitmap size is the view size in screen
77 // coordinates. However, if there's more pixel detail available on the
78 // current system, increase the requested bitmap size to capture it all.
79 const gfx::Size view_size
= view
->GetViewBounds().size();
80 gfx::Size bitmap_size
= view_size
;
81 const gfx::NativeView native_view
= view
->GetNativeView();
82 gfx::Screen
* const screen
= gfx::Screen::GetScreenFor(native_view
);
84 screen
->GetDisplayNearestWindow(native_view
).device_scale_factor();
86 bitmap_size
= gfx::ToCeiledSize(gfx::ScaleSize(view_size
, scale
));
88 host
->CopyFromBackingStore(
91 base::Bind(&CaptureWebContentsFunction::CopyFromBackingStoreComplete
,
97 void CaptureWebContentsFunction::CopyFromBackingStoreComplete(
98 const SkBitmap
& bitmap
,
99 content::ReadbackResponse response
) {
100 if (response
== content::READBACK_SUCCESS
) {
101 OnCaptureSuccess(bitmap
);
104 OnCaptureFailure(FAILURE_REASON_UNKNOWN
);
107 void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap
& bitmap
) {
108 std::vector
<unsigned char> data
;
109 SkAutoLockPixels
screen_capture_lock(bitmap
);
110 bool encoded
= false;
111 std::string mime_type
;
112 switch (image_format_
) {
113 case core_api::extension_types::IMAGE_FORMAT_JPEG
:
114 encoded
= gfx::JPEGCodec::Encode(
115 reinterpret_cast<unsigned char*>(bitmap
.getAddr32(0, 0)),
116 gfx::JPEGCodec::FORMAT_SkBitmap
,
119 static_cast<int>(bitmap
.rowBytes()),
122 mime_type
= kMimeTypeJpeg
;
124 case core_api::extension_types::IMAGE_FORMAT_PNG
:
126 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap
,
127 true, // Discard transparency.
129 mime_type
= kMimeTypePng
;
132 NOTREACHED() << "Invalid image format.";
136 OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED
);
140 std::string base64_result
;
141 base::StringPiece
stream_as_string(
142 reinterpret_cast<const char*>(vector_as_array(&data
)), data
.size());
144 base::Base64Encode(stream_as_string
, &base64_result
);
145 base64_result
.insert(
146 0, base::StringPrintf("data:%s;base64,", mime_type
.c_str()));
147 SetResult(new base::StringValue(base64_result
));
151 } // namespace extensions