Commit 4d8435dc authored by dominicc's avatar dominicc Committed by Commit bot

Expose RTF content on the clipboard as strings to pages when pasting.

BUG=317807
CQ_INCLUDE_TRYBOTS=master.tryserver.chromium.linux:linux_site_isolation

Review-Url: https://codereview.chromium.org/2146323002
Cr-Commit-Position: refs/heads/master@{#407039}
parent 6427de29
...@@ -8,20 +8,17 @@ ...@@ -8,20 +8,17 @@
#include "base/macros.h" #include "base/macros.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/synchronization/waitable_event.h"
#include "build/build_config.h"
#include "content/browser/web_contents/web_contents_impl.h" #include "content/browser/web_contents/web_contents_impl.h"
#include "content/common/clipboard_messages.h" #include "content/common/clipboard_messages.h"
#include "content/common/frame_messages.h" #include "content/common/frame_messages.h"
#include "content/public/browser/browser_message_filter.h" #include "content/public/browser/browser_message_filter.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/interstitial_page_delegate.h" #include "content/public/browser/interstitial_page_delegate.h"
#include "content/public/test/browser_test_utils.h" #include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h" #include "content/public/test/content_browser_test.h"
#include "content/public/test/test_utils.h" #include "content/public/test/test_utils.h"
#include "content/shell/browser/shell.h" #include "content/shell/browser/shell.h"
#include "ipc/message_filter.h" #include "ipc/message_filter.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/test/test_clipboard.h"
namespace content { namespace content {
...@@ -135,46 +132,6 @@ class InterstitialPageImplTest : public ContentBrowserTest { ...@@ -135,46 +132,6 @@ class InterstitialPageImplTest : public ContentBrowserTest {
~InterstitialPageImplTest() override {} ~InterstitialPageImplTest() override {}
protected: protected:
void SetUpTestClipboard() {
#if defined(OS_WIN)
// On Windows, clipboard reads are handled on the IO thread. So, the test
// clipboard should be created for the IO thread.
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(
base::Bind(&InterstitialPageImplTest::SetUpTestClipboard, this));
return;
}
#endif
ui::TestClipboard::CreateForCurrentThread();
}
void TearDownTestClipboard() {
#if defined(OS_WIN)
// On Windows, test clipboard is created for the IO thread. So, destroy it
// for the IO thread, too.
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(
base::Bind(&InterstitialPageImplTest::TearDownTestClipboard, this));
return;
}
#endif
ui::Clipboard::DestroyClipboardForCurrentThread();
}
void SetClipboardText(const std::string& text) {
#if defined(OS_WIN)
// On Windows, clipboard reads are handled on the IO thread. So, set the
// text for the IO thread clipboard.
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(
base::Bind(&InterstitialPageImplTest::SetClipboardText, this, text));
return;
}
#endif
ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
clipboard_writer.WriteText(base::ASCIIToUTF16(text));
}
void SetUpInterstitialPage() { void SetUpInterstitialPage() {
WebContentsImpl* web_contents = WebContentsImpl* web_contents =
static_cast<WebContentsImpl*>(shell()->web_contents()); static_cast<WebContentsImpl*>(shell()->web_contents());
...@@ -277,21 +234,6 @@ class InterstitialPageImplTest : public ContentBrowserTest { ...@@ -277,21 +234,6 @@ class InterstitialPageImplTest : public ContentBrowserTest {
} }
private: private:
void RunTaskOnIOThreadAndWait(const base::Closure& task) {
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
base::Bind(&InterstitialPageImplTest::RunTask, this,
task, &completion));
completion.Wait();
}
void RunTask(const base::Closure& task, base::WaitableEvent* completion) {
task.Run();
completion->Signal();
}
std::unique_ptr<InterstitialPageImpl> interstitial_; std::unique_ptr<InterstitialPageImpl> interstitial_;
scoped_refptr<ClipboardMessageWatcher> clipboard_message_watcher_; scoped_refptr<ClipboardMessageWatcher> clipboard_message_watcher_;
...@@ -331,10 +273,10 @@ IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Copy) { ...@@ -331,10 +273,10 @@ IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Copy) {
} }
IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) { IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) {
SetUpTestClipboard(); BrowserTestClipboardScope clipboard;
SetUpInterstitialPage(); SetUpInterstitialPage();
SetClipboardText("text-to-paste"); clipboard.SetText("text-to-paste");
ASSERT_TRUE(CreateInputAndSetText(std::string())); ASSERT_TRUE(CreateInputAndSetText(std::string()));
ASSERT_TRUE(FocusInputAndSelectText()); ASSERT_TRUE(FocusInputAndSelectText());
...@@ -346,7 +288,6 @@ IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) { ...@@ -346,7 +288,6 @@ IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, Paste) {
EXPECT_EQ("text-to-paste", input_text); EXPECT_EQ("text-to-paste", input_text);
TearDownInterstitialPage(); TearDownInterstitialPage();
TearDownTestClipboard();
} }
IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, SelectAll) { IN_PROC_BROWSER_TEST_F(InterstitialPageImplTest, SelectAll) {
......
...@@ -300,6 +300,7 @@ ...@@ -300,6 +300,7 @@
'renderer/render_view_browsertest_mac.mm', 'renderer/render_view_browsertest_mac.mm',
'renderer/render_widget_browsertest.cc', 'renderer/render_widget_browsertest.cc',
'renderer/visual_state_browsertest.cc', 'renderer/visual_state_browsertest.cc',
'renderer/webclipboard_impl_browsertest.cc',
'test/browser_test_utils_browsertest.cc', 'test/browser_test_utils_browsertest.cc',
'test/content_browser_test_test.cc', 'test/content_browser_test_test.cc',
'test/webui_resource_browsertest.cc', 'test/webui_resource_browsertest.cc',
......
...@@ -41,6 +41,7 @@ ...@@ -41,6 +41,7 @@
#include "content/common/view_messages.h" #include "content/common/view_messages.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_plugin_guest_manager.h" #include "content/public/browser/browser_plugin_guest_manager.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/histogram_fetcher.h" #include "content/public/browser/histogram_fetcher.h"
#include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_entry.h"
#include "content/public/browser/notification_service.h" #include "content/public/browser/notification_service.h"
...@@ -62,7 +63,10 @@ ...@@ -62,7 +63,10 @@
#include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context.h"
#include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_context_getter.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/clipboard/clipboard.h"
#include "ui/base/clipboard/scoped_clipboard_writer.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/base/test/test_clipboard.h"
#include "ui/compositor/test/draw_waiter_for_test.h" #include "ui/compositor/test/draw_waiter_for_test.h"
#include "ui/events/gesture_detection/gesture_configuration.h" #include "ui/events/gesture_detection/gesture_configuration.h"
#include "ui/events/keycodes/dom/dom_code.h" #include "ui/events/keycodes/dom/dom_code.h"
...@@ -1431,4 +1435,76 @@ uint32_t InputMsgWatcher::WaitForAck() { ...@@ -1431,4 +1435,76 @@ uint32_t InputMsgWatcher::WaitForAck() {
return ack_result_; return ack_result_;
} }
#if defined(OS_WIN)
static void RunTaskAndSignalCompletion(const base::Closure& task,
base::WaitableEvent* completion) {
task.Run();
completion->Signal();
}
static void RunTaskOnIOThreadAndWait(const base::Closure& task) {
base::WaitableEvent completion(
base::WaitableEvent::ResetPolicy::AUTOMATIC,
base::WaitableEvent::InitialState::NOT_SIGNALED);
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(&RunTaskAndSignalCompletion, task, &completion));
completion.Wait();
}
#endif
static void SetUpTestClipboard() {
#if defined(OS_WIN)
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(base::Bind(&SetUpTestClipboard));
return;
}
#endif
ui::TestClipboard::CreateForCurrentThread();
}
// TODO(dcheng): Make the test clipboard on different threads share the
// same backing store. crbug.com/629765
BrowserTestClipboardScope::BrowserTestClipboardScope() {
SetUpTestClipboard();
}
static void TearDownTestClipboard() {
#if defined(OS_WIN)
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(base::Bind(&TearDownTestClipboard));
return;
}
#endif
ui::Clipboard::DestroyClipboardForCurrentThread();
}
BrowserTestClipboardScope::~BrowserTestClipboardScope() {
TearDownTestClipboard();
}
void BrowserTestClipboardScope::SetRtf(const std::string& rtf) {
#if defined(OS_WIN)
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(base::Bind(&BrowserTestClipboardScope::SetRtf,
base::Unretained(this), rtf));
return;
}
#endif
ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
clipboard_writer.WriteRTF(rtf);
}
void BrowserTestClipboardScope::SetText(const std::string& text) {
#if defined(OS_WIN)
if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
RunTaskOnIOThreadAndWait(base::Bind(&BrowserTestClipboardScope::SetText,
base::Unretained(this), text));
return;
}
#endif
ui::ScopedClipboardWriter clipboard_writer(ui::CLIPBOARD_TYPE_COPY_PASTE);
clipboard_writer.WriteText(base::ASCIIToUTF16(text));
}
} // namespace content } // namespace content
...@@ -553,6 +553,27 @@ class InputMsgWatcher : public BrowserMessageFilter { ...@@ -553,6 +553,27 @@ class InputMsgWatcher : public BrowserMessageFilter {
DISALLOW_COPY_AND_ASSIGN(InputMsgWatcher); DISALLOW_COPY_AND_ASSIGN(InputMsgWatcher);
}; };
// Sets up a ui::TestClipboard for use in browser tests. On Windows,
// clipboard is handled on the IO thread, BrowserTestClipboardScope
// hops messages onto the right thread.
class BrowserTestClipboardScope {
public:
// Sets up a ui::TestClipboard.
BrowserTestClipboardScope();
// Tears down the clipboard.
~BrowserTestClipboardScope();
// Puts text/rtf |rtf| on the clipboard.
void SetRtf(const std::string& rtf);
// Puts plain text |text| on the clipboard.
void SetText(const std::string& text);
private:
DISALLOW_COPY_AND_ASSIGN(BrowserTestClipboardScope);
};
} // namespace content } // namespace content
#endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_ #endif // CONTENT_PUBLIC_TEST_BROWSER_TEST_UTILS_H_
...@@ -109,6 +109,16 @@ WebString WebClipboardImpl::readHTML(Buffer buffer, WebURL* source_url, ...@@ -109,6 +109,16 @@ WebString WebClipboardImpl::readHTML(Buffer buffer, WebURL* source_url,
return html_stdstr; return html_stdstr;
} }
WebString WebClipboardImpl::readRTF(Buffer buffer) {
ui::ClipboardType clipboard_type;
if (!ConvertBufferType(buffer, &clipboard_type))
return WebString();
std::string rtf;
delegate_->ReadRTF(clipboard_type, &rtf);
return WebString::fromLatin1(rtf);
}
WebBlobInfo WebClipboardImpl::readImage(Buffer buffer) { WebBlobInfo WebClipboardImpl::readImage(Buffer buffer) {
ui::ClipboardType clipboard_type; ui::ClipboardType clipboard_type;
if (!ConvertBufferType(buffer, &clipboard_type)) if (!ConvertBufferType(buffer, &clipboard_type))
......
...@@ -33,6 +33,7 @@ class WebClipboardImpl : public blink::WebClipboard { ...@@ -33,6 +33,7 @@ class WebClipboardImpl : public blink::WebClipboard {
blink::WebURL* source_url, blink::WebURL* source_url,
unsigned* fragment_start, unsigned* fragment_start,
unsigned* fragment_end) override; unsigned* fragment_end) override;
blink::WebString readRTF(Buffer buffer) override;
blink::WebBlobInfo readImage(Buffer buffer) override; blink::WebBlobInfo readImage(Buffer buffer) override;
blink::WebString readCustomData(Buffer buffer, blink::WebString readCustomData(Buffer buffer,
const blink::WebString& type) override; const blink::WebString& type) override;
......
// Copyright 2016 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/renderer/webclipboard_impl.h"
#include "base/strings/utf_string_conversions.h"
#include "content/public/browser/web_contents.h"
#include "content/public/test/browser_test_utils.h"
#include "content/public/test/content_browser_test.h"
#include "content/public/test/content_browser_test_utils.h"
#include "content/shell/browser/shell.h"
namespace content {
namespace {
class WebClipboardImplTest : public ContentBrowserTest {
public:
WebClipboardImplTest() = default;
~WebClipboardImplTest() override = default;
};
IN_PROC_BROWSER_TEST_F(WebClipboardImplTest, PasteRTF) {
BrowserTestClipboardScope clipboard;
const std::string rtf_content = "{\\rtf1\\ansi Hello, {\\b world.}}";
clipboard.SetRtf(rtf_content);
// paste_listener.html takes RTF from the clipboard and sets the title.
NavigateToURL(shell(), GetTestUrl(".", "paste_listener.html"));
const base::string16 expected_title = base::UTF8ToUTF16(rtf_content);
content::TitleWatcher title_watcher(shell()->web_contents(), expected_title);
shell()->web_contents()->Paste();
EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
}
}
} // namespace content
<title>Waiting for paste</title>
<body>
<script>
document.body.contentEditable = true;
document.body.addEventListener('paste', (event) => {
Array.prototype.forEach.call(event.clipboardData.items, (item) => {
if (item.type != 'text/rtf') {
return;
}
item.getAsString((s) => {
document.title = s;
});
});
});
</script>
...@@ -139,6 +139,8 @@ String DataObjectItem::getAsString() const ...@@ -139,6 +139,8 @@ String DataObjectItem::getAsString() const
// This is ugly but there's no real alternative. // This is ugly but there's no real alternative.
if (m_type == mimeTypeTextPlain) { if (m_type == mimeTypeTextPlain) {
data = Platform::current()->clipboard()->readPlainText(buffer); data = Platform::current()->clipboard()->readPlainText(buffer);
} else if (m_type == mimeTypeTextRTF) {
data = Platform::current()->clipboard()->readRTF(buffer);
} else if (m_type == mimeTypeTextHTML) { } else if (m_type == mimeTypeTextHTML) {
WebURL ignoredSourceURL; WebURL ignoredSourceURL;
unsigned ignored; unsigned ignored;
......
...@@ -36,6 +36,7 @@ const char mimeTypeText[] = "text"; ...@@ -36,6 +36,7 @@ const char mimeTypeText[] = "text";
const char mimeTypeTextPlain[] = "text/plain"; const char mimeTypeTextPlain[] = "text/plain";
const char mimeTypeTextPlainEtc[] = "text/plain;"; const char mimeTypeTextPlainEtc[] = "text/plain;";
const char mimeTypeTextHTML[] = "text/html"; const char mimeTypeTextHTML[] = "text/html";
const char mimeTypeTextRTF[] = "text/rtf";
const char mimeTypeURL[] = "url"; const char mimeTypeURL[] = "url";
const char mimeTypeTextURIList[] = "text/uri-list"; const char mimeTypeTextURIList[] = "text/uri-list";
const char mimeTypeDownloadURL[] = "downloadurl"; const char mimeTypeDownloadURL[] = "downloadurl";
......
...@@ -39,6 +39,7 @@ PLATFORM_EXPORT extern const char mimeTypeText[]; ...@@ -39,6 +39,7 @@ PLATFORM_EXPORT extern const char mimeTypeText[];
PLATFORM_EXPORT extern const char mimeTypeTextPlain[]; PLATFORM_EXPORT extern const char mimeTypeTextPlain[];
PLATFORM_EXPORT extern const char mimeTypeTextPlainEtc[]; PLATFORM_EXPORT extern const char mimeTypeTextPlainEtc[];
PLATFORM_EXPORT extern const char mimeTypeTextHTML[]; PLATFORM_EXPORT extern const char mimeTypeTextHTML[];
PLATFORM_EXPORT extern const char mimeTypeTextRTF[];
PLATFORM_EXPORT extern const char mimeTypeURL[]; PLATFORM_EXPORT extern const char mimeTypeURL[];
PLATFORM_EXPORT extern const char mimeTypeTextURIList[]; PLATFORM_EXPORT extern const char mimeTypeTextURIList[];
PLATFORM_EXPORT extern const char mimeTypeDownloadURL[]; PLATFORM_EXPORT extern const char mimeTypeDownloadURL[];
......
...@@ -77,6 +77,7 @@ public: ...@@ -77,6 +77,7 @@ public:
virtual WebString readHTML( virtual WebString readHTML(
Buffer buffer, WebURL* pageURL, unsigned* fragmentStart, Buffer buffer, WebURL* pageURL, unsigned* fragmentStart,
unsigned* fragmentEnd) { return WebString(); } unsigned* fragmentEnd) { return WebString(); }
virtual WebString readRTF(Buffer) { return WebString(); }
virtual WebBlobInfo readImage(Buffer) { return WebBlobInfo(); } virtual WebBlobInfo readImage(Buffer) { return WebBlobInfo(); }
virtual WebString readCustomData( virtual WebString readCustomData(
Buffer, const WebString& type) { return WebString(); } Buffer, const WebString& type) { return WebString(); }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment