- add sources.
[platform/framework/web/crosswalk.git] / src / ui / base / clipboard / clipboard_aura.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/clipboard/clipboard.h"
6
7 #include <list>
8
9 #include "base/basictypes.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/memory/scoped_ptr.h"
13 #include "base/stl_util.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "third_party/skia/include/core/SkBitmap.h"
16 #include "ui/base/clipboard/custom_data_helper.h"
17 #include "ui/gfx/size.h"
18
19 namespace ui {
20
21 namespace {
22 const char kMimeTypeFilename[] = "chromium/filename";
23 const char kMimeTypeBitmap[] = "image/bmp";
24 const char kMimeTypePepperCustomData[] = "chromium/x-pepper-custom-data";
25 const char kMimeTypeWebkitSmartPaste[] = "chromium/x-webkit-paste";
26 const size_t kMaxClipboardSize = 1;
27
28 // Clipboard data format used by AuraClipboard.
29 enum AuraClipboardFormat {
30   TEXT      = 1 << 0,
31   HTML      = 1 << 1,
32   RTF       = 1 << 2,
33   BOOKMARK  = 1 << 3,
34   BITMAP    = 1 << 4,
35   CUSTOM    = 1 << 5,
36   WEB       = 1 << 6,
37 };
38
39 // ClipboardData contains data copied to the Clipboard for a variety of formats.
40 // It mostly just provides APIs to cleanly access and manipulate this data.
41 class ClipboardData {
42  public:
43   ClipboardData()
44       : bitmap_data_(),
45         web_smart_paste_(false),
46         format_(0) {}
47
48   virtual ~ClipboardData() {}
49
50   // Bitmask of AuraClipboardFormat types.
51   const int format() const { return format_; }
52
53   const std::string& text() const { return text_; }
54   void set_text(const std::string& text) {
55     text_ = text;
56     format_ |= TEXT;
57   }
58
59   const std::string& markup_data() const { return markup_data_; }
60   void set_markup_data(const std::string& markup_data) {
61     markup_data_ = markup_data;
62     format_ |= HTML;
63   }
64
65   const std::string& rtf_data() const { return rtf_data_; }
66   void SetRTFData(const std::string& rtf_data) {
67     rtf_data_ = rtf_data;
68     format_ |= RTF;
69   }
70
71   const std::string& url() const { return url_; }
72   void set_url(const std::string& url) {
73     url_ = url;
74     format_ |= HTML;
75   }
76
77   const std::string& bookmark_title() const { return bookmark_title_; }
78   void set_bookmark_title(const std::string& bookmark_title) {
79     bookmark_title_ = bookmark_title;
80     format_ |= BOOKMARK;
81   }
82
83   const std::string& bookmark_url() const { return bookmark_url_; }
84   void set_bookmark_url(const std::string& bookmark_url) {
85     bookmark_url_ = bookmark_url;
86     format_ |= BOOKMARK;
87   }
88
89   uint8_t* bitmap_data() const { return bitmap_data_.get(); }
90   const gfx::Size& bitmap_size() const { return bitmap_size_; }
91   void SetBitmapData(const char* pixel_data, const char* size_data) {
92     bitmap_size_ = *reinterpret_cast<const gfx::Size*>(size_data);
93
94     // We assume 4-byte pixel data.
95     size_t bitmap_data_len = 4 * bitmap_size_.width() * bitmap_size_.height();
96     bitmap_data_.reset(new uint8_t[bitmap_data_len]);
97     memcpy(bitmap_data_.get(), pixel_data, bitmap_data_len);
98     format_ |= BITMAP;
99   }
100
101   const std::string& custom_data_format() const { return custom_data_format_; }
102   const std::string& custom_data_data() const { return custom_data_data_; }
103   void SetCustomData(const std::string& data_format,
104                      const std::string& data_data) {
105     if (data_data.size() == 0) {
106       custom_data_data_.clear();
107       custom_data_format_.clear();
108       return;
109     }
110     custom_data_data_ = data_data;
111     custom_data_format_ = data_format;
112     format_ |= CUSTOM;
113   }
114
115   bool web_smart_paste() const { return web_smart_paste_; }
116   void set_web_smart_paste(bool web_smart_paste) {
117     web_smart_paste_ = web_smart_paste;
118     format_ |= WEB;
119   }
120
121  private:
122   // Plain text in UTF8 format.
123   std::string text_;
124
125   // HTML markup data in UTF8 format.
126   std::string markup_data_;
127   std::string url_;
128
129   // RTF data.
130   std::string rtf_data_;
131
132   // Bookmark title in UTF8 format.
133   std::string bookmark_title_;
134   std::string bookmark_url_;
135
136   // Filenames.
137   std::vector<std::string> files_;
138
139   // Bitmap images.
140   scoped_ptr<uint8_t[]> bitmap_data_;
141   gfx::Size bitmap_size_;
142
143   // Data with custom format.
144   std::string custom_data_format_;
145   std::string custom_data_data_;
146
147   // WebKit smart paste data.
148   bool web_smart_paste_;
149
150   int format_;
151
152   DISALLOW_COPY_AND_ASSIGN(ClipboardData);
153 };
154
155 // Platform clipboard implementation for Aura. This handles things like format
156 // conversion, versioning of clipboard items etc. The goal is to roughly provide
157 // a substitute to platform clipboards on other platforms such as GtkClipboard
158 // on gtk or winapi clipboard on win.
159 class AuraClipboard {
160  public:
161   AuraClipboard() {}
162
163   ~AuraClipboard() {
164     Clear();
165   }
166
167   void Clear() {
168     STLDeleteContainerPointers(data_list_.begin(), data_list_.end());
169     data_list_.clear();
170   }
171
172   // Returns the number of entries currently in the clipboard stack.
173   size_t GetNumClipboardEntries() {
174     return data_list_.size();
175   }
176
177   // Returns the data currently on the top of the clipboard stack, NULL if the
178   // clipboard stack is empty.
179   const ClipboardData* GetData() const {
180     if (data_list_.empty())
181       return NULL;
182     return data_list_.front();
183   }
184
185   // Returns true if the data on top of the clipboard stack has format |format|
186   // or another format that can be converted to |format|.
187   bool IsFormatAvailable(AuraClipboardFormat format) const {
188     switch (format) {
189       case TEXT:
190         return HasFormat(TEXT) || HasFormat(BOOKMARK);
191       default:
192         return HasFormat(format);
193     }
194   }
195
196   // Reads text from the data at the top of clipboard stack.
197   void ReadText(string16* result) const {
198     std::string utf8_result;
199     ReadAsciiText(&utf8_result);
200     *result = UTF8ToUTF16(utf8_result);
201   }
202
203   // Reads ascii text from the data at the top of clipboard stack.
204   void ReadAsciiText(std::string* result) const {
205     result->clear();
206     const ClipboardData* data = GetData();
207     if (!data)
208       return;
209     if (HasFormat(TEXT))
210       *result = data->text();
211     else if (HasFormat(HTML))
212       *result = data->markup_data();
213     else if (HasFormat(BOOKMARK))
214       *result = data->bookmark_url();
215   }
216
217   // Reads HTML from the data at the top of clipboard stack.
218   void ReadHTML(string16* markup,
219                 std::string* src_url,
220                 uint32* fragment_start,
221                 uint32* fragment_end) const {
222     markup->clear();
223     if (src_url)
224       src_url->clear();
225     *fragment_start = 0;
226     *fragment_end = 0;
227
228     if (!HasFormat(HTML))
229       return;
230
231     const ClipboardData* data = GetData();
232     *markup = UTF8ToUTF16(data->markup_data());
233     *src_url = data->url();
234
235     *fragment_start = 0;
236     DCHECK_LE(markup->length(), kuint32max);
237     *fragment_end = static_cast<uint32>(markup->length());
238   }
239
240   // Reads RTF from the data at the top of clipboard stack.
241   void ReadRTF(std::string* result) const {
242     result->clear();
243     const ClipboardData* data = GetData();
244     if (!HasFormat(RTF))
245       return;
246
247     *result = data->rtf_data();
248   }
249
250   // Reads image from the data at the top of clipboard stack.
251   SkBitmap ReadImage() const {
252     SkBitmap img;
253     if (!HasFormat(BITMAP))
254       return img;
255
256     const ClipboardData* data = GetData();
257     const gfx::Size size = data->bitmap_size();
258     uint8_t* bitmap = data->bitmap_data();
259     img.setConfig(SkBitmap::kARGB_8888_Config, size.width(), size.height(), 0);
260     img.allocPixels();
261     img.eraseARGB(0, 0, 0, 0);
262     memcpy(img.getPixels(), bitmap, size.width() * size.height() * 4);
263     return img;
264   }
265
266   // Reads data of type |type| from the data at the top of clipboard stack.
267   void ReadCustomData(const string16& type, string16* result) const {
268     result->clear();
269     const ClipboardData* data = GetData();
270     if (!HasFormat(CUSTOM))
271       return;
272
273     ui::ReadCustomDataForType(data->custom_data_data().c_str(),
274         data->custom_data_data().size(),
275         type, result);
276   }
277
278   // Reads bookmark from the data at the top of clipboard stack.
279   void ReadBookmark(string16* title, std::string* url) const {
280     title->clear();
281     url->clear();
282     if (!HasFormat(BOOKMARK))
283       return;
284
285     const ClipboardData* data = GetData();
286     *title = UTF8ToUTF16(data->bookmark_title());
287     *url = data->bookmark_url();
288   }
289
290   void ReadData(const std::string& type, std::string* result) const {
291     result->clear();
292     const ClipboardData* data = GetData();
293     if (!HasFormat(CUSTOM) || type != data->custom_data_format())
294       return;
295
296     *result = data->custom_data_data();
297   }
298
299   // Writes |data| to the top of the clipboard stack.
300   void WriteData(ClipboardData* data) {
301     DCHECK(data);
302     AddToListEnsuringSize(data);
303   }
304
305  private:
306   // True if the data on top of the clipboard stack has format |format|.
307   bool HasFormat(AuraClipboardFormat format) const {
308     const ClipboardData* data = GetData();
309     if (!data)
310       return false;
311
312     return data->format() & format;
313   }
314
315   void AddToListEnsuringSize(ClipboardData* data) {
316     DCHECK(data);
317     data_list_.push_front(data);
318
319     // If the size of list becomes more than the maximum allowed, we delete the
320     // last element.
321     if (data_list_.size() > kMaxClipboardSize) {
322       ClipboardData* last = data_list_.back();
323       data_list_.pop_back();
324       delete last;
325     }
326   }
327
328   // Stack containing various versions of ClipboardData.
329   std::list<ClipboardData*> data_list_;
330
331   DISALLOW_COPY_AND_ASSIGN(AuraClipboard);
332 };
333
334 AuraClipboard* aura_clipboard = NULL;
335
336 AuraClipboard* GetClipboard() {
337   if (!aura_clipboard)
338     aura_clipboard = new AuraClipboard();
339   return aura_clipboard;
340 }
341
342 void DeleteClipboard() {
343   if (aura_clipboard)
344     delete aura_clipboard;
345   aura_clipboard = NULL;
346 }
347
348 // Helper class to build a ClipboardData object and write it to clipboard.
349 class ClipboardDataBuilder {
350  public:
351   static void CommitToClipboard() {
352     DCHECK(current_data_);
353     GetClipboard()->WriteData(current_data_);
354     current_data_ = NULL;
355   }
356
357   static void WriteText(const char* text_data, size_t text_len) {
358     ClipboardData* data = GetCurrentData();
359     data->set_text(std::string(text_data, text_len));
360   }
361
362   static void WriteHTML(const char* markup_data,
363                         size_t markup_len,
364                         const char* url_data,
365                         size_t url_len) {
366     ClipboardData* data = GetCurrentData();
367     data->set_markup_data(std::string(markup_data, markup_len));
368     data->set_url(std::string(url_data, url_len));
369   }
370
371   static void WriteRTF(const char* rtf_data, size_t rtf_len) {
372     ClipboardData* data = GetCurrentData();
373     data->SetRTFData(std::string(rtf_data, rtf_len));
374   }
375
376   static void WriteBookmark(const char* title_data,
377                             size_t title_len,
378                             const char* url_data,
379                             size_t url_len) {
380     ClipboardData* data = GetCurrentData();
381     data->set_bookmark_title(std::string(title_data, title_len));
382     data->set_bookmark_url(std::string(url_data, url_len));
383   }
384
385   static void WriteWebSmartPaste() {
386     ClipboardData* data = GetCurrentData();
387     data->set_web_smart_paste(true);
388   }
389
390   static void WriteBitmap(const char* pixel_data, const char* size_data) {
391     ClipboardData* data = GetCurrentData();
392     data->SetBitmapData(pixel_data, size_data);
393   }
394
395   static void WriteData(const std::string& format,
396                         const char* data_data,
397                         size_t data_len) {
398     ClipboardData* data = GetCurrentData();
399     data->SetCustomData(format, std::string(data_data, data_len));
400   }
401
402  private:
403   static ClipboardData* GetCurrentData() {
404     if (!current_data_)
405       current_data_ = new ClipboardData;
406     return current_data_;
407   }
408
409   static ClipboardData* current_data_;
410 };
411
412 ClipboardData* ClipboardDataBuilder::current_data_ = NULL;
413
414 }  // namespace
415
416 Clipboard::FormatType::FormatType() {
417 }
418
419 Clipboard::FormatType::FormatType(const std::string& native_format)
420     : data_(native_format) {
421 }
422
423 Clipboard::FormatType::~FormatType() {
424 }
425
426 std::string Clipboard::FormatType::Serialize() const {
427   return data_;
428 }
429
430 // static
431 Clipboard::FormatType Clipboard::FormatType::Deserialize(
432     const std::string& serialization) {
433   return FormatType(serialization);
434 }
435
436 bool Clipboard::FormatType::operator<(const FormatType& other) const {
437   return data_ < other.data_;
438 }
439
440 bool Clipboard::FormatType::Equals(const FormatType& other) const {
441   return data_ == other.data_;
442 }
443
444 Clipboard::Clipboard() {
445   DCHECK(CalledOnValidThread());
446   // Make sure clipboard is created.
447   GetClipboard();
448 }
449
450 Clipboard::~Clipboard() {
451   DCHECK(CalledOnValidThread());
452   DeleteClipboard();
453 }
454
455 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
456   DCHECK(CalledOnValidThread());
457   DCHECK(IsSupportedClipboardType(type));
458   for (ObjectMap::const_iterator iter = objects.begin();
459        iter != objects.end(); ++iter) {
460     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
461   }
462   ClipboardDataBuilder::CommitToClipboard();
463 }
464
465 bool Clipboard::IsFormatAvailable(const FormatType& format,
466                                   ClipboardType type) const {
467   DCHECK(CalledOnValidThread());
468   DCHECK(IsSupportedClipboardType(type));
469   AuraClipboard* clipboard = GetClipboard();
470   if (GetPlainTextFormatType().Equals(format) ||
471       GetUrlFormatType().Equals(format))
472     return clipboard->IsFormatAvailable(TEXT);
473   else if (GetHtmlFormatType().Equals(format))
474     return clipboard->IsFormatAvailable(HTML);
475   else if (GetRtfFormatType().Equals(format))
476     return clipboard->IsFormatAvailable(RTF);
477   else if (GetBitmapFormatType().Equals(format))
478     return clipboard->IsFormatAvailable(BITMAP);
479   else if (GetWebKitSmartPasteFormatType().Equals(format))
480     return clipboard->IsFormatAvailable(WEB);
481   else {
482     const ClipboardData* data = clipboard->GetData();
483     if (data && data->custom_data_format() == format.ToString())
484       return true;
485   }
486   return false;
487 }
488
489 void Clipboard::Clear(ClipboardType type) {
490   DCHECK(CalledOnValidThread());
491   DCHECK(IsSupportedClipboardType(type));
492   AuraClipboard* clipboard = GetClipboard();
493   clipboard->Clear();
494 }
495
496 void Clipboard::ReadAvailableTypes(ClipboardType type,
497                                    std::vector<string16>* types,
498                                    bool* contains_filenames) const {
499   DCHECK(CalledOnValidThread());
500   if (!types || !contains_filenames) {
501     NOTREACHED();
502     return;
503   }
504
505   types->clear();
506   *contains_filenames = false;
507   if (IsFormatAvailable(GetPlainTextFormatType(), type))
508     types->push_back(UTF8ToUTF16(GetPlainTextFormatType().ToString()));
509   if (IsFormatAvailable(GetHtmlFormatType(), type))
510     types->push_back(UTF8ToUTF16(GetHtmlFormatType().ToString()));
511   if (IsFormatAvailable(GetRtfFormatType(), type))
512     types->push_back(UTF8ToUTF16(GetRtfFormatType().ToString()));
513   if (IsFormatAvailable(GetBitmapFormatType(), type))
514     types->push_back(UTF8ToUTF16(kMimeTypePNG));
515
516   AuraClipboard* clipboard = GetClipboard();
517   if (clipboard->IsFormatAvailable(CUSTOM) && clipboard->GetData()) {
518     ui::ReadCustomDataTypes(clipboard->GetData()->custom_data_data().c_str(),
519         clipboard->GetData()->custom_data_data().size(), types);
520   }
521 }
522
523 void Clipboard::ReadText(ClipboardType type, string16* result) const {
524   DCHECK(CalledOnValidThread());
525   GetClipboard()->ReadText(result);
526 }
527
528 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
529   DCHECK(CalledOnValidThread());
530   GetClipboard()->ReadAsciiText(result);
531 }
532
533 void Clipboard::ReadHTML(ClipboardType type,
534                          string16* markup,
535                          std::string* src_url,
536                          uint32* fragment_start,
537                          uint32* fragment_end) const {
538   DCHECK(CalledOnValidThread());
539   GetClipboard()->ReadHTML(markup, src_url, fragment_start, fragment_end);
540 }
541
542 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
543   DCHECK(CalledOnValidThread());
544   GetClipboard()->ReadRTF(result);
545 }
546
547 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
548   DCHECK(CalledOnValidThread());
549   return GetClipboard()->ReadImage();
550 }
551
552 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
553                                const string16& type,
554                                string16* result) const {
555   DCHECK(CalledOnValidThread());
556   GetClipboard()->ReadCustomData(type, result);
557 }
558
559 void Clipboard::ReadBookmark(string16* title, std::string* url) const {
560   DCHECK(CalledOnValidThread());
561   GetClipboard()->ReadBookmark(title, url);
562 }
563
564 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
565   DCHECK(CalledOnValidThread());
566   GetClipboard()->ReadData(format.ToString(), result);
567 }
568
569 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
570   DCHECK(CalledOnValidThread());
571   return GetClipboard()->GetNumClipboardEntries();
572 }
573
574 void Clipboard::WriteText(const char* text_data, size_t text_len) {
575   ClipboardDataBuilder::WriteText(text_data, text_len);
576 }
577
578 void Clipboard::WriteHTML(const char* markup_data,
579                           size_t markup_len,
580                           const char* url_data,
581                           size_t url_len) {
582   ClipboardDataBuilder::WriteHTML(markup_data, markup_len, url_data, url_len);
583 }
584
585 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
586   ClipboardDataBuilder::WriteRTF(rtf_data, data_len);
587 }
588
589 void Clipboard::WriteBookmark(const char* title_data,
590                               size_t title_len,
591                               const char* url_data,
592                               size_t url_len) {
593   ClipboardDataBuilder::WriteBookmark(title_data, title_len, url_data, url_len);
594 }
595
596 void Clipboard::WriteWebSmartPaste() {
597   ClipboardDataBuilder::WriteWebSmartPaste();
598 }
599
600 void Clipboard::WriteBitmap(const char* pixel_data, const char* size_data) {
601   ClipboardDataBuilder::WriteBitmap(pixel_data, size_data);
602 }
603
604 void Clipboard::WriteData(const FormatType& format,
605                           const char* data_data,
606                           size_t data_len) {
607   ClipboardDataBuilder::WriteData(format.ToString(), data_data, data_len);
608 }
609
610 // static
611 Clipboard::FormatType Clipboard::GetFormatType(
612     const std::string& format_string) {
613   return FormatType::Deserialize(format_string);
614 }
615
616 // static
617 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
618   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeURIList));
619   return type;
620 }
621
622 // static
623 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
624   return GetUrlFormatType();
625 }
626
627 // static
628 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
629   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeText));
630   return type;
631 }
632
633 // static
634 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
635   return GetPlainTextFormatType();
636 }
637
638 // static
639 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
640   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeFilename));
641   return type;
642 }
643
644 // static
645 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
646   return Clipboard::GetFilenameFormatType();
647 }
648
649 // static
650 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
651   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeHTML));
652   return type;
653 }
654
655 // static
656 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
657   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeRTF));
658   return type;
659 }
660
661 // static
662 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
663   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeBitmap));
664   return type;
665 }
666
667 // static
668 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
669   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebkitSmartPaste));
670   return type;
671 }
672
673 // static
674 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
675   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypeWebCustomData));
676   return type;
677 }
678
679 // static
680 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
681   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kMimeTypePepperCustomData));
682   return type;
683 }
684
685 }  // namespace ui