blob: 1f66d4ac9e79f213efeadc7e53b0b2556385cfae [file] [log] [blame]
Avi Drissman4e1b7bc32022-09-15 14:03:501// Copyright 2012 The Chromium Authors
Stuart Langleye8300012017-11-24 01:16:182// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
danakjc492bf82020-09-09 20:02:445#include "content/browser/renderer_host/clipboard_host_impl.h"
Stuart Langleye8300012017-11-24 01:16:186
Peter Kasting1557e5f2025-01-28 01:14:087#include <algorithm>
Aya ElAttarfd04e3a2020-08-05 17:17:378#include <memory>
Roger Tawac6170262022-10-28 23:48:529#include <set>
Stuart Langleye8300012017-11-24 01:16:1810#include <utility>
11
Luca Accorsib52ca002023-12-01 08:54:2612#include "base/files/file_path.h"
Avi Drissmanadac21992023-01-11 23:46:3913#include "base/functional/bind.h"
Daniel Cheng6300516f2018-10-09 02:13:2414#include "base/location.h"
Daniel Cheng6f7e1c22021-02-02 05:47:5415#include "base/memory/ptr_util.h"
Keishi Hattori504ae462023-03-29 05:10:0616#include "base/memory/raw_ptr_exclusion.h"
Austin Sullivanfc870892021-04-29 18:40:1117#include "base/notreached.h"
Stuart Langleye8300012017-11-24 01:16:1818#include "base/pickle.h"
Roger Tawac6170262022-10-28 23:48:5219#include "base/strings/string_util.h"
Stuart Langleye8300012017-11-24 01:16:1820#include "base/strings/utf_string_conversions.h"
Patrick Monette643cdf62021-10-15 19:13:4221#include "base/task/sequenced_task_runner.h"
Dominique Fauteux-Chapleauc95ca122023-11-02 19:34:3322#include "base/types/optional_util.h"
Stuart Langleye8300012017-11-24 01:16:1823#include "build/build_config.h"
Joel Hockey4c0cb8c2021-02-22 02:59:5924#include "content/browser/file_system/browser_file_system_helper.h"
25#include "content/browser/file_system_access/file_system_access_manager_impl.h"
Darwin Huang6195d042021-02-12 22:36:0026#include "content/browser/permissions/permission_controller_impl.h"
Joel Hockeyd75d5062021-02-23 19:53:2527#include "content/browser/renderer_host/data_transfer_util.h"
Aya ElAttarf0ebeecf072021-03-05 10:52:1528#include "content/browser/renderer_host/render_frame_host_delegate.h"
Joel Hockey4c0cb8c2021-02-22 02:59:5929#include "content/browser/storage_partition_impl.h"
Sergey Poromov0bd48192021-07-16 18:45:5930#include "content/public/browser/browser_context.h"
Will Harriscd57b832023-01-05 20:03:1031#include "content/public/browser/child_process_host.h"
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:3432#include "content/public/browser/clipboard_types.h"
Roger Tawa1e1812f82020-01-16 15:23:3033#include "content/public/browser/render_frame_host.h"
34#include "content/public/browser/render_process_host.h"
Darwin Huang6195d042021-02-12 22:36:0035#include "content/public/common/content_client.h"
Joel Hockey4c0cb8c2021-02-22 02:59:5936#include "content/public/common/drop_data.h"
Daniel Cheng6f7e1c22021-02-02 05:47:5437#include "mojo/public/cpp/bindings/self_owned_receiver.h"
Stuart Langleye8300012017-11-24 01:16:1838#include "mojo/public/cpp/system/platform_handle.h"
danakjbdf1e0a2020-11-10 18:27:4739#include "skia/ext/skia_utils_base.h"
Joel Hockey4c0cb8c2021-02-22 02:59:5940#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
Sharon Yang2abe1982021-10-01 15:56:3441#include "third_party/blink/public/mojom/drag/drag.mojom-forward.h"
Stuart Langleye8300012017-11-24 01:16:1842#include "third_party/skia/include/core/SkBitmap.h"
43#include "ui/base/clipboard/clipboard.h"
Maksim Sisova33072d22019-01-24 15:44:2544#include "ui/base/clipboard/clipboard_constants.h"
Roger Tawa03ffdbd2020-01-16 18:12:5445#include "ui/base/clipboard/clipboard_format_type.h"
Dominique Fauteux-Chapleaued894b72024-03-19 12:19:4146#include "ui/base/clipboard/clipboard_monitor.h"
47#include "ui/base/clipboard/clipboard_observer.h"
Stuart Langleye8300012017-11-24 01:16:1848#include "ui/base/clipboard/custom_data_helper.h"
Joel Hockey4c0cb8c2021-02-22 02:59:5949#include "ui/base/clipboard/file_info.h"
Stuart Langleye8300012017-11-24 01:16:1850#include "ui/base/clipboard/scoped_clipboard_writer.h"
Aya ElAttar281086a2020-10-29 12:09:2251#include "ui/base/data_transfer_policy/data_transfer_endpoint.h"
Aya ElAttar84e6ef32021-03-02 16:29:1952#include "ui/base/data_transfer_policy/data_transfer_policy_controller.h"
Stuart Langleye8300012017-11-24 01:16:1853#include "url/gurl.h"
54
Georg Neis35ff854b2024-12-17 02:02:0855#if BUILDFLAG(IS_CHROMEOS)
Joel Hockey9fe6d6b82023-06-28 23:11:1356#include "content/public/common/url_constants.h"
Georg Neis35ff854b2024-12-17 02:02:0857#endif // BUILDFLAG(IS_CHROMEOS)
Joel Hockey9fe6d6b82023-06-28 23:11:1358
Stuart Langleye8300012017-11-24 01:16:1859namespace content {
Stuart Langleye8300012017-11-24 01:16:1860
Roger Tawac774694b2023-03-16 20:44:3961namespace {
62
Nancy Xiao200f55b2023-05-03 13:24:4763std::u16string ExtractText(ui::ClipboardBuffer clipboard_buffer,
64 std::unique_ptr<ui::DataTransferEndpoint> data_dst) {
65 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
66 std::u16string result;
67 if (clipboard->IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
68 clipboard_buffer, data_dst.get())) {
69 clipboard->ReadText(clipboard_buffer, data_dst.get(), &result);
70 } else {
71#if BUILDFLAG(IS_WIN)
72 if (clipboard->IsFormatAvailable(ui::ClipboardFormatType::PlainTextAType(),
73 clipboard_buffer, data_dst.get())) {
74 std::string ascii;
75 clipboard->ReadAsciiText(clipboard_buffer, data_dst.get(), &ascii);
76 result = base::ASCIIToUTF16(ascii);
77 }
78#endif
79 }
80 return result;
81}
82
Roger Tawac774694b2023-03-16 20:44:3983} // namespace
84
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:2485ClipboardEndpoint GetSourceClipboardEndpoint(
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:3486 const ui::DataTransferEndpoint* data_dst,
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:2487 ui::ClipboardBuffer clipboard_buffer) {
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:3488 auto* clipboard = ui::Clipboard::GetForCurrentThread();
89 std::string pickled_rfh_token;
90 clipboard->ReadData(SourceRFHTokenType(), data_dst, &pickled_rfh_token);
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:2491
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:3492 auto rfh_token = GlobalRenderFrameHostToken::FromPickle(
93 base::Pickle::WithData(base::as_byte_span(pickled_rfh_token)));
94
95 RenderFrameHost* rfh = nullptr;
96 if (rfh_token) {
97 rfh = RenderFrameHost::FromFrameToken(*rfh_token);
98 }
99
100 if (!rfh) {
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24101 // Fall back to the clipboard source if there is no `seqno` match or RFH, as
102 // `ui::DataTransferEndpoint` can be populated differently based on
103 // platform.
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34104 return ClipboardEndpoint(clipboard->GetSource(clipboard_buffer));
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24105 }
106
107 std::optional<ui::DataTransferEndpoint> source_dte;
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34108 auto clipboard_source_dte = clipboard->GetSource(clipboard_buffer);
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24109 if (clipboard_source_dte) {
110 if (clipboard_source_dte->IsUrlType()) {
111 source_dte = std::make_optional<ui::DataTransferEndpoint>(
112 *clipboard_source_dte->GetURL(),
Dominique Fauteux-Chapleau5e305e82024-06-21 00:02:03113 ui::DataTransferEndpointOptions{
114 .off_the_record = rfh->GetBrowserContext()->IsOffTheRecord()});
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24115 } else {
116 source_dte = std::move(clipboard_source_dte);
117 }
118 }
119
120 return ClipboardEndpoint(
121 std::move(source_dte),
122 base::BindRepeating(
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34123 [](GlobalRenderFrameHostToken rfh_token) -> BrowserContext* {
124 auto* rfh = RenderFrameHost::FromFrameToken(rfh_token);
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24125 if (!rfh) {
126 return nullptr;
127 }
128 return rfh->GetBrowserContext();
129 },
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34130 rfh->GetGlobalFrameToken()),
Dominique Fauteux-Chapleauc174eaa2024-02-12 19:29:24131 *rfh);
132}
133
Alexander Timine3383d02021-06-24 19:57:59134ClipboardHostImpl::ClipboardHostImpl(
danakjc70aec1f2022-07-07 15:48:19135 RenderFrameHost& render_frame_host,
Alexander Timine3383d02021-06-24 19:57:59136 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver)
Daniel Cheng9fb887ff2021-10-01 20:27:38137 : DocumentService(render_frame_host, std::move(receiver)) {
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34138 ResetClipboardWriter();
Roger Tawa1e1812f82020-01-16 15:23:30139}
Stuart Langleye8300012017-11-24 01:16:18140
Julie Jeongeun Kim44b804b22019-08-15 06:14:55141void ClipboardHostImpl::Create(
Roger Tawa1e1812f82020-01-16 15:23:30142 RenderFrameHost* render_frame_host,
Julie Jeongeun Kim44b804b22019-08-15 06:14:55143 mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver) {
danakjc70aec1f2022-07-07 15:48:19144 CHECK(render_frame_host);
Alexander Timine3383d02021-06-24 19:57:59145 // The object is bound to the lifetime of |render_frame_host| and the mojo
Daniel Cheng9fb887ff2021-10-01 20:27:38146 // connection. See DocumentService for details.
danakjc70aec1f2022-07-07 15:48:19147 new ClipboardHostImpl(*render_frame_host, std::move(receiver));
Stuart Langleye8300012017-11-24 01:16:18148}
149
150ClipboardHostImpl::~ClipboardHostImpl() {
151 clipboard_writer_->Reset();
Rohan Raja183dfd92025-04-22 21:41:09152 if (listening_to_clipboard_) {
153 ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
154 listening_to_clipboard_ = false;
155 }
Stuart Langleye8300012017-11-24 01:16:18156}
157
Darwin Huang5c6614c52019-08-21 01:20:10158void ClipboardHostImpl::GetSequenceNumber(ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18159 GetSequenceNumberCallback callback) {
Pavol Markoc73be3022021-07-05 15:41:20160 std::move(callback).Run(
161 ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(
162 clipboard_buffer));
Stuart Langleye8300012017-11-24 01:16:18163}
164
165void ClipboardHostImpl::ReadAvailableTypes(
Darwin Huang5c6614c52019-08-21 01:20:10166 ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18167 ReadAvailableTypesCallback callback) {
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58168 std::vector<std::u16string> types;
Joel Hockeyc69b6442021-09-06 09:27:33169 auto* clipboard = ui::Clipboard::GetForCurrentThread();
170 auto data_endpoint = CreateDataEndpoint();
171
Haihan Chen715e6752025-06-18 19:30:25172 // If an enterprise Data Controls rule modified the clipboard, get the last
173 // replaced clipboard types instead.
174 if (auto policy_types =
175 static_cast<RenderFrameHostImpl&>(render_frame_host())
176 .GetClipboardTypesIfPolicyApplied(
177 clipboard->GetSequenceNumber(clipboard_buffer))) {
178 types = std::move(*policy_types);
179 } else {
180 // ReadAvailableTypes() returns 'text/uri-list' if either files are
181 // provided, or if it was set as a custom web type. If it is set because
182 // files are available, do not include other types such as text/plain which
183 // contain the full path on some platforms (http://crbug.com/1214108). But
184 // do not exclude other types when it is set as a custom web type
185 // (http://crbug.com/1241671).
186 bool file_type_only =
187 clipboard->IsFormatAvailable(ui::ClipboardFormatType::FilenamesType(),
188 clipboard_buffer, data_endpoint.get());
Joel Hockey9fe6d6b82023-06-28 23:11:13189
Georg Neis35ff854b2024-12-17 02:02:08190#if BUILDFLAG(IS_CHROMEOS)
Haihan Chen715e6752025-06-18 19:30:25191 // ChromeOS FilesApp must include the custom 'fs/sources', etc data for
192 // paste that it put on the clipboard during copy (crbug.com/271078230).
193 if (render_frame_host().GetMainFrame()->GetLastCommittedURL().SchemeIs(
194 kChromeUIScheme)) {
195 file_type_only = false;
196 }
Georg Neis35ff854b2024-12-17 02:02:08197#endif // BUILDFLAG(IS_CHROMEOS)
Joel Hockey9fe6d6b82023-06-28 23:11:13198
Haihan Chen715e6752025-06-18 19:30:25199 if (file_type_only) {
200 types = {ui::kMimeTypeUriList16};
201 } else {
202 clipboard->ReadAvailableTypes(clipboard_buffer, data_endpoint.get(),
203 &types);
204 }
Joel Hockeyb210d8dd2021-06-04 23:48:55205 }
Darwin Huang2d5cff0c2020-05-05 00:00:48206 std::move(callback).Run(types);
Stuart Langleye8300012017-11-24 01:16:18207}
208
Stuart Langley4f843cc2017-12-04 21:56:54209void ClipboardHostImpl::IsFormatAvailable(blink::mojom::ClipboardFormat format,
Darwin Huang5c6614c52019-08-21 01:20:10210 ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18211 IsFormatAvailableCallback callback) {
Pavol Markoc73be3022021-07-05 15:41:20212 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
Stuart Langleye8300012017-11-24 01:16:18213 bool result = false;
Aya ElAttarbe0e5df2020-08-21 08:52:46214 auto data_endpoint = CreateDataEndpoint();
Stuart Langleye8300012017-11-24 01:16:18215 switch (format) {
Stuart Langley4f843cc2017-12-04 21:56:54216 case blink::mojom::ClipboardFormat::kPlaintext:
Darwin Huang71a469a2021-07-21 01:44:32217 result =
218 clipboard->IsFormatAvailable(ui::ClipboardFormatType::PlainTextType(),
219 clipboard_buffer, data_endpoint.get());
Xiaohan Wang7f8052e02022-01-14 18:44:28220#if BUILDFLAG(IS_WIN)
Pavol Markoc73be3022021-07-05 15:41:20221 result |= clipboard->IsFormatAvailable(
Darwin Huang71a469a2021-07-21 01:44:32222 ui::ClipboardFormatType::PlainTextAType(), clipboard_buffer,
Aya ElAttarbe0e5df2020-08-21 08:52:46223 data_endpoint.get());
Darwin Huanga29382f2020-01-16 06:21:44224#endif
Stuart Langleye8300012017-11-24 01:16:18225 break;
Stuart Langley4f843cc2017-12-04 21:56:54226 case blink::mojom::ClipboardFormat::kHtml:
Aya ElAttarbe0e5df2020-08-21 08:52:46227 result =
Darwin Huang71a469a2021-07-21 01:44:32228 clipboard->IsFormatAvailable(ui::ClipboardFormatType::HtmlType(),
Pavol Markoc73be3022021-07-05 15:41:20229 clipboard_buffer, data_endpoint.get());
Stuart Langleye8300012017-11-24 01:16:18230 break;
Stuart Langley4f843cc2017-12-04 21:56:54231 case blink::mojom::ClipboardFormat::kSmartPaste:
Pavol Markoc73be3022021-07-05 15:41:20232 result = clipboard->IsFormatAvailable(
Darwin Huang71a469a2021-07-21 01:44:32233 ui::ClipboardFormatType::WebKitSmartPasteType(), clipboard_buffer,
Aya ElAttarbe0e5df2020-08-21 08:52:46234 data_endpoint.get());
Stuart Langleye8300012017-11-24 01:16:18235 break;
Stuart Langley4f843cc2017-12-04 21:56:54236 case blink::mojom::ClipboardFormat::kBookmark:
Xiaohan Wang7f8052e02022-01-14 18:44:28237#if BUILDFLAG(IS_WIN) || BUILDFLAG(IS_MAC)
Aya ElAttarbe0e5df2020-08-21 08:52:46238 result =
Darwin Huang71a469a2021-07-21 01:44:32239 clipboard->IsFormatAvailable(ui::ClipboardFormatType::UrlType(),
Pavol Markoc73be3022021-07-05 15:41:20240 clipboard_buffer, data_endpoint.get());
Stuart Langleye8300012017-11-24 01:16:18241#else
242 result = false;
243#endif
244 break;
245 }
246 std::move(callback).Run(result);
247}
248
Darwin Huang5c6614c52019-08-21 01:20:10249void ClipboardHostImpl::ReadText(ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18250 ReadTextCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20251 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58252 std::move(callback).Run(std::u16string());
Darwin Huang6195d042021-02-12 22:36:00253 return;
254 }
Nancy Xiao200f55b2023-05-03 13:24:47255
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54256 ClipboardPasteData clipboard_paste_data;
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41257 clipboard_paste_data.text =
258 ExtractText(clipboard_buffer, CreateDataEndpoint());
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54259
Nancy Xiao4f3eae5d62023-04-25 19:38:59260 PasteIfPolicyAllowed(
261 clipboard_buffer, ui::ClipboardFormatType::PlainTextType(),
262 std::move(clipboard_paste_data),
263 base::BindOnce(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41264 [](ReadTextCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37265 std::optional<ClipboardPasteData> clipboard_paste_data) {
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41266 std::u16string result;
267 if (clipboard_paste_data) {
268 result = std::move(clipboard_paste_data->text);
Nancy Xiao4f3eae5d62023-04-25 19:38:59269 }
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41270 std::move(callback).Run(std::move(result));
Nancy Xiao4f3eae5d62023-04-25 19:38:59271 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41272 std::move(callback)));
Stuart Langleye8300012017-11-24 01:16:18273}
274
Darwin Huang5c6614c52019-08-21 01:20:10275void ClipboardHostImpl::ReadHtml(ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18276 ReadHtmlCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20277 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58278 std::move(callback).Run(std::u16string(), GURL(), 0, 0);
Darwin Huang6195d042021-02-12 22:36:00279 return;
280 }
Pavol Markoc73be3022021-07-05 15:41:20281 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41282 ClipboardPasteData clipboard_paste_data;
Stuart Langleye8300012017-11-24 01:16:18283 std::string src_url_str;
284 uint32_t fragment_start = 0;
285 uint32_t fragment_end = 0;
Aya ElAttarbe0e5df2020-08-21 08:52:46286 auto data_dst = CreateDataEndpoint();
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41287 clipboard->ReadHTML(clipboard_buffer, data_dst.get(),
288 &clipboard_paste_data.html, &src_url_str, &fragment_start,
289 &fragment_end);
Roger Tawa03ffdbd2020-01-16 18:12:54290
Aya ElAttar84e6ef32021-03-02 16:29:19291 PasteIfPolicyAllowed(
Nancy Xiao4f3eae5d62023-04-25 19:38:59292 clipboard_buffer, ui::ClipboardFormatType::HtmlType(),
293 std::move(clipboard_paste_data),
Roger Tawa03ffdbd2020-01-16 18:12:54294 base::BindOnce(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41295 [](std::string src_url_str, uint32_t fragment_start,
296 uint32_t fragment_end, ReadHtmlCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37297 std::optional<ClipboardPasteData> clipboard_paste_data) {
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41298 std::u16string markup;
299 if (clipboard_paste_data) {
300 markup = std::move(clipboard_paste_data->html);
Nancy Xiao4f3eae5d62023-04-25 19:38:59301 }
Roger Tawa03ffdbd2020-01-16 18:12:54302 std::move(callback).Run(std::move(markup), GURL(src_url_str),
303 fragment_start, fragment_end);
304 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41305 std::move(src_url_str), fragment_start, fragment_end,
306 std::move(callback)));
Stuart Langleye8300012017-11-24 01:16:18307}
308
Dylan Sleeper27d8f042020-08-28 02:56:59309void ClipboardHostImpl::ReadSvg(ui::ClipboardBuffer clipboard_buffer,
310 ReadSvgCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20311 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58312 std::move(callback).Run(std::u16string());
Darwin Huang6195d042021-02-12 22:36:00313 return;
314 }
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54315 ClipboardPasteData clipboard_paste_data;
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41316 ui::Clipboard::GetForCurrentThread()->ReadSvg(clipboard_buffer,
317 /*data_dst=*/nullptr,
318 &clipboard_paste_data.svg);
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54319
Nancy Xiao4f3eae5d62023-04-25 19:38:59320 PasteIfPolicyAllowed(
321 clipboard_buffer, ui::ClipboardFormatType::SvgType(),
322 std::move(clipboard_paste_data),
323 base::BindOnce(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41324 [](ReadSvgCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37325 std::optional<ClipboardPasteData> clipboard_paste_data) {
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41326 std::u16string svg;
327 if (clipboard_paste_data) {
328 svg = std::move(clipboard_paste_data->svg);
Nancy Xiao4f3eae5d62023-04-25 19:38:59329 }
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41330 std::move(callback).Run(std::move(svg));
Nancy Xiao4f3eae5d62023-04-25 19:38:59331 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41332 std::move(callback)));
Dylan Sleeper27d8f042020-08-28 02:56:59333}
334
Darwin Huang5c6614c52019-08-21 01:20:10335void ClipboardHostImpl::ReadRtf(ui::ClipboardBuffer clipboard_buffer,
Stuart Langleye8300012017-11-24 01:16:18336 ReadRtfCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20337 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Darwin Huang6195d042021-02-12 22:36:00338 std::move(callback).Run(std::string());
339 return;
340 }
Roger Tawa03ffdbd2020-01-16 18:12:54341
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54342 ClipboardPasteData clipboard_paste_data;
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41343 auto data_dst = CreateDataEndpoint();
344 ui::Clipboard::GetForCurrentThread()->ReadRTF(
345 clipboard_buffer, data_dst.get(), &clipboard_paste_data.rtf);
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54346
Nancy Xiao4f3eae5d62023-04-25 19:38:59347 PasteIfPolicyAllowed(
348 clipboard_buffer, ui::ClipboardFormatType::RtfType(),
349 std::move(clipboard_paste_data),
350 base::BindOnce(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41351 [](ReadRtfCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37352 std::optional<ClipboardPasteData> clipboard_paste_data) {
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41353 std::string result;
354 if (clipboard_paste_data) {
355 result = std::move(clipboard_paste_data->rtf);
Nancy Xiao4f3eae5d62023-04-25 19:38:59356 }
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41357 std::move(callback).Run(std::move(result));
Nancy Xiao4f3eae5d62023-04-25 19:38:59358 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41359 std::move(callback)));
Stuart Langleye8300012017-11-24 01:16:18360}
361
Austin Sullivanfc870892021-04-29 18:40:11362void ClipboardHostImpl::ReadPng(ui::ClipboardBuffer clipboard_buffer,
363 ReadPngCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20364 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Austin Sullivanfc870892021-04-29 18:40:11365 std::move(callback).Run(mojo_base::BigBuffer());
366 return;
367 }
368 auto data_dst = CreateDataEndpoint();
Pavol Markoc73be3022021-07-05 15:41:20369 ui::Clipboard::GetForCurrentThread()->ReadPng(
370 clipboard_buffer, data_dst.get(),
371 base::BindOnce(&ClipboardHostImpl::OnReadPng,
372 weak_ptr_factory_.GetWeakPtr(), clipboard_buffer,
373 std::move(callback)));
Austin Sullivanfc870892021-04-29 18:40:11374}
375
376void ClipboardHostImpl::OnReadPng(ui::ClipboardBuffer clipboard_buffer,
377 ReadPngCallback callback,
378 const std::vector<uint8_t>& data) {
Nancy Xiao200f55b2023-05-03 13:24:47379 // Pass both image and associated text for content analysis.
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54380 ClipboardPasteData clipboard_paste_data;
381 clipboard_paste_data.text =
382 ExtractText(clipboard_buffer, CreateDataEndpoint());
383 clipboard_paste_data.png = data;
384
Austin Sullivanfc870892021-04-29 18:40:11385 PasteIfPolicyAllowed(
Darwin Huang71a469a2021-07-21 01:44:32386 clipboard_buffer, ui::ClipboardFormatType::PngType(),
Nancy Xiao4f3eae5d62023-04-25 19:38:59387 std::move(clipboard_paste_data),
Austin Sullivanfc870892021-04-29 18:40:11388 base::BindOnce(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41389 [](ReadPngCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37390 std::optional<ClipboardPasteData> clipboard_paste_data) {
Nancy Xiao4f3eae5d62023-04-25 19:38:59391 if (!clipboard_paste_data.has_value()) {
Austin Sullivanfc870892021-04-29 18:40:11392 std::move(callback).Run(mojo_base::BigBuffer());
393 return;
394 }
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41395 std::move(callback).Run(
396 mojo_base::BigBuffer(std::move(clipboard_paste_data->png)));
Austin Sullivanfc870892021-04-29 18:40:11397 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41398 std::move(callback)));
Austin Sullivanfc870892021-04-29 18:40:11399}
Austin Sullivan921b54d32021-10-06 13:59:43400
Joel Hockey4c0cb8c2021-02-22 02:59:59401void ClipboardHostImpl::ReadFiles(ui::ClipboardBuffer clipboard_buffer,
402 ReadFilesCallback callback) {
403 blink::mojom::ClipboardFilesPtr result = blink::mojom::ClipboardFiles::New();
Roger Tawa34dd57f82022-12-15 23:24:20404 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Joel Hockey4c0cb8c2021-02-22 02:59:59405 std::move(callback).Run(std::move(result));
406 return;
407 }
408
Pavol Markoc73be3022021-07-05 15:41:20409 ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread();
Joel Hockey4c0cb8c2021-02-22 02:59:59410 std::vector<ui::FileInfo> filenames;
411 auto data_dst = CreateDataEndpoint();
Pavol Markoc73be3022021-07-05 15:41:20412 clipboard->ReadFilenames(clipboard_buffer, data_dst.get(), &filenames);
Roger Tawac6170262022-10-28 23:48:52413
Luca Accorsib52ca002023-12-01 08:54:26414 // Convert the vector of ui::FileInfo into a vector of base::FilePath so that
Roger Tawac6170262022-10-28 23:48:52415 // it can be passed to PerformPasteIfContentAllowed() for analysis. When
416 // the latter is called with ui::ClipboardFormatType::FilenamesType() the
417 // data to be analyzed is expected to be a newline-separated list of full
418 // paths.
Luca Accorsib52ca002023-12-01 08:54:26419 std::vector<base::FilePath> paths;
Roger Tawac6170262022-10-28 23:48:52420 paths.reserve(filenames.size());
Peter Kasting1557e5f2025-01-28 01:14:08421 std::ranges::transform(filenames, std::back_inserter(paths),
422 [](const ui::FileInfo& info) { return info.path; });
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54423 ClipboardPasteData clipboard_paste_data;
424 clipboard_paste_data.file_paths = std::move(paths);
Joel Hockey4c0cb8c2021-02-22 02:59:59425
Joel Hockey4c0cb8c2021-02-22 02:59:59426 // This code matches the drag-and-drop DataTransfer code in
427 // RenderWidgetHostImpl::DragTargetDrop().
428
Joel Hockeyd75d5062021-02-23 19:53:25429 // Call PrepareDataTransferFilenamesForChildProcess() to register files so
430 // they can be accessed by the renderer.
danakjc70aec1f2022-07-07 15:48:19431 RenderProcessHost* process = render_frame_host().GetProcess();
Joel Hockeyd75d5062021-02-23 19:53:25432 result->file_system_id = PrepareDataTransferFilenamesForChildProcess(
433 filenames, ChildProcessSecurityPolicyImpl::GetInstance(),
Emily Andrewsd15fd762024-12-10 20:41:54434 process->GetDeprecatedID(),
435 process->GetStoragePartition()->GetFileSystemContext());
Joel Hockeyd75d5062021-02-23 19:53:25436
437 // Convert to DataTransferFiles which creates the access token for each file.
Joel Hockey4c0cb8c2021-02-22 02:59:59438 StoragePartitionImpl* storage_partition = static_cast<StoragePartitionImpl*>(
danakjc70aec1f2022-07-07 15:48:19439 render_frame_host().GetProcess()->GetStoragePartition());
Joel Hockeyd75d5062021-02-23 19:53:25440 std::vector<blink::mojom::DataTransferFilePtr> files =
441 FileInfosToDataTransferFiles(
442 filenames, storage_partition->GetFileSystemAccessManager(),
Emily Andrewsd15fd762024-12-10 20:41:54443 process->GetDeprecatedID());
Joel Hockeyd75d5062021-02-23 19:53:25444 std::move(files.begin(), files.end(), std::back_inserter(result->files));
Joel Hockey4c0cb8c2021-02-22 02:59:59445
Luca Accorsia0f03e52023-12-03 08:55:46446 PasteIfPolicyAllowed(
447 clipboard_buffer, ui::ClipboardFormatType::FilenamesType(),
448 std::move(clipboard_paste_data),
Joel Hockey4c0cb8c2021-02-22 02:59:59449 base::BindOnce(
450 [](blink::mojom::ClipboardFilesPtr result, ReadFilesCallback callback,
Arthur Sonzognic686e8f2024-01-11 08:36:37451 std::optional<ClipboardPasteData> clipboard_paste_data) {
Nancy Xiao4f3eae5d62023-04-25 19:38:59452 if (!clipboard_paste_data) {
Joel Hockey4c0cb8c2021-02-22 02:59:59453 result->files.clear();
454 result->file_system_id->clear();
Roger Tawac6170262022-10-28 23:48:52455 } else {
456 // A subset of the files can be copied. Remove any files that
457 // should be blocked. First build a list of the files that are
458 // allowed.
Luca Accorsib52ca002023-12-01 08:54:26459 std::set<base::FilePath> allowed_files(
460 std::move_iterator(clipboard_paste_data->file_paths.begin()),
461 std::move_iterator(clipboard_paste_data->file_paths.end()));
Roger Tawac6170262022-10-28 23:48:52462
463 for (auto it = result->files.begin();
464 it != result->files.end();) {
Luca Accorsib52ca002023-12-01 08:54:26465 if (allowed_files.find(it->get()->path) !=
Roger Tawac6170262022-10-28 23:48:52466 allowed_files.end()) {
467 it = std::next(it);
468 } else {
469 it = result->files.erase(it);
470 }
471 }
Joel Hockey4c0cb8c2021-02-22 02:59:59472 }
473 std::move(callback).Run(std::move(result));
474 },
475 std::move(result), std::move(callback)));
476}
477
Anupam Snigdha3c3f08442024-06-14 18:58:29478void ClipboardHostImpl::ReadDataTransferCustomData(
479 ui::ClipboardBuffer clipboard_buffer,
480 const std::u16string& type,
481 ReadDataTransferCustomDataCallback callback) {
Roger Tawa34dd57f82022-12-15 23:24:20482 if (!IsRendererPasteAllowed(clipboard_buffer, render_frame_host())) {
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58483 std::move(callback).Run(std::u16string());
Darwin Huang6195d042021-02-12 22:36:00484 return;
485 }
Roger Tawa03ffdbd2020-01-16 18:12:54486
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54487 ClipboardPasteData clipboard_paste_data;
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41488 auto data_dst = CreateDataEndpoint();
Anupam Snigdha3c3f08442024-06-14 18:58:29489 ui::Clipboard::GetForCurrentThread()->ReadDataTransferCustomData(
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41490 clipboard_buffer, type, data_dst.get(),
491 &clipboard_paste_data.custom_data[type]);
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54492
Aya ElAttar84e6ef32021-03-02 16:29:19493 PasteIfPolicyAllowed(
Anupam Snigdhae61adbb2024-06-13 07:55:53494 clipboard_buffer, ui::ClipboardFormatType::DataTransferCustomType(),
Nancy Xiao4f3eae5d62023-04-25 19:38:59495 std::move(clipboard_paste_data),
Roger Tawa03ffdbd2020-01-16 18:12:54496 base::BindOnce(
Anupam Snigdha3c3f08442024-06-14 18:58:29497 [](ReadDataTransferCustomDataCallback callback,
498 const std::u16string& type,
Arthur Sonzognic686e8f2024-01-11 08:36:37499 std::optional<ClipboardPasteData> clipboard_paste_data) {
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41500 std::u16string result;
501 if (clipboard_paste_data) {
502 result = std::move(clipboard_paste_data->custom_data[type]);
Nancy Xiao4f3eae5d62023-04-25 19:38:59503 }
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41504 std::move(callback).Run(std::move(result));
Roger Tawa03ffdbd2020-01-16 18:12:54505 },
Dominique Fauteux-Chapleaud3bd4102024-02-21 20:09:41506 std::move(callback), type));
Stuart Langleye8300012017-11-24 01:16:18507}
508
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58509void ClipboardHostImpl::WriteText(const std::u16string& text) {
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10510 ClipboardPasteData data;
511 data.text = text;
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18512 ++pending_writes_;
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53513 GetContentClient()->browser()->IsClipboardCopyAllowedByPolicy(
514 CreateClipboardEndpoint(),
515 {
516 .size = text.size() * sizeof(std::u16string::value_type),
517 .format_type = ui::ClipboardFormatType::PlainTextType(),
518 },
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10519 data,
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16520 base::BindOnce(&ClipboardHostImpl::OnCopyAllowedResult,
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53521 weak_ptr_factory_.GetWeakPtr()));
Stuart Langleye8300012017-11-24 01:16:18522}
523
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58524void ClipboardHostImpl::WriteHtml(const std::u16string& markup,
Stuart Langleye8300012017-11-24 01:16:18525 const GURL& url) {
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10526 ClipboardPasteData data;
527 data.html = markup;
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18528 ++pending_writes_;
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53529 GetContentClient()->browser()->IsClipboardCopyAllowedByPolicy(
530 CreateClipboardEndpoint(),
531 {
532 .size = markup.size() * sizeof(std::u16string::value_type),
533 .format_type = ui::ClipboardFormatType::HtmlType(),
534 },
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10535 data,
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53536 base::BindOnce(&ClipboardHostImpl::OnCopyHtmlAllowedResult,
537 weak_ptr_factory_.GetWeakPtr(), url));
Stuart Langleye8300012017-11-24 01:16:18538}
539
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58540void ClipboardHostImpl::WriteSvg(const std::u16string& markup) {
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16541 ClipboardPasteData data;
542 data.svg = markup;
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18543 ++pending_writes_;
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16544 GetContentClient()->browser()->IsClipboardCopyAllowedByPolicy(
545 CreateClipboardEndpoint(),
546 {
547 .size = markup.size() * sizeof(std::u16string::value_type),
548 .format_type = ui::ClipboardFormatType::SvgType(),
549 },
550 data,
551 base::BindOnce(&ClipboardHostImpl::OnCopyAllowedResult,
552 weak_ptr_factory_.GetWeakPtr()));
Dylan Sleeper27d8f042020-08-28 02:56:59553}
554
Darwin Huang53e59b42019-04-27 03:23:42555void ClipboardHostImpl::WriteSmartPasteMarker() {
Stuart Langleye8300012017-11-24 01:16:18556 clipboard_writer_->WriteWebSmartPaste();
557}
558
Anupam Snigdha56968e72024-06-18 16:40:36559void ClipboardHostImpl::WriteDataTransferCustomData(
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58560 const base::flat_map<std::u16string, std::u16string>& data) {
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16561 ClipboardPasteData clipboard_paste_data;
562 clipboard_paste_data.custom_data = data;
563
564 size_t total_size = 0;
565 for (const auto& entry : clipboard_paste_data.custom_data) {
566 total_size += entry.second.size();
567 }
568
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18569 ++pending_writes_;
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16570 GetContentClient()->browser()->IsClipboardCopyAllowedByPolicy(
571 CreateClipboardEndpoint(),
572 {
573 .size = total_size,
Anupam Snigdhae61adbb2024-06-13 07:55:53574 .format_type = ui::ClipboardFormatType::DataTransferCustomType(),
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16575 },
576 clipboard_paste_data,
577 base::BindOnce(&ClipboardHostImpl::OnCopyAllowedResult,
578 weak_ptr_factory_.GetWeakPtr()));
Stuart Langleye8300012017-11-24 01:16:18579}
580
Darwin Huang53e59b42019-04-27 03:23:42581void ClipboardHostImpl::WriteBookmark(const std::string& url,
Jan Wilken Dörrieaace0cfef2021-03-11 22:01:58582 const std::u16string& title) {
Stuart Langleye8300012017-11-24 01:16:18583 clipboard_writer_->WriteBookmark(title, url);
584}
585
danakj56f34c62020-12-08 19:54:04586void ClipboardHostImpl::WriteImage(const SkBitmap& bitmap) {
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16587 ClipboardPasteData data;
588 data.bitmap = bitmap;
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18589 ++pending_writes_;
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16590 GetContentClient()->browser()->IsClipboardCopyAllowedByPolicy(
591 CreateClipboardEndpoint(),
592 {
593 .size = bitmap.computeByteSize(),
594 .format_type = ui::ClipboardFormatType::BitmapType(),
595 },
596 std::move(data),
597 base::BindOnce(&ClipboardHostImpl::OnCopyAllowedResult,
598 weak_ptr_factory_.GetWeakPtr()));
Stuart Langleye8300012017-11-24 01:16:18599}
600
Darwin Huang53e59b42019-04-27 03:23:42601void ClipboardHostImpl::CommitWrite() {
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18602 if (pending_writes_ != 0) {
603 // This branch indicates that some callbacks passed to
604 // `IsClipboardCopyAllowedByPolicy` still haven't been called, so committing
605 // data to the clipboard should be delayed.
606 pending_commit_write_ = true;
607 return;
608 }
609 pending_commit_write_ = false;
610
Anupam Snigdha5c877582024-03-15 01:28:59611 if (render_frame_host().GetBrowserContext()->IsOffTheRecord()) {
612 clipboard_writer_->MarkAsOffTheRecord();
613 }
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34614 ResetClipboardWriter();
Stuart Langleye8300012017-11-24 01:16:18615}
616
Roger Tawa34dd57f82022-12-15 23:24:20617bool ClipboardHostImpl::IsRendererPasteAllowed(
618 ui::ClipboardBuffer clipboard_buffer,
619 RenderFrameHost& render_frame_host) {
Roger Tawa34dd57f82022-12-15 23:24:20620 return GetContentClient()->browser()->IsClipboardPasteAllowed(
621 &render_frame_host);
622}
623
Anupam Snigdha74b68e42021-08-10 23:35:59624void ClipboardHostImpl::ReadAvailableCustomAndStandardFormats(
625 ReadAvailableCustomAndStandardFormatsCallback callback) {
Anupam Snigdha74b68e42021-08-10 23:35:59626 std::vector<std::u16string> format_types =
627 ui::Clipboard::GetForCurrentThread()
Anupam Snigdha8aa9dc92021-09-20 19:23:33628 ->ReadAvailableStandardAndCustomFormatNames(
Anupam Snigdha74b68e42021-08-10 23:35:59629 ui::ClipboardBuffer::kCopyPaste, CreateDataEndpoint().get());
630 std::move(callback).Run(format_types);
631}
632
633void ClipboardHostImpl::ReadUnsanitizedCustomFormat(
634 const std::u16string& format,
635 ReadUnsanitizedCustomFormatCallback callback) {
Anupam Snigdha74b68e42021-08-10 23:35:59636 // `kMaxFormatSize` includes the null terminator as well so we check if
637 // the `format` size is strictly less than `kMaxFormatSize` or not.
638 if (format.length() >= blink::mojom::ClipboardHost::kMaxFormatSize)
639 return;
640
641 // Extract the custom format names and then query the web custom format
642 // corresponding to the MIME type.
643 std::string format_name = base::UTF16ToASCII(format);
644 auto data_endpoint = CreateDataEndpoint();
645 std::map<std::string, std::string> custom_format_names =
646 ui::Clipboard::GetForCurrentThread()->ExtractCustomPlatformNames(
647 ui::ClipboardBuffer::kCopyPaste, data_endpoint.get());
648 std::string web_custom_format_string;
649 if (custom_format_names.find(format_name) != custom_format_names.end())
650 web_custom_format_string = custom_format_names[format_name];
651 if (web_custom_format_string.empty())
652 return;
653
654 std::string result;
655 ui::Clipboard::GetForCurrentThread()->ReadData(
Daniel Cheng764a8d32024-12-06 08:59:18656 ui::ClipboardFormatType::CustomPlatformType(web_custom_format_string),
Anupam Snigdha74b68e42021-08-10 23:35:59657 data_endpoint.get(), &result);
658 if (result.size() >= blink::mojom::ClipboardHost::kMaxDataSize)
659 return;
Peter Kasting5f6928c2024-11-29 21:25:11660 base::span<const uint8_t> span = base::as_byte_span(result);
Anupam Snigdha74b68e42021-08-10 23:35:59661 mojo_base::BigBuffer buffer = mojo_base::BigBuffer(span);
662 std::move(callback).Run(std::move(buffer));
663}
664
665void ClipboardHostImpl::WriteUnsanitizedCustomFormat(
666 const std::u16string& format,
667 mojo_base::BigBuffer data) {
Anupam Snigdha74b68e42021-08-10 23:35:59668 // `kMaxFormatSize` & `kMaxDataSize` includes the null terminator.
669 if (format.length() >= blink::mojom::ClipboardHost::kMaxFormatSize)
670 return;
671 if (data.size() >= blink::mojom::ClipboardHost::kMaxDataSize)
672 return;
673
674 // The `format` is mapped to user agent defined web custom format before
675 // writing to the clipboard. This happens in
676 // `ScopedClipboardWriter::WriteData`.
677 clipboard_writer_->WriteData(format, std::move(data));
678}
679
Aya ElAttar84e6ef32021-03-02 16:29:19680void ClipboardHostImpl::PasteIfPolicyAllowed(
681 ui::ClipboardBuffer clipboard_buffer,
682 const ui::ClipboardFormatType& data_type,
Nancy Xiao4f3eae5d62023-04-25 19:38:59683 ClipboardPasteData clipboard_paste_data,
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58684 IsClipboardPasteAllowedCallback callback) {
Arthur Sonzognic686e8f2024-01-11 08:36:37685 std::optional<size_t> data_size;
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58686 if (clipboard_paste_data.file_paths.empty()) {
Dominique Fauteux-Chapleau16d14fb32024-02-16 20:55:54687 data_size = clipboard_paste_data.size();
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58688 }
689
Dominique Fauteux-Chapleau859e737d2024-04-22 22:00:49690 ui::ClipboardSequenceNumberToken seqno =
691 ui::Clipboard::GetForCurrentThread()->GetSequenceNumber(clipboard_buffer);
692
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34693 auto data_dst = CreateClipboardEndpoint();
694 const ui::DataTransferEndpoint* data_dst_endpoint =
695 base::OptionalToPtr(data_dst.data_transfer_endpoint());
danakjc70aec1f2022-07-07 15:48:19696 static_cast<RenderFrameHostImpl&>(render_frame_host())
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58697 .IsClipboardPasteAllowedByPolicy(
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34698 GetSourceClipboardEndpoint(data_dst_endpoint, clipboard_buffer),
699 std::move(data_dst),
Dominique Fauteux-Chapleau4407a85d2024-01-05 13:18:58700 {
701 .size = data_size,
702 .format_type = data_type,
703 .seqno = seqno,
704 },
Dominique Fauteux-Chapleau859e737d2024-04-22 22:00:49705 std::move(clipboard_paste_data), std::move(callback));
Roger Tawa03ffdbd2020-01-16 18:12:54706}
707
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53708void ClipboardHostImpl::OnCopyHtmlAllowedResult(
709 const GURL& source_url,
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16710 const ui::ClipboardFormatType& data_type,
Dominique Fauteux-Chapleau88798b92024-03-14 20:22:10711 const ClipboardPasteData& data,
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53712 std::optional<std::u16string> replacement_data) {
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18713 DCHECK_GT(pending_writes_, 0);
714 --pending_writes_;
715
Dominique Fauteux-Chapleau1f19c232025-03-13 16:59:10716 AddSourceDataToClipboardWriter();
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16717
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53718 if (replacement_data) {
719 clipboard_writer_->WriteText(std::move(*replacement_data));
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18720 } else {
721 clipboard_writer_->WriteHTML(data.html, source_url.spec());
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16722 }
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18723 if (pending_commit_write_) {
724 CommitWrite();
725 }
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16726}
727
728void ClipboardHostImpl::OnCopyAllowedResult(
729 const ui::ClipboardFormatType& data_type,
730 const ClipboardPasteData& data,
731 std::optional<std::u16string> replacement_data) {
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18732 DCHECK_GT(pending_writes_, 0);
733 --pending_writes_;
734
Dominique Fauteux-Chapleau1f19c232025-03-13 16:59:10735 AddSourceDataToClipboardWriter();
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16736
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18737 // If `replacement_data` is empty, only one of these fields should be
738 // non-empty depending on which "Write" method was called by the renderer.
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16739 if (replacement_data) {
740 // `replacement_data` having a value implies the copy was not allowed and
741 // that a warning message should instead be put into the clipboard.
742 clipboard_writer_->WriteText(std::move(*replacement_data));
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18743 } else if (data_type == ui::ClipboardFormatType::PlainTextType()) {
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16744 // This branch should be reached only after `WriteText()` is called.
745 clipboard_writer_->WriteText(data.text);
746 } else if (data_type == ui::ClipboardFormatType::SvgType()) {
747 // This branch should be reached only after `WriteSvg()` is called.
748 clipboard_writer_->WriteSvg(data.svg);
749 } else if (data_type == ui::ClipboardFormatType::BitmapType()) {
750 // This branch should be reached only after `WriteImage()` is called.
751 clipboard_writer_->WriteImage(data.bitmap);
Anupam Snigdhae61adbb2024-06-13 07:55:53752 } else if (data_type == ui::ClipboardFormatType::DataTransferCustomType()) {
Dominique Fauteux-Chapleau302580f2024-04-03 20:51:16753 // This branch should be reached only after `WriteCustomData()` is called.
754 base::Pickle pickle;
755 ui::WriteCustomDataToPickle(data.custom_data, &pickle);
756 clipboard_writer_->WritePickledData(
Anupam Snigdhae61adbb2024-06-13 07:55:53757 pickle, ui::ClipboardFormatType::DataTransferCustomType());
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53758 } else {
Peter Boströmfc7ddc182024-10-31 19:37:21759 NOTREACHED();
Anthony Vallee-Duboisac847702021-12-06 21:00:48760 }
Dominique Fauteux-Chapleau3685eb12024-05-03 17:46:18761
762 if (pending_commit_write_) {
763 CommitWrite();
764 }
siashah1cac9c52024-07-09 23:50:36765
766 // Notify the observer that the write was committed to the clipboard. We do
767 // this only for text copies but it can be extended to other types if needed.
768 if (!replacement_data &&
769 data_type == ui::ClipboardFormatType::PlainTextType()) {
770 static_cast<RenderFrameHostImpl&>(render_frame_host())
771 .OnTextCopiedToClipboard(data.text);
772 }
Anthony Vallee-Duboisac847702021-12-06 21:00:48773}
774
Dominique Fauteux-Chapleau2cdc6a92024-01-29 17:39:37775std::unique_ptr<ui::DataTransferEndpoint>
776ClipboardHostImpl::CreateDataEndpoint() {
Dominique Fauteux-Chapleaud92e1fe2024-06-25 20:20:05777 if (!render_frame_host().GetMainFrame()->GetLastCommittedURL().is_valid()) {
778 return nullptr;
779 }
780
Alexander Timine3383d02021-06-24 19:57:59781 return std::make_unique<ui::DataTransferEndpoint>(
danakjc70aec1f2022-07-07 15:48:19782 render_frame_host().GetMainFrame()->GetLastCommittedURL(),
Dominique Fauteux-Chapleau5e305e82024-06-21 00:02:03783 ui::DataTransferEndpointOptions{
784 .notify_if_restricted =
785 render_frame_host().HasTransientUserActivation(),
786 .off_the_record =
787 render_frame_host().GetBrowserContext()->IsOffTheRecord(),
788 });
Aya ElAttarbe0e5df2020-08-21 08:52:46789}
Dominique Fauteux-Chapleauf6e59f22024-02-05 19:57:53790
791ClipboardEndpoint ClipboardHostImpl::CreateClipboardEndpoint() {
792 return ClipboardEndpoint(
793 CreateDataEndpoint().get(),
794 base::BindRepeating(
795 [](GlobalRenderFrameHostId rfh_id) -> BrowserContext* {
796 auto* rfh = RenderFrameHost::FromID(rfh_id);
797 if (!rfh) {
798 return nullptr;
799 }
800 return rfh->GetBrowserContext();
801 },
802 render_frame_host().GetGlobalId()),
803 render_frame_host());
804}
805
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34806void ClipboardHostImpl::ResetClipboardWriter() {
807 clipboard_writer_ = std::make_unique<ui::ScopedClipboardWriter>(
808 ui::ClipboardBuffer::kCopyPaste, CreateDataEndpoint());
Dominique Fauteux-Chapleau1f19c232025-03-13 16:59:10809}
810
811void ClipboardHostImpl::AddSourceDataToClipboardWriter() {
812 clipboard_writer_->SetDataSourceURL(
813 render_frame_host().GetMainFrame()->GetLastCommittedURL(),
814 render_frame_host().GetLastCommittedURL());
Dominique Fauteux-Chapleau61a53592025-01-17 15:21:34815 clipboard_writer_->WritePickledData(
816 render_frame_host().GetGlobalFrameToken().ToPickle(),
817 SourceRFHTokenType());
818}
819
Rohan Raja183dfd92025-04-22 21:41:09820void ClipboardHostImpl::OnClipboardDataChanged() {
821 if (!listening_to_clipboard_) {
822 return;
823 }
824 if (clipboard_listener_) {
825 clipboard_listener_->OnClipboardDataChanged();
826 }
827}
828
829void ClipboardHostImpl::RegisterClipboardListener(
830 mojo::PendingRemote<blink::mojom::ClipboardListener> listener) {
831 // Replace the current listener with the new one
832 clipboard_listener_.reset();
833 clipboard_listener_.Bind(std::move(listener));
834
835 // Set up connection error handler to stop observing when connection is closed
836 clipboard_listener_.set_disconnect_handler(
837 base::BindOnce(&ClipboardHostImpl::StopObservingClipboard,
838 weak_ptr_factory_.GetWeakPtr()));
839
840 // Start listening for clipboard changes if not already doing so
841 if (!listening_to_clipboard_) {
842 ui::ClipboardMonitor::GetInstance()->AddObserver(this);
843 listening_to_clipboard_ = true;
844 }
845}
846
847void ClipboardHostImpl::StopObservingClipboard() {
848 if (listening_to_clipboard_) {
849 ui::ClipboardMonitor::GetInstance()->RemoveObserver(this);
850 listening_to_clipboard_ = false;
851 }
852 clipboard_listener_.reset();
853}
854
Stuart Langleye8300012017-11-24 01:16:18855} // namespace content