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