blob: 7a69378eded1edb7e6621112e8ab72dd3ad189fa [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/bookmarks/browser/url_index.h"
#include "base/containers/adapters.h"
#include "components/bookmarks/browser/url_and_title.h"
namespace bookmarks {
UrlIndex::UrlIndex(std::unique_ptr<BookmarkNode> root)
: root_(std::move(root)) {
base::AutoLock url_lock(url_lock_);
AddImpl(root_.get());
}
void UrlIndex::Add(BookmarkNode* parent,
size_t index,
std::unique_ptr<BookmarkNode> node) {
base::AutoLock url_lock(url_lock_);
AddImpl(parent->Add(std::move(node), index));
}
std::unique_ptr<BookmarkNode> UrlIndex::Remove(BookmarkNode* node,
std::set<GURL>* removed_urls) {
base::AutoLock url_lock(url_lock_);
RemoveImpl(node, removed_urls);
if (removed_urls) {
// RemoveImpl() adds an entry to removed_urls for each node of type URL. As
// duplicates are allowed we need to remove any entries that are still
// bookmarked.
for (auto i = removed_urls->begin(); i != removed_urls->end();) {
if (IsBookmarkedNoLock(*i)) {
// When we erase the iterator pointing at the erasee is
// invalidated, so using i++ here within the "erase" call is
// important as it advances the iterator before passing the
// old value through to erase.
removed_urls->erase(i++);
} else {
++i;
}
}
}
BookmarkNode* parent = node->parent();
return parent->Remove(size_t{parent->GetIndexOf(node)});
}
void UrlIndex::SetUrl(BookmarkNode* node, const GURL& url) {
base::AutoLock url_lock(url_lock_);
RemoveImpl(node, nullptr);
node->set_url(url);
AddImpl(node);
}
void UrlIndex::GetNodesWithIconUrl(const GURL& icon_url,
std::set<const BookmarkNode*>* nodes) {
base::AutoLock url_lock(url_lock_);
for (const BookmarkNode* node : nodes_ordered_by_url_set_) {
if (node->icon_url() && icon_url == *node->icon_url())
nodes->insert(node);
}
}
void UrlIndex::GetNodesByUrl(const GURL& url,
std::vector<const BookmarkNode*>* nodes) {
base::AutoLock url_lock(url_lock_);
BookmarkNode tmp_node(url);
auto i = nodes_ordered_by_url_set_.find(&tmp_node);
while (i != nodes_ordered_by_url_set_.end() && (*i)->url() == url) {
nodes->push_back(*i);
++i;
}
}
bool UrlIndex::HasBookmarks() const {
base::AutoLock url_lock(url_lock_);
return !nodes_ordered_by_url_set_.empty();
}
size_t UrlIndex::UrlCount() const {
base::AutoLock url_lock(url_lock_);
return nodes_ordered_by_url_set_.size();
}
bool UrlIndex::IsBookmarked(const GURL& url) {
base::AutoLock url_lock(url_lock_);
return IsBookmarkedNoLock(url);
}
void UrlIndex::GetBookmarks(std::vector<UrlAndTitle>* bookmarks) {
base::AutoLock url_lock(url_lock_);
const GURL* last_url = nullptr;
for (auto i = nodes_ordered_by_url_set_.begin();
i != nodes_ordered_by_url_set_.end(); ++i) {
const GURL* url = &((*i)->url());
// Only add unique URLs.
if (!last_url || *url != *last_url) {
UrlAndTitle bookmark;
bookmark.url = *url;
bookmark.title = (*i)->GetTitle();
bookmarks->push_back(bookmark);
}
last_url = url;
}
}
UrlIndex::~UrlIndex() = default;
bool UrlIndex::IsBookmarkedNoLock(const GURL& url) {
url_lock_.AssertAcquired();
BookmarkNode tmp_node(url);
return (nodes_ordered_by_url_set_.find(&tmp_node) !=
nodes_ordered_by_url_set_.end());
}
void UrlIndex::AddImpl(BookmarkNode* node) {
url_lock_.AssertAcquired();
if (node->is_url())
nodes_ordered_by_url_set_.insert(node);
for (const auto& child : node->children())
AddImpl(child.get());
}
void UrlIndex::RemoveImpl(BookmarkNode* node, std::set<GURL>* removed_urls) {
url_lock_.AssertAcquired();
if (node->is_url()) {
auto 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);
if (removed_urls)
removed_urls->insert(node->url());
}
for (const auto& child : base::Reversed(node->children()))
RemoveImpl(child.get(), removed_urls);
}
} // namespace bookmarks