| Index: chrome/renderer/automation/automation_renderer_helper.cc
|
| diff --git a/chrome/renderer/automation/automation_renderer_helper.cc b/chrome/renderer/automation/automation_renderer_helper.cc
|
| index 28a8b180a66d1148d286314aeaf61dbaa764f001..10cfc964fead7293c169b0c18f25ea01ed4fab4a 100644
|
| --- a/chrome/renderer/automation/automation_renderer_helper.cc
|
| +++ b/chrome/renderer/automation/automation_renderer_helper.cc
|
| @@ -4,21 +4,135 @@
|
|
|
| #include "chrome/renderer/automation/automation_renderer_helper.h"
|
|
|
| +#include <algorithm>
|
| +
|
| #include "base/basictypes.h"
|
| #include "chrome/common/automation_messages.h"
|
| +#include "content/public/renderer/render_view.h"
|
| +#include "skia/ext/platform_canvas.h"
|
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
|
| #include "third_party/WebKit/Source/WebKit/chromium/public/WebURL.h"
|
| +#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
|
| +#include "ui/gfx/codec/png_codec.h"
|
| +#include "ui/gfx/point.h"
|
| +#include "ui/gfx/rect.h"
|
| +#include "ui/gfx/size.h"
|
| +#include "webkit/glue/webkit_glue.h"
|
|
|
| using WebKit::WebFrame;
|
| +using WebKit::WebSize;
|
| using WebKit::WebURL;
|
| +using WebKit::WebView;
|
|
|
| AutomationRendererHelper::AutomationRendererHelper(
|
| content::RenderView* render_view)
|
| - : content::RenderViewObserver(render_view) {
|
| + : content::RenderViewObserver(render_view),
|
| + content::RenderViewObserverTracker<AutomationRendererHelper>(
|
| + render_view) {
|
| }
|
|
|
| AutomationRendererHelper::~AutomationRendererHelper() { }
|
|
|
| +bool AutomationRendererHelper::SnapshotEntirePage(
|
| + WebView* view,
|
| + std::vector<unsigned char>* png_data,
|
| + std::string* error_msg) {
|
| + // We don't want to change the widget's layout by resizing. Just scroll
|
| + // the main frame and incremently capture the full page contents.
|
| + WebFrame* frame = view->mainFrame();
|
| + WebSize old_scroll = frame->scrollOffset();
|
| + // For RTL, the minimum scroll offset may be negative and the maximum zero.
|
| + WebSize min_scroll = frame->minimumScrollOffset();
|
| + WebSize max_scroll = frame->maximumScrollOffset();
|
| + WebSize scroll_size(max_scroll.width - min_scroll.width,
|
| + max_scroll.height - min_scroll.height);
|
| + WebSize content_size = frame->contentsSize();
|
| + // This is the size of the content that is visible in the scroll view (i.e.,
|
| + // the window size minus scrollbars).
|
| + WebSize viewport_size(content_size.width - scroll_size.width,
|
| + content_size.height - scroll_size.height);
|
| + if (viewport_size.width <= 0 || viewport_size.height <= 0) {
|
| + *error_msg = "cannot take snapshot because viewport is too small";
|
| + return false;
|
| + }
|
| +
|
| + skia::PlatformCanvas canvas(
|
| + content_size.width, content_size.height, true /* is_opaque */);
|
| + for (int y = 0; y < content_size.height; y += viewport_size.height) {
|
| + int constrain_y = std::min(y, content_size.height - viewport_size.height);
|
| + for (int x = 0; x < content_size.width; x += viewport_size.width) {
|
| + int constrain_x = std::min(x, content_size.width - viewport_size.width);
|
| + frame->setScrollOffset(WebSize(constrain_x, constrain_y));
|
| + canvas.save();
|
| + canvas.translate(static_cast<SkScalar>(constrain_x),
|
| + static_cast<SkScalar>(constrain_y));
|
| + gfx::Point offset(x - constrain_x, y - constrain_y);
|
| + gfx::Rect view_region(offset, gfx::Size(
|
| + viewport_size.width - offset.x(), viewport_size.height - offset.y()));
|
| + view->paint(webkit_glue::ToWebCanvas(&canvas), view_region);
|
| + canvas.restore();
|
| + }
|
| + }
|
| + // One would think scrollOffset and setScrollOffset would deal in the
|
| + // same type of coordinates, but using just |old_scroll| here doesn't work
|
| + // for RTL pages.
|
| + frame->setScrollOffset(WebSize(old_scroll.width - min_scroll.width,
|
| + old_scroll.height - min_scroll.height));
|
| +
|
| + const SkBitmap& bmp = skia::GetTopDevice(canvas)->accessBitmap(false);
|
| + SkAutoLockPixels lock_pixels(bmp);
|
| + // EncodeBGRA uses FORMAT_SkBitmap, which doesn't work on windows for some
|
| + // cases dealing with transparency. See crbug.com/96317. Use FORMAT_BGRA.
|
| + bool encode_success = gfx::PNGCodec::Encode(
|
| + reinterpret_cast<unsigned char*>(bmp.getPixels()),
|
| + gfx::PNGCodec::FORMAT_BGRA,
|
| + gfx::Size(bmp.width(), bmp.height()),
|
| + bmp.rowBytes(),
|
| + true, // discard_transparency
|
| + std::vector<gfx::PNGCodec::Comment>(),
|
| + png_data);
|
| + if (!encode_success)
|
| + *error_msg = "failed to encode image as png";
|
| + return encode_success;
|
| +}
|
| +
|
| +void AutomationRendererHelper::OnSnapshotEntirePage() {
|
| + std::vector<unsigned char> png_data;
|
| + std::string error_msg;
|
| + bool success = false;
|
| + if (render_view()->GetWebView()) {
|
| + success = SnapshotEntirePage(
|
| + render_view()->GetWebView(), &png_data, &error_msg);
|
| + } else {
|
| + error_msg = "cannot snapshot page because webview is null";
|
| + }
|
| +
|
| + // Check that the image is not too large, allowing a 1kb buffer for other
|
| + // message data.
|
| + if (success && png_data.size() > IPC::Channel::kMaximumMessageSize - 1024) {
|
| + png_data.clear();
|
| + success = false;
|
| + error_msg = "image is too large to be transferred over ipc";
|
| + }
|
| + Send(new AutomationMsg_SnapshotEntirePageACK(
|
| + routing_id(), success, png_data, error_msg));
|
| +}
|
| +
|
| +bool AutomationRendererHelper::OnMessageReceived(const IPC::Message& message) {
|
| + bool handled = true;
|
| + bool deserialize_success = true;
|
| + IPC_BEGIN_MESSAGE_MAP_EX(AutomationRendererHelper, message,
|
| + deserialize_success)
|
| + IPC_MESSAGE_HANDLER(AutomationMsg_SnapshotEntirePage, OnSnapshotEntirePage)
|
| + IPC_MESSAGE_UNHANDLED(handled = false)
|
| + IPC_END_MESSAGE_MAP_EX()
|
| + if (!deserialize_success) {
|
| + LOG(ERROR) << "Failed to deserialize an IPC message";
|
| + }
|
| + return handled;
|
| +}
|
| +
|
| void AutomationRendererHelper::WillPerformClientRedirect(
|
| WebFrame* frame, const WebURL& from, const WebURL& to, double interval,
|
| double fire_time) {
|
|
|