summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authornoelutz@google.com <noelutz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-23 22:42:17 +0000
committernoelutz@google.com <noelutz@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-23 22:42:17 +0000
commit0695ef4d095a441148ae80a08576c25c2ab8bc40 (patch)
tree73909c32f2b4840452d5051b15f7efcaa60c56db
parent4bb1dc9e6231e64eae2f411f3a528f082f00f47e (diff)
downloadchromium_src-0695ef4d095a441148ae80a08576c25c2ab8bc40.zip
chromium_src-0695ef4d095a441148ae80a08576c25c2ab8bc40.tar.gz
chromium_src-0695ef4d095a441148ae80a08576c25c2ab8bc40.tar.bz2
Client-side phishing detection: grab snapshot of custom sized view.
Client-side phishing detection needs to be able to take a snapshot of a particular page that has a constant size and aspect ratio (e.g., 1024x768). This CL adds a helper function (safe_browsing::GrabPhishingThumbnail) which re-sizes the view a given size, grabs the snapshot, and then re-sizes the view back to its previous size. Note: this function can be slow since it might re-layout the page twice. This function will only be called if we are very confident that the current page is a phishing site in which case we are OK with taking a slow snapshot. Also, this CL adds a test for the OnMsgPaintAtSize method in the RenderWidget since it does something very similar than the new Thumbnailer. BUG=None TEST=GrabPhishingThumbnail Review URL: http://codereview.chromium.org/3380001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60368 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/chrome_renderer.gypi2
-rw-r--r--chrome/chrome_tests.gypi3
-rw-r--r--chrome/renderer/render_view.cc9
-rw-r--r--chrome/renderer/render_view.h8
-rw-r--r--chrome/renderer/render_widget.h2
-rw-r--r--chrome/renderer/render_widget_browsertest.cc141
-rw-r--r--chrome/renderer/render_widget_browsertest.h59
-rw-r--r--chrome/renderer/safe_browsing/phishing_thumbnailer.cc82
-rw-r--r--chrome/renderer/safe_browsing/phishing_thumbnailer.h40
-rw-r--r--chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc33
10 files changed, 372 insertions, 7 deletions
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 3d072c0..9fe4e5b 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -205,6 +205,8 @@
'renderer/safe_browsing/phishing_dom_feature_extractor.h',
'renderer/safe_browsing/phishing_term_feature_extractor.cc',
'renderer/safe_browsing/phishing_term_feature_extractor.h',
+ 'renderer/safe_browsing/phishing_thumbnailer.cc',
+ 'renderer/safe_browsing/phishing_thumbnailer.h',
'renderer/safe_browsing/phishing_url_feature_extractor.cc',
'renderer/safe_browsing/phishing_url_feature_extractor.h',
'renderer/safe_browsing/scorer.cc',
diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi
index dbd9519..3d66fde 100644
--- a/chrome/chrome_tests.gypi
+++ b/chrome/chrome_tests.gypi
@@ -1808,9 +1808,12 @@
'renderer/pepper_devices_browsertest.cc',
'renderer/render_view_browsertest.cc',
'renderer/render_view_browsertest_mac.mm',
+ 'renderer/render_widget_browsertest.cc',
+ 'renderer/render_widget_browsertest.h',
'renderer/safe_browsing/mock_feature_extractor_clock.h',
'renderer/safe_browsing/phishing_classifier_browsertest.cc',
'renderer/safe_browsing/phishing_dom_feature_extractor_browsertest.cc',
+ 'renderer/safe_browsing/phishing_thumbnailer_browsertest.cc',
'renderer/safe_browsing/render_view_fake_resources_test.cc',
'renderer/safe_browsing/render_view_fake_resources_test.h',
'renderer/translate_helper_browsertest.cc',
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index b570f7e..037a275 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -4661,14 +4661,9 @@ void RenderView::OnResize(const gfx::Size& new_size,
const gfx::Rect& resizer_rect) {
if (webview()) {
webview()->hidePopups();
-
if (send_preferred_size_changes_) {
- // If resizing to a size larger than |disable_scrollbars_size_limit_| in
- // either width or height, allow scroll bars.
- bool allow_scrollbars = (
- disable_scrollbars_size_limit_.width() <= new_size.width() ||
- disable_scrollbars_size_limit_.height() <= new_size.height());
- webview()->mainFrame()->setCanHaveScrollbars(allow_scrollbars);
+ webview()->mainFrame()->setCanHaveScrollbars(
+ should_display_scrollbars(new_size.width(), new_size.height()));
}
}
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index bf43b2e..f0dad4d4 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -220,6 +220,14 @@ class RenderView : public RenderWidget,
return page_click_tracker_.get();
}
+ // Returns true if we should display scrollbars for the given view size and
+ // false if the scrollbars should be hidden.
+ bool should_display_scrollbars(int width, int height) const {
+ return (!send_preferred_size_changes_ ||
+ (disable_scrollbars_size_limit_.width() <= width ||
+ disable_scrollbars_size_limit_.height() <= height));
+ }
+
// Called from JavaScript window.external.AddSearchProvider() to add a
// keyword for a provider described in the given OpenSearch document.
void AddSearchProvider(const std::string& url);
diff --git a/chrome/renderer/render_widget.h b/chrome/renderer/render_widget.h
index f08f333..6d80b62 100644
--- a/chrome/renderer/render_widget.h
+++ b/chrome/renderer/render_widget.h
@@ -128,6 +128,8 @@ class RenderWidget : public IPC::Channel::Listener,
// Friend RefCounted so that the dtor can be non-public. Using this class
// without ref-counting is an error.
friend class base::RefCounted<RenderWidget>;
+ // For unit tests.
+ friend class RenderWidgetTest;
RenderWidget(RenderThreadBase* render_thread,
WebKit::WebPopupType popup_type);
diff --git a/chrome/renderer/render_widget_browsertest.cc b/chrome/renderer/render_widget_browsertest.cc
new file mode 100644
index 0000000..0c4ff04
--- /dev/null
+++ b/chrome/renderer/render_widget_browsertest.cc
@@ -0,0 +1,141 @@
+// Copyright (c) 2010 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 "app/surface/transport_dib.h"
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "base/file_util.h"
+#include "base/ref_counted_memory.h"
+#include "base/stringprintf.h"
+#include "chrome/common/render_messages.h"
+#include "chrome/common/render_messages_params.h"
+#include "chrome/renderer/render_widget_browsertest.h"
+#include "gfx/codec/jpeg_codec.h"
+#include "gfx/size.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
+
+const int RenderWidgetTest::kNumBytesPerPixel = 4;
+const int RenderWidgetTest::kLargeWidth = 1024;
+const int RenderWidgetTest::kLargeHeight = 768;
+const int RenderWidgetTest::kSmallWidth = 600;
+const int RenderWidgetTest::kSmallHeight = 450;
+const int RenderWidgetTest::kTextPositionX = 800;
+const int RenderWidgetTest::kTextPositionY = 600;
+const int RenderWidgetTest::kSequenceNum = 1;
+const uint32 RenderWidgetTest::kRedARGB = 0xFFFF0000;
+
+RenderWidgetTest::RenderWidgetTest() {}
+
+void RenderWidgetTest::ResizeAndPaint(const gfx::Size& page_size,
+ const gfx::Size& desired_size,
+ SkBitmap* snapshot) {
+ ASSERT_TRUE(snapshot);
+ scoped_ptr<TransportDIB> pixels(
+ TransportDIB::Create(
+ page_size.width() * page_size.height() * kNumBytesPerPixel,
+ kSequenceNum));
+ view_->OnMsgPaintAtSize(pixels->handle(), kSequenceNum, page_size,
+ desired_size);
+ ProcessPendingMessages();
+ const IPC::Message* msg = render_thread_.sink().GetUniqueMessageMatching(
+ ViewHostMsg_PaintAtSize_ACK::ID);
+ ASSERT_NE(static_cast<IPC::Message*>(NULL), msg);
+ ViewHostMsg_PaintAtSize_ACK::Param params;
+ ViewHostMsg_PaintAtSize_ACK::Read(msg, &params);
+ render_thread_.sink().ClearMessages();
+ EXPECT_EQ(kSequenceNum, params.a);
+ gfx::Size size = params.b;
+ EXPECT_EQ(desired_size, size);
+
+ SkBitmap tmp_bitmap;
+ tmp_bitmap.setConfig(SkBitmap::kARGB_8888_Config,
+ size.width(), size.height());
+ tmp_bitmap.setPixels(pixels->memory());
+ // Copy the pixels from the TransportDIB object to the given snapshot.
+ ASSERT_TRUE(tmp_bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config));
+}
+
+void RenderWidgetTest::TestResizeAndPaint() {
+ // Hello World message is only visible if the view size is at least
+ // kTextPositionX x kTextPositionY
+ LoadHTML(StringPrintf(
+ "<html><body><div style='position: absolute; top: %d; left: "
+ "%d; background-color: red;'>Hello World</div></body></html>",
+ kTextPositionY, kTextPositionX).c_str());
+ WebKit::WebSize old_size = view_->webview()->size();
+
+ SkBitmap bitmap;
+ // If we re-size the view to something smaller than where the 'Hello World'
+ // text is displayed we won't see any text in the snapshot. Hence,
+ // the snapshot should not contain any red.
+ gfx::Size size(kSmallWidth, kSmallHeight);
+ ResizeAndPaint(size, size, &bitmap);
+ // Make sure that the view has been re-sized to its old size.
+ EXPECT_EQ(old_size, view_->webview()->size());
+ EXPECT_EQ(kSmallWidth, bitmap.width());
+ EXPECT_EQ(kSmallHeight, bitmap.height());
+ EXPECT_FALSE(ImageContainsColor(bitmap, kRedARGB));
+
+ // Since we ask for the view to be re-sized to something larger than where the
+ // 'Hello World' text is written the text should be visible in the snapshot.
+ // Hence, the snapshot should contain some red.
+ size.SetSize(kLargeWidth, kLargeHeight);
+ ResizeAndPaint(size, size, &bitmap);
+ EXPECT_EQ(old_size, view_->webview()->size());
+ EXPECT_EQ(kLargeWidth, bitmap.width());
+ EXPECT_EQ(kLargeHeight, bitmap.height());
+ EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
+
+ // Even if the desired size is smaller than where the text is located we
+ // should still see the 'Hello World' message since the view size is
+ // still large enough.
+ ResizeAndPaint(size, gfx::Size(kSmallWidth, kSmallHeight), &bitmap);
+ EXPECT_EQ(old_size, view_->webview()->size());
+ EXPECT_EQ(kSmallWidth, bitmap.width());
+ EXPECT_EQ(kSmallHeight, bitmap.height());
+ EXPECT_TRUE(ImageContainsColor(bitmap, kRedARGB));
+}
+
+bool RenderWidgetTest::ImageContainsColor(const SkBitmap& bitmap,
+ uint32 argb_color) {
+ SkAutoLockPixels lock(bitmap);
+ bool ready = bitmap.readyToDraw();
+ EXPECT_TRUE(ready);
+ if (!ready) {
+ return false;
+ }
+ for (int x = 0; x < bitmap.width(); ++x) {
+ for (int y = 0; y < bitmap.height(); ++y) {
+ if (argb_color == *bitmap.getAddr32(x, y)) {
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+void RenderWidgetTest::OutputBitmapToFile(const SkBitmap& bitmap,
+ const FilePath& file_path) {
+ scoped_refptr<RefCountedBytes> bitmap_data = new RefCountedBytes();
+ SkAutoLockPixels lock(bitmap);
+ ASSERT_TRUE(gfx::JPEGCodec::Encode(
+ reinterpret_cast<unsigned char*>(bitmap.getAddr32(0, 0)),
+ gfx::JPEGCodec::FORMAT_BGRA,
+ bitmap.width(),
+ bitmap.height(),
+ static_cast<int>(bitmap.rowBytes()),
+ 90 /* quality */,
+ &bitmap_data->data));
+ ASSERT_LT(0, file_util::WriteFile(
+ file_path,
+ reinterpret_cast<const char*>(bitmap_data->front()),
+ bitmap_data->size()));
+}
+
+TEST_F(RenderWidgetTest, OnMsgPaintAtSize) {
+ TestResizeAndPaint();
+}
diff --git a/chrome/renderer/render_widget_browsertest.h b/chrome/renderer/render_widget_browsertest.h
new file mode 100644
index 0000000..cf124dd
--- /dev/null
+++ b/chrome/renderer/render_widget_browsertest.h
@@ -0,0 +1,59 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_
+#define CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_
+#pragma once
+
+#include "base/basictypes.h"
+#include "base/file_path.h"
+#include "chrome/test/render_view_test.h"
+
+namespace gfx {
+class Size;
+}
+
+class SkBitmap;
+class TransportDIB;
+
+class RenderWidgetTest : public RenderViewTest {
+ public:
+ RenderWidgetTest();
+
+ protected:
+ static const int kNumBytesPerPixel;
+ static const int kLargeWidth;
+ static const int kLargeHeight;
+ static const int kSmallWidth;
+ static const int kSmallHeight;
+ static const int kTextPositionX;
+ static const int kTextPositionY;
+ static const int kSequenceNum;
+ static const uint32 kRedARGB;
+
+ // Helper function which calls OnMsgPaintAtSize and also paints the result
+ // in the given bitmap. The widget is resized to |page_size| before we paint
+ // and the final image is resized to |desired_size|. This method is virtual so
+ // that TestResizeAndPaint() can be reused by subclasses of this test class.
+ virtual void ResizeAndPaint(const gfx::Size& page_size,
+ const gfx::Size& desired_size,
+ SkBitmap* snapshot);
+
+ // Test for ResizeAndPaint.
+ void TestResizeAndPaint();
+
+ // Helper function which returns true if the given bitmap contains the given
+ // ARGB color and false otherwise.
+ bool ImageContainsColor(const SkBitmap& bitmap, uint32 argb_color);
+
+ // This can be used for debugging if you want to output a bitmap
+ // image to a file.
+ // FilePath tmp_path;
+ // file_util::CreateTemporaryFile(&tmp_path);
+ // OutputBitmapToFile(bitmap, tmp_path);
+ // LOG(INFO) << "Bitmap image stored at: " << tmp_path.value();
+ void OutputBitmapToFile(const SkBitmap& bitmap, const FilePath& file_path);
+};
+
+#endif // CHROME_RENDERER_RENDER_WIDGET_BROWSERTEST_H_
diff --git a/chrome/renderer/safe_browsing/phishing_thumbnailer.cc b/chrome/renderer/safe_browsing/phishing_thumbnailer.cc
new file mode 100644
index 0000000..439a40e
--- /dev/null
+++ b/chrome/renderer/safe_browsing/phishing_thumbnailer.cc
@@ -0,0 +1,82 @@
+// Copyright (c) 2010 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/renderer/safe_browsing/phishing_thumbnailer.h"
+
+#include "base/histogram.h"
+#include "base/logging.h"
+#include "base/time.h"
+#include "chrome/renderer/render_view.h"
+#include "gfx/size.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/image_operations.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebRect.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
+#include "webkit/glue/webkit_glue.h"
+
+using WebKit::WebRect;
+using WebKit::WebSize;
+using WebKit::WebView;
+
+namespace safe_browsing {
+
+SkBitmap GrabPhishingThumbnail(RenderView* render_view,
+ const gfx::Size& view_size,
+ const gfx::Size& thumbnail_size) {
+ if (!render_view || !render_view->webview()) {
+ NOTREACHED();
+ return SkBitmap();
+ }
+ WebView* view = render_view->webview();
+ base::TimeTicks beginning_time = base::TimeTicks::Now();
+ skia::PlatformCanvas canvas;
+ if (!canvas.initialize(view_size.width(), view_size.height(), true)) {
+ return SkBitmap();
+ }
+
+ // Make sure we are not using any zoom when we take the snapshot. We will
+ // restore the previous zoom level after the snapshot is taken.
+ int old_zoom_level = view->zoomLevel();
+ if (view->zoomLevel() != 0) {
+ view->setZoomLevel(false, 0);
+ }
+ WebSize old_size = view->size();
+ // TODO(noelutz): not only should we hide all scroll bars but we should also
+ // make sure that all scroll-bars are at the top.
+ view->mainFrame()->setCanHaveScrollbars(false); // always hide scrollbars.
+ view->resize(view_size);
+ view->layout();
+ view->paint(webkit_glue::ToWebCanvas(&canvas),
+ WebRect(0, 0, view_size.width(), view_size.height()));
+
+ skia::BitmapPlatformDevice& device =
+ static_cast<skia::BitmapPlatformDevice&>(canvas.getTopPlatformDevice());
+
+ // Now resize the thumbnail to the right size. Note: it is important that we
+ // use this resize algorithm here.
+ const SkBitmap& bitmap = device.accessBitmap(false);
+ SkBitmap thumbnail = skia::ImageOperations::Resize(
+ bitmap,
+ skia::ImageOperations::RESIZE_LANCZOS3,
+ thumbnail_size.width(),
+ thumbnail_size.height());
+
+ // Put things back as they were before.
+ if (view->zoomLevel() != old_zoom_level) {
+ view->setZoomLevel(false, old_zoom_level);
+ }
+ // Maybe re-display the scrollbars and resize the view to its old size.
+ view->mainFrame()->setCanHaveScrollbars(
+ render_view->should_display_scrollbars(old_size.width, old_size.height));
+ view->resize(old_size);
+
+ HISTOGRAM_TIMES("SBClientPhishing.GrabPhishingThumbnail",
+ base::TimeTicks::Now() - beginning_time);
+ return thumbnail;
+}
+
+} // namespace safe_browsing
diff --git a/chrome/renderer/safe_browsing/phishing_thumbnailer.h b/chrome/renderer/safe_browsing/phishing_thumbnailer.h
new file mode 100644
index 0000000..99460c6
--- /dev/null
+++ b/chrome/renderer/safe_browsing/phishing_thumbnailer.h
@@ -0,0 +1,40 @@
+// Copyright (c) 2010 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.
+//
+// Helper function which takes a custom thumbnail for the client-side phishing
+// detector.
+//
+// Important note: in some circumstances grabbing a thumbnail using
+// this function can be very slow since it may need to re-layout the page
+// twice. Also, using this class may have some side effects (e.g.,
+// onScroll and onResize will be called, etc). Currently, this function
+// is only used if Chrome is almost certain that the current page is
+// phishing (according to the client-side phishing detector) in which
+// case we are not too worried about performance or possibly causing
+// some JavaScript weirdness on the page.
+
+#ifndef CHROME_RENDERER_SAFE_BROWSING_PHISHING_THUMBNAILER_H_
+#define CHROME_RENDERER_SAFE_BROWSING_PHISHING_THUMBNAILER_H_
+#pragma once
+
+namespace gfx {
+class Size;
+}
+class RenderView;
+class SkBitmap;
+
+namespace safe_browsing {
+
+// Grabs a thumbnail returns a bitmap that contains the result. Before grabbing
+// a snapshot the view will be re-sized to |view_size| and the resulting
+// snapshot will then be re-sized to the given |thumbnail_size|. If grabbing
+// the thumbnail fails this function returns SkBitmap() in which case calling
+// isNull() on the returned bitmap will return true.
+SkBitmap GrabPhishingThumbnail(RenderView* render_view,
+ const gfx::Size& view_size,
+ const gfx::Size& thumbnail_size);
+
+} // namespace safe_browsing
+
+#endif // CHROME_RENDERER_SAFE_BROWSING_PHISHING_THUMBNAILER_H_
diff --git a/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc b/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc
new file mode 100644
index 0000000..a894b2d
--- /dev/null
+++ b/chrome/renderer/safe_browsing/phishing_thumbnailer_browsertest.cc
@@ -0,0 +1,33 @@
+// Copyright (c) 2010 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 "base/basictypes.h"
+#include "chrome/renderer/render_widget_browsertest.h"
+#include "chrome/renderer/safe_browsing/phishing_thumbnailer.h"
+#include "testing/gtest/include/gtest/gtest.h"
+#include "third_party/skia/include/core/SkBitmap.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebSize.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebView.h"
+
+namespace safe_browsing {
+
+class ThumbnailerTest : public RenderWidgetTest {
+ public:
+ ThumbnailerTest() {}
+
+ protected:
+ virtual void ResizeAndPaint(const gfx::Size& page_size,
+ const gfx::Size& desired_size,
+ SkBitmap* snapshot) {
+ ASSERT_TRUE(snapshot);
+ *snapshot = GrabPhishingThumbnail(view_.get(), page_size, desired_size);
+ EXPECT_FALSE(snapshot->isNull());
+ }
+};
+
+TEST_F(ThumbnailerTest, GrabPhishingThumbnail) {
+ TestResizeAndPaint();
+}
+
+} // namespace safe_browsing