OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "components/bookmarks/browser/bookmark_model.h" | 5 #include "components/bookmarks/browser/bookmark_model.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <functional> | 8 #include <functional> |
9 | 9 |
10 #include "base/bind.h" | 10 #include "base/bind.h" |
(...skipping 24 matching lines...) Expand all Loading... |
35 // Helper to get a mutable bookmark node. | 35 // Helper to get a mutable bookmark node. |
36 BookmarkNode* AsMutable(const BookmarkNode* node) { | 36 BookmarkNode* AsMutable(const BookmarkNode* node) { |
37 return const_cast<BookmarkNode*>(node); | 37 return const_cast<BookmarkNode*>(node); |
38 } | 38 } |
39 | 39 |
40 // Helper to get a mutable permanent bookmark node. | 40 // Helper to get a mutable permanent bookmark node. |
41 BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) { | 41 BookmarkPermanentNode* AsMutable(const BookmarkPermanentNode* node) { |
42 return const_cast<BookmarkPermanentNode*>(node); | 42 return const_cast<BookmarkPermanentNode*>(node); |
43 } | 43 } |
44 | 44 |
| 45 // Removes |node| from |set|. This method is useful when the multiset has a |
| 46 // custom comparator. |
| 47 template<class T> void RemoveFromMultiset( |
| 48 std::multiset<BookmarkNode*, T>* set, |
| 49 BookmarkNode* node) { |
| 50 std::multiset<BookmarkNode*>::iterator it = set->find(node); |
| 51 if (it == set->end()) |
| 52 return; |
| 53 |
| 54 while (*it != node) |
| 55 ++it; |
| 56 set->erase(it); |
| 57 } |
| 58 |
45 // Comparator used when sorting permanent nodes. Nodes that are initially | 59 // Comparator used when sorting permanent nodes. Nodes that are initially |
46 // visible are sorted before nodes that are initially hidden. | 60 // visible are sorted before nodes that are initially hidden. |
47 class VisibilityComparator | 61 class VisibilityComparator |
48 : public std::binary_function<const BookmarkPermanentNode*, | 62 : public std::binary_function<const BookmarkPermanentNode*, |
49 const BookmarkPermanentNode*, | 63 const BookmarkPermanentNode*, |
50 bool> { | 64 bool> { |
51 public: | 65 public: |
52 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {} | 66 explicit VisibilityComparator(BookmarkClient* client) : client_(client) {} |
53 | 67 |
54 // Returns true if |n1| preceeds |n2|. | 68 // Returns true if |n1| preceeds |n2|. |
(...skipping 284 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
339 BookmarkNodeChanged(this, node)); | 353 BookmarkNodeChanged(this, node)); |
340 } | 354 } |
341 | 355 |
342 void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) { | 356 void BookmarkModel::SetURL(const BookmarkNode* node, const GURL& url) { |
343 DCHECK(node && !node->is_folder()); | 357 DCHECK(node && !node->is_folder()); |
344 | 358 |
345 if (node->url() == url) | 359 if (node->url() == url) |
346 return; | 360 return; |
347 | 361 |
348 BookmarkNode* mutable_node = AsMutable(node); | 362 BookmarkNode* mutable_node = AsMutable(node); |
349 mutable_node->InvalidateFavicon(); | 363 InvalidateFavicon(mutable_node); |
350 CancelPendingFaviconLoadRequests(mutable_node); | |
351 | 364 |
352 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 365 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
353 OnWillChangeBookmarkNode(this, node)); | 366 OnWillChangeBookmarkNode(this, node)); |
354 | 367 |
355 { | 368 { |
356 base::AutoLock url_lock(url_lock_); | 369 base::AutoLock url_lock(url_lock_); |
357 RemoveNodeFromInternalMaps(mutable_node); | 370 RemoveNodeFromInternalMaps(mutable_node); |
358 mutable_node->set_url(url); | 371 mutable_node->set_url(url); |
359 AddNodeToInternalMaps(mutable_node); | 372 AddNodeToInternalMaps(mutable_node); |
360 } | 373 } |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
428 DCHECK(client_->CanSyncNode(node)); | 441 DCHECK(client_->CanSyncNode(node)); |
429 | 442 |
430 if (sync_transaction_version == node->sync_transaction_version()) | 443 if (sync_transaction_version == node->sync_transaction_version()) |
431 return; | 444 return; |
432 | 445 |
433 AsMutable(node)->set_sync_transaction_version(sync_transaction_version); | 446 AsMutable(node)->set_sync_transaction_version(sync_transaction_version); |
434 if (store_.get()) | 447 if (store_.get()) |
435 store_->ScheduleSave(); | 448 store_->ScheduleSave(); |
436 } | 449 } |
437 | 450 |
438 void BookmarkModel::OnFaviconChanged(const std::set<GURL>& urls) { | 451 void BookmarkModel::OnFaviconsChanged(const std::vector<GURL>& page_urls, |
| 452 const std::vector<GURL>& icon_urls) { |
439 // Ignore events if |Load| has not been called yet. | 453 // Ignore events if |Load| has not been called yet. |
440 if (!store_) | 454 if (!store_) |
441 return; | 455 return; |
442 | 456 |
443 // Prevent the observers from getting confused for multiple favicon loads. | 457 std::set<const BookmarkNode*> to_update; |
444 for (std::set<GURL>::const_iterator i = urls.begin(); i != urls.end(); ++i) { | 458 for (const GURL& page_url : page_urls) { |
445 std::vector<const BookmarkNode*> nodes; | 459 std::vector<const BookmarkNode*> nodes; |
446 GetNodesByURL(*i, &nodes); | 460 GetNodesByURL(page_url, &nodes); |
447 for (size_t i = 0; i < nodes.size(); ++i) { | 461 for (const BookmarkNode* node : nodes) |
448 // Got an updated favicon, for a URL, do a new request. | 462 to_update.insert(node); |
449 BookmarkNode* node = AsMutable(nodes[i]); | 463 } |
450 node->InvalidateFavicon(); | 464 |
451 CancelPendingFaviconLoadRequests(node); | 465 for (const GURL& icon_url : icon_urls) { |
452 FOR_EACH_OBSERVER(BookmarkModelObserver, | 466 std::vector<const BookmarkNode*> nodes; |
453 observers_, | 467 GetNodesByIconURL(icon_url, &nodes); |
454 BookmarkNodeFaviconChanged(this, node)); | 468 for (const BookmarkNode* node : nodes) |
455 } | 469 to_update.insert(node); |
| 470 } |
| 471 |
| 472 for (const BookmarkNode* node : to_update) { |
| 473 // Rerequest the favicon. |
| 474 BookmarkNode* mutable_node = AsMutable(node); |
| 475 InvalidateFavicon(mutable_node); |
| 476 FOR_EACH_OBSERVER(BookmarkModelObserver, |
| 477 observers_, |
| 478 BookmarkNodeFaviconChanged(this, node)); |
456 } | 479 } |
457 } | 480 } |
458 | 481 |
459 void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) { | 482 void BookmarkModel::SetDateAdded(const BookmarkNode* node, Time date_added) { |
460 DCHECK(node && !is_permanent_node(node)); | 483 DCHECK(node && !is_permanent_node(node)); |
461 | 484 |
462 if (node->date_added() == date_added) | 485 if (node->date_added() == date_added) |
463 return; | 486 return; |
464 | 487 |
465 AsMutable(node)->set_date_added(date_added); | 488 AsMutable(node)->set_date_added(date_added); |
(...skipping 11 matching lines...) Expand all Loading... |
477 std::vector<const BookmarkNode*>* nodes) { | 500 std::vector<const BookmarkNode*>* nodes) { |
478 base::AutoLock url_lock(url_lock_); | 501 base::AutoLock url_lock(url_lock_); |
479 BookmarkNode tmp_node(url); | 502 BookmarkNode tmp_node(url); |
480 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node); | 503 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(&tmp_node); |
481 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) { | 504 while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) { |
482 nodes->push_back(*i); | 505 nodes->push_back(*i); |
483 ++i; | 506 ++i; |
484 } | 507 } |
485 } | 508 } |
486 | 509 |
| 510 void BookmarkModel::GetNodesByIconURL(const GURL& icon_url, |
| 511 std::vector<const BookmarkNode*>* nodes) { |
| 512 BookmarkNode tmp_node = BookmarkNode(GURL()); |
| 513 tmp_node.set_icon_url(icon_url); |
| 514 NodesOrderedByURLSet::iterator i = |
| 515 nodes_ordered_by_favicon_url_set_.find(&tmp_node); |
| 516 while (i != nodes_ordered_by_favicon_url_set_.end() && |
| 517 (*i)->icon_url() == icon_url) { |
| 518 nodes->push_back(*i); |
| 519 ++i; |
| 520 } |
| 521 } |
| 522 |
487 const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL( | 523 const BookmarkNode* BookmarkModel::GetMostRecentlyAddedUserNodeForURL( |
488 const GURL& url) { | 524 const GURL& url) { |
489 std::vector<const BookmarkNode*> nodes; | 525 std::vector<const BookmarkNode*> nodes; |
490 GetNodesByURL(url, &nodes); | 526 GetNodesByURL(url, &nodes); |
491 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded); | 527 std::sort(nodes.begin(), nodes.end(), &MoreRecentlyAdded); |
492 | 528 |
493 // Look for the first node that the user can edit. | 529 // Look for the first node that the user can edit. |
494 for (size_t i = 0; i < nodes.size(); ++i) { | 530 for (size_t i = 0; i < nodes.size(); ++i) { |
495 if (client_->CanBeEditedByUser(nodes[i])) | 531 if (client_->CanBeEditedByUser(nodes[i])) |
496 return nodes[i]; | 532 return nodes[i]; |
(...skipping 346 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
843 store_->ScheduleSave(); | 879 store_->ScheduleSave(); |
844 | 880 |
845 FOR_EACH_OBSERVER( | 881 FOR_EACH_OBSERVER( |
846 BookmarkModelObserver, | 882 BookmarkModelObserver, |
847 observers_, | 883 observers_, |
848 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); | 884 BookmarkNodeRemoved(this, parent, index, node.get(), removed_urls)); |
849 } | 885 } |
850 | 886 |
851 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { | 887 void BookmarkModel::RemoveNodeFromInternalMaps(BookmarkNode* node) { |
852 index_->Remove(node); | 888 index_->Remove(node); |
| 889 if (!node->icon_url().is_empty()) |
| 890 RemoveFromMultiset(&nodes_ordered_by_favicon_url_set_, node); |
853 // NOTE: this is called in such a way that url_lock_ is already held. As | 891 // NOTE: this is called in such a way that url_lock_ is already held. As |
854 // such, this doesn't explicitly grab the lock. | 892 // such, this doesn't explicitly grab the lock. |
855 url_lock_.AssertAcquired(); | 893 url_lock_.AssertAcquired(); |
856 NodesOrderedByURLSet::iterator i = nodes_ordered_by_url_set_.find(node); | 894 RemoveFromMultiset(&nodes_ordered_by_url_set_, node); |
857 DCHECK(i != nodes_ordered_by_url_set_.end()); | |
858 // i points to the first node with the URL, advance until we find the | |
859 // node we're removing. | |
860 while (*i != node) | |
861 ++i; | |
862 nodes_ordered_by_url_set_.erase(i); | |
863 } | 895 } |
864 | 896 |
865 void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node, | 897 void BookmarkModel::RemoveNodeAndGetRemovedUrls(BookmarkNode* node, |
866 std::set<GURL>* removed_urls) { | 898 std::set<GURL>* removed_urls) { |
867 // NOTE: this method should be always called with |url_lock_| held. | 899 // NOTE: this method should be always called with |url_lock_| held. |
868 // This method does not explicitly acquires a lock. | 900 // This method does not explicitly acquires a lock. |
869 url_lock_.AssertAcquired(); | 901 url_lock_.AssertAcquired(); |
870 DCHECK(removed_urls); | 902 DCHECK(removed_urls); |
871 BookmarkNode* parent = node->parent(); | 903 BookmarkNode* parent = node->parent(); |
872 DCHECK(parent); | 904 DCHECK(parent); |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
904 } | 936 } |
905 | 937 |
906 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 938 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
907 BookmarkNodeAdded(this, parent, index)); | 939 BookmarkNodeAdded(this, parent, index)); |
908 | 940 |
909 return node; | 941 return node; |
910 } | 942 } |
911 | 943 |
912 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { | 944 void BookmarkModel::AddNodeToInternalMaps(BookmarkNode* node) { |
913 index_->Add(node); | 945 index_->Add(node); |
| 946 if (!node->icon_url().is_empty()) |
| 947 nodes_ordered_by_favicon_url_set_.insert(node); |
914 url_lock_.AssertAcquired(); | 948 url_lock_.AssertAcquired(); |
915 nodes_ordered_by_url_set_.insert(node); | 949 nodes_ordered_by_url_set_.insert(node); |
916 } | 950 } |
917 | 951 |
918 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, | 952 bool BookmarkModel::IsValidIndex(const BookmarkNode* parent, |
919 int index, | 953 int index, |
920 bool allow_end) { | 954 bool allow_end) { |
921 return (parent && parent->is_folder() && | 955 return (parent && parent->is_folder() && |
922 (index >= 0 && (index < parent->child_count() || | 956 (index >= 0 && (index < parent->child_count() || |
923 (allow_end && index == parent->child_count())))); | 957 (allow_end && index == parent->child_count())))); |
(...skipping 30 matching lines...) Expand all Loading... |
954 } | 988 } |
955 | 989 |
956 void BookmarkModel::OnFaviconDataAvailable( | 990 void BookmarkModel::OnFaviconDataAvailable( |
957 BookmarkNode* node, | 991 BookmarkNode* node, |
958 favicon_base::IconType icon_type, | 992 favicon_base::IconType icon_type, |
959 const favicon_base::FaviconImageResult& image_result) { | 993 const favicon_base::FaviconImageResult& image_result) { |
960 DCHECK(node); | 994 DCHECK(node); |
961 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); | 995 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); |
962 node->set_favicon_state(BookmarkNode::LOADED_FAVICON); | 996 node->set_favicon_state(BookmarkNode::LOADED_FAVICON); |
963 if (!image_result.image.IsEmpty()) { | 997 if (!image_result.image.IsEmpty()) { |
| 998 SetFaviconURL(node, image_result.icon_url); |
964 node->set_favicon_type(icon_type); | 999 node->set_favicon_type(icon_type); |
965 node->set_favicon(image_result.image); | 1000 node->set_favicon(image_result.image); |
966 node->set_icon_url(image_result.icon_url); | 1001 |
967 FaviconLoaded(node); | 1002 FaviconLoaded(node); |
968 } else if (icon_type == favicon_base::TOUCH_ICON) { | 1003 } else if (icon_type == favicon_base::TOUCH_ICON) { |
969 // Couldn't load the touch icon, fallback to the regular favicon. | 1004 // Couldn't load the touch icon, fallback to the regular favicon. |
970 DCHECK(client_->PreferTouchIcon()); | 1005 DCHECK(client_->PreferTouchIcon()); |
971 LoadFavicon(node, favicon_base::FAVICON); | 1006 LoadFavicon(node, favicon_base::FAVICON); |
972 } | 1007 } |
973 } | 1008 } |
974 | 1009 |
975 void BookmarkModel::LoadFavicon(BookmarkNode* node, | 1010 void BookmarkModel::LoadFavicon(BookmarkNode* node, |
976 favicon_base::IconType icon_type) { | 1011 favicon_base::IconType icon_type) { |
(...skipping 14 matching lines...) Expand all Loading... |
991 &cancelable_task_tracker_); | 1026 &cancelable_task_tracker_); |
992 if (taskId != base::CancelableTaskTracker::kBadTaskId) | 1027 if (taskId != base::CancelableTaskTracker::kBadTaskId) |
993 node->set_favicon_load_task_id(taskId); | 1028 node->set_favicon_load_task_id(taskId); |
994 } | 1029 } |
995 | 1030 |
996 void BookmarkModel::FaviconLoaded(const BookmarkNode* node) { | 1031 void BookmarkModel::FaviconLoaded(const BookmarkNode* node) { |
997 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, | 1032 FOR_EACH_OBSERVER(BookmarkModelObserver, observers_, |
998 BookmarkNodeFaviconChanged(this, node)); | 1033 BookmarkNodeFaviconChanged(this, node)); |
999 } | 1034 } |
1000 | 1035 |
| 1036 void BookmarkModel::SetFaviconURL(BookmarkNode* node, const GURL& icon_url) { |
| 1037 if (!node->icon_url().is_empty()) |
| 1038 RemoveFromMultiset(&nodes_ordered_by_favicon_url_set_, node); |
| 1039 node->set_icon_url(icon_url); |
| 1040 if (!node->icon_url().is_empty()) |
| 1041 nodes_ordered_by_favicon_url_set_.insert(node); |
| 1042 } |
| 1043 |
| 1044 void BookmarkModel::InvalidateFavicon(BookmarkNode* node) { |
| 1045 SetFaviconURL(node, GURL()); |
| 1046 node->set_favicon(gfx::Image()); |
| 1047 node->set_favicon_type(favicon_base::INVALID_ICON); |
| 1048 node->set_favicon_state(BookmarkNode::INVALID_FAVICON); |
| 1049 CancelPendingFaviconLoadRequests(node); |
| 1050 } |
| 1051 |
1001 void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) { | 1052 void BookmarkModel::CancelPendingFaviconLoadRequests(BookmarkNode* node) { |
1002 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) { | 1053 if (node->favicon_load_task_id() != base::CancelableTaskTracker::kBadTaskId) { |
1003 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id()); | 1054 cancelable_task_tracker_.TryCancel(node->favicon_load_task_id()); |
1004 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); | 1055 node->set_favicon_load_task_id(base::CancelableTaskTracker::kBadTaskId); |
1005 } | 1056 } |
1006 } | 1057 } |
1007 | 1058 |
1008 void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) { | 1059 void BookmarkModel::PopulateNodesByURL(BookmarkNode* node) { |
1009 // NOTE: this is called with url_lock_ already held. As such, this doesn't | 1060 // NOTE: this is called with url_lock_ already held. As such, this doesn't |
1010 // explicitly grab the lock. | 1061 // explicitly grab the lock. |
(...skipping 18 matching lines...) Expand all Loading... |
1029 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( | 1080 return scoped_ptr<BookmarkLoadDetails>(new BookmarkLoadDetails( |
1030 bb_node, | 1081 bb_node, |
1031 other_node, | 1082 other_node, |
1032 mobile_node, | 1083 mobile_node, |
1033 client_->GetLoadExtraNodesCallback(), | 1084 client_->GetLoadExtraNodesCallback(), |
1034 new BookmarkIndex(client_, accept_languages), | 1085 new BookmarkIndex(client_, accept_languages), |
1035 next_node_id_)); | 1086 next_node_id_)); |
1036 } | 1087 } |
1037 | 1088 |
1038 } // namespace bookmarks | 1089 } // namespace bookmarks |
OLD | NEW |