blob: d03d9e8b3e0ce5b6b5e317277453b9306325fe86 [file] [log] [blame]
[email protected]57118ea2020-07-17 03:17:141// Copyright 2020 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/ui/ash/clipboard_util.h"
6
[email protected]026b7c4f2020-10-27 12:05:217#include <stdint.h>
8#include <memory>
9
Alex Newcomer9fd616332021-01-15 23:04:5810#include "ash/public/cpp/clipboard_history_controller.h"
[email protected]57118ea2020-07-17 03:17:1411#include "base/base64.h"
[email protected]026b7c4f2020-10-27 12:05:2112#include "base/callback.h"
[email protected]57118ea2020-07-17 03:17:1413#include "base/files/file_util.h"
14#include "base/memory/ref_counted_memory.h"
[email protected]026b7c4f2020-10-27 12:05:2115#include "base/memory/scoped_refptr.h"
[email protected]57118ea2020-07-17 03:17:1416#include "base/metrics/user_metrics.h"
Lei Zhang2b7c9e02020-09-25 21:30:4717#include "base/strings/strcat.h"
[email protected]57118ea2020-07-17 03:17:1418#include "base/threading/scoped_blocking_call.h"
19#include "content/public/browser/browser_task_traits.h"
20#include "content/public/browser/browser_thread.h"
21#include "services/data_decoder/public/cpp/decode_image.h"
22#include "ui/base/clipboard/clipboard.h"
[email protected]026b7c4f2020-10-27 12:05:2123#include "ui/base/clipboard/clipboard_buffer.h"
24#include "ui/base/clipboard/clipboard_data.h"
25#include "ui/base/clipboard/clipboard_non_backed.h"
[email protected]57118ea2020-07-17 03:17:1426#include "ui/base/clipboard/scoped_clipboard_writer.h"
27
28namespace clipboard_util {
29namespace {
30
[email protected]026b7c4f2020-10-27 12:05:2131void CopyAndMaintainClipboard(
32 std::unique_ptr<ui::ClipboardData> data_with_image,
33 const std::string& markup_content,
34 scoped_refptr<base::RefCountedString> png_data,
35 const SkBitmap& decoded_image) {
[email protected]57118ea2020-07-17 03:17:1436 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
37
[email protected]026b7c4f2020-10-27 12:05:2138 data_with_image->set_markup_data(markup_content);
39 data_with_image->SetBitmapData(decoded_image);
40 ui::ClipboardNonBacked::GetForCurrentThread()->WriteClipboardData(
41 std::move(data_with_image));
42}
43
44/*
45 * `maintain_clipboard` indicates whether the clipboard state should attempt to
46 * be maintained.
47 * `clipboard_sequence` is the versioning of the clipboard when we start our
48 * copy operation.
49 * `callback` alerts whether or not the image was copied to the clipboard while
50 * meeting the `maintain_clipboard` state. If the image is copied it will return
51 * true, otherwise if the image is not copied because the `clipboard_sequence`
52 * does not match, it will return false.
53 * `decoded_image` is the image we are attempting to copy to the clipboard.
54 */
55void CopyImageToClipboard(bool maintain_clipboard,
56 uint64_t clipboard_sequence,
57 base::OnceCallback<void(bool)> callback,
58 scoped_refptr<base::RefCountedString> png_data,
59 const SkBitmap& decoded_image) {
60 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
[email protected]57118ea2020-07-17 03:17:1461
Lei Zhang2b7c9e02020-09-25 21:30:4762 // Send both HTML and and Image formats to clipboard. HTML format is needed
63 // by ARC, while Image is needed by Hangout.
64 static const char kImageClipboardFormatPrefix[] =
65 "<img src='data:image/png;base64,";
66 static const char kImageClipboardFormatSuffix[] = "'>";
67
68 std::string encoded =
69 base::Base64Encode(base::as_bytes(base::make_span(png_data->data())));
70 std::string html = base::StrCat(
71 {kImageClipboardFormatPrefix, encoded, kImageClipboardFormatSuffix});
[email protected]026b7c4f2020-10-27 12:05:2172
[email protected]5754c662020-11-18 01:16:5173 if (!maintain_clipboard ||
74 !ui::ClipboardNonBacked::GetForCurrentThread()->GetClipboardData(
75 nullptr)) {
[email protected]026b7c4f2020-10-27 12:05:2176 ui::ScopedClipboardWriter clipboard_writer(ui::ClipboardBuffer::kCopyPaste);
77 clipboard_writer.WriteHTML(base::UTF8ToUTF16(html), std::string());
78 clipboard_writer.WriteImage(decoded_image);
79 std::move(callback).Run(true);
80 return;
81 }
82
83 uint64_t current_sequence =
84 ui::ClipboardNonBacked::GetForCurrentThread()->GetSequenceNumber(
85 ui::ClipboardBuffer::kCopyPaste);
86 if (current_sequence != clipboard_sequence) {
87 // Clipboard data changed and this copy operation is no longer relevant.
88 std::move(callback).Run(false);
89 return;
90 }
91 std::unique_ptr<ui::ClipboardData> current_data =
92 std::make_unique<ui::ClipboardData>(
93 *ui::ClipboardNonBacked::GetForCurrentThread()->GetClipboardData(
94 nullptr));
Alex Newcomer9fd616332021-01-15 23:04:5895
96 // Before modifying the clipboard, remove the old entry in ClipboardHistory.
97 // CopyAndMaintainClipboard will write to the clipboard a second time,
98 // creating a new entry in clipboard history.
99 ash::ClipboardHistoryController::Get()->DeleteClipboardItemByClipboardData(
100 current_data.get());
[email protected]026b7c4f2020-10-27 12:05:21101 CopyAndMaintainClipboard(std::move(current_data), html, png_data,
102 decoded_image);
103 std::move(callback).Run(true);
[email protected]57118ea2020-07-17 03:17:14104}
105
[email protected]57118ea2020-07-17 03:17:14106} // namespace
107
108void ReadFileAndCopyToClipboardLocal(const base::FilePath& local_file) {
109 DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
110 base::ScopedBlockingCall scoped_blocking_call(FROM_HERE,
111 base::BlockingType::WILL_BLOCK);
Lei Zhang2b7c9e02020-09-25 21:30:47112 auto png_data = base::MakeRefCounted<base::RefCountedString>();
[email protected]57118ea2020-07-17 03:17:14113 if (!base::ReadFileToString(local_file, &(png_data->data()))) {
114 LOG(ERROR) << "Failed to read the screenshot file: " << local_file.value();
115 return;
116 }
117
118 content::GetUIThreadTaskRunner({})->PostTask(
[email protected]026b7c4f2020-10-27 12:05:21119 FROM_HERE, base::BindOnce(&DecodeImageFileAndCopyToClipboard,
120 /*clipboard_sequence=*/0,
121 /*maintain_clipboard=*/false, png_data,
122 base::DoNothing::Once<bool>()));
[email protected]2ae4df182020-08-27 16:48:09123}
124
125void DecodeImageFileAndCopyToClipboard(
[email protected]026b7c4f2020-10-27 12:05:21126 uint64_t clipboard_sequence,
127 bool maintain_clipboard,
128 scoped_refptr<base::RefCountedString> png_data,
129 base::OnceCallback<void(bool)> callback) {
[email protected]2ae4df182020-08-27 16:48:09130 DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
131
132 // Decode the image in sandboxed process because |png_data| comes from
133 // external storage.
134 data_decoder::DecodeImageIsolated(
135 std::vector<uint8_t>(png_data->data().begin(), png_data->data().end()),
136 data_decoder::mojom::ImageCodec::DEFAULT, false,
137 data_decoder::kDefaultMaxSizeInBytes, gfx::Size(),
[email protected]026b7c4f2020-10-27 12:05:21138 base::BindOnce(&CopyImageToClipboard, maintain_clipboard,
139 clipboard_sequence, std::move(callback), png_data));
[email protected]57118ea2020-07-17 03:17:14140}
141} // namespace clipboard_util