Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(369)

Side by Side Diff: chrome/renderer/chrome_render_observer.cc

Issue 6873014: Clear RenderThread of any Chrome specific code, and move a bunch of stuff out of RenderView. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/renderer/chrome_render_observer.h"
6
7 #include "base/command_line.h"
8 #include "base/message_loop.h"
9 #include "base/metrics/histogram.h"
10 #include "chrome/common/chrome_switches.h"
11 #include "chrome/common/render_messages.h"
12 #include "chrome/common/thumbnail_score.h"
13 #include "chrome/renderer/safe_browsing/phishing_classifier_delegate.h"
14 #include "chrome/renderer/translate_helper.h"
15 #include "content/renderer/content_renderer_client.h"
16 #include "content/renderer/render_view.h"
17 #include "skia/ext/bitmap_platform_device.h"
18 #include "skia/ext/image_operations.h"
19 #include "skia/ext/platform_canvas.h"
20 #include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
21 #include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
22 #include "third_party/WebKit/Source/WebKit/chromium/public/WebRect.h"
23 #include "third_party/WebKit/Source/WebKit/chromium/public/WebSize.h"
24 #include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
25 #include "ui/gfx/color_utils.h"
26 #include "ui/gfx/skbitmap_operations.h"
27 #include "webkit/glue/webkit_glue.h"
28
29 using WebKit::WebDataSource;
30 using WebKit::WebFrame;
31 using WebKit::WebRect;
32 using WebKit::WebSize;
33 using WebKit::WebView;
34
35 // Delay in milliseconds that we'll wait before capturing the page contents
36 // and thumbnail.
37 static const int kDelayForCaptureMs = 500;
38
39 // Typically, we capture the page data once the page is loaded.
40 // Sometimes, the page never finishes to load, preventing the page capture
41 // To workaround this problem, we always perform a capture after the following
42 // delay.
43 static const int kDelayForForcedCaptureMs = 6000;
44
45 // define to write the time necessary for thumbnail/DOM text retrieval,
46 // respectively, into the system debug log
47 // #define TIME_TEXT_RETRIEVAL
48
49 // maximum number of characters in the document to index, any text beyond this
50 // point will be clipped
51 static const size_t kMaxIndexChars = 65535;
52
53 // Size of the thumbnails that we'll generate
54 static const int kThumbnailWidth = 212;
55 static const int kThumbnailHeight = 132;
56
57 static bool PaintViewIntoCanvas(WebView* view,
58 skia::PlatformCanvas& canvas) {
59 view->layout();
60 const WebSize& size = view->size();
61
62 if (!canvas.initialize(size.width, size.height, true))
63 return false;
64
65 view->paint(webkit_glue::ToWebCanvas(&canvas),
66 WebRect(0, 0, size.width, size.height));
67 // TODO: Add a way to snapshot the whole page, not just the currently
68 // visible part.
69
70 return true;
71 }
72
73 // Calculates how "boring" a thumbnail is. The boring score is the
74 // 0,1 ranged percentage of pixels that are the most common
75 // luma. Higher boring scores indicate that a higher percentage of a
76 // bitmap are all the same brightness.
77 static double CalculateBoringScore(SkBitmap* bitmap) {
78 int histogram[256] = {0};
79 color_utils::BuildLumaHistogram(bitmap, histogram);
80
81 int color_count = *std::max_element(histogram, histogram + 256);
82 int pixel_count = bitmap->width() * bitmap->height();
83 return static_cast<double>(color_count) / pixel_count;
84 }
85
86 ChromeRenderObserver::ChromeRenderObserver(
87 RenderView* render_view,
88 TranslateHelper* translate_helper,
89 safe_browsing::PhishingClassifierDelegate* phishing_classifier)
90 : RenderViewObserver(render_view),
91 translate_helper_(translate_helper),
92 phishing_classifier_(phishing_classifier),
93 last_indexed_page_id_(-1),
94 ALLOW_THIS_IN_INITIALIZER_LIST(page_info_method_factory_(this)) {
95 }
96
97 ChromeRenderObserver::~ChromeRenderObserver() {
98 }
99
100 bool ChromeRenderObserver::OnMessageReceived(const IPC::Message& message) {
101 bool handled = true;
102 IPC_BEGIN_MESSAGE_MAP(ChromeRenderObserver, message)
103 IPC_MESSAGE_HANDLER(ViewMsg_CaptureSnapshot, OnCaptureSnapshot)
104 IPC_MESSAGE_UNHANDLED(handled = false)
105 IPC_END_MESSAGE_MAP()
106 return handled;
107 }
108
109 void ChromeRenderObserver::OnCaptureSnapshot() {
110 SkBitmap snapshot;
111 bool error = false;
112
113 WebFrame* main_frame = render_view()->webview()->mainFrame();
114 if (!main_frame)
115 error = true;
116
117 if (!error && !CaptureSnapshot(render_view()->webview(), &snapshot))
118 error = true;
119
120 DCHECK(error == snapshot.empty()) <<
121 "Snapshot should be empty on error, non-empty otherwise.";
122
123 // Send the snapshot to the browser process.
124 Send(new ViewHostMsg_Snapshot(routing_id(), snapshot));
125 }
126
127 void ChromeRenderObserver::DidStopLoading() {
128 MessageLoop::current()->PostDelayedTask(
129 FROM_HERE,
130 page_info_method_factory_.NewRunnableMethod(
131 &ChromeRenderObserver::CapturePageInfo, render_view()->page_id(),
132 false),
133 render_view()->content_state_immediately() ? 0 : kDelayForCaptureMs);
134 }
135
136 void ChromeRenderObserver::DidCommitProvisionalLoad(WebFrame* frame,
137 bool is_new_navigation) {
138 if (!is_new_navigation)
139 return;
140
141 MessageLoop::current()->PostDelayedTask(
142 FROM_HERE,
143 page_info_method_factory_.NewRunnableMethod(
144 &ChromeRenderObserver::CapturePageInfo, render_view()->page_id(),
145 true),
146 kDelayForForcedCaptureMs);
147 }
148
149 void ChromeRenderObserver::CapturePageInfo(int load_id,
150 bool preliminary_capture) {
151 if (load_id != render_view()->page_id())
152 return; // This capture call is no longer relevant due to navigation.
153
154 if (load_id == last_indexed_page_id_)
155 return; // we already indexed this page
156
157 if (!render_view()->webview())
158 return;
159
160 WebFrame* main_frame = render_view()->webview()->mainFrame();
161 if (!main_frame)
162 return;
163
164 // Don't index/capture pages that are in view source mode.
165 if (main_frame->isViewSourceModeEnabled())
166 return;
167
168 // Don't index/capture pages that failed to load. This only checks the top
169 // level frame so the thumbnail may contain a frame that failed to load.
170 WebDataSource* ds = main_frame->dataSource();
171 if (ds && ds->hasUnreachableURL())
172 return;
173
174 if (!preliminary_capture)
175 last_indexed_page_id_ = load_id;
176
177 // Get the URL for this page.
178 GURL url(main_frame->url());
179 if (url.is_empty())
180 return;
181
182 // Retrieve the frame's full text.
183 string16 contents;
184 CaptureText(main_frame, &contents);
185 if (contents.size()) {
186 if (translate_helper_)
187 translate_helper_->PageCaptured(contents);
188 // Send the text to the browser for indexing (the browser might decide not
189 // to index, if the URL is HTTPS for instance) and language discovery.
190 Send(new ViewHostMsg_PageContents(routing_id(), url, load_id, contents));
191 }
192
193 // Generate the thumbnail here if the in-browser thumbnailing isn't
194 // enabled. TODO(satorux): Remove this and related code once
195 // crbug.com/65936 is complete.
196 if (!CommandLine::ForCurrentProcess()->HasSwitch(
197 switches::kEnableInBrowserThumbnailing)) {
198 CaptureThumbnail();
199 }
200
201 // Will swap out the string.
202 if (phishing_classifier_)
203 phishing_classifier_->PageCaptured(&contents, preliminary_capture);
204 }
205
206 void ChromeRenderObserver::CaptureText(WebFrame* frame, string16* contents) {
207 contents->clear();
208 if (!frame)
209 return;
210
211 #ifdef TIME_TEXT_RETRIEVAL
212 double begin = time_util::GetHighResolutionTimeNow();
213 #endif
214
215 // get the contents of the frame
216 *contents = frame->contentAsText(kMaxIndexChars);
217
218 #ifdef TIME_TEXT_RETRIEVAL
219 double end = time_util::GetHighResolutionTimeNow();
220 char buf[128];
221 sprintf_s(buf, "%d chars retrieved for indexing in %gms\n",
222 contents.size(), (end - begin)*1000);
223 OutputDebugStringA(buf);
224 #endif
225
226 // When the contents are clipped to the maximum, we don't want to have a
227 // partial word indexed at the end that might have been clipped. Therefore,
228 // terminate the string at the last space to ensure no words are clipped.
229 if (contents->size() == kMaxIndexChars) {
230 size_t last_space_index = contents->find_last_of(kWhitespaceUTF16);
231 if (last_space_index == std::wstring::npos)
232 return; // don't index if we got a huge block of text with no spaces
233 contents->resize(last_space_index);
234 }
235 }
236
237 void ChromeRenderObserver::CaptureThumbnail() {
238 WebFrame* main_frame = render_view()->webview()->mainFrame();
239 if (!main_frame)
240 return;
241
242 // get the URL for this page
243 GURL url(main_frame->url());
244 if (url.is_empty())
245 return;
246
247 if (render_view()->size().IsEmpty())
248 return; // Don't create an empty thumbnail!
249
250 ThumbnailScore score;
251 SkBitmap thumbnail;
252 if (!CaptureFrameThumbnail(render_view()->webview(), kThumbnailWidth,
253 kThumbnailHeight, &thumbnail, &score))
254 return;
255
256 // send the thumbnail message to the browser process
257 Send(new ViewHostMsg_Thumbnail(routing_id(), url, score, thumbnail));
258 }
259
260 bool ChromeRenderObserver::CaptureFrameThumbnail(WebView* view,
261 int w,
262 int h,
263 SkBitmap* thumbnail,
264 ThumbnailScore* score) {
265 base::TimeTicks beginning_time = base::TimeTicks::Now();
266
267 skia::PlatformCanvas canvas;
268
269 // Paint |view| into |canvas|.
270 if (!PaintViewIntoCanvas(view, canvas))
271 return false;
272
273 skia::BitmapPlatformDevice& device =
274 static_cast<skia::BitmapPlatformDevice&>(canvas.getTopPlatformDevice());
275
276 const SkBitmap& src_bmp = device.accessBitmap(false);
277
278 SkRect dest_rect = { 0, 0, SkIntToScalar(w), SkIntToScalar(h) };
279 float dest_aspect = dest_rect.width() / dest_rect.height();
280
281 // Get the src rect so that we can preserve the aspect ratio while filling
282 // the destination.
283 SkIRect src_rect;
284 if (src_bmp.width() < dest_rect.width() ||
285 src_bmp.height() < dest_rect.height()) {
286 // Source image is smaller: we clip the part of source image within the
287 // dest rect, and then stretch it to fill the dest rect. We don't respect
288 // the aspect ratio in this case.
289 src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()),
290 static_cast<S16CPU>(dest_rect.height()));
291 score->good_clipping = false;
292 } else {
293 float src_aspect = static_cast<float>(src_bmp.width()) / src_bmp.height();
294 if (src_aspect > dest_aspect) {
295 // Wider than tall, clip horizontally: we center the smaller thumbnail in
296 // the wider screen.
297 S16CPU new_width = static_cast<S16CPU>(src_bmp.height() * dest_aspect);
298 S16CPU x_offset = (src_bmp.width() - new_width) / 2;
299 src_rect.set(x_offset, 0, new_width + x_offset, src_bmp.height());
300 score->good_clipping = false;
301 } else {
302 src_rect.set(0, 0, src_bmp.width(),
303 static_cast<S16CPU>(src_bmp.width() / dest_aspect));
304 score->good_clipping = true;
305 }
306 }
307
308 score->at_top = (view->mainFrame()->scrollOffset().height == 0);
309
310 SkBitmap subset;
311 device.accessBitmap(false).extractSubset(&subset, src_rect);
312
313 // First do a fast downsample by powers of two to get close to the final size.
314 SkBitmap downsampled_subset =
315 SkBitmapOperations::DownsampleByTwoUntilSize(subset, w, h);
316
317 // Do a high-quality resize from the downscaled size to the final size.
318 *thumbnail = skia::ImageOperations::Resize(
319 downsampled_subset, skia::ImageOperations::RESIZE_LANCZOS3, w, h);
320
321 score->boring_score = CalculateBoringScore(thumbnail);
322
323 HISTOGRAM_TIMES("Renderer4.Thumbnail",
324 base::TimeTicks::Now() - beginning_time);
325
326 return true;
327 }
328
329 bool ChromeRenderObserver::CaptureSnapshot(WebView* view, SkBitmap* snapshot) {
330 base::TimeTicks beginning_time = base::TimeTicks::Now();
331
332 skia::PlatformCanvas canvas;
333 if (!PaintViewIntoCanvas(view, canvas))
334 return false;
335
336 skia::BitmapPlatformDevice& device =
337 static_cast<skia::BitmapPlatformDevice&>(canvas.getTopPlatformDevice());
338
339 const SkBitmap& bitmap = device.accessBitmap(false);
340 if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config))
341 return false;
342
343 HISTOGRAM_TIMES("Renderer4.Snapshot",
344 base::TimeTicks::Now() - beginning_time);
345 return true;
346 }
OLDNEW
« no previous file with comments | « chrome/renderer/chrome_render_observer.h ('k') | chrome/renderer/chrome_render_process_observer.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698