blob: 44aecac03382fe129a04d035ca6aca9327d7787a [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 "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,
int 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;
}
}
}
return node->parent()->Remove(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() {
base::AutoLock url_lock(url_lock_);
return !nodes_ordered_by_url_set_.empty();
}
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 (int i = 0; i < node->child_count(); ++i)
AddImpl(node->GetChild(i));
}
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 (int i = node->child_count() - 1; i >= 0; --i)
RemoveImpl(node->GetChild(i), removed_urls);
}
} // namespace bookmarks