Pepper: Access PepperMediaDeviceManager through a WeakPtr
[chromium-blink-merge.git] / ui / base / clipboard / clipboard_mac.mm
blob0b6d3a709ae9776da0580c5b9dccd2ce53e4fd32
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.
5 #include "ui/base/clipboard/clipboard.h"
7 #import <Cocoa/Cocoa.h>
9 #include "base/basictypes.h"
10 #include "base/files/file_path.h"
11 #include "base/logging.h"
12 #include "base/mac/mac_util.h"
13 #include "base/mac/scoped_cftyperef.h"
14 #import "base/mac/scoped_nsexception_enabler.h"
15 #include "base/mac/scoped_nsobject.h"
16 #include "base/stl_util.h"
17 #include "base/strings/sys_string_conversions.h"
18 #include "base/strings/utf_string_conversions.h"
19 #include "skia/ext/skia_utils_mac.h"
20 #import "third_party/mozilla/NSPasteboard+Utils.h"
21 #include "third_party/skia/include/core/SkBitmap.h"
22 #include "ui/base/clipboard/custom_data_helper.h"
23 #include "ui/gfx/canvas.h"
24 #include "ui/gfx/scoped_ns_graphics_context_save_gstate_mac.h"
25 #include "ui/gfx/size.h"
27 namespace ui {
29 namespace {
31 // Would be nice if this were in UTCoreTypes.h, but it isn't
32 NSString* const kUTTypeURLName = @"public.url-name";
34 // Tells us if WebKit was the last to write to the pasteboard. There's no
35 // actual data associated with this type.
36 NSString* const kWebSmartPastePboardType = @"NeXT smart paste pasteboard type";
38 // Pepper custom data format type.
39 NSString* const kPepperCustomDataPboardType =
40     @"org.chromium.pepper-custom-data";
42 NSPasteboard* GetPasteboard() {
43   // The pasteboard should not be nil in a UI session, but this handy DCHECK
44   // can help track down problems if someone tries using clipboard code outside
45   // of a UI session.
46   NSPasteboard* pasteboard = [NSPasteboard generalPasteboard];
47   DCHECK(pasteboard);
48   return pasteboard;
51 }  // namespace
53 Clipboard::FormatType::FormatType() : data_(nil) {
56 Clipboard::FormatType::FormatType(NSString* native_format)
57     : data_([native_format retain]) {
60 Clipboard::FormatType::FormatType(const FormatType& other)
61     : data_([other.data_ retain]) {
64 Clipboard::FormatType& Clipboard::FormatType::operator=(
65     const FormatType& other) {
66   if (this != &other) {
67     [data_ release];
68     data_ = [other.data_ retain];
69   }
70   return *this;
73 bool Clipboard::FormatType::Equals(const FormatType& other) const {
74   return [data_ isEqualToString:other.data_];
77 Clipboard::FormatType::~FormatType() {
78   [data_ release];
81 std::string Clipboard::FormatType::Serialize() const {
82   return base::SysNSStringToUTF8(data_);
85 // static
86 Clipboard::FormatType Clipboard::FormatType::Deserialize(
87     const std::string& serialization) {
88   return FormatType(base::SysUTF8ToNSString(serialization));
91 Clipboard::Clipboard() {
92   DCHECK(CalledOnValidThread());
95 Clipboard::~Clipboard() {
96   DCHECK(CalledOnValidThread());
99 void Clipboard::WriteObjects(ClipboardType type, const ObjectMap& objects) {
100   DCHECK(CalledOnValidThread());
101   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
103   NSPasteboard* pb = GetPasteboard();
104   [pb declareTypes:[NSArray array] owner:nil];
106   for (ObjectMap::const_iterator iter = objects.begin();
107        iter != objects.end(); ++iter) {
108     DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
109   }
112 void Clipboard::WriteText(const char* text_data, size_t text_len) {
113   std::string text_str(text_data, text_len);
114   NSString *text = base::SysUTF8ToNSString(text_str);
115   NSPasteboard* pb = GetPasteboard();
116   [pb addTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
117   [pb setString:text forType:NSStringPboardType];
120 void Clipboard::WriteHTML(const char* markup_data,
121                           size_t markup_len,
122                           const char* url_data,
123                           size_t url_len) {
124   // We need to mark it as utf-8. (see crbug.com/11957)
125   std::string html_fragment_str("<meta charset='utf-8'>");
126   html_fragment_str.append(markup_data, markup_len);
127   NSString *html_fragment = base::SysUTF8ToNSString(html_fragment_str);
129   // TODO(avi): url_data?
130   NSPasteboard* pb = GetPasteboard();
131   [pb addTypes:[NSArray arrayWithObject:NSHTMLPboardType] owner:nil];
132   [pb setString:html_fragment forType:NSHTMLPboardType];
135 void Clipboard::WriteRTF(const char* rtf_data, size_t data_len) {
136   WriteData(GetRtfFormatType(), rtf_data, data_len);
139 void Clipboard::WriteBookmark(const char* title_data,
140                               size_t title_len,
141                               const char* url_data,
142                               size_t url_len) {
143   std::string title_str(title_data, title_len);
144   NSString *title =  base::SysUTF8ToNSString(title_str);
145   std::string url_str(url_data, url_len);
146   NSString *url =  base::SysUTF8ToNSString(url_str);
148   // TODO(playmobil): In the Windows version of this function, an HTML
149   // representation of the bookmark is also added to the clipboard, to support
150   // drag and drop of web shortcuts.  I don't think we need to do this on the
151   // Mac, but we should double check later on.
152   NSURL* nsurl = [NSURL URLWithString:url];
154   NSPasteboard* pb = GetPasteboard();
155   // passing UTIs into the pasteboard methods is valid >= 10.5
156   [pb addTypes:[NSArray arrayWithObjects:NSURLPboardType,
157                                          kUTTypeURLName,
158                                          nil]
159          owner:nil];
160   [nsurl writeToPasteboard:pb];
161   [pb setString:title forType:kUTTypeURLName];
164 void Clipboard::WriteBitmap(const SkBitmap& bitmap) {
165   NSImage* image = gfx::SkBitmapToNSImageWithColorSpace(
166       bitmap, base::mac::GetSystemColorSpace());
167   // An API to ask the NSImage to write itself to the clipboard comes in 10.6 :(
168   // For now, spit out the image as a TIFF.
169   NSPasteboard* pb = GetPasteboard();
170   [pb addTypes:[NSArray arrayWithObject:NSTIFFPboardType] owner:nil];
171   NSData *tiff_data = [image TIFFRepresentation];
172   LOG_IF(ERROR, tiff_data == NULL) << "Failed to allocate image for clipboard";
173   if (tiff_data) {
174     [pb setData:tiff_data forType:NSTIFFPboardType];
175   }
178 void Clipboard::WriteData(const FormatType& format,
179                           const char* data_data,
180                           size_t data_len) {
181   NSPasteboard* pb = GetPasteboard();
182   [pb addTypes:[NSArray arrayWithObject:format.ToNSString()] owner:nil];
183   [pb setData:[NSData dataWithBytes:data_data length:data_len]
184       forType:format.ToNSString()];
187 // Write an extra flavor that signifies WebKit was the last to modify the
188 // pasteboard. This flavor has no data.
189 void Clipboard::WriteWebSmartPaste() {
190   NSPasteboard* pb = GetPasteboard();
191   NSString* format = GetWebKitSmartPasteFormatType().ToNSString();
192   [pb addTypes:[NSArray arrayWithObject:format] owner:nil];
193   [pb setData:nil forType:format];
196 uint64 Clipboard::GetSequenceNumber(ClipboardType type) {
197   DCHECK(CalledOnValidThread());
198   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
200   NSPasteboard* pb = GetPasteboard();
201   return [pb changeCount];
204 bool Clipboard::IsFormatAvailable(const FormatType& format,
205                                   ClipboardType type) const {
206   DCHECK(CalledOnValidThread());
207   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
209   NSPasteboard* pb = GetPasteboard();
210   NSArray* types = [pb types];
212   // Safari only places RTF on the pasteboard, never HTML. We can convert RTF
213   // to HTML, so the presence of either indicates success when looking for HTML.
214   if ([format.ToNSString() isEqualToString:NSHTMLPboardType]) {
215     return [types containsObject:NSHTMLPboardType] ||
216            [types containsObject:NSRTFPboardType];
217   }
218   return [types containsObject:format.ToNSString()];
221 void Clipboard::Clear(ClipboardType type) {
222   DCHECK(CalledOnValidThread());
223   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
225   NSPasteboard* pb = GetPasteboard();
226   [pb declareTypes:[NSArray array] owner:nil];
229 void Clipboard::ReadAvailableTypes(ClipboardType type,
230                                    std::vector<base::string16>* types,
231                                    bool* contains_filenames) const {
232   DCHECK(CalledOnValidThread());
233   types->clear();
234   if (IsFormatAvailable(Clipboard::GetPlainTextFormatType(), type))
235     types->push_back(base::UTF8ToUTF16(kMimeTypeText));
236   if (IsFormatAvailable(Clipboard::GetHtmlFormatType(), type))
237     types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
238   if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type))
239     types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
240   if ([NSImage canInitWithPasteboard:GetPasteboard()])
241     types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
242   *contains_filenames = false;
244   NSPasteboard* pb = GetPasteboard();
245   if ([[pb types] containsObject:kWebCustomDataPboardType]) {
246     NSData* data = [pb dataForType:kWebCustomDataPboardType];
247     if ([data length])
248       ReadCustomDataTypes([data bytes], [data length], types);
249   }
252 void Clipboard::ReadText(ClipboardType type, base::string16* result) const {
253   DCHECK(CalledOnValidThread());
254   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
255   NSPasteboard* pb = GetPasteboard();
256   NSString* contents = [pb stringForType:NSStringPboardType];
258   *result = base::SysNSStringToUTF16(contents);
261 void Clipboard::ReadAsciiText(ClipboardType type, std::string* result) const {
262   DCHECK(CalledOnValidThread());
263   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
264   NSPasteboard* pb = GetPasteboard();
265   NSString* contents = [pb stringForType:NSStringPboardType];
267   if (!contents)
268     result->clear();
269   else
270     result->assign([contents UTF8String]);
273 void Clipboard::ReadHTML(ClipboardType type,
274                          base::string16* markup,
275                          std::string* src_url,
276                          uint32* fragment_start,
277                          uint32* fragment_end) const {
278   DCHECK(CalledOnValidThread());
279   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
281   // TODO(avi): src_url?
282   markup->clear();
283   if (src_url)
284     src_url->clear();
286   NSPasteboard* pb = GetPasteboard();
287   NSArray* supportedTypes = [NSArray arrayWithObjects:NSHTMLPboardType,
288                                                       NSRTFPboardType,
289                                                       NSStringPboardType,
290                                                       nil];
291   NSString* bestType = [pb availableTypeFromArray:supportedTypes];
292   if (bestType) {
293     NSString* contents = [pb stringForType:bestType];
294     if ([bestType isEqualToString:NSRTFPboardType])
295       contents = [pb htmlFromRtf];
296     *markup = base::SysNSStringToUTF16(contents);
297   }
299   *fragment_start = 0;
300   DCHECK(markup->length() <= kuint32max);
301   *fragment_end = static_cast<uint32>(markup->length());
304 void Clipboard::ReadRTF(ClipboardType type, std::string* result) const {
305   DCHECK(CalledOnValidThread());
306   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
308   return ReadData(GetRtfFormatType(), result);
311 SkBitmap Clipboard::ReadImage(ClipboardType type) const {
312   DCHECK(CalledOnValidThread());
313   DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
315   // If the pasteboard's image data is not to its liking, the guts of NSImage
316   // may throw, and that exception will leak. Prevent a crash in that case;
317   // a blank image is better.
318   base::scoped_nsobject<NSImage> image(base::mac::RunBlockIgnoringExceptions(^{
319       return [[NSImage alloc] initWithPasteboard:GetPasteboard()];
320   }));
321   SkBitmap bitmap;
322   if (image.get()) {
323     bitmap = gfx::NSImageToSkBitmapWithColorSpace(
324         image.get(), /*is_opaque=*/ false, base::mac::GetSystemColorSpace());
325   }
326   return bitmap;
329 void Clipboard::ReadCustomData(ClipboardType clipboard_type,
330                                const base::string16& type,
331                                base::string16* result) const {
332   DCHECK(CalledOnValidThread());
333   DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE);
335   NSPasteboard* pb = GetPasteboard();
336   if ([[pb types] containsObject:kWebCustomDataPboardType]) {
337     NSData* data = [pb dataForType:kWebCustomDataPboardType];
338     if ([data length])
339       ReadCustomDataForType([data bytes], [data length], type, result);
340   }
343 void Clipboard::ReadBookmark(base::string16* title, std::string* url) const {
344   DCHECK(CalledOnValidThread());
345   NSPasteboard* pb = GetPasteboard();
347   if (title) {
348     NSString* contents = [pb stringForType:kUTTypeURLName];
349     *title = base::SysNSStringToUTF16(contents);
350   }
352   if (url) {
353     NSString* url_string = [[NSURL URLFromPasteboard:pb] absoluteString];
354     if (!url_string)
355       url->clear();
356     else
357       url->assign([url_string UTF8String]);
358   }
361 void Clipboard::ReadData(const FormatType& format, std::string* result) const {
362   DCHECK(CalledOnValidThread());
363   NSPasteboard* pb = GetPasteboard();
364   NSData* data = [pb dataForType:format.ToNSString()];
365   if ([data length])
366     result->assign(static_cast<const char*>([data bytes]), [data length]);
369 // static
370 Clipboard::FormatType Clipboard::GetFormatType(
371     const std::string& format_string) {
372   return FormatType::Deserialize(format_string);
375 // static
376 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
377   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSURLPboardType));
378   return type;
381 // static
382 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
383   return GetUrlFormatType();
386 // static
387 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
388   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSStringPboardType));
389   return type;
392 // static
393 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
394   return GetPlainTextFormatType();
397 // static
398 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
399   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSFilenamesPboardType));
400   return type;
403 // static
404 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
405   return GetFilenameFormatType();
408 // static
409 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
410   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSHTMLPboardType));
411   return type;
414 // static
415 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
416   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSRTFPboardType));
417   return type;
420 // static
421 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
422   CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSTIFFPboardType));
423   return type;
426 // static
427 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
428   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kWebSmartPastePboardType));
429   return type;
432 // static
433 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
434   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kWebCustomDataPboardType));
435   return type;
438 // static
439 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
440   CR_DEFINE_STATIC_LOCAL(FormatType, type, (kPepperCustomDataPboardType));
441   return type;
444 }  // namespace ui