blob: fc27340d6b810eb9f1990b1886ed8d340d701634 [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_
#define CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <vector>
#include "base/functional/callback_forward.h"
#include "base/gtest_prod_util.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "build/build_config.h"
#include "content/browser/renderer_host/render_frame_host_impl.h"
#include "content/common/content_export.h"
#include "content/public/browser/clipboard_types.h"
#include "content/public/browser/document_service.h"
#include "mojo/public/cpp/base/big_buffer.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "third_party/blink/public/mojom/clipboard/clipboard.mojom.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/clipboard_observer.h"
class GURL;
namespace ui {
class ScopedClipboardWriter;
} // namespace ui
namespace content {
class ClipboardHostImplTest;
// Returns a representation of the last source ClipboardEndpoint. This will
// either match the last clipboard write if there is an RFH token in the
// clipboard, or an endpoint built from `Clipboard::GetSource()` called with
// `clipboard_buffer` otherwise.
//
// //content maintains additional metadata on top of what the //ui layer already
// tracks about clipboard data's source, e.g. the WebContents that provided the
// data. This function allows retrieving both the //ui metadata and the
// //content metadata in a single call.
CONTENT_EXPORT ClipboardEndpoint
GetSourceClipboardEndpoint(const ui::DataTransferEndpoint* data_dst,
ui::ClipboardBuffer clipboard_buffer);
class CONTENT_EXPORT ClipboardHostImpl
: public DocumentService<blink::mojom::ClipboardHost>,
public ui::ClipboardObserver {
public:
~ClipboardHostImpl() override;
// Override for ui::ClipboardObserver
void OnClipboardDataChanged() override;
static void Create(
RenderFrameHost* render_frame_host,
mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
using ClipboardPasteData = content::ClipboardPasteData;
protected:
// These types and methods are protected for testing.
using IsClipboardPasteAllowedCallback =
RenderFrameHostImpl::IsClipboardPasteAllowedCallback;
explicit ClipboardHostImpl(
RenderFrameHost& render_frame_host,
mojo::PendingReceiver<blink::mojom::ClipboardHost> receiver);
// Performs a check to see if pasting `data` is allowed by data transfer
// policies and invokes FinishPasteIfAllowed upon completion.
void PasteIfPolicyAllowed(ui::ClipboardBuffer clipboard_buffer,
const ui::ClipboardFormatType& data_type,
ClipboardPasteData clipboard_paste_data,
IsClipboardPasteAllowedCallback callback);
private:
friend class ClipboardHostImplTest;
friend class ClipboardHostImplWriteTest;
friend class ClipboardHostImplAsyncWriteTest;
friend class ClipboardHostImplChangeTest;
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteText);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteText_Empty);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteHtml);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteHtml_Empty);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteSvg);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteSvg_Empty);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteBitmap);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, WriteBitmap_Empty);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest,
WriteDataTransferCustomData);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest,
WriteDataTransferCustomData_Empty);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest,
PerformPasteIfAllowed_EmptyData);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest,
NoSourceWithoutDataWrite);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, MainFrameURL);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplWriteTest, GetSourceEndpoint);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplAsyncWriteTest, WriteText);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplAsyncWriteTest, WriteHtml);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplAsyncWriteTest, WriteTextAndHtml);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplAsyncWriteTest, ConcurrentWrites);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplChangeTest, AddClipboardListener);
FRIEND_TEST_ALL_PREFIXES(ClipboardHostImplChangeTest,
ClipboardListenerDisconnect);
// mojom::ClipboardHost
void RegisterClipboardListener(
mojo::PendingRemote<blink::mojom::ClipboardListener> listener) override;
void GetSequenceNumber(ui::ClipboardBuffer clipboard_buffer,
GetSequenceNumberCallback callback) override;
void IsFormatAvailable(blink::mojom::ClipboardFormat format,
ui::ClipboardBuffer clipboard_buffer,
IsFormatAvailableCallback callback) override;
void ReadAvailableTypes(ui::ClipboardBuffer clipboard_buffer,
ReadAvailableTypesCallback callback) override;
void ReadText(ui::ClipboardBuffer clipboard_buffer,
ReadTextCallback callback) override;
void ReadHtml(ui::ClipboardBuffer clipboard_buffer,
ReadHtmlCallback callback) override;
void ReadSvg(ui::ClipboardBuffer clipboard_buffer,
ReadSvgCallback callback) override;
void ReadRtf(ui::ClipboardBuffer clipboard_buffer,
ReadRtfCallback callback) override;
void ReadPng(ui::ClipboardBuffer clipboard_buffer,
ReadPngCallback callback) override;
void ReadFiles(ui::ClipboardBuffer clipboard_buffer,
ReadFilesCallback callback) override;
void ReadDataTransferCustomData(
ui::ClipboardBuffer clipboard_buffer,
const std::u16string& type,
ReadDataTransferCustomDataCallback callback) override;
void ReadAvailableCustomAndStandardFormats(
ReadAvailableCustomAndStandardFormatsCallback callback) override;
void ReadUnsanitizedCustomFormat(
const std::u16string& format,
ReadUnsanitizedCustomFormatCallback callback) override;
void WriteUnsanitizedCustomFormat(const std::u16string& format,
mojo_base::BigBuffer data) override;
void WriteText(const std::u16string& text) override;
void WriteHtml(const std::u16string& markup, const GURL& url) override;
void WriteSvg(const std::u16string& markup) override;
void WriteSmartPasteMarker() override;
void WriteDataTransferCustomData(
const base::flat_map<std::u16string, std::u16string>& data) override;
void WriteBookmark(const std::string& url,
const std::u16string& title) override;
void WriteImage(const SkBitmap& unsafe_bitmap) override;
void CommitWrite() override;
#if BUILDFLAG(IS_MAC)
void WriteStringToFindPboard(const std::u16string& text) override;
void GetPlatformPermissionState(
GetPlatformPermissionStateCallback callback) override;
#endif
// Checks if the renderer allows pasting. This check is skipped if called
// soon after a successful content allowed request.
bool IsRendererPasteAllowed(ui::ClipboardBuffer clipboard_buffer,
RenderFrameHost& render_frame_host);
// Helper to be used when checking if data is allowed to be copied.
//
// If `replacement_data` is null, `clipboard_writer_` will be used to write
// `data` to the clipboard. `data` should only have one of its fields set
// depending on which "Write" method lead to `OnCopyAllowedResult()` being
// called. That field should correspond to `data_type`.
//
// If `replacement_data` is not null, instead that replacement string is
// written to the clipboard as plaintext.
//
// This method can be called asynchronously.
virtual void OnCopyAllowedResult(
const ui::ClipboardFormatType& data_type,
const ClipboardPasteData& data,
std::optional<std::u16string> replacement_data);
// Does the same thing as the previous function with an extra `source_url`
// used to propagate the URL obtained in the `WriteHtml()` method call.
//
// This method can be called asynchronously.
virtual void OnCopyHtmlAllowedResult(
const GURL& source_url,
const ui::ClipboardFormatType& data_type,
const ClipboardPasteData& data,
std::optional<std::u16string> replacement_data);
using CopyAllowedCallback = base::OnceCallback<void()>;
void OnReadPng(ui::ClipboardBuffer clipboard_buffer,
ReadPngCallback callback,
const std::vector<uint8_t>& data);
// Resets `clipboard_writer_` to write its data to the clipboard, and
// reinitialize it in preparation for the next write.
void ResetClipboardWriter();
// Adds source-tracking metadata to `clipboard_writer_` so it can be written
// to the clipboard on the next `CommitWrite()` call.
void AddSourceDataToClipboardWriter();
// Creates a `ui::DataTransferEndpoint` representing the last committed URL.
std::unique_ptr<ui::DataTransferEndpoint> CreateDataEndpoint();
// Creates a `content::ClipboardEndpoint` representing the last committed URL.
ClipboardEndpoint CreateClipboardEndpoint();
// Stops observing clipboard changes and resets the listener.
void StopObservingClipboard();
std::unique_ptr<ui::ScopedClipboardWriter> clipboard_writer_;
// Counts the number of expected `Write*` calls to be made to the current
// `clipboard_writer_`. This should be used to handle asynchronous `Write*`
// calls made by `IsClipboardCopyAllowedByPolicy`.
int pending_writes_ = 0;
// Indicates that the renderer called `CommitWrite()`, but that
// `pending_writes_` was not 0 at that time and that it should instead be
// called when the last pending `Write*` call is made.
bool pending_commit_write_ = false;
// Tracks whether this instance is currently observing clipboard changes.
bool listening_to_clipboard_ = false;
// Single clipboard listener that will be notified on clipboard changes
mojo::Remote<blink::mojom::ClipboardListener> clipboard_listener_;
base::WeakPtrFactory<ClipboardHostImpl> weak_ptr_factory_{this};
};
} // namespace content
#endif // CONTENT_BROWSER_RENDERER_HOST_CLIPBOARD_HOST_IMPL_H_