Index: components/bookmarks/browser/bookmark_model.cc |
diff --git a/components/bookmarks/browser/bookmark_model.cc b/components/bookmarks/browser/bookmark_model.cc |
index d781fdbe8242beed9270e347d1384cdcdddec876..8439e35ef8bf274664f6fdb675af620a0917feed 100644 |
--- a/components/bookmarks/browser/bookmark_model.cc |
+++ b/components/bookmarks/browser/bookmark_model.cc |
@@ -42,6 +42,20 @@ BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) { |
return const_cast<BookmarkPermanentNode*>(node); |
} |
+// Removes |node| from |set|. This method is useful when the multiset has a |
+// custom comparator. |
+template<class T> void RemoveFromMultiset( |
+ std::multiset<BookmarkNode*, T>* set, |
+ BookmarkNode* node) { |
+ std::multiset<BookmarkNode*>::iterator it = set->find(node); |
+ if (it == set->end()) |
+ return; |
+ |
+ while (*it != node) |
+ ++it; |
+ set->erase(it); |
+} |
+ |
// Comparator used when sorting permanent nodes. Nodes that are initially |
// visible are sorted before nodes that are initially hidden. |
class VisibilityComparator |
@@ -346,8 +360,7 @@ void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) { |
return; |
BookmarkNode* mutable_node = AsMutable(node); |
- mutable_node->InvalidateFavicon(); |
- CancelPendingFaviconLoadRequests(mutable_node); |
+ InvalidateFavicon(mutable_node); |
FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
OnWillChangeBookmarkNode(this, node)); |
@@ -435,24 +448,34 @@ void BookmarkModel::SetNodeSyncTransactionVersion( |
store_->ScheduleSave(); |
} |
-void BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) { |
+void BookmarkModel::OnFaviconsChanged(const std::vector<GURL>& page_urls, |
+ const std::vector<GURL>& icon_urls) { |
// Ignore events if |Load| has not been called yet. |
if (!store_) |
return; |
- // Prevent the observers from getting confused for multiple favicon loads. |
- for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) { |
+ std::set<const BookmarkNode*> to_update; |
+ for (const GURL& page_url : page_urls) { |
std::vector<const BookmarkNode*> nodes; |
- GetNodesByURL(*i, &nodes); |
- for (size_t i = 0; i < nodes.size(); ++i) { |
- // Got an updated favicon, for a URL, do a new request. |
- BookmarkNode* node = AsMutable(nodes[i]); |
- node->InvalidateFavicon(); |
- CancelPendingFaviconLoadRequests(node); |
- FOR_EACH_OBSERVER(BookmarkModelObserver, |
- observers_, |
- BookmarkNodeFaviconChanged(this, node)); |
- } |
+ GetNodesByURL(page_url, &nodes); |
+ for (const BookmarkNode* node : nodes) |
+ to_update.insert(node); |
+ } |
+ |
+ for (const GURL& icon_url : icon_urls) { |
+ std::vector<const BookmarkNode*> nodes; |
+ GetNodesByIconURL(icon_url, &nodes); |
+ for (const BookmarkNode* node : nodes) |
+ to_update.insert(node); |
+ } |
+ |
+ for (const BookmarkNode* node : to_update) { |
+ // Rerequest the favicon. |
+ BookmarkNode* mutable_node = AsMutable(node); |
+ InvalidateFavicon(mutable_node); |
+ FOR_EACH_OBSERVER(BookmarkModelObserver, |
+ observers_, |
+ BookmarkNodeFaviconChanged(this, node)); |
} |
} |
@@ -484,6 +507,19 @@ void BookmarkModel::GetNodesByURL(const GURL& url, |
} |
} |
+void BookmarkModel::GetNodesByIconURL(const GURL& icon_url, |
+ std::vector<const BookmarkNode*>* nodes) { |
+ BookmarkNode tmp_node = BookmarkNode(GURL()); |
+ tmp_node.set_icon_url(icon_url); |
+ NodesOrderedByURLSet::iterator i = |
+ nodes_ordered_by_favicon_url_set_.find(&tmp_node); |
+ while (i != nodes_ordered_by_favicon_url_set_.end() && |
+ (*i)->icon_url() == icon_url) { |
+ nodes->push_back(*i); |
+ ++i; |
+ } |
+} |
+ |
const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL( |
const GURL& url) { |
std::vector<const BookmarkNode*> nodes; |
@@ -850,16 +886,12 @@ void BookmarkModel::RemoveAndDeleteNode(BookmarkNode* delete_me) { |
void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { |
index_->Remove(node); |
+ if (!node->icon_url().is_empty()) |
+ RemoveFromMultiset(&nodes_ordered_by_favicon_url_set_, node); |
// NOTE: this is called in such a way that url_lock_ is already held. As |
// such, this doesn't explicitly grab the lock. |
url_lock_.AssertAcquired(); |
- NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); |
- DCHECK(i != nodes_ordered_by_url_set_.end()); |
- // i points to the first node with the URL, advance until we find the |
- // node we're removing. |
- while (*i != node) |
- ++i; |
- nodes_ordered_by_url_set_.erase(i); |
+ RemoveFromMultiset(&nodes_ordered_by_url_set_, node); |
} |
void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node, |
@@ -911,6 +943,8 @@ BookmarkNode* BookmarkModel::AddNode(BookmarkNode* parent, |
void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { |
index_->Add(node); |
+ if (!node->icon_url().is_empty()) |
+ nodes_ordered_by_favicon_url_set_.insert(node); |
url_lock_.AssertAcquired(); |
nodes_ordered_by_url_set_.insert(node); |
} |
@@ -961,9 +995,10 @@ void BookmarkModel::OnFaviconDataAvailable( |
node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); |
node->set_favicon_state(BookmarkNode::LOADED_FAVICON); |
if (!image_result.image.IsEmpty()) { |
+ SetFaviconURL(node, image_result.icon_url); |
node->set_favicon_type(icon_type); |
node->set_favicon(image_result.image); |
- node->set_icon_url(image_result.icon_url); |
+ |
FaviconLoaded(node); |
} else if (icon_type == favicon_base::TOUCH_ICON) { |
// Couldn't load the touch icon, fallback to the regular favicon. |
@@ -998,6 +1033,22 @@ void BookmarkModel::FaviconLoaded(const BookmarkNode* node) { |
BookmarkNodeFaviconChanged(this, node)); |
} |
+void BookmarkModel::SetFaviconURL(BookmarkNode* node, const GURL& icon_url) { |
+ if (!node->icon_url().is_empty()) |
+ RemoveFromMultiset(&nodes_ordered_by_favicon_url_set_, node); |
+ node->set_icon_url(icon_url); |
+ if (!node->icon_url().is_empty()) |
+ nodes_ordered_by_favicon_url_set_.insert(node); |
+} |
+ |
+void BookmarkModel::InvalidateFavicon(BookmarkNode* node) { |
+ SetFaviconURL(node, GURL()); |
+ node->set_favicon(gfx::Image()); |
+ node->set_favicon_type(favicon_base::INVALID_ICON); |
+ node->set_favicon_state(BookmarkNode::INVALID_FAVICON); |
+ CancelPendingFaviconLoadRequests(node); |
+} |
+ |
void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) { |
if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) { |
cancelable_task_tracker_.TryCancel(node->favicon_load_task_id()); |