Raw Clipboard: Implement read.

Implement Raw Clipboard interface for reading arbitrary data. Also,
implements mock interfaces for automated content_shell/WPT tests.

The browser-side change is more simple than the equivalent Raw Write and
Raw Format CLs due to platform-specific code already being handled in
ui::Clipboard::read().

The Raw Clipboard API is only accessible if the user turns on the
Raw Clipboard feature flag, and explicitly provides permission via
permission prompt. These checks are contained in both the browser and
renderer.

Design Doc: https://tinyurl.com/raw-clipboard-access-design

Bug: 897289
Change-Id: Ic5a778cf4c6421ea15bf44faebf08d23e3b39b5b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2107156
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Reviewed-by: Victor Costan <pwnall@chromium.org>
Commit-Queue: Darwin Huang <huangdarwin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#766694}
diff --git a/clipboard-apis/async-platform-specific-write-read.tentative.https.html b/clipboard-apis/async-platform-specific-write-read.tentative.https.html
new file mode 100644
index 0000000..c1e8323
--- /dev/null
+++ b/clipboard-apis/async-platform-specific-write-read.tentative.https.html
@@ -0,0 +1,67 @@
+<!doctype html>
+<meta charset="utf-8">
+<title>Async Clipboard raw platform-specific write -> read tests</title>
+<link rel="help" href="https://w3c.github.io/clipboard-apis/#async-clipboard-api">
+<script src="/resources/testharness.js"></script>
+<script src="/resources/testharnessreport.js"></script>
+<script>
+'use strict';
+
+async function rawWriteBeforeTest() {
+  const format = 'RawClipboardDisabledFormat';
+  const blob = new Blob(['RawClipboardDisabled'], {type: format});
+  const clipboardItem = new ClipboardItem({[format]: blob}, {raw: true});
+  await navigator.clipboard.write([clipboardItem]);
+}
+
+function platformFormat() {
+  if(navigator.platform.includes('Win'))
+    return 'CF_TEXT';
+  if(navigator.platform.includes('Linux'))
+    return 'text/plain';
+  return 'PlatformNeutralFormat';
+}
+
+// Writes a payload with platform-specific content and checks to ensure the
+// correct data was written successfully.
+promise_test(async t => {
+  // This extra raw write is used to create consistency in the error message
+  // when the RawClipboard flag isn't enabled.
+  // TODO(https://crbug.com/897289): Remove this after RawClipboard is enabled
+  // by default.
+  await rawWriteBeforeTest();
+  const dataToWrite = 'Test text.';
+  const format = platformFormat();
+
+  const blobInput = new Blob([dataToWrite], {type: format});
+  // Blob types are automatically converted to lower-case.
+  assert_equals(blobInput.type, format.toLowerCase());
+  const clipboardItemInput = new ClipboardItem(
+      {[format]: blobInput}, {raw: true});
+  await navigator.clipboard.write([clipboardItemInput]);
+
+  // Items should be readable on a raw clipboard after raw write.
+  const clipboardItems = await navigator.clipboard.read({raw: true});
+  assert_equals(clipboardItems.length, 1);
+  const clipboardItem = clipboardItems[0];
+  assert_true(clipboardItem instanceof ClipboardItem);
+
+  const blobOutput = await clipboardItem.getType(format);
+  assert_equals(blobOutput.type, format);
+  const data = await (new Response(blobOutput)).text();
+  assert_equals(data, dataToWrite);
+
+  if(format === 'PlatformNeutralFormat')
+    return;
+  // These examples use native text formats, so these formats should be
+  // accessible as text.
+  const textOutput = await navigator.clipboard.readText();
+  assert_equals(textOutput, dataToWrite);
+
+}, 'Verify write and read clipboard given platform-specific raw input');
+</script>
+<p>
+  Note: This is a manual test because it writes/reads to the shared system
+  clipboard and thus cannot be run async with other tests that might interact
+  with the clipboard.
+</p>
diff --git a/clipboard-apis/async-raw-write-read.tentative.https.html b/clipboard-apis/async-raw-write-read.tentative.https.html
index a6889d6..bd11a7f 100644
--- a/clipboard-apis/async-raw-write-read.tentative.https.html
+++ b/clipboard-apis/async-raw-write-read.tentative.https.html
@@ -1,23 +1,47 @@
 <!doctype html>
 <meta charset="utf-8">
-<title> Async Clipboard raw write -> Async Clipboard raw read tests </title>
+<title>Async Clipboard raw write -> Async Clipboard raw read test</title>
 <link rel="help" href="https://w3c.github.io/clipboard-apis/#async-clipboard-api">
 <script src="/resources/testharness.js"></script>
 <script src="/resources/testharnessreport.js"></script>
 <script>
-async function readWriteTest(rawInput) {
-  promise_test(async t => {
-    const blobInput = new Blob([rawInput], {type: 'chromium/x-test-format'});
-    const clipboardItem = new ClipboardItem(
-        {'chromium/x-test-format': blobInput}, {raw: true});
+'use strict';
 
-    await navigator.clipboard.write([clipboardItem]);
-    // TODO(https://crbug.com/897289): Implement raw clipboard read.
+// TODO(huangdarwin): Move raw clipboard tests/expectations into a separate
+// folder (in a follow-up CL, to aid in easier reviewing of diffs).
+promise_test(async t => {
+  const format1 = 'application/x-raw-clipboard-test-format-1';
+  const format2 = 'application/x-raw-clipboard-test-format-2';
+  const blobInput1 = new Blob(['input data 1'], {type: format1});
+  const blobInput2 = new Blob(['input data 2'], {type: format2});
+  const clipboardItemInput = new ClipboardItem(
+      {[format1]: blobInput1, [format2]: blobInput2}, {raw: true});
+  await navigator.clipboard.write([clipboardItemInput]);
 
-  }, 'Verify write and read clipboard given arbitrary raw input: ' + rawInput);
-}
+  // Items may not be readable on the sanitized clipboard after raw write.
+  await promise_rejects_dom(t, 'DataError',
+      navigator.clipboard.read({raw: false}));
 
-readWriteTest('Async Clipboard raw write -> Async Clipboard raw read tests');
+  // Items should be readable on a raw clipboard after raw write.
+  const clipboardItems = await navigator.clipboard.read({raw: true});
+  assert_equals(clipboardItems.length, 1);
+  const clipboardItem = clipboardItems[0];
+  assert_true(clipboardItem instanceof ClipboardItem);
+  // This test can't verify clipboardItem.types, because its size and values
+  // are both platform-dependent.
+
+  const blobOutput1 = await clipboardItem.getType(format1);
+  assert_equals(blobOutput1.type, format1);
+  const data1 = await (new Response(blobOutput1)).text();
+  assert_equals(data1, 'input data 1');
+
+  const blobOutput2 = await clipboardItem.getType(format2);
+  assert_equals(blobOutput2.type, format2);
+  const data2 = await (new Response(blobOutput2)).text();
+  assert_equals(data2, 'input data 2');
+
+}, 'Verify write and read clipboard given 2 platform-neutral raw inputs');
+
 </script>
 <p>
   Note: This is a manual test because it writes/reads to the shared system