| OLD | NEW |
| (Empty) |
| 1 // Copyright 2016 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 "ui/views/mus/os_exchange_data_provider_mus.h" | |
| 6 | |
| 7 #include <memory> | |
| 8 #include <string> | |
| 9 #include <utility> | |
| 10 #include <vector> | |
| 11 | |
| 12 #include "base/stl_util.h" | |
| 13 #include "base/strings/string_split.h" | |
| 14 #include "base/strings/string_util.h" | |
| 15 #include "base/strings/utf_string_conversions.h" | |
| 16 #include "mojo/common/common_type_converters.h" | |
| 17 #include "net/base/filename_util.h" | |
| 18 #include "services/ui/public/interfaces/clipboard.mojom.h" | |
| 19 #include "ui/base/dragdrop/file_info.h" | |
| 20 #include "url/gurl.h" | |
| 21 | |
| 22 namespace views { | |
| 23 | |
| 24 namespace { | |
| 25 | |
| 26 std::vector<uint8_t> FromString(const std::string& str) { | |
| 27 return std::vector<uint8_t>(str.begin(), str.end()); | |
| 28 } | |
| 29 | |
| 30 std::string ToString(const std::vector<uint8_t>& v) { | |
| 31 return std::string(v.begin(), v.end()); | |
| 32 } | |
| 33 | |
| 34 base::string16 ToString16(const std::vector<uint8_t>& v) { | |
| 35 DCHECK_EQ(0u, v.size() % 2); | |
| 36 return base::string16( | |
| 37 reinterpret_cast<const base::char16*>(v.data()), | |
| 38 v.size() / 2); | |
| 39 } | |
| 40 | |
| 41 std::vector<base::StringPiece> ParseURIList(const std::vector<uint8_t>& data) { | |
| 42 return base::SplitStringPiece( | |
| 43 base::StringPiece( | |
| 44 reinterpret_cast<const char*>(&data.front()), data.size()), | |
| 45 "\n", | |
| 46 base::KEEP_WHITESPACE, base::SPLIT_WANT_NONEMPTY); | |
| 47 } | |
| 48 | |
| 49 void AddString16ToVector(const base::string16& str, | |
| 50 std::vector<uint8_t>* bytes) { | |
| 51 const unsigned char* front = | |
| 52 reinterpret_cast<const uint8_t*>(str.data()); | |
| 53 bytes->insert(bytes->end(), front, front + (str.size() * 2)); | |
| 54 } | |
| 55 | |
| 56 } // namespace | |
| 57 | |
| 58 OSExchangeDataProviderMus::OSExchangeDataProviderMus() {} | |
| 59 | |
| 60 OSExchangeDataProviderMus::OSExchangeDataProviderMus(Data data) | |
| 61 : mime_data_(std::move(data)) {} | |
| 62 | |
| 63 OSExchangeDataProviderMus::~OSExchangeDataProviderMus() {} | |
| 64 | |
| 65 OSExchangeDataProviderMus::Data OSExchangeDataProviderMus::GetData() const { | |
| 66 return mime_data_; | |
| 67 } | |
| 68 | |
| 69 std::unique_ptr<ui::OSExchangeData::Provider> | |
| 70 OSExchangeDataProviderMus::Clone() const { | |
| 71 std::unique_ptr<OSExchangeDataProviderMus> r = | |
| 72 base::MakeUnique<OSExchangeDataProviderMus>(); | |
| 73 r->drag_image_ = drag_image_; | |
| 74 r->drag_image_offset_ = drag_image_offset_; | |
| 75 r->mime_data_ = mime_data_; | |
| 76 return base::WrapUnique<ui::OSExchangeData::Provider>(r.release()); | |
| 77 } | |
| 78 | |
| 79 void OSExchangeDataProviderMus::MarkOriginatedFromRenderer() { | |
| 80 // Currently unimplemented because ChromeOS doesn't need this. | |
| 81 // | |
| 82 // TODO(erg): Implement this when we start porting mus to other platforms. | |
| 83 } | |
| 84 | |
| 85 bool OSExchangeDataProviderMus::DidOriginateFromRenderer() const { | |
| 86 return false; | |
| 87 } | |
| 88 | |
| 89 void OSExchangeDataProviderMus::SetString(const base::string16& data) { | |
| 90 if (HasString()) | |
| 91 return; | |
| 92 | |
| 93 mime_data_[ui::mojom::kMimeTypeText] = FromString(base::UTF16ToUTF8(data)); | |
| 94 } | |
| 95 | |
| 96 void OSExchangeDataProviderMus::SetURL(const GURL& url, | |
| 97 const base::string16& title) { | |
| 98 base::string16 spec = base::UTF8ToUTF16(url.spec()); | |
| 99 std::vector<unsigned char> data; | |
| 100 AddString16ToVector(spec, &data); | |
| 101 AddString16ToVector(base::ASCIIToUTF16("\n"), &data); | |
| 102 AddString16ToVector(title, &data); | |
| 103 mime_data_[ui::mojom::kMimeTypeMozillaURL] = std::move(data); | |
| 104 | |
| 105 if (!base::ContainsKey(mime_data_, ui::mojom::kMimeTypeText)) | |
| 106 mime_data_[ui::mojom::kMimeTypeText] = FromString(url.spec()); | |
| 107 } | |
| 108 | |
| 109 void OSExchangeDataProviderMus::SetFilename(const base::FilePath& path) { | |
| 110 std::vector<ui::FileInfo> data; | |
| 111 data.push_back(ui::FileInfo(path, base::FilePath())); | |
| 112 SetFilenames(data); | |
| 113 } | |
| 114 | |
| 115 void OSExchangeDataProviderMus::SetFilenames( | |
| 116 const std::vector<ui::FileInfo>& file_names) { | |
| 117 std::vector<std::string> paths; | |
| 118 for (std::vector<ui::FileInfo>::const_iterator it = file_names.begin(); | |
| 119 it != file_names.end(); | |
| 120 ++it) { | |
| 121 std::string url_spec = net::FilePathToFileURL(it->path).spec(); | |
| 122 if (!url_spec.empty()) | |
| 123 paths.push_back(url_spec); | |
| 124 } | |
| 125 | |
| 126 std::string joined_data = base::JoinString(paths, "\n"); | |
| 127 mime_data_[ui::mojom::kMimeTypeURIList] = FromString(joined_data); | |
| 128 } | |
| 129 | |
| 130 void OSExchangeDataProviderMus::SetPickledData( | |
| 131 const ui::Clipboard::FormatType& format, | |
| 132 const base::Pickle& pickle) { | |
| 133 const unsigned char* bytes = | |
| 134 reinterpret_cast<const unsigned char*>(pickle.data()); | |
| 135 | |
| 136 mime_data_[format.Serialize()] = mojo::Array<uint8_t>( | |
| 137 std::vector<uint8_t>(bytes, bytes + pickle.size())); | |
| 138 } | |
| 139 | |
| 140 bool OSExchangeDataProviderMus::GetString(base::string16* data) const { | |
| 141 auto it = mime_data_.find(ui::mojom::kMimeTypeText); | |
| 142 if (it != mime_data_.end()) | |
| 143 *data = base::UTF8ToUTF16(ToString(it->second)); | |
| 144 return it != mime_data_.end(); | |
| 145 } | |
| 146 | |
| 147 bool OSExchangeDataProviderMus::GetURLAndTitle( | |
| 148 ui::OSExchangeData::FilenameToURLPolicy policy, | |
| 149 GURL* url, | |
| 150 base::string16* title) const { | |
| 151 auto it = mime_data_.find(ui::mojom::kMimeTypeMozillaURL); | |
| 152 if (it == mime_data_.end()) { | |
| 153 title->clear(); | |
| 154 return GetPlainTextURL(url) || | |
| 155 (policy == ui::OSExchangeData::CONVERT_FILENAMES && GetFileURL(url)); | |
| 156 } | |
| 157 | |
| 158 base::string16 data = ToString16(it->second); | |
| 159 base::string16::size_type newline = data.find('\n'); | |
| 160 if (newline == std::string::npos) | |
| 161 return false; | |
| 162 | |
| 163 GURL unparsed_url(data.substr(0, newline)); | |
| 164 if (!unparsed_url.is_valid()) | |
| 165 return false; | |
| 166 | |
| 167 *url = unparsed_url; | |
| 168 *title = data.substr(newline + 1); | |
| 169 return true; | |
| 170 } | |
| 171 | |
| 172 bool OSExchangeDataProviderMus::GetFilename(base::FilePath* path) const { | |
| 173 std::vector<ui::FileInfo> filenames; | |
| 174 if (GetFilenames(&filenames)) { | |
| 175 *path = filenames.front().path; | |
| 176 return true; | |
| 177 } | |
| 178 | |
| 179 return false; | |
| 180 } | |
| 181 | |
| 182 bool OSExchangeDataProviderMus::GetFilenames( | |
| 183 std::vector<ui::FileInfo>* file_names) const { | |
| 184 auto it = mime_data_.find(ui::mojom::kMimeTypeURIList); | |
| 185 if (it == mime_data_.end()) | |
| 186 return false; | |
| 187 | |
| 188 file_names->clear(); | |
| 189 for (const base::StringPiece& piece : ParseURIList(it->second)) { | |
| 190 GURL url(piece); | |
| 191 base::FilePath file_path; | |
| 192 if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) | |
| 193 file_names->push_back(ui::FileInfo(file_path, base::FilePath())); | |
| 194 } | |
| 195 | |
| 196 return true; | |
| 197 } | |
| 198 | |
| 199 bool OSExchangeDataProviderMus::GetPickledData( | |
| 200 const ui::Clipboard::FormatType& format, | |
| 201 base::Pickle* data) const { | |
| 202 auto it = mime_data_.find(format.Serialize()); | |
| 203 if (it == mime_data_.end()) | |
| 204 return false; | |
| 205 | |
| 206 // Note that the pickle object on the right hand side of the assignment | |
| 207 // only refers to the bytes in |data|. The assignment copies the data. | |
| 208 *data = base::Pickle(reinterpret_cast<const char*>(it->second.data()), | |
| 209 static_cast<int>(it->second.size())); | |
| 210 return true; | |
| 211 } | |
| 212 | |
| 213 bool OSExchangeDataProviderMus::HasString() const { | |
| 214 return base::ContainsKey(mime_data_, ui::mojom::kMimeTypeText); | |
| 215 } | |
| 216 | |
| 217 bool OSExchangeDataProviderMus::HasURL( | |
| 218 ui::OSExchangeData::FilenameToURLPolicy policy) const { | |
| 219 if (base::ContainsKey(mime_data_, ui::mojom::kMimeTypeMozillaURL)) | |
| 220 return true; | |
| 221 | |
| 222 auto it = mime_data_.find(ui::mojom::kMimeTypeURIList); | |
| 223 if (it == mime_data_.end()) | |
| 224 return false; | |
| 225 | |
| 226 for (const base::StringPiece& piece : ParseURIList(it->second)) { | |
| 227 if (!GURL(piece).SchemeIsFile() || | |
| 228 policy == ui::OSExchangeData::CONVERT_FILENAMES) { | |
| 229 return true; | |
| 230 } | |
| 231 } | |
| 232 | |
| 233 return false; | |
| 234 } | |
| 235 | |
| 236 bool OSExchangeDataProviderMus::HasFile() const { | |
| 237 auto it = mime_data_.find(ui::mojom::kMimeTypeURIList); | |
| 238 if (it == mime_data_.end()) | |
| 239 return false; | |
| 240 | |
| 241 for (const base::StringPiece& piece : ParseURIList(it->second)) { | |
| 242 GURL url(piece); | |
| 243 base::FilePath file_path; | |
| 244 if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) | |
| 245 return true; | |
| 246 } | |
| 247 | |
| 248 return false; | |
| 249 } | |
| 250 | |
| 251 bool OSExchangeDataProviderMus::HasCustomFormat( | |
| 252 const ui::Clipboard::FormatType& format) const { | |
| 253 return base::ContainsKey(mime_data_, format.Serialize()); | |
| 254 } | |
| 255 | |
| 256 // These methods were added in an ad-hoc way to different operating | |
| 257 // systems. We need to support them until they get cleaned up. | |
| 258 #if (!defined(OS_CHROMEOS) && defined(USE_X11)) || defined(OS_WIN) | |
| 259 void OSExchangeDataProviderMus::SetFileContents( | |
| 260 const base::FilePath& filename, | |
| 261 const std::string& file_contents) { | |
| 262 } | |
| 263 #endif | |
| 264 | |
| 265 #if defined(OS_WIN) | |
| 266 bool OSExchangeDataProviderMus::GetFileContents( | |
| 267 base::FilePath* filename, | |
| 268 std::string* file_contents) const { | |
| 269 return false; | |
| 270 } | |
| 271 | |
| 272 bool OSExchangeDataProviderMus::HasFileContents() const { | |
| 273 return false; | |
| 274 } | |
| 275 | |
| 276 void OSExchangeDataProviderMus::SetDownloadFileInfo( | |
| 277 const ui::OSExchangeData::DownloadFileInfo& download) { | |
| 278 } | |
| 279 #endif | |
| 280 | |
| 281 #if defined(USE_AURA) | |
| 282 void OSExchangeDataProviderMus::SetHtml(const base::string16& html, | |
| 283 const GURL& base_url) { | |
| 284 std::vector<unsigned char> bytes; | |
| 285 // Manually jam a UTF16 BOM into bytes because otherwise, other programs will | |
| 286 // assume UTF-8. | |
| 287 bytes.push_back(0xFF); | |
| 288 bytes.push_back(0xFE); | |
| 289 AddString16ToVector(html, &bytes); | |
| 290 mime_data_[ui::mojom::kMimeTypeHTML] = bytes; | |
| 291 } | |
| 292 | |
| 293 bool OSExchangeDataProviderMus::GetHtml(base::string16* html, | |
| 294 GURL* base_url) const { | |
| 295 auto it = mime_data_.find(ui::mojom::kMimeTypeHTML); | |
| 296 if (it == mime_data_.end()) | |
| 297 return false; | |
| 298 | |
| 299 const unsigned char* data = it->second.data(); | |
| 300 size_t size = it->second.size(); | |
| 301 base::string16 markup; | |
| 302 | |
| 303 // If the data starts with 0xFEFF, i.e., Byte Order Mark, assume it is | |
| 304 // UTF-16, otherwise assume UTF-8. | |
| 305 if (size >= 2 && | |
| 306 reinterpret_cast<const uint16_t*>(data)[0] == 0xFEFF) { | |
| 307 markup.assign(reinterpret_cast<const base::char16*>(data) + 1, | |
| 308 (size / 2) - 1); | |
| 309 } else { | |
| 310 base::UTF8ToUTF16(reinterpret_cast<const char*>(data), size, &markup); | |
| 311 } | |
| 312 | |
| 313 // If there is a terminating NULL, drop it. | |
| 314 if (!markup.empty() && markup.at(markup.length() - 1) == '\0') | |
| 315 markup.resize(markup.length() - 1); | |
| 316 | |
| 317 *html = markup; | |
| 318 *base_url = GURL(); | |
| 319 return true; | |
| 320 } | |
| 321 | |
| 322 bool OSExchangeDataProviderMus::HasHtml() const { | |
| 323 return base::ContainsKey(mime_data_, ui::mojom::kMimeTypeHTML); | |
| 324 } | |
| 325 #endif | |
| 326 | |
| 327 #if defined(USE_AURA) || defined(OS_MACOSX) | |
| 328 void OSExchangeDataProviderMus::SetDragImage( | |
| 329 const gfx::ImageSkia& image, | |
| 330 const gfx::Vector2d& cursor_offset) { | |
| 331 drag_image_ = image; | |
| 332 drag_image_offset_ = cursor_offset; | |
| 333 } | |
| 334 | |
| 335 const gfx::ImageSkia& OSExchangeDataProviderMus::GetDragImage() const { | |
| 336 return drag_image_; | |
| 337 } | |
| 338 | |
| 339 const gfx::Vector2d& OSExchangeDataProviderMus::GetDragImageOffset() const { | |
| 340 return drag_image_offset_; | |
| 341 } | |
| 342 #endif | |
| 343 | |
| 344 bool OSExchangeDataProviderMus::GetFileURL(GURL* url) const { | |
| 345 base::FilePath file_path; | |
| 346 if (!GetFilename(&file_path)) | |
| 347 return false; | |
| 348 | |
| 349 GURL test_url = net::FilePathToFileURL(file_path); | |
| 350 if (!test_url.is_valid()) | |
| 351 return false; | |
| 352 | |
| 353 if (url) | |
| 354 *url = test_url; | |
| 355 return true; | |
| 356 } | |
| 357 | |
| 358 bool OSExchangeDataProviderMus::GetPlainTextURL(GURL* url) const { | |
| 359 base::string16 str; | |
| 360 if (!GetString(&str)) | |
| 361 return false; | |
| 362 | |
| 363 GURL test_url(str); | |
| 364 if (!test_url.is_valid()) | |
| 365 return false; | |
| 366 | |
| 367 if (url) | |
| 368 *url = test_url; | |
| 369 return true; | |
| 370 } | |
| 371 | |
| 372 } // namespace views | |
| OLD | NEW |