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.
4
5 #include "extensions/browser/api/capture_web_contents_function.h"
6
7 #include "base/base64.h"
8 #include "base/strings/stringprintf.h"
9 #include "content/public/browser/render_view_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
17 using content::RenderViewHost;
18 using content::RenderWidgetHost;
19 using content::RenderWidgetHostView;
20 using content::WebContents;
21
22 namespace extensions {
23
HasPermission()24 bool CaptureWebContentsFunction::HasPermission() {
25 return true;
26 }
27
RunAsync()28 bool CaptureWebContentsFunction::RunAsync() {
29 EXTENSION_FUNCTION_VALIDATE(args_);
30
31 context_id_ = extension_misc::kCurrentWindowId;
32 args_->GetInteger(0, &context_id_);
33
34 scoped_ptr<ImageDetails> image_details;
35 if (args_->GetSize() > 1) {
36 base::Value* spec = NULL;
37 EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &spec) && spec);
38 image_details = ImageDetails::FromValue(*spec);
39 }
40
41 if (!IsScreenshotEnabled())
42 return false;
43
44 WebContents* contents = GetWebContentsForID(context_id_);
45 if (!contents)
46 return false;
47
48 // The default format and quality setting used when encoding jpegs.
49 const ImageDetails::Format kDefaultFormat = ImageDetails::FORMAT_JPEG;
50 const int kDefaultQuality = 90;
51
52 image_format_ = kDefaultFormat;
53 image_quality_ = kDefaultQuality;
54
55 if (image_details) {
56 if (image_details->format != ImageDetails::FORMAT_NONE)
57 image_format_ = image_details->format;
58 if (image_details->quality.get())
59 image_quality_ = *image_details->quality;
60 }
61
62 RenderViewHost* render_view_host = contents->GetRenderViewHost();
63 RenderWidgetHostView* view = render_view_host->GetView();
64 if (!view) {
65 OnCaptureFailure(FAILURE_REASON_VIEW_INVISIBLE);
66 return false;
67 }
68 render_view_host->CopyFromBackingStore(
69 gfx::Rect(),
70 view->GetViewBounds().size(),
71 base::Bind(&CaptureWebContentsFunction::CopyFromBackingStoreComplete,
72 this),
73 kN32_SkColorType);
74 return true;
75 }
76
CopyFromBackingStoreComplete(bool succeeded,const SkBitmap & bitmap)77 void CaptureWebContentsFunction::CopyFromBackingStoreComplete(
78 bool succeeded,
79 const SkBitmap& bitmap) {
80 if (succeeded) {
81 OnCaptureSuccess(bitmap);
82 return;
83 }
84 OnCaptureFailure(FAILURE_REASON_UNKNOWN);
85 }
86
OnCaptureSuccess(const SkBitmap & bitmap)87 void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) {
88 std::vector<unsigned char> data;
89 SkAutoLockPixels screen_capture_lock(bitmap);
90 bool encoded = false;
91 std::string mime_type;
92 switch (image_format_) {
93 case ImageDetails::FORMAT_JPEG:
94 encoded = gfx::JPEGCodec::Encode(
95 reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
96 gfx::JPEGCodec::FORMAT_SkBitmap,
97 bitmap.width(),
98 bitmap.height(),
99 static_cast<int>(bitmap.rowBytes()),
100 image_quality_,
101 &data);
102 mime_type = kMimeTypeJpeg;
103 break;
104 case ImageDetails::FORMAT_PNG:
105 encoded =
106 gfx::PNGCodec::EncodeBGRASkBitmap(bitmap,
107 true, // Discard transparency.
108 &data);
109 mime_type = kMimeTypePng;
110 break;
111 default:
112 NOTREACHED() << "Invalid image format.";
113 }
114
115 if (!encoded) {
116 OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED);
117 return;
118 }
119
120 std::string base64_result;
121 base::StringPiece stream_as_string(
122 reinterpret_cast<const char*>(vector_as_array(&data)), data.size());
123
124 base::Base64Encode(stream_as_string, &base64_result);
125 base64_result.insert(
126 0, base::StringPrintf("data:%s;base64,", mime_type.c_str()));
127 SetResult(new base::StringValue(base64_result));
128 SendResponse(true);
129 }
130
131 } // namespace extensions
132