Add testing/scripts/OWNERS
[chromium-blink-merge.git] / extensions / browser / api / capture_web_contents_function.cc
bloba888284deb42913e5327e45f940c5a2e4f8c6039
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 bool CaptureWebContentsFunction::HasPermission() {
27 return true;
30 bool CaptureWebContentsFunction::RunAsync() {
31 EXTENSION_FUNCTION_VALIDATE(args_);
33 context_id_ = extension_misc::kCurrentWindowId;
34 args_->GetInteger(0, &context_id_);
36 scoped_ptr<ImageDetails> image_details;
37 if (args_->GetSize() > 1) {
38 base::Value* spec = NULL;
39 EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &spec) && spec);
40 image_details = ImageDetails::FromValue(*spec);
43 if (!IsScreenshotEnabled())
44 return false;
46 WebContents* contents = GetWebContentsForID(context_id_);
47 if (!contents)
48 return false;
50 // The default format and quality setting used when encoding jpegs.
51 const ImageDetails::Format kDefaultFormat = ImageDetails::FORMAT_JPEG;
52 const int kDefaultQuality = 90;
54 image_format_ = kDefaultFormat;
55 image_quality_ = kDefaultQuality;
57 if (image_details) {
58 if (image_details->format != ImageDetails::FORMAT_NONE)
59 image_format_ = image_details->format;
60 if (image_details->quality.get())
61 image_quality_ = *image_details->quality;
64 // TODO(miu): Account for fullscreen render widget? http://crbug.com/419878
65 RenderWidgetHostView* const view = contents->GetRenderWidgetHostView();
66 RenderWidgetHost* const host = view ? view->GetRenderWidgetHost() : nullptr;
67 if (!view || !host) {
68 OnCaptureFailure(FAILURE_REASON_VIEW_INVISIBLE);
69 return false;
72 // By default, the requested bitmap size is the view size in screen
73 // coordinates. However, if there's more pixel detail available on the
74 // current system, increase the requested bitmap size to capture it all.
75 const gfx::Size view_size = view->GetViewBounds().size();
76 gfx::Size bitmap_size = view_size;
77 const gfx::NativeView native_view = view->GetNativeView();
78 gfx::Screen* const screen = gfx::Screen::GetScreenFor(native_view);
79 const float scale =
80 screen->GetDisplayNearestWindow(native_view).device_scale_factor();
81 if (scale > 1.0f)
82 bitmap_size = gfx::ToCeiledSize(gfx::ScaleSize(view_size, scale));
84 host->CopyFromBackingStore(
85 gfx::Rect(view_size),
86 bitmap_size,
87 base::Bind(&CaptureWebContentsFunction::CopyFromBackingStoreComplete,
88 this),
89 kN32_SkColorType);
90 return true;
93 void CaptureWebContentsFunction::CopyFromBackingStoreComplete(
94 bool succeeded,
95 const SkBitmap& bitmap) {
96 if (succeeded) {
97 OnCaptureSuccess(bitmap);
98 return;
100 OnCaptureFailure(FAILURE_REASON_UNKNOWN);
103 void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) {
104 std::vector<unsigned char> data;
105 SkAutoLockPixels screen_capture_lock(bitmap);
106 bool encoded = false;
107 std::string mime_type;
108 switch (image_format_) {
109 case ImageDetails::FORMAT_JPEG:
110 encoded = gfx::JPEGCodec::Encode(
111 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
112 gfx::JPEGCodec::FORMAT_SkBitmap,
113 bitmap.width(),
114 bitmap.height(),
115 static_cast<int>(bitmap.rowBytes()),
116 image_quality_,
117 &data);
118 mime_type = kMimeTypeJpeg;
119 break;
120 case ImageDetails::FORMAT_PNG:
121 encoded =
122 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
123 true, // Discard transparency.
124 &data);
125 mime_type = kMimeTypePng;
126 break;
127 default:
128 NOTREACHED() << "Invalid image format.";
131 if (!encoded) {
132 OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED);
133 return;
136 std::string base64_result;
137 base::StringPiece stream_as_string(
138 reinterpret_cast<const char*>(vector_as_array(&data)), data.size());
140 base::Base64Encode(stream_as_string, &base64_result);
141 base64_result.insert(
142 0, base::StringPrintf("data:%s;base64,", mime_type.c_str()));
143 SetResult(new base::StringValue(base64_result));
144 SendResponse(true);
147 } // namespace extensions