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

Unified Diff: chrome/browser/ui/metro_pin_tab_helper_win.cc

Issue 11306005: Download large icon if available when creating secondary tiles on Windows 8. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 2 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/metro_pin_tab_helper_win.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/browser/ui/metro_pin_tab_helper_win.cc
diff --git a/chrome/browser/ui/metro_pin_tab_helper_win.cc b/chrome/browser/ui/metro_pin_tab_helper_win.cc
index e3fa0faca50c4e6c55fb4dc3e6da586762f18cd9..44ddcc3f13e2a9448805aa12d182226babbdfc7f 100644
--- a/chrome/browser/ui/metro_pin_tab_helper_win.cc
+++ b/chrome/browser/ui/metro_pin_tab_helper_win.cc
@@ -4,6 +4,8 @@
#include "chrome/browser/ui/metro_pin_tab_helper_win.h"
+#include <set>
+
#include "base/base_paths.h"
#include "base/bind.h"
#include "base/file_path.h"
@@ -16,11 +18,15 @@
#include "base/utf_string_conversions.h"
#include "base/win/metro.h"
#include "chrome/browser/favicon/favicon_tab_helper.h"
+#include "chrome/browser/favicon/favicon_util.h"
#include "chrome/browser/ui/tab_contents/tab_contents.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/common/icon_messages.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "crypto/sha2.h"
+#include "third_party/skia/include/core/SkCanvas.h"
+#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/canvas.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/color_analysis.h"
@@ -68,24 +74,30 @@ bool CreateSiteSpecificLogo(const gfx::ImageSkia& image,
const int kCaptionHeight = 20;
const double kBoxFade = 0.75;
const int kColorMeanDarknessLimit = 100;
- const int kColorMeanLightnessLimit = 100;
+ const int kColorMeanLightnessLimit = 650;
if (image.isNull())
return false;
- *logo_path = logo_dir.Append(tile_id).ReplaceExtension(L".png");
-
- // Use a canvas to paint the tile logo.
- gfx::Canvas canvas(gfx::Size(kLogoWidth, kLogoHeight), ui::SCALE_FACTOR_100P,
- true);
+ // First paint the image onto an opaque background to get rid of transparency.
+ // White is used as it will be disregarded in the mean calculation because of
+ // lightness limit.
+ SkPaint paint;
+ paint.setColor(SK_ColorWHITE);
+ gfx::Canvas favicon_canvas(gfx::Size(image.width(), image.height()),
+ ui::SCALE_FACTOR_100P, true);
+ favicon_canvas.DrawRect(gfx::Rect(0, 0, image.width(), image.height()),
+ paint);
+ favicon_canvas.DrawImageInt(image, 0, 0);
// Fill the tile logo with the average color from bitmap. To do this we need
// to work out the 'average color' which is calculated using PNG encoded data
// of the bitmap.
- SkPaint paint;
std::vector<unsigned char> icon_png;
- if (!gfx::PNGCodec::EncodeBGRASkBitmap(*image.bitmap(), true, &icon_png))
+ if (!gfx::PNGCodec::EncodeBGRASkBitmap(
+ favicon_canvas.ExtractImageRep().sk_bitmap(), false, &icon_png)) {
return false;
+ }
scoped_refptr<base::RefCountedStaticMemory> icon_mem(
new base::RefCountedStaticMemory(&icon_png.front(), icon_png.size()));
@@ -93,6 +105,8 @@ bool CreateSiteSpecificLogo(const gfx::ImageSkia& image,
SkColor mean_color = color_utils::CalculateKMeanColorOfPNG(
icon_mem, kColorMeanDarknessLimit, kColorMeanLightnessLimit, sampler);
paint.setColor(mean_color);
+ gfx::Canvas canvas(gfx::Size(kLogoWidth, kLogoHeight), ui::SCALE_FACTOR_100P,
+ true);
canvas.DrawRect(gfx::Rect(0, 0, kLogoWidth, kLogoHeight), paint);
// Now paint a faded square for the favicon to go in.
@@ -113,6 +127,7 @@ bool CreateSiteSpecificLogo(const gfx::ImageSkia& image,
if (!gfx::PNGCodec::EncodeBGRASkBitmap(logo_bitmap, true, &logo_png))
return false;
+ *logo_path = logo_dir.Append(tile_id).ReplaceExtension(L".png");
return file_util::WriteFile(*logo_path,
reinterpret_cast<char*>(&logo_png[0]),
logo_png.size()) > 0;
@@ -140,23 +155,178 @@ bool GetPathToBackupLogo(const FilePath& logo_dir,
} // namespace
-class MetroPinTabHelper::TaskRunner
- : public base::RefCountedThreadSafe<TaskRunner> {
+class MetroPinTabHelper::PagePinner
sky 2012/10/26 20:01:15 How come this is ref counted?
benwells 2012/10/29 06:38:41 This class is now split into two. One half is not
+ : public base::RefCountedThreadSafe<PagePinner> {
public:
- TaskRunner() {}
-
+ PagePinner() {}
+
+ // Updated when we have a new set of candidate favicon URLs for the current
+ // page.
+ void SetFaviconCandidates(const std::vector<FaviconURL>& candidates);
+
+ // This will clear any information we have about the current page's favicon,
+ // and also cancel any pin requests that are still having favicons downloaded.
+ void ClearCurrentPageInfo();
sky 2012/10/26 20:01:15 Why do we need this?
benwells 2012/10/29 06:38:41 This still exists, kind of, but is now in MetroPin
+
+ // Start downloading favicons from the candidate URLs, and then proceed on
+ // to create a secondary tile. |history_image| is the favicon we get from
+ // the history service. It is too small so we try to get a bigger one
+ // directly.
+ void StartDownloadingFavicons(content::RenderViewHost* host,
+ const string16& title,
+ const string16& url,
+ const gfx::ImageSkia& history_image);
+
+ // Callback for when a favicon has been downloaded. The best bitmap so far
+ // will be stored in best_candidate_. If this is the last URL that was being
sky 2012/10/26 20:01:15 |s around references to parameters and fields.
benwells 2012/10/29 06:38:41 Done.
+ // downloaded, the page is pinned by calling PinPageToStartScreen on the FILE
+ // thread.
+ void OnDidDownloadFavicon(int id,
+ const GURL& image_url,
+ bool errored,
+ int requested_size,
+ const std::vector<SkBitmap>& bitmaps);
+
+ // We now have found the best favicon we can, so create the tile. This is
+ // executed on the FILE thread.
void PinPageToStartScreen(const string16& title,
const string16& url,
const gfx::ImageSkia& image);
private:
- ~TaskRunner() {}
+ ~PagePinner() {}
+
+ // The best candidate we have so far for the current pin operation.
+ gfx::ImageSkia best_candidate_;
+
+ // Title and URL of the page being pinned.
+ string16 title_;
+ string16 url_;
- friend class base::RefCountedThreadSafe<TaskRunner>;
- DISALLOW_COPY_AND_ASSIGN(TaskRunner);
+ // Candidate Favicon URLs for the current page.
+ std::vector<FaviconURL> favicon_url_candidates_;
+
+ // Favicon URLs that are being downloaded. While this is not empty there
+ // is a pin request being processed, if any others are started they will
+ // be ignored.
+ std::set<GURL> in_progress_urls_;
+
+ friend class base::RefCountedThreadSafe<PagePinner>;
+ DISALLOW_COPY_AND_ASSIGN(PagePinner);
};
-void MetroPinTabHelper::TaskRunner::PinPageToStartScreen(
+void MetroPinTabHelper::PagePinner::SetFaviconCandidates(
+ const std::vector<FaviconURL>& candidates) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ favicon_url_candidates_ = candidates;
+}
+
+void MetroPinTabHelper::PagePinner::ClearCurrentPageInfo() {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ favicon_url_candidates_.clear();
+ in_progress_urls_.clear();
+}
+
+void MetroPinTabHelper::PagePinner::StartDownloadingFavicons(
+ content::RenderViewHost* host,
+ const string16& title,
+ const string16& url,
+ const gfx::ImageSkia& history_image) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ // If the PagePinner is already pinning the current page, ignore any more
+ // requests.
+ if (!in_progress_urls_.empty())
sky 2012/10/26 20:01:15 Should we create a pinner per url? Seems like it w
benwells 2012/10/29 06:38:41 I've separated out the logic into a MetroPinTabHel
+ return;
+
+ // If there are no candidate URLs, progress straight to pinning.
+ if (favicon_url_candidates_.empty()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&PagePinner::PinPageToStartScreen,
+ this,
+ title,
+ url,
+ history_image));
+ return;
+ }
+
+ best_candidate_ = history_image;
+ title_ = title;
+ url_ = url;
+
+ // Request all the candidates.
+ int image_size = 0; // Request the full sized image.
+ for (std::vector<FaviconURL>::const_iterator iter =
+ favicon_url_candidates_.begin();
+ iter != favicon_url_candidates_.end();
+ ++iter) {
+ // Ignore any duplicate URLs in the candidates.
+ if (in_progress_urls_.find(iter->icon_url) != in_progress_urls_.end())
+ continue;
+
+ in_progress_urls_.insert(iter->icon_url);
+ FaviconUtil::DownloadFavicon(host, iter->icon_url, image_size);
sky 2012/10/26 20:01:15 You need to cache the return value and compare tha
benwells 2012/10/29 06:38:41 Done. Yeah I was checking the URLs when they come
+ }
+}
+
+void MetroPinTabHelper::PagePinner::OnDidDownloadFavicon(
+ int id,
+ const GURL& image_url,
+ bool errored,
+ int requested_size,
+ const std::vector<SkBitmap>& bitmaps) {
+ const int kMaxIconSize = 32;
+
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ std::set<GURL>::iterator iter = in_progress_urls_.find(image_url);
+ // If this URL isn't in the in progress list, the page must have been
+ // navigated since the request started, cancelling this request.
+ if (iter == in_progress_urls_.end())
+ return;
+
+ in_progress_urls_.erase(iter);
+
+ // Process the bitmaps, keeping the one that is best so far.
+ if (!errored) {
+ for (std::vector<SkBitmap>::const_iterator iter = bitmaps.begin();
+ iter != bitmaps.end();
+ ++iter) {
+
+ // If we don't have a best candidate yet, this is better so just grab it.
+ if (best_candidate_.isNull()) {
+ best_candidate_ = gfx::ImageSkia(*iter).DeepCopy();
+ continue;
+ }
+ // If the new bitmap is bigger than the best candidate, and not greater
+ // than the max size, grab it.
+ if (iter->height() > kMaxIconSize || iter->width() > kMaxIconSize)
+ continue;
+
+ if (iter->height() <= best_candidate_.height() ||
+ iter->width() <= best_candidate_.width()) {
+ continue;
+ }
+
+ best_candidate_ = gfx::ImageSkia(*iter).DeepCopy();
+ }
+ }
+
+ // If there are no more URLs to download, pin the page on the FILE thread.
+ if (in_progress_urls_.empty()) {
+ content::BrowserThread::PostTask(
+ content::BrowserThread::FILE,
+ FROM_HERE,
+ base::Bind(&PagePinner::PinPageToStartScreen,
+ this,
+ title_,
+ url_,
+ best_candidate_));
+ return;
+ }
+}
+
+void MetroPinTabHelper::PagePinner::PinPageToStartScreen(
const string16& title,
const string16& url,
const gfx::ImageSkia& image) {
@@ -198,7 +368,7 @@ void MetroPinTabHelper::TaskRunner::PinPageToStartScreen(
MetroPinTabHelper::MetroPinTabHelper(content::WebContents* web_contents)
: content::WebContentsObserver(web_contents),
is_pinned_(false),
- task_runner_(new TaskRunner) {}
+ page_pinner_(new PagePinner) {}
MetroPinTabHelper::~MetroPinTabHelper() {}
@@ -216,42 +386,58 @@ void MetroPinTabHelper::TogglePinnedToStartScreen() {
return;
}
- // TODO(benwells): Handle downloading a larger favicon if there is one.
GURL url = web_contents()->GetURL();
string16 url_str = UTF8ToUTF16(url.spec());
string16 title = web_contents()->GetTitle();
- TabContents* tab_contents = TabContents::FromWebContents(web_contents());
- DCHECK(tab_contents);
FaviconTabHelper* favicon_tab_helper = FaviconTabHelper::FromWebContents(
- tab_contents->web_contents());
+ web_contents());
if (favicon_tab_helper->FaviconIsValid()) {
gfx::Image favicon = favicon_tab_helper->GetFavicon();
gfx::ImageSkia favicon_skia = favicon.AsImageSkia().DeepCopy();
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&TaskRunner::PinPageToStartScreen,
- task_runner_,
- title,
- url_str,
- favicon_skia));
+ page_pinner_->StartDownloadingFavicons(web_contents()->GetRenderViewHost(),
+ title,
+ url_str,
+ favicon_skia);
return;
}
- content::BrowserThread::PostTask(
- content::BrowserThread::FILE,
- FROM_HERE,
- base::Bind(&TaskRunner::PinPageToStartScreen,
- task_runner_,
- title,
- url_str,
- gfx::ImageSkia()));
+ page_pinner_->StartDownloadingFavicons(web_contents()->GetRenderViewHost(),
+ title,
+ url_str,
+ gfx::ImageSkia());
}
void MetroPinTabHelper::DidNavigateMainFrame(
const content::LoadCommittedDetails& /*details*/,
const content::FrameNavigateParams& /*params*/) {
UpdatePinnedStateForCurrentURL();
+ page_pinner_->ClearCurrentPageInfo();
+}
+
+bool MetroPinTabHelper::OnMessageReceived(const IPC::Message& message) {
+ bool message_handled = false; // Allow other handlers to receive these.
+ IPC_BEGIN_MESSAGE_MAP(MetroPinTabHelper, message)
+ IPC_MESSAGE_HANDLER(IconHostMsg_UpdateFaviconURL, OnUpdateFaviconURL)
+ IPC_MESSAGE_HANDLER(IconHostMsg_DidDownloadFavicon, OnDidDownloadFavicon)
+ IPC_MESSAGE_UNHANDLED(message_handled = false)
+ IPC_END_MESSAGE_MAP()
+ return message_handled;
+}
+
+void MetroPinTabHelper::OnUpdateFaviconURL(
+ int32 page_id,
+ const std::vector<FaviconURL>& candidates) {
+ page_pinner_->SetFaviconCandidates(candidates);
+}
+
+void MetroPinTabHelper::OnDidDownloadFavicon(
+ int id,
+ const GURL& image_url,
+ bool errored,
+ int requested_size,
+ const std::vector<SkBitmap>& bitmaps) {
+ page_pinner_->OnDidDownloadFavicon(id, image_url, errored, requested_size,
+ bitmaps);
}
void MetroPinTabHelper::UpdatePinnedStateForCurrentURL() {
« no previous file with comments | « chrome/browser/ui/metro_pin_tab_helper_win.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698