| 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;
|
| -}
|
|
|