Index: chrome/renderer/chrome_render_observer.cc |
=================================================================== |
--- chrome/renderer/chrome_render_observer.cc (revision 81801) |
+++ chrome/renderer/chrome_render_observer.cc (working copy) |
@@ -1,346 +0,0 @@ |
-// Copyright (c) 2011 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/chrome_render_observer.h" |
- |
-#include "base/command_line.h" |
-#include "base/message_loop.h" |
-#include "base/metrics/histogram.h" |
-#include "chrome/common/chrome_switches.h" |
-#include "chrome/common/render_messages.h" |
-#include "chrome/common/thumbnail_score.h" |
-#include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h" |
-#include "chrome/renderer/translate_helper.h" |
-#include "content/renderer/content_renderer_client.h" |
-#include "content/renderer/render_view.h" |
-#include "skia/ext/bitmap_platform_device.h" |
-#include "skia/ext/image_operations.h" |
-#include "skia/ext/platform_canvas.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h" |
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h" |
-#include "ui/gfx/color_utils.h" |
-#include "ui/gfx/skbitmap_operations.h" |
-#include "webkit/glue/webkit_glue.h" |
- |
-using WebKit::WebDataSource; |
-using WebKit::WebFrame; |
-using WebKit::WebRect; |
-using WebKit::WebSize; |
-using WebKit::WebView; |
- |
-// Delay in milliseconds that we'll wait before capturing the page contents |
-// and thumbnail. |
-static const int kDelayForCaptureMs = 500; |
- |
-// Typically, we capture the page data once the page is loaded. |
-// Sometimes, the page never finishes to load, preventing the page capture |
-// To workaround this problem, we always perform a capture after the following |
-// delay. |
-static const int kDelayForForcedCaptureMs = 6000; |
- |
-// define to write the time necessary for thumbnail/DOM text retrieval, |
-// respectively, into the system debug log |
-// #define TIME_TEXT_RETRIEVAL |
- |
-// maximum number of characters in the document to index, any text beyond this |
-// point will be clipped |
-static const size_t kMaxIndexChars = 65535; |
- |
-// Size of the thumbnails that we'll generate |
-static const int kThumbnailWidth = 212; |
-static const int kThumbnailHeight = 132; |
- |
-static bool PaintViewIntoCanvas(WebView* view, |
- skia::PlatformCanvas& canvas) { |
- view->layout(); |
- const WebSize& size = view->size(); |
- |
- if (!canvas.initialize(size.width, size.height, true)) |
- return false; |
- |
- view->paint(webkit_glue::ToWebCanvas(&canvas), |
- WebRect(0, 0, size.width, size.height)); |
- // TODO: Add a way to snapshot the whole page, not just the currently |
- // visible part. |
- |
- return true; |
-} |
- |
-// Calculates how "boring" a thumbnail is. The boring score is the |
-// 0,1 ranged percentage of pixels that are the most common |
-// luma. Higher boring scores indicate that a higher percentage of a |
-// bitmap are all the same brightness. |
-static double CalculateBoringScore(SkBitmap* bitmap) { |
- int histogram[256] = {0}; |
- color_utils::BuildLumaHistogram(bitmap, histogram); |
- |
- int color_count = *std::max_element(histogram, histogram + 256); |
- int pixel_count = bitmap->width() * bitmap->height(); |
- return static_cast<double>(color_count) / pixel_count; |
-} |
- |
-ChromeRenderObserver::ChromeRenderObserver( |
- RenderView* render_view, |
- TranslateHelper* translate_helper, |
- safe_browsing::PhishingClassifierDelegate* phishing_classifier) |
- : RenderViewObserver(render_view), |
- translate_helper_(translate_helper), |
- phishing_classifier_(phishing_classifier), |
- last_indexed_page_id_(-1), |
- ALLOW_THIS_IN_INITIALIZER_LIST(page_info_method_factory_(this)) { |
-} |
- |
-ChromeRenderObserver::~ChromeRenderObserver() { |
-} |
- |
-bool ChromeRenderObserver::OnMessageReceived(const IPC::Message& message) { |
- bool handled = true; |
- IPC_BEGIN_MESSAGE_MAP(ChromeRenderObserver, message) |
- IPC_MESSAGE_HANDLER(ViewMsg_CaptureSnapshot, OnCaptureSnapshot) |
- IPC_MESSAGE_UNHANDLED(handled = false) |
- IPC_END_MESSAGE_MAP() |
- return handled; |
-} |
- |
-void ChromeRenderObserver::OnCaptureSnapshot() { |
- SkBitmap snapshot; |
- bool error = false; |
- |
- WebFrame* main_frame = render_view()->webview()->mainFrame(); |
- if (!main_frame) |
- error = true; |
- |
- if (!error && !CaptureSnapshot(render_view()->webview(), &snapshot)) |
- error = true; |
- |
- DCHECK(error == snapshot.empty()) << |
- "Snapshot should be empty on error, non-empty otherwise."; |
- |
- // Send the snapshot to the browser process. |
- Send(new ViewHostMsg_Snapshot(routing_id(), snapshot)); |
-} |
- |
-void ChromeRenderObserver::DidStopLoading() { |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- page_info_method_factory_.NewRunnableMethod( |
- &ChromeRenderObserver::CapturePageInfo, render_view()->page_id(), |
- false), |
- render_view()->content_state_immediately() ? 0 : kDelayForCaptureMs); |
-} |
- |
-void ChromeRenderObserver::DidCommitProvisionalLoad(WebFrame* frame, |
- bool is_new_navigation) { |
- if (!is_new_navigation) |
- return; |
- |
- MessageLoop::current()->PostDelayedTask( |
- FROM_HERE, |
- page_info_method_factory_.NewRunnableMethod( |
- &ChromeRenderObserver::CapturePageInfo, render_view()->page_id(), |
- true), |
- kDelayForForcedCaptureMs); |
-} |
- |
-void ChromeRenderObserver::CapturePageInfo(int load_id, |
- bool preliminary_capture) { |
- if (load_id != render_view()->page_id()) |
- return; // This capture call is no longer relevant due to navigation. |
- |
- if (load_id == last_indexed_page_id_) |
- return; // we already indexed this page |
- |
- if (!render_view()->webview()) |
- return; |
- |
- WebFrame* main_frame = render_view()->webview()->mainFrame(); |
- if (!main_frame) |
- return; |
- |
- // Don't index/capture pages that are in view source mode. |
- if (main_frame->isViewSourceModeEnabled()) |
- return; |
- |
- // Don't index/capture pages that failed to load. This only checks the top |
- // level frame so the thumbnail may contain a frame that failed to load. |
- WebDataSource* ds = main_frame->dataSource(); |
- if (ds && ds->hasUnreachableURL()) |
- return; |
- |
- if (!preliminary_capture) |
- last_indexed_page_id_ = load_id; |
- |
- // Get the URL for this page. |
- GURL url(main_frame->url()); |
- if (url.is_empty()) |
- return; |
- |
- // Retrieve the frame's full text. |
- string16 contents; |
- CaptureText(main_frame, &contents); |
- if (contents.size()) { |
- if (translate_helper_) |
- translate_helper_->PageCaptured(contents); |
- // Send the text to the browser for indexing (the browser might decide not |
- // to index, if the URL is HTTPS for instance) and language discovery. |
- Send(new ViewHostMsg_PageContents(routing_id(), url, load_id, contents)); |
- } |
- |
- // Generate the thumbnail here if the in-browser thumbnailing isn't |
- // enabled. TODO(satorux): Remove this and related code once |
- // crbug.com/65936 is complete. |
- if (!CommandLine::ForCurrentProcess()->HasSwitch( |
- switches::kEnableInBrowserThumbnailing)) { |
- CaptureThumbnail(); |
- } |
- |
- // Will swap out the string. |
- if (phishing_classifier_) |
- phishing_classifier_->PageCaptured(&contents, preliminary_capture); |
-} |
- |
-void ChromeRenderObserver::CaptureText(WebFrame* frame, string16* contents) { |
- contents->clear(); |
- if (!frame) |
- return; |
- |
-#ifdef TIME_TEXT_RETRIEVAL |
- double begin = time_util::GetHighResolutionTimeNow(); |
-#endif |
- |
- // get the contents of the frame |
- *contents = frame->contentAsText(kMaxIndexChars); |
- |
-#ifdef TIME_TEXT_RETRIEVAL |
- double end = time_util::GetHighResolutionTimeNow(); |
- char buf[128]; |
- sprintf_s(buf, "%d chars retrieved for indexing in %gms\n", |
- contents.size(), (end - begin)*1000); |
- OutputDebugStringA(buf); |
-#endif |
- |
- // When the contents are clipped to the maximum, we don't want to have a |
- // partial word indexed at the end that might have been clipped. Therefore, |
- // terminate the string at the last space to ensure no words are clipped. |
- if (contents->size() == kMaxIndexChars) { |
- size_t last_space_index = contents->find_last_of(kWhitespaceUTF16); |
- if (last_space_index == std::wstring::npos) |
- return; // don't index if we got a huge block of text with no spaces |
- contents->resize(last_space_index); |
- } |
-} |
- |
-void ChromeRenderObserver::CaptureThumbnail() { |
- WebFrame* main_frame = render_view()->webview()->mainFrame(); |
- if (!main_frame) |
- return; |
- |
- // get the URL for this page |
- GURL url(main_frame->url()); |
- if (url.is_empty()) |
- return; |
- |
- if (render_view()->size().IsEmpty()) |
- return; // Don't create an empty thumbnail! |
- |
- ThumbnailScore score; |
- SkBitmap thumbnail; |
- if (!CaptureFrameThumbnail(render_view()->webview(), kThumbnailWidth, |
- kThumbnailHeight, &thumbnail, &score)) |
- return; |
- |
- // send the thumbnail message to the browser process |
- Send(new ViewHostMsg_Thumbnail(routing_id(), url, score, thumbnail)); |
-} |
- |
-bool ChromeRenderObserver::CaptureFrameThumbnail(WebView* view, |
- int w, |
- int h, |
- SkBitmap* thumbnail, |
- ThumbnailScore* score) { |
- base::TimeTicks beginning_time = base::TimeTicks::Now(); |
- |
- skia::PlatformCanvas canvas; |
- |
- // Paint |view| into |canvas|. |
- if (!PaintViewIntoCanvas(view, canvas)) |
- return false; |
- |
- skia::BitmapPlatformDevice& device = |
- static_cast<skia::BitmapPlatformDevice&>(canvas.getTopPlatformDevice()); |
- |
- const SkBitmap& src_bmp = device.accessBitmap(false); |
- |
- SkRect dest_rect = { 0, 0, SkIntToScalar(w), SkIntToScalar(h) }; |
- float dest_aspect = dest_rect.width() / dest_rect.height(); |
- |
- // Get the src rect so that we can preserve the aspect ratio while filling |
- // the destination. |
- SkIRect src_rect; |
- if (src_bmp.width() < dest_rect.width() || |
- src_bmp.height() < dest_rect.height()) { |
- // Source image is smaller: we clip the part of source image within the |
- // dest rect, and then stretch it to fill the dest rect. We don't respect |
- // the aspect ratio in this case. |
- src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()), |
- static_cast<S16CPU>(dest_rect.height())); |
- score->good_clipping = false; |
- } else { |
- float src_aspect = static_cast<float>(src_bmp.width()) / src_bmp.height(); |
- if (src_aspect > dest_aspect) { |
- // Wider than tall, clip horizontally: we center the smaller thumbnail in |
- // the wider screen. |
- S16CPU new_width = static_cast<S16CPU>(src_bmp.height() * dest_aspect); |
- S16CPU x_offset = (src_bmp.width() - new_width) / 2; |
- src_rect.set(x_offset, 0, new_width + x_offset, src_bmp.height()); |
- score->good_clipping = false; |
- } else { |
- src_rect.set(0, 0, src_bmp.width(), |
- static_cast<S16CPU>(src_bmp.width() / dest_aspect)); |
- score->good_clipping = true; |
- } |
- } |
- |
- score->at_top = (view->mainFrame()->scrollOffset().height == 0); |
- |
- SkBitmap subset; |
- device.accessBitmap(false).extractSubset(&subset, src_rect); |
- |
- // First do a fast downsample by powers of two to get close to the final size. |
- SkBitmap downsampled_subset = |
- SkBitmapOperations::DownsampleByTwoUntilSize(subset, w, h); |
- |
- // Do a high-quality resize from the downscaled size to the final size. |
- *thumbnail = skia::ImageOperations::Resize( |
- downsampled_subset, skia::ImageOperations::RESIZE_LANCZOS3, w, h); |
- |
- score->boring_score = CalculateBoringScore(thumbnail); |
- |
- HISTOGRAM_TIMES("Renderer4.Thumbnail", |
- base::TimeTicks::Now() - beginning_time); |
- |
- return true; |
-} |
- |
-bool ChromeRenderObserver::CaptureSnapshot(WebView* view, SkBitmap* snapshot) { |
- base::TimeTicks beginning_time = base::TimeTicks::Now(); |
- |
- skia::PlatformCanvas canvas; |
- if (!PaintViewIntoCanvas(view, canvas)) |
- return false; |
- |
- skia::BitmapPlatformDevice& device = |
- static_cast<skia::BitmapPlatformDevice&>(canvas.getTopPlatformDevice()); |
- |
- const SkBitmap& bitmap = device.accessBitmap(false); |
- if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config)) |
- return false; |
- |
- HISTOGRAM_TIMES("Renderer4.Snapshot", |
- base::TimeTicks::Now() - beginning_time); |
- return true; |
-} |