diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 22:30:51 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-03-01 22:30:51 +0000 |
commit | 2b6eb7a41393fad6757ad261130f6eb109903a60 (patch) | |
tree | 08fdf00136ec0495e55dbcba1836cd69ce26614e /chrome/browser/cocoa/history_menu_bridge.mm | |
parent | 4f73d569a58162958e75eecb6eae1059280e8ce7 (diff) | |
download | chromium_src-2b6eb7a41393fad6757ad261130f6eb109903a60.zip chromium_src-2b6eb7a41393fad6757ad261130f6eb109903a60.tar.gz chromium_src-2b6eb7a41393fad6757ad261130f6eb109903a60.tar.bz2 |
Re-land r40275 (broke TabRestoreUITest.RestoreIntoSameWindow).
[Mac] Add favicons to the history menu.
BUG=20464
TEST=Open History menu, see icons.
Original CL: http://codereview.chromium.org/660250
As a side effect of fixing the bustage, we no longer list duplicate sites in
the "Recently Closed" section.
BUG=21314
TEST=Open and navigate two three different sites. Close the first one. History menu has 1 closed site. Close second tab. Should see both sites listed under "Recently Closed" exactly once.
Review URL: http://codereview.chromium.org/660282
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@40308 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/cocoa/history_menu_bridge.mm')
-rw-r--r-- | chrome/browser/cocoa/history_menu_bridge.mm | 131 |
1 files changed, 106 insertions, 25 deletions
diff --git a/chrome/browser/cocoa/history_menu_bridge.mm b/chrome/browser/cocoa/history_menu_bridge.mm index 30b4488..b6f151c 100644 --- a/chrome/browser/cocoa/history_menu_bridge.mm +++ b/chrome/browser/cocoa/history_menu_bridge.mm @@ -3,9 +3,13 @@ // found in the LICENSE file. #include "chrome/browser/cocoa/history_menu_bridge.h" + +#include "app/gfx/codec/png_codec.h" +#include "app/resource_bundle.h" #include "base/callback.h" -#include "base/sys_string_conversions.h" +#include "base/stl_util-inl.h" #include "base/string_util.h" +#include "base/sys_string_conversions.h" #include "chrome/app/chrome_dll_resource.h" // IDC_HISTORY_MENU #import "chrome/browser/app_controller_mac.h" #import "chrome/browser/cocoa/history_menu_cocoa_controller.h" @@ -15,6 +19,8 @@ #include "chrome/common/notification_registrar.h" #include "chrome/common/notification_service.h" #include "chrome/common/url_constants.h" +#include "grit/app_resources.h" +#include "skia/ext/skia_utils_mac.h" namespace { @@ -60,6 +66,9 @@ HistoryMenuBridge::HistoryMenuBridge(Profile* profile) tab_restore_service_->AddObserver(this); } + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + default_favicon_.reset([rb.GetNSImageNamed(IDR_DEFAULT_FAVICON) retain]); + // The service is not ready for use yet, so become notified when it does. if (!history_service_) { registrar_.Add(this, @@ -68,6 +77,9 @@ HistoryMenuBridge::HistoryMenuBridge(Profile* profile) } } +// Note that all requests sent to either the history service or the favicon +// service will be automatically cancelled by their respective Consumers, so +// task cancellation is not done manually here in the dtor. HistoryMenuBridge::~HistoryMenuBridge() { // Unregister ourselves as observers and notifications. const NotificationSource& src = NotificationService::AllSources(); @@ -114,12 +126,7 @@ void HistoryMenuBridge::TabRestoreServiceChanged(TabRestoreService* service) { // Clear the history menu before modifying |closed_results_|. NSMenu* menu = HistoryMenu(); ClearMenuSection(menu, IDC_HISTORY_MENU_CLOSED, closed_results_.size()); - - // If the number of entries in the tab restore service is less than - // what's cached, throw it away and rebuild it. It probably means - // the browsing data was cleared by the user. - if (entries.size() < closed_results_.size()) - closed_results_.clear(); + closed_results_.reset(); unsigned int added_count = 0; for (TabRestoreService::Entries::const_iterator it = entries.begin(); @@ -148,15 +155,15 @@ void HistoryMenuBridge::TabRestoreServiceChanged(TabRestoreService* service) { // Remove extraneous/old results. if (closed_results_.size() > kRecentlyClosedCount) - closed_results_.erase(closed_results_.begin(), - closed_results_.end() - kRecentlyClosedCount); + STLDeleteContainerPointers(closed_results_.begin(), + closed_results_.end() - kRecentlyClosedCount); NSInteger top_index = [menu indexOfItemWithTag:IDC_HISTORY_MENU_CLOSED] + 1; int i = 0; // Count offsets for |tag| and |index| in AddItemToMenu(). - for (std::vector<HistoryItem>::const_iterator it = closed_results_.begin(); + for (ScopedVector<HistoryItem>::const_iterator it = closed_results_.begin(); it != closed_results_.end(); ++it) { - HistoryItem item = *it; + HistoryItem* item = *it; NSInteger tag = IDC_HISTORY_MENU_CLOSED + 1 + i; AddItemToMenu(item, HistoryMenu(), tag, top_index + i); ++i; @@ -176,12 +183,12 @@ Profile* HistoryMenuBridge::profile() { return profile_; } -std::vector<HistoryMenuBridge::HistoryItem>* +const ScopedVector<HistoryMenuBridge::HistoryItem>* const HistoryMenuBridge::visited_results() { return &visited_results_; } -std::vector<HistoryMenuBridge::HistoryItem>* +const ScopedVector<HistoryMenuBridge::HistoryItem>* const HistoryMenuBridge::closed_results() { return &closed_results_; } @@ -210,6 +217,14 @@ void HistoryMenuBridge::ClearMenuSection(NSMenu* menu, NSMenuItem* menu_item = [menu itemAtIndex:index]; item_tag = [menu_item tag]; if ([menu_item action] == @selector(openHistoryMenuItem:)) { + // If there is a pending favicon request for this menu item, find and + // cancel it. + HistoryItem* item = + const_cast<HistoryItem*>([controller_ itemForTag:item_tag]); + if (item) + CancelFaviconRequest(item); + + // Now remove it from the menu. [menu removeItemAtIndex:index]; --count; } @@ -219,12 +234,12 @@ void HistoryMenuBridge::ClearMenuSection(NSMenu* menu, } } -void HistoryMenuBridge::AddItemToMenu(const HistoryItem& item, +void HistoryMenuBridge::AddItemToMenu(HistoryItem* item, NSMenu* menu, NSInteger tag, NSInteger index) { - NSString* title = base::SysUTF16ToNSString(item.title); - std::string url_string = item.url.possibly_invalid_spec(); + NSString* title = base::SysUTF16ToNSString(item->title); + std::string url_string = item->url.possibly_invalid_spec(); // If we don't have a title, use the URL. if ([title isEqualToString:@""]) @@ -245,6 +260,10 @@ void HistoryMenuBridge::AddItemToMenu(const HistoryItem& item, [menu_item setTarget:controller_]; [menu_item setAction:@selector(openHistoryMenuItem:)]; [menu_item setTag:tag]; + if (item->icon.get()) + [menu_item setImage:item->icon.get()]; + else + [menu_item setImage:default_favicon_.get()]; // Add a tooltip. NSString* tooltip = [NSString stringWithFormat:@"%@\n%s", full_title, @@ -252,6 +271,7 @@ void HistoryMenuBridge::AddItemToMenu(const HistoryItem& item, [menu_item setToolTip:tooltip]; [menu insertItem:menu_item atIndex:index]; + item->menu_item = menu_item; } void HistoryMenuBridge::Init() { @@ -282,16 +302,22 @@ void HistoryMenuBridge::OnVisitedHistoryResults( NSInteger top_item = [menu indexOfItemWithTag:IDC_HISTORY_MENU_VISITED] + 1; ClearMenuSection(menu, IDC_HISTORY_MENU_VISITED, visited_results_.size()); - visited_results_.clear(); + visited_results_.reset(); size_t count = results->size(); for (size_t i = 0; i < count; ++i) { PageUsageData* history_item = (*results)[i]; - HistoryItem item; - item.title = history_item->GetTitle(); - item.url = history_item->GetURL(); - visited_results_.push_back(item); + HistoryItem* item = new HistoryItem(); + item->title = history_item->GetTitle(); + item->url = history_item->GetURL(); + if (history_item->HasFavIcon()) { + const SkBitmap* icon = history_item->GetFavIcon(); + item->icon.reset([gfx::SkBitmapToNSImage(*icon) retain]); + } else { + GetFaviconForHistoryItem(item); + } + visited_results_.push_back(item); // ScopedVector takes ownership. // Use the large gaps in tags assignment to create the tag for history menu // items. @@ -316,9 +342,64 @@ bool HistoryMenuBridge::AddNavigationForTab( if (current_navigation.url() == GURL(chrome::kChromeUINewTabURL)) return false; - HistoryItem item; - item.title = current_navigation.title(); - item.url = current_navigation.url(); - closed_results_.push_back(item); + HistoryItem* item = new HistoryItem(); + item->title = current_navigation.title(); + item->url = current_navigation.url(); + closed_results_.push_back(item); // ScopedVector takes ownership. + + // Tab navigations don't come with icons, so we always have to request them. + GetFaviconForHistoryItem(item); + return true; } + +void HistoryMenuBridge::GetFaviconForHistoryItem(HistoryItem* item) { + FaviconService* service = + profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); + FaviconService::Handle handle = service->GetFaviconForURL(item->url, + &favicon_consumer_, + NewCallback(this, &HistoryMenuBridge::GotFaviconData)); + favicon_consumer_.SetClientData(service, handle, item); + item->icon_handle = handle; + item->icon_requested = true; +} + +void HistoryMenuBridge::GotFaviconData(FaviconService::Handle handle, + bool know_favicon, + scoped_refptr<RefCountedBytes> data, + bool expired, + GURL url) { + // Since we're going to do Cocoa-y things, make sure this is the main thread. + DCHECK([NSThread isMainThread]); + + HistoryItem* item = + favicon_consumer_.GetClientData( + profile_->GetFaviconService(Profile::EXPLICIT_ACCESS), handle); + DCHECK(item); + item->icon_requested = false; + item->icon_handle = NULL; + + // Convert the raw data to Skia and then to a NSImage. + // TODO(rsesek): Is there an easier way to do this? + SkBitmap icon; + if (know_favicon && data.get() && data->size() && + gfx::PNGCodec::Decode(data->front(), data->size(), &icon)) { + NSImage* image = gfx::SkBitmapToNSImage(icon); + if (image) { + // The conversion was successful. + item->icon.reset([image retain]); + [item->menu_item setImage:item->icon.get()]; + } + } +} + +void HistoryMenuBridge::CancelFaviconRequest(HistoryItem* item) { + DCHECK(item); + if (item->icon_requested) { + FaviconService* service = + profile_->GetFaviconService(Profile::EXPLICIT_ACCESS); + service->CancelRequest(item->icon_handle); + item->icon_requested = false; + item->icon_handle = NULL; + } +} |