// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "chrome/browser/extensions/api/capture_web_contents_function.h" #include "base/base64.h" #include "base/strings/stringprintf.h" #include "chrome/browser/extensions/api/tabs/tabs_constants.h" #include "chrome/common/extensions/extension_constants.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" #include "extensions/browser/extension_function.h" #include "ui/gfx/codec/jpeg_codec.h" #include "ui/gfx/codec/png_codec.h" using content::RenderViewHost; using content::RenderWidgetHost; using content::RenderWidgetHostView; using content::WebContents; namespace extensions { CaptureWebContentsFunction::CaptureWebContentsFunction() { } CaptureWebContentsFunction::~CaptureWebContentsFunction() { } bool CaptureWebContentsFunction::HasPermission() { return true; } bool CaptureWebContentsFunction::RunImpl() { EXTENSION_FUNCTION_VALIDATE(args_); context_id_ = extension_misc::kCurrentWindowId; args_->GetInteger(0, &context_id_); scoped_ptr image_details; if (args_->GetSize() > 1) { base::Value* spec = NULL; EXTENSION_FUNCTION_VALIDATE(args_->Get(1, &spec) && spec); image_details = ImageDetails::FromValue(*spec); } if (!IsScreenshotEnabled()) return false; WebContents* contents = GetWebContentsForID(context_id_); if (!contents) return false; // The default format and quality setting used when encoding jpegs. const ImageDetails::Format kDefaultFormat = ImageDetails::FORMAT_JPEG; const int kDefaultQuality = 90; image_format_ = kDefaultFormat; image_quality_ = kDefaultQuality; if (image_details) { if (image_details->format != ImageDetails::FORMAT_NONE) image_format_ = image_details->format; if (image_details->quality.get()) image_quality_ = *image_details->quality; } RenderViewHost* render_view_host = contents->GetRenderViewHost(); RenderWidgetHostView* view = render_view_host->GetView(); if (!view) { OnCaptureFailure(FAILURE_REASON_VIEW_INVISIBLE); return false; } render_view_host->CopyFromBackingStore( gfx::Rect(), view->GetViewBounds().size(), base::Bind(&CaptureWebContentsFunction::CopyFromBackingStoreComplete, this)); return true; } void CaptureWebContentsFunction::CopyFromBackingStoreComplete( bool succeeded, const SkBitmap& bitmap) { if (succeeded) { OnCaptureSuccess(bitmap); return; } WebContents* contents = GetWebContentsForID(context_id_); if (!contents) { OnCaptureFailure(FAILURE_REASON_CONTENT_NOT_FOUND); return; } // Ask the renderer for a snapshot of the page. RenderWidgetHost* render_widget_host = contents->GetRenderViewHost(); render_widget_host->GetSnapshotFromRenderer( gfx::Rect(), base::Bind(&CaptureWebContentsFunction::GetSnapshotFromRendererComplete, this)); } void CaptureWebContentsFunction::GetSnapshotFromRendererComplete( bool succeeded, const SkBitmap& bitmap) { if (succeeded) OnCaptureSuccess(bitmap); else OnCaptureFailure(FAILURE_REASON_UNKNOWN); } void CaptureWebContentsFunction::OnCaptureSuccess(const SkBitmap& bitmap) { std::vector data; SkAutoLockPixels screen_capture_lock(bitmap); bool encoded = false; std::string mime_type; switch (image_format_) { case ImageDetails::FORMAT_JPEG: encoded = gfx::JPEGCodec::Encode( reinterpret_cast(bitmap.getAddr32(0, 0)), gfx::JPEGCodec::FORMAT_SkBitmap, bitmap.width(), bitmap.height(), static_cast(bitmap.rowBytes()), image_quality_, &data); mime_type = tabs_constants::kMimeTypeJpeg; break; case ImageDetails::FORMAT_PNG: encoded = gfx::PNGCodec::EncodeBGRASkBitmap( bitmap, true, // Discard transparency. &data); mime_type = tabs_constants::kMimeTypePng; break; default: NOTREACHED() << "Invalid image format."; } if (!encoded) { OnCaptureFailure(FAILURE_REASON_ENCODING_FAILED); return; } std::string base64_result; base::StringPiece stream_as_string( reinterpret_cast(vector_as_array(&data)), data.size()); base::Base64Encode(stream_as_string, &base64_result); base64_result.insert(0, base::StringPrintf("data:%s;base64,", mime_type.c_str())); SetResult(new base::StringValue(base64_result)); SendResponse(true); } } // namespace extensions