diff options
Diffstat (limited to 'chrome/browser/prerender/prerender_tab_helper.cc')
-rw-r--r-- | chrome/browser/prerender/prerender_tab_helper.cc | 126 |
1 files changed, 126 insertions, 0 deletions
diff --git a/chrome/browser/prerender/prerender_tab_helper.cc b/chrome/browser/prerender/prerender_tab_helper.cc index 8f01fef..1d1feac 100644 --- a/chrome/browser/prerender/prerender_tab_helper.cc +++ b/chrome/browser/prerender/prerender_tab_helper.cc @@ -7,12 +7,20 @@ #include "base/metrics/histogram.h" #include "base/string_number_conversions.h" #include "base/time.h" +#include "chrome/browser/prerender/prerender_histograms.h" #include "chrome/browser/prerender/prerender_manager.h" #include "chrome/browser/prerender/prerender_manager_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/tab_contents/core_tab_helper.h" #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" +#include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/web_contents_view.h" +#include "skia/ext/platform_canvas.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/rect.h" + +using content::WebContents; namespace prerender { @@ -33,8 +41,113 @@ void RecordPageviewEvent(PAGEVIEW_EVENTS event) { } // namespace +// Helper class to compute pixel-based stats on the paint progress +// between when a prerendered page is swapped in and when the onload event +// fires. +class PrerenderTabHelper::PixelStats { + public: + explicit PixelStats(PrerenderTabHelper* tab_helper) : + weak_factory_(this), + tab_helper_(tab_helper) { + } + + // Reasons why we need to fetch bitmaps: either a prerender was swapped in, + // or a prerendered page has finished loading. + enum BitmapType { + BITMAP_SWAP_IN, + BITMAP_ON_LOAD + }; + + void GetBitmap(BitmapType bitmap_type, WebContents* web_contents) { + if (bitmap_type == BITMAP_SWAP_IN) { + bitmap_.reset(); + bitmap_web_contents_ = web_contents; + } + + if (bitmap_type == BITMAP_ON_LOAD && bitmap_web_contents_ != web_contents) + return; + + if (!web_contents || !web_contents->GetView() || + !web_contents->GetRenderViewHost()) { + return; + } + + skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; + web_contents->GetRenderViewHost()->CopyFromBackingStore( + gfx::Rect(), gfx::Size(), temp_canvas, + base::Bind(&PrerenderTabHelper::PixelStats::HandleBitmapResult, + weak_factory_.GetWeakPtr(), + bitmap_type, + web_contents, + base::Owned(temp_canvas))); + } + + private: + void HandleBitmapResult(BitmapType bitmap_type, + WebContents* web_contents, + skia::PlatformCanvas* temp_canvas, + bool succeeded) { + scoped_ptr<SkBitmap> bitmap; + if (succeeded) { + const SkBitmap& canvas_bitmap = + skia::GetTopDevice(*temp_canvas)->accessBitmap(false); + bitmap.reset(new SkBitmap()); + canvas_bitmap.copyTo(bitmap.get(), SkBitmap::kARGB_8888_Config); + } + + if (bitmap_web_contents_ != web_contents) + return; + + if (bitmap_type == BITMAP_SWAP_IN) + bitmap_.swap(bitmap); + + if (bitmap_type == BITMAP_ON_LOAD) { + PrerenderManager* prerender_manager = + tab_helper_->MaybeGetPrerenderManager(); + if (prerender_manager) { + prerender_manager->histograms()->RecordFractionPixelsFinalAtSwapin( + CompareBitmaps(bitmap_.get(), bitmap.get())); + } + bitmap_.reset(); + bitmap_web_contents_ = NULL; + } + } + + // Helper comparing two bitmaps of identical size. + // Returns a value < 0.0 if there is an error, and otherwise, a double in + // [0, 1] indicating the fraction of pixels that are the same. + double CompareBitmaps(SkBitmap* bitmap1, SkBitmap* bitmap2) { + if (!bitmap1 || !bitmap2) { + return -2.0; + } + if (bitmap1->width() != bitmap2->width() || + bitmap1->height() != bitmap2->height()) { + return -1.0; + } + int pixels = bitmap1->width() * bitmap1->height(); + int same_pixels = 0; + for (int y = 0; y < bitmap1->height(); ++y) { + for (int x = 0; x < bitmap1->width(); ++x) { + if (bitmap1->getColor(x, y) == bitmap2->getColor(x, y)) + same_pixels++; + } + } + return static_cast<double>(same_pixels) / static_cast<double>(pixels); + } + + // Bitmap of what the last swapped in prerendered tab looked like at swapin, + // and the WebContents that it was swapped into. + scoped_ptr<SkBitmap> bitmap_; + WebContents* bitmap_web_contents_; + + base::WeakPtrFactory<PixelStats> weak_factory_; + + PrerenderTabHelper* tab_helper_; +}; + PrerenderTabHelper::PrerenderTabHelper(TabContentsWrapper* tab) : content::WebContentsObserver(tab->web_contents()), + pixel_stats_(new PixelStats(this)), tab_(tab) { } @@ -93,6 +206,8 @@ void PrerenderTabHelper::DidStopLoading() { PrerenderManager::RecordPerceivedPageLoadTime( now - pplt_load_start_, fraction_elapsed_at_swapin, web_contents(), url_); + if (IsPrerendered()) + pixel_stats_->GetBitmap(PixelStats::BITMAP_ON_LOAD, web_contents()); } // Reset the PPLT metric. @@ -129,6 +244,13 @@ bool PrerenderTabHelper::IsPrerendering() { return prerender_manager->IsWebContentsPrerendering(web_contents()); } +bool PrerenderTabHelper::IsPrerendered() { + PrerenderManager* prerender_manager = MaybeGetPrerenderManager(); + if (!prerender_manager) + return false; + return prerender_manager->IsWebContentsPrerendered(web_contents()); +} + void PrerenderTabHelper::PrerenderSwappedIn() { // Ensure we are not prerendering any more. DCHECK(!IsPrerendering()); @@ -136,11 +258,15 @@ void PrerenderTabHelper::PrerenderSwappedIn() { // If we have already finished loading, report a 0 PPLT. PrerenderManager::RecordPerceivedPageLoadTime(base::TimeDelta(), 1.0, web_contents(), url_); + PrerenderManager* prerender_manager = MaybeGetPrerenderManager(); + if (prerender_manager) + prerender_manager->histograms()->RecordFractionPixelsFinalAtSwapin(1.0); } else { // If we have not finished loading yet, record the actual load start, and // rebase the start time to now. actual_load_start_ = pplt_load_start_; pplt_load_start_ = base::TimeTicks::Now(); + pixel_stats_->GetBitmap(PixelStats::BITMAP_SWAP_IN, web_contents()); } } |