Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / ui / base / dragdrop / os_exchange_data_provider_aurax11.cc
1 // Copyright (c) 2012 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/base/dragdrop/os_exchange_data_provider_aurax11.h"
6
7 #include "base/logging.h"
8 #include "base/memory/ref_counted_memory.h"
9 #include "base/message_loop/message_pump_x11.h"
10 #include "base/strings/string_util.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "net/base/net_util.h"
13 #include "ui/base/clipboard/clipboard.h"
14 #include "ui/base/clipboard/scoped_clipboard_writer.h"
15 #include "ui/base/x/selection_utils.h"
16 #include "ui/base/x/x11_util.h"
17
18 // Note: the GetBlah() methods are used immediately by the
19 // web_contents_view_aura.cc:PrepareDropData(), while the omnibox is a
20 // little more discriminating and calls HasBlah() before trying to get the
21 // information.
22
23 namespace ui {
24
25 namespace {
26
27 const char kDndSelection[] = "XdndSelection";
28
29 const char* kAtomsToCache[] = {
30   kString,
31   kText,
32   kUtf8String,
33   kDndSelection,
34   Clipboard::kMimeTypeURIList,
35   kMimeTypeMozillaURL,
36   Clipboard::kMimeTypeText,
37   NULL
38 };
39
40 }  // namespace
41
42 OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11(
43     ::Window x_window,
44     const SelectionFormatMap& selection)
45     : x_display_(gfx::GetXDisplay()),
46       x_root_window_(DefaultRootWindow(x_display_)),
47       own_window_(false),
48       x_window_(x_window),
49       atom_cache_(x_display_, kAtomsToCache),
50       format_map_(selection),
51       selection_owner_(x_display_, x_window_,
52                        atom_cache_.GetAtom(kDndSelection)) {
53   // We don't know all possible MIME types at compile time.
54   atom_cache_.allow_uncached_atoms();
55 }
56
57 OSExchangeDataProviderAuraX11::OSExchangeDataProviderAuraX11()
58     : x_display_(gfx::GetXDisplay()),
59       x_root_window_(DefaultRootWindow(x_display_)),
60       own_window_(true),
61       x_window_(XCreateWindow(
62           x_display_,
63           x_root_window_,
64           -100, -100, 10, 10,  // x, y, width, height
65           0,                   // border width
66           CopyFromParent,      // depth
67           InputOnly,
68           CopyFromParent,      // visual
69           0,
70           NULL)),
71       atom_cache_(x_display_, kAtomsToCache),
72       format_map_(),
73       selection_owner_(x_display_, x_window_,
74                        atom_cache_.GetAtom(kDndSelection)) {
75   // We don't know all possible MIME types at compile time.
76   atom_cache_.allow_uncached_atoms();
77
78   XStoreName(x_display_, x_window_, "Chromium Drag & Drop Window");
79
80   base::MessagePumpX11::Current()->AddDispatcherForWindow(this, x_window_);
81 }
82
83 OSExchangeDataProviderAuraX11::~OSExchangeDataProviderAuraX11() {
84   if (own_window_) {
85     base::MessagePumpX11::Current()->RemoveDispatcherForWindow(x_window_);
86     XDestroyWindow(x_display_, x_window_);
87   }
88 }
89
90 void OSExchangeDataProviderAuraX11::TakeOwnershipOfSelection() const {
91   selection_owner_.TakeOwnershipOfSelection(format_map_);
92 }
93
94 void OSExchangeDataProviderAuraX11::RetrieveTargets(
95     std::vector<Atom>* targets) const {
96   selection_owner_.RetrieveTargets(targets);
97 }
98
99 SelectionFormatMap OSExchangeDataProviderAuraX11::GetFormatMap() const {
100   // We return the |selection_owner_|'s format map instead of our own in case
101   // ours has been modified since TakeOwnershipOfSelection() was called.
102   return selection_owner_.selection_format_map();
103 }
104
105 OSExchangeData::Provider* OSExchangeDataProviderAuraX11::Clone() const {
106   OSExchangeDataProviderAuraX11* ret = new OSExchangeDataProviderAuraX11();
107   ret->format_map_ = format_map_;
108   return ret;
109 }
110
111 void OSExchangeDataProviderAuraX11::SetString(const base::string16& text_data) {
112   std::string utf8 = base::UTF16ToUTF8(text_data);
113   scoped_refptr<base::RefCountedMemory> mem(
114       base::RefCountedString::TakeString(&utf8));
115
116   format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeText), mem);
117   format_map_.Insert(atom_cache_.GetAtom(kText), mem);
118   format_map_.Insert(atom_cache_.GetAtom(kString), mem);
119   format_map_.Insert(atom_cache_.GetAtom(kUtf8String), mem);
120 }
121
122 void OSExchangeDataProviderAuraX11::SetURL(const GURL& url,
123                                            const base::string16& title) {
124   // Mozilla's URL format: (UTF16: URL, newline, title)
125   if (url.is_valid()) {
126     base::string16 spec = base::UTF8ToUTF16(url.spec());
127
128     std::vector<unsigned char> data;
129     ui::AddString16ToVector(spec, &data);
130     ui::AddString16ToVector(base::ASCIIToUTF16("\n"), &data);
131     ui::AddString16ToVector(title, &data);
132     scoped_refptr<base::RefCountedMemory> mem(
133         base::RefCountedBytes::TakeVector(&data));
134
135     format_map_.Insert(atom_cache_.GetAtom(kMimeTypeMozillaURL), mem);
136
137     SetString(spec);
138   }
139 }
140
141 void OSExchangeDataProviderAuraX11::SetFilename(const base::FilePath& path) {
142   std::vector<OSExchangeData::FileInfo> data;
143   data.push_back(OSExchangeData::FileInfo(path, base::FilePath()));
144   SetFilenames(data);
145 }
146
147 void OSExchangeDataProviderAuraX11::SetFilenames(
148     const std::vector<OSExchangeData::FileInfo>& filenames) {
149   std::vector<std::string> paths;
150   for (std::vector<OSExchangeData::FileInfo>::const_iterator it =
151            filenames.begin(); it != filenames.end(); ++it) {
152     std::string url_spec = net::FilePathToFileURL(it->path).spec();
153     if (!url_spec.empty())
154       paths.push_back(url_spec);
155   }
156
157   std::string joined_data = JoinString(paths, '\n');
158   scoped_refptr<base::RefCountedMemory> mem(
159       base::RefCountedString::TakeString(&joined_data));
160   format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeURIList), mem);
161 }
162
163 void OSExchangeDataProviderAuraX11::SetPickledData(
164     const OSExchangeData::CustomFormat& format,
165     const Pickle& pickle) {
166   const unsigned char* data =
167       reinterpret_cast<const unsigned char*>(pickle.data());
168
169   std::vector<unsigned char> bytes;
170   bytes.insert(bytes.end(), data, data + pickle.size());
171   scoped_refptr<base::RefCountedMemory> mem(
172       base::RefCountedBytes::TakeVector(&bytes));
173
174   format_map_.Insert(atom_cache_.GetAtom(format.ToString().c_str()), mem);
175 }
176
177 bool OSExchangeDataProviderAuraX11::GetString(base::string16* result) const {
178   if (HasFile()) {
179     // Various Linux file managers both pass a list of file:// URIs and set the
180     // string representation to the URI. We explicitly don't want to return use
181     // this representation.
182     return false;
183   }
184
185   std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
186   std::vector< ::Atom> requested_types;
187   ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
188
189   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
190   if (data.IsValid()) {
191     std::string text = data.GetText();
192     *result = base::UTF8ToUTF16(text);
193     return true;
194   }
195
196   return false;
197 }
198
199 bool OSExchangeDataProviderAuraX11::GetURLAndTitle(
200     OSExchangeData::FilenameToURLPolicy policy,
201     GURL* url,
202     base::string16* title) const {
203   std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
204   std::vector< ::Atom> requested_types;
205   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
206
207   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
208   if (data.IsValid()) {
209     // TODO(erg): Technically, both of these forms can accept multiple URLs,
210     // but that doesn't match the assumptions of the rest of the system which
211     // expect single types.
212
213     if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) {
214       // Mozilla URLs are (UTF16: URL, newline, title).
215       base::string16 unparsed;
216       data.AssignTo(&unparsed);
217
218       std::vector<base::string16> tokens;
219       size_t num_tokens = Tokenize(unparsed, base::ASCIIToUTF16("\n"), &tokens);
220       if (num_tokens > 0) {
221         if (num_tokens > 1)
222           *title = tokens[1];
223         else
224           *title = base::string16();
225
226         *url = GURL(tokens[0]);
227         return true;
228       }
229     } else if (data.GetType() == atom_cache_.GetAtom(
230                    Clipboard::kMimeTypeURIList)) {
231       std::vector<std::string> tokens = ui::ParseURIList(data);
232       for (std::vector<std::string>::const_iterator it = tokens.begin();
233            it != tokens.end(); ++it) {
234         GURL test_url(*it);
235         if (!test_url.SchemeIsFile() ||
236             policy == OSExchangeData::CONVERT_FILENAMES) {
237           *url = test_url;
238           *title = base::string16();
239           return true;
240         }
241       }
242     }
243   }
244
245   return false;
246 }
247
248 bool OSExchangeDataProviderAuraX11::GetFilename(base::FilePath* path) const {
249   std::vector<OSExchangeData::FileInfo> filenames;
250   if (GetFilenames(&filenames)) {
251     *path = filenames.front().path;
252     return true;
253   }
254
255   return false;
256 }
257
258 bool OSExchangeDataProviderAuraX11::GetFilenames(
259     std::vector<OSExchangeData::FileInfo>* filenames) const {
260   std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
261   std::vector< ::Atom> requested_types;
262   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
263
264   filenames->clear();
265   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
266   if (data.IsValid()) {
267     std::vector<std::string> tokens = ui::ParseURIList(data);
268     for (std::vector<std::string>::const_iterator it = tokens.begin();
269          it != tokens.end(); ++it) {
270       GURL url(*it);
271       base::FilePath file_path;
272       if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path)) {
273         filenames->push_back(OSExchangeData::FileInfo(file_path,
274                                                       base::FilePath()));
275       }
276     }
277   }
278
279   return !filenames->empty();
280 }
281
282 bool OSExchangeDataProviderAuraX11::GetPickledData(
283     const OSExchangeData::CustomFormat& format,
284     Pickle* pickle) const {
285   std::vector< ::Atom> requested_types;
286   requested_types.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
287
288   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
289   if (data.IsValid()) {
290     // Note that the pickle object on the right hand side of the assignment
291     // only refers to the bytes in |data|. The assignment copies the data.
292     *pickle = Pickle(reinterpret_cast<const char*>(data.GetData()),
293                      static_cast<int>(data.GetSize()));
294     return true;
295   }
296
297   return false;
298 }
299
300 bool OSExchangeDataProviderAuraX11::HasString() const {
301   std::vector< ::Atom> text_atoms = ui::GetTextAtomsFrom(&atom_cache_);
302   std::vector< ::Atom> requested_types;
303   ui::GetAtomIntersection(text_atoms, GetTargets(), &requested_types);
304   return !requested_types.empty() && !HasFile();
305 }
306
307 bool OSExchangeDataProviderAuraX11::HasURL() const {
308   std::vector< ::Atom> url_atoms = ui::GetURLAtomsFrom(&atom_cache_);
309   std::vector< ::Atom> requested_types;
310   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
311
312   if (requested_types.empty())
313     return false;
314
315   // The Linux desktop doesn't differentiate between files and URLs like
316   // Windows does and stuffs all the data into one mime type.
317   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
318   if (data.IsValid()) {
319     if (data.GetType() == atom_cache_.GetAtom(kMimeTypeMozillaURL)) {
320       // File managers shouldn't be using this type, so this is a URL.
321       return true;
322     } else if (data.GetType() == atom_cache_.GetAtom(
323         ui::Clipboard::kMimeTypeURIList)) {
324       std::vector<std::string> tokens = ui::ParseURIList(data);
325       for (std::vector<std::string>::const_iterator it = tokens.begin();
326            it != tokens.end(); ++it) {
327         if (!GURL(*it).SchemeIsFile())
328           return true;
329       }
330
331       return false;
332     }
333   }
334
335   return false;
336 }
337
338 bool OSExchangeDataProviderAuraX11::HasFile() const {
339   std::vector< ::Atom> url_atoms = ui::GetURIListAtomsFrom(&atom_cache_);
340   std::vector< ::Atom> requested_types;
341   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
342
343   if (requested_types.empty())
344     return false;
345
346   // To actually answer whether we have a file, we need to look through the
347   // contents of the kMimeTypeURIList type, and see if any of them are file://
348   // URIs.
349   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
350   if (data.IsValid()) {
351     std::vector<std::string> tokens = ui::ParseURIList(data);
352     for (std::vector<std::string>::const_iterator it = tokens.begin();
353          it != tokens.end(); ++it) {
354       GURL url(*it);
355       base::FilePath file_path;
356       if (url.SchemeIsFile() && net::FileURLToFilePath(url, &file_path))
357         return true;
358     }
359   }
360
361   return false;
362 }
363
364 bool OSExchangeDataProviderAuraX11::HasCustomFormat(
365     const OSExchangeData::CustomFormat& format) const {
366   std::vector< ::Atom> url_atoms;
367   url_atoms.push_back(atom_cache_.GetAtom(format.ToString().c_str()));
368   std::vector< ::Atom> requested_types;
369   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
370
371   return !requested_types.empty();
372 }
373
374 void OSExchangeDataProviderAuraX11::SetHtml(const base::string16& html,
375                                             const GURL& base_url) {
376   std::vector<unsigned char> bytes;
377   // Manually jam a UTF16 BOM into bytes because otherwise, other programs will
378   // assume UTF-8.
379   bytes.push_back(0xFF);
380   bytes.push_back(0xFE);
381   ui::AddString16ToVector(html, &bytes);
382   scoped_refptr<base::RefCountedMemory> mem(
383       base::RefCountedBytes::TakeVector(&bytes));
384
385   format_map_.Insert(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML), mem);
386 }
387
388 bool OSExchangeDataProviderAuraX11::GetHtml(base::string16* html,
389                                             GURL* base_url) const {
390   std::vector< ::Atom> url_atoms;
391   url_atoms.push_back(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML));
392   std::vector< ::Atom> requested_types;
393   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
394
395   ui::SelectionData data(format_map_.GetFirstOf(requested_types));
396   if (data.IsValid()) {
397     *html = data.GetHtml();
398     *base_url = GURL();
399     return true;
400   }
401
402   return false;
403 }
404
405 bool OSExchangeDataProviderAuraX11::HasHtml() const {
406   std::vector< ::Atom> url_atoms;
407   url_atoms.push_back(atom_cache_.GetAtom(Clipboard::kMimeTypeHTML));
408   std::vector< ::Atom> requested_types;
409   ui::GetAtomIntersection(url_atoms, GetTargets(), &requested_types);
410
411   return !requested_types.empty();
412 }
413
414 void OSExchangeDataProviderAuraX11::SetDragImage(
415     const gfx::ImageSkia& image,
416     const gfx::Vector2d& cursor_offset) {
417   drag_image_ = image;
418   drag_image_offset_ = cursor_offset;
419 }
420
421 const gfx::ImageSkia& OSExchangeDataProviderAuraX11::GetDragImage() const {
422   return drag_image_;
423 }
424
425 const gfx::Vector2d& OSExchangeDataProviderAuraX11::GetDragImageOffset() const {
426   return drag_image_offset_;
427 }
428
429 uint32_t OSExchangeDataProviderAuraX11::Dispatch(
430     const base::NativeEvent& event) {
431   XEvent* xev = event;
432   switch (xev->type) {
433     case SelectionRequest:
434       selection_owner_.OnSelectionRequest(xev->xselectionrequest);
435       break;
436     default:
437       NOTIMPLEMENTED();
438   }
439
440   return POST_DISPATCH_NONE;
441 }
442
443 bool OSExchangeDataProviderAuraX11::GetPlainTextURL(GURL* url) const {
444   base::string16 text;
445   if (GetString(&text)) {
446     GURL test_url(text);
447     if (test_url.is_valid()) {
448       *url = test_url;
449       return true;
450     }
451   }
452
453   return false;
454 }
455
456 std::vector< ::Atom> OSExchangeDataProviderAuraX11::GetTargets() const {
457   return format_map_.GetTypes();
458 }
459
460 ///////////////////////////////////////////////////////////////////////////////
461 // OSExchangeData, public:
462
463 // static
464 OSExchangeData::Provider* OSExchangeData::CreateProvider() {
465   return new OSExchangeDataProviderAuraX11();
466 }
467
468 }  // namespace ui