blob: 33b88796f2d7f97888eb73723a57e9508a4443fc [file] [log] [blame]
// Copyright (c) 2012 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 "content/browser/renderer_host/clipboard_host_impl.h"
#include <utility>
#include "base/bind.h"
#include "base/location.h"
#include "base/macros.h"
#include "base/pickle.h"
#include "base/sequenced_task_runner.h"
#include "base/strings/utf_string_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "build/build_config.h"
#include "mojo/public/cpp/system/platform_handle.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_constants.h"
#include "ui/base/clipboard/custom_data_helper.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "url/gurl.h"
namespace content {
ClipboardHostImpl::ClipboardHostImpl(
mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver)
: receiver_(this, std::move(receiver)),
clipboard_(ui::Clipboard::GetForCurrentThread()),
clipboard_writer_(
new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste)) {}
void ClipboardHostImpl::Create(
mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver) {
// Clipboard implementations do interesting things, like run nested message
// loops. Use manual memory management instead of SelfOwnedReceiver<T> which
// synchronously destroys on failure and can result in some unfortunate
// use-after-frees after the nested message loops exit.
auto* host = new ClipboardHostImpl(std::move(receiver));
host->receiver_.set_disconnect_handler(base::BindOnce(
[](ClipboardHostImpl* host) {
base::SequencedTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, host);
},
host));
}
ClipboardHostImpl::~ClipboardHostImpl() {
clipboard_writer_->Reset();
}
void ClipboardHostImpl::GetSequenceNumber(ui::ClipboardBuffer clipboard_buffer,
GetSequenceNumberCallback callback) {
std::move(callback).Run(clipboard_->GetSequenceNumber(clipboard_buffer));
}
void ClipboardHostImpl::ReadAvailableTypes(
ui::ClipboardBuffer clipboard_buffer,
ReadAvailableTypesCallback callback) {
std::vector<base::string16> types;
bool contains_filenames;
clipboard_->ReadAvailableTypes(clipboard_buffer, &types, &contains_filenames);
std::move(callback).Run(types, contains_filenames);
}
void ClipboardHostImpl::IsFormatAvailable(blink::mojom::ClipboardFormat format,
ui::ClipboardBuffer clipboard_buffer,
IsFormatAvailableCallback callback) {
bool result = false;
switch (format) {
case blink::mojom::ClipboardFormat::kPlaintext:
result =
clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetPlainTextWType(), clipboard_buffer) ||
clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetPlainTextType(), clipboard_buffer);
break;
case blink::mojom::ClipboardFormat::kHtml:
result = clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetHtmlType(), clipboard_buffer);
break;
case blink::mojom::ClipboardFormat::kSmartPaste:
result = clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetWebKitSmartPasteType(), clipboard_buffer);
break;
case blink::mojom::ClipboardFormat::kBookmark:
#if defined(OS_WIN) || defined(OS_MACOSX)
result = clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetUrlWType(), clipboard_buffer);
#else
result = false;
#endif
break;
}
std::move(callback).Run(result);
}
void ClipboardHostImpl::ReadText(ui::ClipboardBuffer clipboard_buffer,
ReadTextCallback callback) {
base::string16 result;
if (clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetPlainTextWType(), clipboard_buffer)) {
clipboard_->ReadText(clipboard_buffer, &result);
} else if (clipboard_->IsFormatAvailable(
ui::ClipboardFormatType::GetPlainTextType(),
clipboard_buffer)) {
std::string ascii;
clipboard_->ReadAsciiText(clipboard_buffer, &ascii);
result = base::ASCIIToUTF16(ascii);
}
std::move(callback).Run(result);
}
void ClipboardHostImpl::ReadHtml(ui::ClipboardBuffer clipboard_buffer,
ReadHtmlCallback callback) {
base::string16 markup;
std::string src_url_str;
uint32_t fragment_start = 0;
uint32_t fragment_end = 0;
clipboard_->ReadHTML(clipboard_buffer, &markup, &src_url_str, &fragment_start,
&fragment_end);
std::move(callback).Run(std::move(markup), GURL(src_url_str), fragment_start,
fragment_end);
}
void ClipboardHostImpl::ReadRtf(ui::ClipboardBuffer clipboard_buffer,
ReadRtfCallback callback) {
std::string result;
clipboard_->ReadRTF(clipboard_buffer, &result);
std::move(callback).Run(result);
}
void ClipboardHostImpl::ReadImage(ui::ClipboardBuffer clipboard_buffer,
ReadImageCallback callback) {
SkBitmap result = clipboard_->ReadImage(clipboard_buffer);
std::move(callback).Run(result);
}
void ClipboardHostImpl::ReadCustomData(ui::ClipboardBuffer clipboard_buffer,
const base::string16& type,
ReadCustomDataCallback callback) {
base::string16 result;
clipboard_->ReadCustomData(clipboard_buffer, type, &result);
std::move(callback).Run(result);
}
void ClipboardHostImpl::WriteText(const base::string16& text) {
clipboard_writer_->WriteText(text);
}
void ClipboardHostImpl::WriteHtml(const base::string16& markup,
const GURL& url) {
clipboard_writer_->WriteHTML(markup, url.spec());
}
void ClipboardHostImpl::WriteSmartPasteMarker() {
clipboard_writer_->WriteWebSmartPaste();
}
void ClipboardHostImpl::WriteCustomData(
const base::flat_map<base::string16, base::string16>& data) {
base::Pickle pickle;
ui::WriteCustomDataToPickle(data, &pickle);
clipboard_writer_->WritePickledData(
pickle, ui::ClipboardFormatType::GetWebCustomDataType());
}
void ClipboardHostImpl::WriteRawData(const base::string16& format,
mojo_base::BigBuffer data) {
// Windows / X11 clipboards enter an unrecoverable state after registering
// some amount of unique formats, and there's no way to un-register these
// formats. For these clipboards, use a conservative limit to avoid
// registering too many formats, as:
// (1) Other native applications may also register clipboard formats.
// (2) |registered_formats| only persists over one Chrome Clipboard session.
// (3) Chrome also registers other clipboard formats.
//
// The limit is based on Windows, which has the smallest limit, at 0x4000.
// Windows represents clipboard formats using values in 0xC000 - 0xFFFF.
// Therefore, Windows supports at most 0x4000 registered formats. Reference:
// https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclipboardformata
static constexpr int kMaxWindowsClipboardFormats = 0x4000;
static constexpr int kMaxRegisteredFormats = kMaxWindowsClipboardFormats / 4;
static base::NoDestructor<std::set<base::string16>> registered_formats;
if (!base::Contains(*registered_formats, format)) {
if (registered_formats->size() >= kMaxRegisteredFormats)
return;
registered_formats->emplace(format);
}
clipboard_writer_->WriteData(format, std::move(data));
}
void ClipboardHostImpl::WriteBookmark(const std::string& url,
const base::string16& title) {
clipboard_writer_->WriteBookmark(title, url);
}
void ClipboardHostImpl::WriteImage(const SkBitmap& bitmap) {
clipboard_writer_->WriteImage(bitmap);
}
void ClipboardHostImpl::CommitWrite() {
clipboard_writer_.reset(
new ui::ScopedClipboardWriter(ui::ClipboardBuffer::kCopyPaste));
}
} // namespace content