1 // Copyright 2017 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 "headless/lib/browser/headless_clipboard.h"
6 
7 #include "base/memory/ptr_util.h"
8 #include "base/numerics/safe_conversions.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "ui/base/clipboard/clipboard_constants.h"
11 
12 namespace headless {
13 
HeadlessClipboard()14 HeadlessClipboard::HeadlessClipboard()
15     : default_store_buffer_(ui::ClipboardBuffer::kCopyPaste) {}
16 
17 HeadlessClipboard::~HeadlessClipboard() = default;
18 
OnPreShutdown()19 void HeadlessClipboard::OnPreShutdown() {}
20 
GetSequenceNumber(ui::ClipboardBuffer buffer) const21 uint64_t HeadlessClipboard::GetSequenceNumber(
22     ui::ClipboardBuffer buffer) const {
23   return GetStore(buffer).sequence_number;
24 }
25 
IsFormatAvailable(const ui::ClipboardFormatType & format,ui::ClipboardBuffer buffer) const26 bool HeadlessClipboard::IsFormatAvailable(const ui::ClipboardFormatType& format,
27                                           ui::ClipboardBuffer buffer) const {
28   return base::Contains(GetStore(buffer).data, format);
29 }
30 
Clear(ui::ClipboardBuffer buffer)31 void HeadlessClipboard::Clear(ui::ClipboardBuffer buffer) {
32   GetStore(buffer).Clear();
33 }
34 
ReadAvailableTypes(ui::ClipboardBuffer buffer,std::vector<base::string16> * types,bool * contains_filenames) const35 void HeadlessClipboard::ReadAvailableTypes(ui::ClipboardBuffer buffer,
36                                            std::vector<base::string16>* types,
37                                            bool* contains_filenames) const {
38   types->clear();
39 
40   if (IsFormatAvailable(ui::ClipboardFormatType::GetPlainTextType(), buffer))
41     types->push_back(base::UTF8ToUTF16(ui::kMimeTypeText));
42   if (IsFormatAvailable(ui::ClipboardFormatType::GetHtmlType(), buffer))
43     types->push_back(base::UTF8ToUTF16(ui::kMimeTypeHTML));
44 
45   if (IsFormatAvailable(ui::ClipboardFormatType::GetRtfType(), buffer))
46     types->push_back(base::UTF8ToUTF16(ui::kMimeTypeRTF));
47   if (IsFormatAvailable(ui::ClipboardFormatType::GetBitmapType(), buffer))
48     types->push_back(base::UTF8ToUTF16(ui::kMimeTypePNG));
49 
50   *contains_filenames = false;
51 }
52 
53 std::vector<base::string16>
ReadAvailablePlatformSpecificFormatNames(ui::ClipboardBuffer buffer) const54 HeadlessClipboard::ReadAvailablePlatformSpecificFormatNames(
55     ui::ClipboardBuffer buffer) const {
56   const auto& data = GetStore(buffer).data;
57   std::vector<base::string16> types;
58   types.reserve(data.size());
59   for (const auto& it : data) {
60     base::string16 type = base::UTF8ToUTF16(it.first.GetName());
61     types.push_back(type);
62   }
63 
64   return types;
65 }
66 
ReadText(ui::ClipboardBuffer buffer,base::string16 * result) const67 void HeadlessClipboard::ReadText(ui::ClipboardBuffer buffer,
68                                  base::string16* result) const {
69   std::string result8;
70   ReadAsciiText(buffer, &result8);
71   *result = base::UTF8ToUTF16(result8);
72 }
73 
ReadAsciiText(ui::ClipboardBuffer buffer,std::string * result) const74 void HeadlessClipboard::ReadAsciiText(ui::ClipboardBuffer buffer,
75                                       std::string* result) const {
76   result->clear();
77   const DataStore& store = GetStore(buffer);
78   auto it = store.data.find(ui::ClipboardFormatType::GetPlainTextType());
79   if (it != store.data.end())
80     *result = it->second;
81 }
82 
ReadHTML(ui::ClipboardBuffer buffer,base::string16 * markup,std::string * src_url,uint32_t * fragment_start,uint32_t * fragment_end) const83 void HeadlessClipboard::ReadHTML(ui::ClipboardBuffer buffer,
84                                  base::string16* markup,
85                                  std::string* src_url,
86                                  uint32_t* fragment_start,
87                                  uint32_t* fragment_end) const {
88   markup->clear();
89   src_url->clear();
90   const DataStore& store = GetStore(buffer);
91   auto it = store.data.find(ui::ClipboardFormatType::GetHtmlType());
92   if (it != store.data.end())
93     *markup = base::UTF8ToUTF16(it->second);
94   *src_url = store.html_src_url;
95   *fragment_start = 0;
96   *fragment_end = base::checked_cast<uint32_t>(markup->size());
97 }
98 
ReadRTF(ui::ClipboardBuffer buffer,std::string * result) const99 void HeadlessClipboard::ReadRTF(ui::ClipboardBuffer buffer,
100                                 std::string* result) const {
101   result->clear();
102   const DataStore& store = GetStore(buffer);
103   auto it = store.data.find(ui::ClipboardFormatType::GetRtfType());
104   if (it != store.data.end())
105     *result = it->second;
106 }
107 
ReadImage(ui::ClipboardBuffer buffer,ReadImageCallback callback) const108 void HeadlessClipboard::ReadImage(ui::ClipboardBuffer buffer,
109                                   ReadImageCallback callback) const {
110   std::move(callback).Run(GetStore(buffer).image);
111 }
112 
ReadCustomData(ui::ClipboardBuffer clipboard_buffer,const base::string16 & type,base::string16 * result) const113 void HeadlessClipboard::ReadCustomData(ui::ClipboardBuffer clipboard_buffer,
114                                        const base::string16& type,
115                                        base::string16* result) const {}
116 
ReadBookmark(base::string16 * title,std::string * url) const117 void HeadlessClipboard::ReadBookmark(base::string16* title,
118                                      std::string* url) const {
119   const DataStore& store = GetDefaultStore();
120   auto it = store.data.find(ui::ClipboardFormatType::GetUrlType());
121   if (it != store.data.end())
122     *url = it->second;
123   *title = base::UTF8ToUTF16(store.url_title);
124 }
125 
ReadData(const ui::ClipboardFormatType & format,std::string * result) const126 void HeadlessClipboard::ReadData(const ui::ClipboardFormatType& format,
127                                  std::string* result) const {
128   result->clear();
129   const DataStore& store = GetDefaultStore();
130   auto it = store.data.find(format);
131   if (it != store.data.end())
132     *result = it->second;
133 }
134 
WritePortableRepresentations(ui::ClipboardBuffer buffer,const ObjectMap & objects)135 void HeadlessClipboard::WritePortableRepresentations(ui::ClipboardBuffer buffer,
136                                                      const ObjectMap& objects) {
137   Clear(buffer);
138   default_store_buffer_ = buffer;
139   for (const auto& kv : objects)
140     DispatchPortableRepresentation(kv.first, kv.second);
141   default_store_buffer_ = ui::ClipboardBuffer::kCopyPaste;
142 }
143 
WritePlatformRepresentations(ui::ClipboardBuffer buffer,std::vector<Clipboard::PlatformRepresentation> platform_representations)144 void HeadlessClipboard::WritePlatformRepresentations(
145     ui::ClipboardBuffer buffer,
146     std::vector<Clipboard::PlatformRepresentation> platform_representations) {
147   Clear(buffer);
148   default_store_buffer_ = buffer;
149   DispatchPlatformRepresentations(std::move(platform_representations));
150   default_store_buffer_ = ui::ClipboardBuffer::kCopyPaste;
151 }
152 
WriteText(const char * text_data,size_t text_len)153 void HeadlessClipboard::WriteText(const char* text_data, size_t text_len) {
154   std::string text(text_data, text_len);
155   GetDefaultStore().data[ui::ClipboardFormatType::GetPlainTextType()] = text;
156   if (IsSupportedClipboardBuffer(ui::ClipboardBuffer::kSelection)) {
157     GetStore(ui::ClipboardBuffer::kSelection)
158         .data[ui::ClipboardFormatType::GetPlainTextType()] = text;
159   }
160 }
161 
WriteHTML(const char * markup_data,size_t markup_len,const char * url_data,size_t url_len)162 void HeadlessClipboard::WriteHTML(const char* markup_data,
163                                   size_t markup_len,
164                                   const char* url_data,
165                                   size_t url_len) {
166   base::string16 markup;
167   base::UTF8ToUTF16(markup_data, markup_len, &markup);
168   GetDefaultStore().data[ui::ClipboardFormatType::GetHtmlType()] =
169       base::UTF16ToUTF8(markup);
170   GetDefaultStore().html_src_url = std::string(url_data, url_len);
171 }
172 
WriteRTF(const char * rtf_data,size_t data_len)173 void HeadlessClipboard::WriteRTF(const char* rtf_data, size_t data_len) {
174   GetDefaultStore().data[ui::ClipboardFormatType::GetRtfType()] =
175       std::string(rtf_data, data_len);
176 }
177 
WriteBookmark(const char * title_data,size_t title_len,const char * url_data,size_t url_len)178 void HeadlessClipboard::WriteBookmark(const char* title_data,
179                                       size_t title_len,
180                                       const char* url_data,
181                                       size_t url_len) {
182   GetDefaultStore().data[ui::ClipboardFormatType::GetUrlType()] =
183       std::string(url_data, url_len);
184   GetDefaultStore().url_title = std::string(title_data, title_len);
185 }
186 
WriteWebSmartPaste()187 void HeadlessClipboard::WriteWebSmartPaste() {
188   // Create a dummy entry.
189   GetDefaultStore().data[ui::ClipboardFormatType::GetWebKitSmartPasteType()];
190 }
191 
WriteBitmap(const SkBitmap & bitmap)192 void HeadlessClipboard::WriteBitmap(const SkBitmap& bitmap) {
193   // Create a dummy entry.
194   GetDefaultStore().data[ui::ClipboardFormatType::GetBitmapType()];
195   SkBitmap& dst = GetDefaultStore().image;
196   if (dst.tryAllocPixels(bitmap.info())) {
197     bitmap.readPixels(dst.info(), dst.getPixels(), dst.rowBytes(), 0, 0);
198   }
199 }
200 
WriteData(const ui::ClipboardFormatType & format,const char * data_data,size_t data_len)201 void HeadlessClipboard::WriteData(const ui::ClipboardFormatType& format,
202                                   const char* data_data,
203                                   size_t data_len) {
204   GetDefaultStore().data[format] = std::string(data_data, data_len);
205 }
206 
DataStore()207 HeadlessClipboard::DataStore::DataStore() : sequence_number(0) {}
208 
209 HeadlessClipboard::DataStore::DataStore(const DataStore& other) = default;
210 
211 HeadlessClipboard::DataStore::~DataStore() = default;
212 
Clear()213 void HeadlessClipboard::DataStore::Clear() {
214   data.clear();
215   url_title.clear();
216   html_src_url.clear();
217   image = SkBitmap();
218 }
219 
GetStore(ui::ClipboardBuffer buffer) const220 const HeadlessClipboard::DataStore& HeadlessClipboard::GetStore(
221     ui::ClipboardBuffer buffer) const {
222   CHECK(IsSupportedClipboardBuffer(buffer));
223   return stores_[buffer];
224 }
225 
GetStore(ui::ClipboardBuffer buffer)226 HeadlessClipboard::DataStore& HeadlessClipboard::GetStore(
227     ui::ClipboardBuffer buffer) {
228   CHECK(IsSupportedClipboardBuffer(buffer));
229   DataStore& store = stores_[buffer];
230   ++store.sequence_number;
231   return store;
232 }
233 
GetDefaultStore() const234 const HeadlessClipboard::DataStore& HeadlessClipboard::GetDefaultStore() const {
235   return GetStore(default_store_buffer_);
236 }
237 
GetDefaultStore()238 HeadlessClipboard::DataStore& HeadlessClipboard::GetDefaultStore() {
239   return GetStore(default_store_buffer_);
240 }
241 
242 }  // namespace headless
243