summaryrefslogtreecommitdiffstats
path: root/chrome/browser/cocoa/history_menu_bridge.mm
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 22:30:51 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-03-01 22:30:51 +0000
commit2b6eb7a41393fad6757ad261130f6eb109903a60 (patch)
tree08fdf00136ec0495e55dbcba1836cd69ce26614e /chrome/browser/cocoa/history_menu_bridge.mm
parent4f73d569a58162958e75eecb6eae1059280e8ce7 (diff)
downloadchromium_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.mm131
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;
+ }
+}