Chromium Code Reviews| 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..511ad34192d96207701fb75ac625381e4f38b279 100644 |
| --- a/chrome/renderer/automation/automation_renderer_helper.cc |
| +++ b/chrome/renderer/automation/automation_renderer_helper.cc |
| @@ -4,21 +4,130 @@ |
| #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 |
|
Paweł Hajdan Jr.
2011/10/18 10:21:35
Please get additional reviewer for this WebKit stu
kkania
2011/10/18 18:30:19
Done.
|
| + // 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; |
| + IPC_BEGIN_MESSAGE_MAP(AutomationRendererHelper, message) |
|
Paweł Hajdan Jr.
2011/10/18 10:21:35
Please use MAP_EX to avoid a DCHECK on malformed m
kkania
2011/10/18 18:30:19
Done.
|
| + IPC_MESSAGE_HANDLER(AutomationMsg_SnapshotEntirePage, OnSnapshotEntirePage) |
| + IPC_MESSAGE_UNHANDLED(handled = false) |
| + IPC_END_MESSAGE_MAP() |
| + return handled; |
| +} |
| + |
| void AutomationRendererHelper::WillPerformClientRedirect( |
| WebFrame* frame, const WebURL& from, const WebURL& to, double interval, |
| double fire_time) { |