Commit 84161c41 authored by Dana Fried's avatar Dana Fried Committed by Commit Bot

Debounce watching of thumbnails.

Instead of watching and unwatching the thumbnail associated with a hover
card every time the mouse moves on or off a tab (or something grabs
mouse focus) we now watch a handful of thumbnails of tabs we've recently
hovered.

Note that re-watching a tab with a valid thumbnail is mostly a no-op.

Bug: 1021332
Change-Id: I55646c89514a001052cd6d453ffe3a3b6e11a731
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1899388
Auto-Submit: Dana Fried <dfried@chromium.org>
Reviewed-by: default avatarCaroline Rising <corising@chromium.org>
Commit-Queue: Caroline Rising <corising@chromium.org>
Cr-Commit-Position: refs/heads/master@{#712810}
parent a072b700
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <algorithm> #include <algorithm>
#include <memory> #include <memory>
#include "base/containers/mru_cache.h"
#include "base/metrics/field_trial_params.h" #include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h" #include "base/metrics/histogram_macros.h"
#include "build/build_config.h" #include "build/build_config.h"
...@@ -308,6 +309,75 @@ class TabHoverCardBubbleView::FadeLabel : public views::Label { ...@@ -308,6 +309,75 @@ class TabHoverCardBubbleView::FadeLabel : public views::Label {
} }
}; };
// Maintains a set of thumbnails to watch, ensuring the capture count on the
// associated WebContents stays nonzero until a valid thumbnail has been
// captured.
class TabHoverCardBubbleView::ThumbnailWatcher {
public:
explicit ThumbnailWatcher(TabHoverCardBubbleView* hover_card)
: hover_card_(hover_card) {}
~ThumbnailWatcher() = default;
// Begin watching the specified thumbnail image for updates. Ideally, should
// trigger the associated WebContents to load (if not loaded already) and
// retrieve a valid thumbnail. If too many thumbnails are being watched, the
// least-recently watched will be unwatched.
void Watch(scoped_refptr<ThumbnailImage> thumbnail_image) {
ThumbnailImage* const ptr = thumbnail_image.get();
auto it = recent_observers_.Get(ptr);
if (it == recent_observers_.end()) {
recent_observers_.Put(ptr, std::make_unique<ThumbnailObserver>(
this, std::move(thumbnail_image)));
}
ptr->RequestThumbnailImage();
}
// Returns the current (most recent) thumbnail being watched.
ThumbnailImage* current_image() const {
return recent_observers_.empty() ? nullptr
: recent_observers_.begin()->first;
}
void OnNewImage(const ThumbnailImage* thumbnail, gfx::ImageSkia image) {
DCHECK(!recent_observers_.empty());
if (recent_observers_.begin()->first == thumbnail)
hover_card_->OnThumbnailImageAvailable(std::move(image));
}
private:
// Actually does the work of watching a single thumbnail. Cleans itself up
// (including unregistering as an observer) on destruction.
class ThumbnailObserver : public ThumbnailImage::Observer {
public:
ThumbnailObserver(ThumbnailWatcher* thumbnail_watcher,
scoped_refptr<ThumbnailImage> thumbnail_image)
: thumbnail_watcher_(thumbnail_watcher),
thumbnail_image_(std::move(thumbnail_image)) {
scoped_observer_.Add(thumbnail_image_.get());
}
~ThumbnailObserver() override = default;
base::Optional<gfx::Size> GetThumbnailSizeHint() const override {
return TabStyle::GetPreviewImageSize();
}
void OnThumbnailImageAvailable(gfx::ImageSkia preview_image) override {
thumbnail_watcher_->OnNewImage(thumbnail_image_.get(),
std::move(preview_image));
}
private:
ThumbnailWatcher* const thumbnail_watcher_;
scoped_refptr<ThumbnailImage> thumbnail_image_;
ScopedObserver<ThumbnailImage, ThumbnailImage::Observer> scoped_observer_{
this};
};
TabHoverCardBubbleView* const hover_card_;
base::MRUCache<ThumbnailImage*, std::unique_ptr<ThumbnailObserver>>
recent_observers_{5};
};
TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab) TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
: BubbleDialogDelegateView(tab, views::BubbleBorder::TOP_LEFT) { : BubbleDialogDelegateView(tab, views::BubbleBorder::TOP_LEFT) {
// We'll do all of our own layout inside the bubble, so no need to inset this // We'll do all of our own layout inside the bubble, so no need to inset this
...@@ -403,6 +473,7 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab) ...@@ -403,6 +473,7 @@ TabHoverCardBubbleView::TabHoverCardBubbleView(Tab* tab)
std::make_unique<WidgetSlideAnimationDelegate>(this); std::make_unique<WidgetSlideAnimationDelegate>(this);
fade_animation_delegate_ = fade_animation_delegate_ =
std::make_unique<WidgetFadeAnimationDelegate>(widget_); std::make_unique<WidgetFadeAnimationDelegate>(widget_);
thumbnail_watcher_ = std::make_unique<ThumbnailWatcher>(this);
constexpr int kFootnoteVerticalMargin = 8; constexpr int kFootnoteVerticalMargin = 8;
GetBubbleFrameView()->set_footnote_margins( GetBubbleFrameView()->set_footnote_margins(
...@@ -504,7 +575,6 @@ bool TabHoverCardBubbleView::IsVisible() { ...@@ -504,7 +575,6 @@ bool TabHoverCardBubbleView::IsVisible() {
void TabHoverCardBubbleView::FadeOutToHide() { void TabHoverCardBubbleView::FadeOutToHide() {
delayed_show_timer_.Stop(); delayed_show_timer_.Stop();
RegisterToThumbnailImageUpdates(nullptr);
if (!widget_->IsVisible()) if (!widget_->IsVisible())
return; return;
slide_animation_delegate_->StopAnimation(); slide_animation_delegate_->StopAnimation();
...@@ -665,7 +735,13 @@ void TabHoverCardBubbleView::UpdateCardContent(const Tab* tab) { ...@@ -665,7 +735,13 @@ void TabHoverCardBubbleView::UpdateCardContent(const Tab* tab) {
// If the preview image feature is not enabled, |preview_image_| will be null. // If the preview image feature is not enabled, |preview_image_| will be null.
if (preview_image_ && preview_image_->GetVisible()) { if (preview_image_ && preview_image_->GetVisible()) {
RegisterToThumbnailImageUpdates(tab->data().thumbnail); auto thumbnail = tab->data().thumbnail;
if (!thumbnail) {
ClearPreviewImage();
} else if (thumbnail != thumbnail_watcher_->current_image()) {
waiting_for_decompress_ = true;
thumbnail_watcher_->Watch(thumbnail);
}
} }
} }
...@@ -674,28 +750,6 @@ void TabHoverCardBubbleView::UpdateTextFade(double percent) { ...@@ -674,28 +750,6 @@ void TabHoverCardBubbleView::UpdateTextFade(double percent) {
domain_fade_label_->SetFade(percent); domain_fade_label_->SetFade(percent);
} }
void TabHoverCardBubbleView::RegisterToThumbnailImageUpdates(
scoped_refptr<ThumbnailImage> thumbnail_image) {
if (thumbnail_image_ == thumbnail_image)
return;
if (thumbnail_image_) {
thumbnail_observer_.Remove(thumbnail_image_.get());
thumbnail_image_.reset();
}
if (thumbnail_image) {
if (!thumbnail_image->has_data())
ClearPreviewImage();
else
waiting_for_decompress_ = true;
thumbnail_image_ = thumbnail_image;
thumbnail_observer_.Add(thumbnail_image_.get());
thumbnail_image->RequestThumbnailImage();
}
}
void TabHoverCardBubbleView::ClearPreviewImage() { void TabHoverCardBubbleView::ClearPreviewImage() {
// Check the no-preview color and size to see if it needs to be // Check the no-preview color and size to see if it needs to be
// regenerated. DPI or theme change can cause a regeneration. // regenerated. DPI or theme change can cause a regeneration.
...@@ -748,10 +802,6 @@ void TabHoverCardBubbleView::OnThumbnailImageAvailable( ...@@ -748,10 +802,6 @@ void TabHoverCardBubbleView::OnThumbnailImageAvailable(
waiting_for_decompress_ = false; waiting_for_decompress_ = false;
} }
base::Optional<gfx::Size> TabHoverCardBubbleView::GetThumbnailSizeHint() const {
return TabStyle::GetPreviewImageSize();
}
gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const { gfx::Size TabHoverCardBubbleView::CalculatePreferredSize() const {
gfx::Size preferred_size = GetLayoutManager()->GetPreferredSize(this); gfx::Size preferred_size = GetLayoutManager()->GetPreferredSize(this);
preferred_size.set_width(TabStyle::GetPreviewImageSize().width()); preferred_size.set_width(TabStyle::GetPreviewImageSize().width());
......
...@@ -7,12 +7,10 @@ ...@@ -7,12 +7,10 @@
#include <memory> #include <memory>
#include "base/memory/weak_ptr.h"
#include "base/scoped_observer.h" #include "base/scoped_observer.h"
#include "base/time/time.h" #include "base/time/time.h"
#include "base/timer/timer.h" #include "base/timer/timer.h"
#include "chrome/browser/ui/tabs/tab_utils.h" #include "chrome/browser/ui/tabs/tab_utils.h"
#include "chrome/browser/ui/thumbnails/thumbnail_image.h"
#include "ui/views/bubble/bubble_dialog_delegate_view.h" #include "ui/views/bubble/bubble_dialog_delegate_view.h"
namespace gfx { namespace gfx {
...@@ -28,8 +26,7 @@ class Widget; ...@@ -28,8 +26,7 @@ class Widget;
class Tab; class Tab;
// Dialog that displays an informational hover card containing page information. // Dialog that displays an informational hover card containing page information.
class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, class TabHoverCardBubbleView : public views::BubbleDialogDelegateView {
public ThumbnailImage::Observer {
public: public:
explicit TabHoverCardBubbleView(Tab* tab); explicit TabHoverCardBubbleView(Tab* tab);
...@@ -71,6 +68,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, ...@@ -71,6 +68,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView,
class WidgetFadeAnimationDelegate; class WidgetFadeAnimationDelegate;
class WidgetSlideAnimationDelegate; class WidgetSlideAnimationDelegate;
class FadeLabel; class FadeLabel;
class ThumbnailWatcher;
// Get delay in milliseconds based on tab width. // Get delay in milliseconds based on tab width.
base::TimeDelta GetDelay(int tab_width) const; base::TimeDelta GetDelay(int tab_width) const;
...@@ -83,9 +81,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, ...@@ -83,9 +81,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView,
// Update the text fade to the given percent, which should be between 0 and 1. // Update the text fade to the given percent, which should be between 0 and 1.
void UpdateTextFade(double percent); void UpdateTextFade(double percent);
void RegisterToThumbnailImageUpdates( void OnThumbnailImageAvailable(gfx::ImageSkia thumbnail_image);
scoped_refptr<ThumbnailImage> thumbnail_image);
void ClearPreviewImage(); void ClearPreviewImage();
// Called when a hover card lands on the tab it's supposed to be a preview // Called when a hover card lands on the tab it's supposed to be a preview
...@@ -93,10 +89,6 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, ...@@ -93,10 +89,6 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView,
// animation completes. // animation completes.
void OnHoverCardLanded(); void OnHoverCardLanded();
// ThumbnailImage::Observer:
void OnThumbnailImageAvailable(gfx::ImageSkia thumbnail_image) override;
base::Optional<gfx::Size> GetThumbnailSizeHint() const override;
// views::BubbleDialogDelegateView: // views::BubbleDialogDelegateView:
gfx::Size CalculatePreferredSize() const override; gfx::Size CalculatePreferredSize() const override;
...@@ -109,6 +101,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, ...@@ -109,6 +101,7 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView,
std::unique_ptr<WidgetFadeAnimationDelegate> fade_animation_delegate_; std::unique_ptr<WidgetFadeAnimationDelegate> fade_animation_delegate_;
// Used to animate the tab hover card's movement between tabs. // Used to animate the tab hover card's movement between tabs.
std::unique_ptr<WidgetSlideAnimationDelegate> slide_animation_delegate_; std::unique_ptr<WidgetSlideAnimationDelegate> slide_animation_delegate_;
std::unique_ptr<ThumbnailWatcher> thumbnail_watcher_;
// Timestamp of the last time a hover card was visible, recorded before it is // Timestamp of the last time a hover card was visible, recorded before it is
// hidden. This is used for metrics. // hidden. This is used for metrics.
...@@ -130,13 +123,8 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView, ...@@ -130,13 +123,8 @@ class TabHoverCardBubbleView : public views::BubbleDialogDelegateView,
// Counter used to keep track of the number of tab hover cards seen before a // Counter used to keep track of the number of tab hover cards seen before a
// tab is selected by mouse press. // tab is selected by mouse press.
size_t hover_cards_seen_count_ = 0; size_t hover_cards_seen_count_ = 0;
scoped_refptr<ThumbnailImage> thumbnail_image_;
ScopedObserver<ThumbnailImage, ThumbnailImage::Observer> thumbnail_observer_{
this};
bool waiting_for_decompress_ = false; bool waiting_for_decompress_ = false;
base::WeakPtrFactory<TabHoverCardBubbleView> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(TabHoverCardBubbleView); DISALLOW_COPY_AND_ASSIGN(TabHoverCardBubbleView);
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment