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) { |