Index: content/browser/devtools/renderer_overrides_handler.cc |
diff --git a/content/browser/devtools/renderer_overrides_handler.cc b/content/browser/devtools/renderer_overrides_handler.cc |
index 69fe055fd90a790ef8d459727041a60e9105a77a..d23e527e8c1ad070be625348ce90de9b2287cebc 100644 |
--- a/content/browser/devtools/renderer_overrides_handler.cc |
+++ b/content/browser/devtools/renderer_overrides_handler.cc |
@@ -11,11 +11,13 @@ |
#include "base/bind_helpers.h" |
#include "base/files/file_path.h" |
#include "base/strings/string16.h" |
+#include "base/time/time.h" |
#include "base/values.h" |
#include "content/browser/child_process_security_policy_impl.h" |
#include "content/browser/devtools/devtools_protocol_constants.h" |
#include "content/browser/devtools/devtools_tracing_handler.h" |
#include "content/browser/renderer_host/render_view_host_delegate.h" |
+#include "content/port/browser/render_widget_host_view_port.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/devtools_agent_host.h" |
#include "content/public/browser/javascript_dialog_manager.h" |
@@ -27,9 +29,22 @@ |
#include "content/public/browser/web_contents_delegate.h" |
#include "content/public/common/page_transition_types.h" |
#include "content/public/common/referrer.h" |
+#include "ui/gfx/codec/jpeg_codec.h" |
+#include "ui/gfx/codec/png_codec.h" |
+#include "ui/gfx/size_conversions.h" |
#include "ui/snapshot/snapshot.h" |
#include "url/gurl.h" |
+using base::TimeTicks; |
+ |
+namespace { |
+ |
+static const char kPng[] = "png"; |
+static const char kJpeg[] = "jpeg"; |
+static int kDefaultScreenshotQuality = 80; |
+ |
+} // namespace |
+ |
namespace content { |
RendererOverridesHandler::RendererOverridesHandler(DevToolsAgentHost* agent) |
@@ -141,44 +156,119 @@ RendererOverridesHandler::PageNavigate( |
scoped_refptr<DevToolsProtocol::Response> |
RendererOverridesHandler::PageCaptureScreenshot( |
scoped_refptr<DevToolsProtocol::Command> command) { |
- // Emulate async processing. |
- BrowserThread::PostTask( |
- BrowserThread::UI, FROM_HERE, |
- base::Bind(&RendererOverridesHandler::CaptureScreenshot, |
- weak_factory_.GetWeakPtr(), |
- command)); |
- |
- return command->AsyncResponsePromise(); |
-} |
- |
-void RendererOverridesHandler::CaptureScreenshot( |
- scoped_refptr<DevToolsProtocol::Command> command) { |
+ // Parse input parameters. |
+ std::string format; |
+ int quality = kDefaultScreenshotQuality; |
+ double scale = 1; |
+ base::DictionaryValue* params = command->params(); |
+ if (params) { |
+ params->GetString(devtools::Page::captureScreenshot::kParamFormat, |
+ &format); |
+ params->GetInteger(devtools::Page::captureScreenshot::kParamQuality, |
+ &quality); |
+ params->GetDouble(devtools::Page::captureScreenshot::kParamScale, |
+ &scale); |
+ } |
+ if (format.empty()) |
+ format = kPng; |
+ if (quality < 0 || quality > 100) |
+ quality = kDefaultScreenshotQuality; |
+ if (scale <= 0 || scale > 1) |
+ scale = 1; |
RenderViewHost* host = agent_->GetRenderViewHost(); |
gfx::Rect view_bounds = host->GetView()->GetViewBounds(); |
- gfx::Rect snapshot_bounds(view_bounds.size()); |
- gfx::Size snapshot_size = snapshot_bounds.size(); |
+ // Grab screen pixels if available for current platform. |
+ // TODO(pfeldman): support format, scale and quality in ui::GrabViewSnapshot. |
std::vector<unsigned char> png; |
- if (ui::GrabViewSnapshot(host->GetView()->GetNativeView(), |
- &png, |
- snapshot_bounds)) { |
- std::string base_64_data; |
+ bool is_unscaled_png = scale == 1 && format == kPng; |
+ if (is_unscaled_png && ui::GrabViewSnapshot(host->GetView()->GetNativeView(), |
+ &png, view_bounds)) { |
+ std::string base64_data; |
bool success = base::Base64Encode( |
base::StringPiece(reinterpret_cast<char*>(&*png.begin()), png.size()), |
- &base_64_data); |
+ &base64_data); |
if (success) { |
base::DictionaryValue* result = new base::DictionaryValue(); |
result->SetString( |
- devtools::Page::captureScreenshot::kResponseData, base_64_data); |
- scoped_refptr<DevToolsProtocol::Response> response = |
- command->SuccessResponse(result); |
- SendRawMessage(response->Serialize()); |
- return; |
+ devtools::Page::captureScreenshot::kResponseData, base64_data); |
+ return command->SuccessResponse(result); |
} |
+ return command->InternalErrorResponse("Unable to base64encode screenshot"); |
+ } |
+ |
+ // Fallback to copying from compositing surface. |
+ RenderWidgetHostViewPort* view_port = |
+ RenderWidgetHostViewPort::FromRWHV(host->GetView()); |
+ |
+ gfx::Size snapshot_size = gfx::ToFlooredSize( |
+ gfx::ScaleSize(view_bounds.size(), scale)); |
+ view_port->CopyFromCompositingSurface( |
+ view_bounds, snapshot_size, |
+ base::Bind(&RendererOverridesHandler::ScreenshotCaptured, |
+ weak_factory_.GetWeakPtr(), command, format, quality, scale)); |
+ return command->AsyncResponsePromise(); |
+} |
+ |
+void RendererOverridesHandler::ScreenshotCaptured( |
+ scoped_refptr<DevToolsProtocol::Command> command, |
+ const std::string& format, |
+ int quality, |
+ double scale, |
+ bool success, |
+ const SkBitmap& bitmap) { |
+ if (!success) { |
+ SendRawMessage( |
+ command->InternalErrorResponse("Unable to capture screenshot")-> |
+ Serialize()); |
+ return; |
+ } |
+ |
+ std::vector<unsigned char> data; |
+ SkAutoLockPixels lock_image(bitmap); |
+ bool encoded; |
+ if (format == kPng) { |
+ encoded = gfx::PNGCodec::Encode( |
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), |
+ gfx::PNGCodec::FORMAT_SkBitmap, |
+ gfx::Size(bitmap.width(), bitmap.height()), |
+ bitmap.width() * bitmap.bytesPerPixel(), |
+ false, std::vector<gfx::PNGCodec::Comment>(), &data); |
+ } else if (format == kJpeg) { |
+ encoded = gfx::JPEGCodec::Encode( |
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)), |
+ gfx::JPEGCodec::FORMAT_SkBitmap, |
+ bitmap.width(), |
+ bitmap.height(), |
+ bitmap.width() * bitmap.bytesPerPixel(), |
+ quality, &data); |
+ } else { |
+ encoded = false; |
+ } |
+ |
+ if (!encoded) { |
+ SendRawMessage( |
+ command->InternalErrorResponse("Unable to encode screenshot")-> |
+ Serialize()); |
+ return; |
} |
- SendRawMessage(command-> |
- InternalErrorResponse("Unable to capture a screenshot")->Serialize()); |
+ |
+ std::string base_64_data; |
+ if (!base::Base64Encode(base::StringPiece( |
+ reinterpret_cast<char*>(&data[0]), |
+ data.size()), |
+ &base_64_data)) { |
+ SendRawMessage( |
+ command->InternalErrorResponse("Unable to base64 encode screenshot")-> |
+ Serialize()); |
+ return; |
+ } |
+ |
+ base::DictionaryValue* response = new base::DictionaryValue(); |
+ response->SetString( |
+ devtools::Page::captureScreenshot::kResponseData, base_64_data); |
+ SendRawMessage(command->SuccessResponse(response)->Serialize()); |
} |
} // namespace content |