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 24 bool CaptureWebContentsFunction::HasPermission() { 25 return true; 26 } 27 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 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 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