// Copyright 2020 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/renderer_context_menu/read_write_card_observer.h"
#include <utility>
#include <vector>
#include "base/check_is_test.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/chromeos/read_write_cards/read_write_card_controller.h"
#include "chrome/browser/ui/chromeos/read_write_cards/read_write_cards_manager.h"
#include "components/renderer_context_menu/render_view_context_menu_proxy.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/context_menu_params.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/web_contents.h"
namespace {
constexpr int kMaxSurroundingTextLength = 300;
void SetUiControllerContextMenuBounds(const gfx::Rect& bounds_in_screen) {
chromeos::ReadWriteCardsManager* cards_manager =
chromeos::ReadWriteCardsManager::Get();
if (cards_manager) {
cards_manager->SetContextMenuBounds(
/*context_menu_bounds=*/bounds_in_screen);
} else {
// `cards_manager` should only be null in a test environment (since in some
// tests the global `ReadWriteCardsManager` is not constructed).
CHECK_IS_TEST();
}
}
} // namespace
ReadWriteCardObserver::ReadWriteCardObserver(RenderViewContextMenuProxy* proxy,
Profile* profile)
: proxy_(proxy), profile_(profile) {}
ReadWriteCardObserver::~ReadWriteCardObserver() = default;
void ReadWriteCardObserver::OnContextMenuShown(
const content::ContextMenuParams& params,
const gfx::Rect& bounds_in_screen) {
bounds_in_screen_ = bounds_in_screen;
chromeos::ReadWriteCardsManager* cards_manager =
chromeos::ReadWriteCardsManager::Get();
CHECK(cards_manager);
// Before cards_manager executes FetchController, sends a request to create
// the editor session.
cards_manager->TryCreatingEditorSession(params, profile_);
cards_manager->FetchController(
params, profile_,
base::BindOnce(&ReadWriteCardObserver::OnFetchControllers,
weak_factory_.GetWeakPtr(), params));
}
void ReadWriteCardObserver::OnContextMenuViewBoundsChanged(
const gfx::Rect& bounds_in_screen) {
bounds_in_screen_ = bounds_in_screen;
for (auto controller : read_write_card_controllers_) {
if (!controller) {
continue;
}
SetUiControllerContextMenuBounds(bounds_in_screen_);
controller->OnAnchorBoundsChanged(bounds_in_screen_);
}
}
void ReadWriteCardObserver::OnMenuClosed() {
for (auto controller : read_write_card_controllers_) {
if (!controller) {
continue;
}
controller->OnDismiss(is_other_command_executed_);
}
read_write_card_controllers_.clear();
is_other_command_executed_ = false;
}
void ReadWriteCardObserver::CommandWillBeExecuted(int command_id) {
is_other_command_executed_ = true;
}
void ReadWriteCardObserver::OnTextSurroundingSelectionAvailable(
const std::u16string& selected_text,
const std::u16string& surrounding_text,
uint32_t start_offset,
uint32_t end_offset) {
for (auto controller : read_write_card_controllers_) {
if (!controller) {
continue;
}
controller->OnTextAvailable(bounds_in_screen_,
base::UTF16ToUTF8(selected_text),
base::UTF16ToUTF8(surrounding_text));
}
}
void ReadWriteCardObserver::OnFetchControllers(
const content::ContextMenuParams& params,
std::vector<base::WeakPtr<chromeos::ReadWriteCardController>> controllers) {
if (controllers.empty()) {
read_write_card_controllers_.clear();
return;
}
SetUiControllerContextMenuBounds(bounds_in_screen_);
content::RenderFrameHost* focused_frame =
proxy_->GetWebContents()->GetFocusedFrame();
for (auto controller : controllers) {
if (!controller) {
continue;
}
if (focused_frame) {
controller->OnContextMenuShown(profile_);
}
read_write_card_controllers_.emplace_back(controller.get());
}
if (focused_frame) {
focused_frame->RequestTextSurroundingSelection(
base::BindOnce(
&ReadWriteCardObserver::OnTextSurroundingSelectionAvailable,
weak_factory_.GetWeakPtr(), params.selection_text),
kMaxSurroundingTextLength);
}
}