910e62b5创建于 1月15日历史提交
// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/ui/webui_browser/bookmark_bar_page_handler.h"

#include <algorithm>

#include "base/functional/bind.h"
#include "base/functional/callback_helpers.h"
#include "base/logging.h"
#include "base/notreached.h"
#include "base/strings/utf_string_conversions.h"
#include "base/time/time.h"
#include "chrome/browser/bookmarks/bookmark_model_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/bookmarks/bookmark_utils_desktop.h"
#include "chrome/browser/ui/browser.h"
#include "components/bookmarks/browser/bookmark_model.h"
#include "components/bookmarks/browser/bookmark_node.h"
#include "components/bookmarks/browser/bookmark_utils.h"
#include "components/page_load_metrics/browser/navigation_handle_user_data.h"
#include "ui/base/window_open_disposition.h"

namespace {

bookmark_bar::mojom::BookmarkType ConvertType(
    bookmarks::BookmarkNode::Type type) {
  switch (type) {
    case bookmarks::BookmarkNode::URL:
      return bookmark_bar::mojom::BookmarkType::URL;
    case bookmarks::BookmarkNode::FOLDER:
      return bookmark_bar::mojom::BookmarkType::FOLDER;
    case bookmarks::BookmarkNode::BOOKMARK_BAR:
      return bookmark_bar::mojom::BookmarkType::BOOKMARK_BAR;
    case bookmarks::BookmarkNode::OTHER_NODE:
      return bookmark_bar::mojom::BookmarkType::OTHER_NODE;
    case bookmarks::BookmarkNode::MOBILE:
      return bookmark_bar::mojom::BookmarkType::MOBILE;
  }
  NOTREACHED();
}

}  // namespace

WebUIBrowserBookmarkBarPageHandler::WebUIBrowserBookmarkBarPageHandler(
    mojo::PendingReceiver<bookmark_bar::mojom::PageHandler> receiver,
    mojo::PendingRemote<bookmark_bar::mojom::Page> page,
    content::WebUI* web_ui,
    Browser* browser)
    : receiver_(this, std::move(receiver)),
      page_(std::move(page)),
      web_ui_(web_ui),
      browser_(browser) {
  bookmark_model_ =
      BookmarkModelFactory::GetForBrowserContext(browser_->profile());

  if (bookmark_model_) {
    bookmark_model_->AddObserver(this);
    if (bookmark_model_->loaded()) {
      BookmarkModelLoaded(false);
    }
    // else case: we'll receive notification back from the BookmarkModel when
    // done loading, then we'll populate the bar.
  }
}

WebUIBrowserBookmarkBarPageHandler::~WebUIBrowserBookmarkBarPageHandler() {
  if (bookmark_model_) {
    bookmark_model_->RemoveObserver(this);
  }
}

void WebUIBrowserBookmarkBarPageHandler::SetBookmarkBarState(
    BookmarkBar::State state,
    BookmarkBar::AnimateChangeType animate_type) {
  // TODO(webium): Do we care about disabling animation for parity in Webium?
  if (bookmark_bar_state_ == state) {
    return;
  }

  if (state == BookmarkBar::SHOW) {
    page_->Show();
  } else {
    page_->Hide();
  }

  bookmark_bar_state_ = state;
}

bookmark_bar::mojom::BookmarkDataPtr
WebUIBrowserBookmarkBarPageHandler::GetBookmarkData(
    const bookmarks::BookmarkNode* node) {
  auto bookmark_data = bookmark_bar::mojom::BookmarkData::New();
  bookmark_data->title = base::UTF16ToUTF8(node->GetTitle());
  bookmark_data->id = node->id();
  bookmark_data->type = ConvertType(node->type());
  if (!node->is_favicon_loaded() && !node->is_favicon_loading()) {
    // Trigger a request to fetch fav icon.
    bookmark_model_->GetFavicon(node);
  } else if (node->icon_url()) {
    bookmark_data->page_url_for_favicon = node->url();
  }

  return bookmark_data;
}

void WebUIBrowserBookmarkBarPageHandler::GetBookmarkBar(
    GetBookmarkBarCallback callback) {
  std::vector<bookmark_bar::mojom::BookmarkDataPtr> bookmarks;

  if (bookmark_model_->loaded() &&
      !bookmark_model_->bookmark_bar_node()->children().empty()) {
    // This is calculated by the display size
    // Will need to be fetched from the UI? Or perhaps just send all bookmarks
    // to the WebUI? For now just pick a random number.
    const int max_bookmarks = 20;
    const int bookmark_model_count =
        bookmark_model_->loaded()
            ? bookmark_model_->bookmark_bar_node()->children().size()
            : 0;
    int bookmark_count = std::min(max_bookmarks, bookmark_model_count);
    for (int i = 0; i < bookmark_count; i++) {
      bookmarks.push_back(GetBookmarkData(
          bookmark_model_->bookmark_bar_node()->children()[i].get()));
    }
  }

  std::move(callback).Run(std::move(bookmarks));
}

void WebUIBrowserBookmarkBarPageHandler::OpenInNewTab(int64_t node_id) {
  const bookmarks::BookmarkNode* node =
      bookmarks::GetBookmarkNodeByID(bookmark_model_, node_id);
  bookmarks::OpenAllIfAllowed(
      browser_, {node}, WindowOpenDisposition::CURRENT_TAB,
      bookmarks::OpenAllBookmarksContext::kNone,
      page_load_metrics::NavigationHandleUserData::InitiatorLocation::
          kBookmarkBar,
      {{BookmarkLaunchLocation::kAttachedBar, base::TimeTicks::Now()}});
}

// bookmarks::BookmarkModelObserver:
void WebUIBrowserBookmarkBarPageHandler::BookmarkModelLoaded(
    bool ids_reassigned) {
  page_->BookmarkLoaded();
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkModelBeingDeleted() {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeMoved(
    const bookmarks::BookmarkNode* old_parent,
    size_t old_index,
    const bookmarks::BookmarkNode* new_parent,
    size_t new_index) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeAdded(
    const bookmarks::BookmarkNode* parent,
    size_t index,
    bool added_by_user) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeRemoved(
    const bookmarks::BookmarkNode* parent,
    size_t old_index,
    const bookmarks::BookmarkNode* node,
    const std::set<GURL>& removed_urls,
    const base::Location& location) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkAllUserNodesRemoved(
    const std::set<GURL>& removed_urls,
    const base::Location& location) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeChanged(
    const bookmarks::BookmarkNode* node) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeChildrenReordered(
    const bookmarks::BookmarkNode* node) {
  // TODO(webium): Implement.
}

void WebUIBrowserBookmarkBarPageHandler::BookmarkNodeFaviconChanged(
    const bookmarks::BookmarkNode* node) {
  if (node->is_favicon_loaded()) {
    page_->FavIconChanged(GetBookmarkData(node));
  }
}