blob: 5bf4213f3c08b955f4161deccd77f6d8df509e64 [file] [log] [blame]
// Copyright 2020 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 "ash/clipboard/clipboard_history.h"
#include "ash/clipboard/clipboard_history_controller.h"
#include "ash/shell.h"
#include "base/stl_util.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_buffer.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/clipboard/clipboard_monitor.h"
namespace ash {
namespace {
constexpr size_t kMaxClipboardItemsShared = 5;
} // namespace
ClipboardHistory::ScopedPause::ScopedPause(ClipboardHistory* clipboard_history)
: clipboard_history_(clipboard_history) {
clipboard_history_->PauseClipboardHistory();
}
ClipboardHistory::ScopedPause::~ScopedPause() {
clipboard_history_->UnPauseClipboardHistory();
}
ClipboardHistory::ClipboardHistory() {
ui::ClipboardMonitor::GetInstance()->AddObserver(this);
}
ClipboardHistory::~ClipboardHistory() {
ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
}
void ClipboardHistory::ClearHistory() {
history_with_duplicates_ = std::deque<ui::ClipboardData>();
}
std::vector<ui::ClipboardData>
ClipboardHistory::GetRecentClipboardDataWithNoDuplicates() const {
std::vector<ui::ClipboardData> history_without_duplicates;
for (auto it = history_with_duplicates_.crbegin();
it != history_with_duplicates_.crend(); ++it) {
if (history_without_duplicates.size() == kMaxClipboardItemsShared)
break;
const ui::ClipboardData& current_data = *it;
if (!base::Contains(history_without_duplicates, current_data))
history_without_duplicates.push_back(current_data);
}
return history_without_duplicates;
}
bool ClipboardHistory::IsEmpty() const {
return history_with_duplicates_.empty();
}
void ClipboardHistory::OnClipboardDataChanged() {
// TODO(newcomer): Prevent Clipboard from recording metrics when pausing
// observation.
if (num_pause_clipboard_history_ > 0)
return;
ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
CHECK(clipboard);
std::vector<base::string16> mime_types;
clipboard->ReadAvailableTypes(ui::ClipboardBuffer::kCopyPaste,
/* data_dst = */ nullptr, &mime_types);
ui::ClipboardData new_data;
for (const auto& type16 : mime_types) {
const std::string type(base::UTF16ToUTF8(type16));
if (type == ui::ClipboardFormatType::GetPlainTextType().GetName()) {
base::string16 text;
clipboard->ReadText(ui::ClipboardBuffer::kCopyPaste,
/* data_dst = */ nullptr, &text);
new_data.set_text(base::UTF16ToUTF8(text));
} else if (type == ui::ClipboardFormatType::GetHtmlType().GetName()) {
uint32_t start, end;
base::string16 html_markup;
std::string src_url;
clipboard->ReadHTML(ui::ClipboardBuffer::kCopyPaste,
/* data_dst = */ nullptr, &html_markup, &src_url,
&start, &end);
new_data.set_markup_data(base::UTF16ToUTF8(html_markup));
new_data.set_url(src_url);
} else if (type == ui::ClipboardFormatType::GetRtfType().GetName()) {
std::string rtf_data;
clipboard->ReadRTF(ui::ClipboardBuffer::kCopyPaste,
/* data_dst = */ nullptr, &rtf_data);
new_data.SetRTFData(rtf_data);
} else if (type == ui::ClipboardFormatType::GetBitmapType().GetName()) {
// TODO(newcomer): Read the bitmap asynchronously.
}
// TODO(newcomer): Handle custom data, which could be files.
}
// Keep duplicates to maintain most recent ordering.
history_with_duplicates_.push_back(std::move(new_data));
// Keep the history with duplicates to a reasonable limit, but greater than
// kMaxClipboardItemsShared, so that repeated copies to not push off relevant
// data.
if (history_with_duplicates_.size() > kMaxClipboardItemsShared * 2)
history_with_duplicates_.pop_front();
}
void ClipboardHistory::PauseClipboardHistory() {
++num_pause_clipboard_history_;
}
void ClipboardHistory::UnPauseClipboardHistory() {
--num_pause_clipboard_history_;
}
} // namespace ash