Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(618)

Side by Side Diff: ui/base/clipboard/clipboard_mac.mm

Issue 851853002: It is time. (Closed) Base URL: https://github.com/domokit/mojo.git@master
Patch Set: Trying to reup because the last upload failed. Created 5 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « ui/base/clipboard/clipboard_mac.h ('k') | ui/base/clipboard/clipboard_types.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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_mac.h"
6
7 #import <Cocoa/Cocoa.h>
8
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"
26
27 namespace ui {
28
29 namespace {
30
31 // Would be nice if this were in UTCoreTypes.h, but it isn't
32 NSString* const kUTTypeURLName = @"public.url-name";
33
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";
37
38 // Pepper custom data format type.
39 NSString* const kPepperCustomDataPboardType =
40 @"org.chromium.pepper-custom-data";
41
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;
49 }
50
51 } // namespace
52
53 // Clipboard::FormatType implementation.
54 Clipboard::FormatType::FormatType() : data_(nil) {
55 }
56
57 Clipboard::FormatType::FormatType(NSString* native_format)
58 : data_([native_format retain]) {
59 }
60
61 Clipboard::FormatType::FormatType(const FormatType& other)
62 : data_([other.data_ retain]) {
63 }
64
65 Clipboard::FormatType& Clipboard::FormatType::operator=(
66 const FormatType& other) {
67 if (this != &other) {
68 [data_ release];
69 data_ = [other.data_ retain];
70 }
71 return *this;
72 }
73
74 bool Clipboard::FormatType::Equals(const FormatType& other) const {
75 return [data_ isEqualToString:other.data_];
76 }
77
78 Clipboard::FormatType::~FormatType() {
79 [data_ release];
80 }
81
82 std::string Clipboard::FormatType::Serialize() const {
83 return base::SysNSStringToUTF8(data_);
84 }
85
86 // static
87 Clipboard::FormatType Clipboard::FormatType::Deserialize(
88 const std::string& serialization) {
89 return FormatType(base::SysUTF8ToNSString(serialization));
90 }
91
92 // Various predefined FormatTypes.
93 // static
94 Clipboard::FormatType Clipboard::GetFormatType(
95 const std::string& format_string) {
96 return FormatType::Deserialize(format_string);
97 }
98
99 // static
100 const Clipboard::FormatType& Clipboard::GetUrlFormatType() {
101 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSURLPboardType));
102 return type;
103 }
104
105 // static
106 const Clipboard::FormatType& Clipboard::GetUrlWFormatType() {
107 return GetUrlFormatType();
108 }
109
110 // static
111 const Clipboard::FormatType& Clipboard::GetPlainTextFormatType() {
112 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSStringPboardType));
113 return type;
114 }
115
116 // static
117 const Clipboard::FormatType& Clipboard::GetPlainTextWFormatType() {
118 return GetPlainTextFormatType();
119 }
120
121 // static
122 const Clipboard::FormatType& Clipboard::GetFilenameFormatType() {
123 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSFilenamesPboardType));
124 return type;
125 }
126
127 // static
128 const Clipboard::FormatType& Clipboard::GetFilenameWFormatType() {
129 return GetFilenameFormatType();
130 }
131
132 // static
133 const Clipboard::FormatType& Clipboard::GetHtmlFormatType() {
134 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSHTMLPboardType));
135 return type;
136 }
137
138 // static
139 const Clipboard::FormatType& Clipboard::GetRtfFormatType() {
140 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSRTFPboardType));
141 return type;
142 }
143
144 // static
145 const Clipboard::FormatType& Clipboard::GetBitmapFormatType() {
146 CR_DEFINE_STATIC_LOCAL(FormatType, type, (NSTIFFPboardType));
147 return type;
148 }
149
150 // static
151 const Clipboard::FormatType& Clipboard::GetWebKitSmartPasteFormatType() {
152 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kWebSmartPastePboardType));
153 return type;
154 }
155
156 // static
157 const Clipboard::FormatType& Clipboard::GetWebCustomDataFormatType() {
158 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kWebCustomDataPboardType));
159 return type;
160 }
161
162 // static
163 const Clipboard::FormatType& Clipboard::GetPepperCustomDataFormatType() {
164 CR_DEFINE_STATIC_LOCAL(FormatType, type, (kPepperCustomDataPboardType));
165 return type;
166 }
167
168 // Clipboard factory method.
169 // static
170 Clipboard* Clipboard::Create() {
171 return new ClipboardMac;
172 }
173
174 // ClipboardMac implementation.
175 ClipboardMac::ClipboardMac() {
176 DCHECK(CalledOnValidThread());
177 }
178
179 ClipboardMac::~ClipboardMac() {
180 DCHECK(CalledOnValidThread());
181 }
182
183 uint64 ClipboardMac::GetSequenceNumber(ClipboardType type) {
184 DCHECK(CalledOnValidThread());
185 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
186
187 NSPasteboard* pb = GetPasteboard();
188 return [pb changeCount];
189 }
190
191 bool ClipboardMac::IsFormatAvailable(const FormatType& format,
192 ClipboardType type) const {
193 DCHECK(CalledOnValidThread());
194 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
195
196 NSPasteboard* pb = GetPasteboard();
197 NSArray* types = [pb types];
198
199 // Safari only places RTF on the pasteboard, never HTML. We can convert RTF
200 // to HTML, so the presence of either indicates success when looking for HTML.
201 if ([format.ToNSString() isEqualToString:NSHTMLPboardType]) {
202 return [types containsObject:NSHTMLPboardType] ||
203 [types containsObject:NSRTFPboardType];
204 }
205 return [types containsObject:format.ToNSString()];
206 }
207
208 void ClipboardMac::Clear(ClipboardType type) {
209 DCHECK(CalledOnValidThread());
210 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
211
212 NSPasteboard* pb = GetPasteboard();
213 [pb declareTypes:[NSArray array] owner:nil];
214 }
215
216 void ClipboardMac::ReadAvailableTypes(ClipboardType type,
217 std::vector<base::string16>* types,
218 bool* contains_filenames) const {
219 DCHECK(CalledOnValidThread());
220 types->clear();
221 if (IsFormatAvailable(Clipboard::GetPlainTextFormatType(), type))
222 types->push_back(base::UTF8ToUTF16(kMimeTypeText));
223 if (IsFormatAvailable(Clipboard::GetHtmlFormatType(), type))
224 types->push_back(base::UTF8ToUTF16(kMimeTypeHTML));
225 if (IsFormatAvailable(Clipboard::GetRtfFormatType(), type))
226 types->push_back(base::UTF8ToUTF16(kMimeTypeRTF));
227 if ([NSImage canInitWithPasteboard:GetPasteboard()])
228 types->push_back(base::UTF8ToUTF16(kMimeTypePNG));
229 *contains_filenames = false;
230
231 NSPasteboard* pb = GetPasteboard();
232 if ([[pb types] containsObject:kWebCustomDataPboardType]) {
233 NSData* data = [pb dataForType:kWebCustomDataPboardType];
234 if ([data length])
235 ReadCustomDataTypes([data bytes], [data length], types);
236 }
237 }
238
239 void ClipboardMac::ReadText(ClipboardType type, base::string16* result) const {
240 DCHECK(CalledOnValidThread());
241 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
242 NSPasteboard* pb = GetPasteboard();
243 NSString* contents = [pb stringForType:NSStringPboardType];
244
245 *result = base::SysNSStringToUTF16(contents);
246 }
247
248 void ClipboardMac::ReadAsciiText(ClipboardType type,
249 std::string* result) const {
250 DCHECK(CalledOnValidThread());
251 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
252 NSPasteboard* pb = GetPasteboard();
253 NSString* contents = [pb stringForType:NSStringPboardType];
254
255 if (!contents)
256 result->clear();
257 else
258 result->assign([contents UTF8String]);
259 }
260
261 void ClipboardMac::ReadHTML(ClipboardType type,
262 base::string16* markup,
263 std::string* src_url,
264 uint32* fragment_start,
265 uint32* fragment_end) const {
266 DCHECK(CalledOnValidThread());
267 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
268
269 // TODO(avi): src_url?
270 markup->clear();
271 if (src_url)
272 src_url->clear();
273
274 NSPasteboard* pb = GetPasteboard();
275 NSArray* supportedTypes = [NSArray arrayWithObjects:NSHTMLPboardType,
276 NSRTFPboardType,
277 NSStringPboardType,
278 nil];
279 NSString* bestType = [pb availableTypeFromArray:supportedTypes];
280 if (bestType) {
281 NSString* contents = [pb stringForType:bestType];
282 if ([bestType isEqualToString:NSRTFPboardType])
283 contents = [pb htmlFromRtf];
284 *markup = base::SysNSStringToUTF16(contents);
285 }
286
287 *fragment_start = 0;
288 DCHECK(markup->length() <= kuint32max);
289 *fragment_end = static_cast<uint32>(markup->length());
290 }
291
292 void ClipboardMac::ReadRTF(ClipboardType type, std::string* result) const {
293 DCHECK(CalledOnValidThread());
294 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
295
296 return ReadData(GetRtfFormatType(), result);
297 }
298
299 SkBitmap ClipboardMac::ReadImage(ClipboardType type) const {
300 DCHECK(CalledOnValidThread());
301 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
302
303 // If the pasteboard's image data is not to its liking, the guts of NSImage
304 // may throw, and that exception will leak. Prevent a crash in that case;
305 // a blank image is better.
306 base::scoped_nsobject<NSImage> image(base::mac::RunBlockIgnoringExceptions(^{
307 return [[NSImage alloc] initWithPasteboard:GetPasteboard()];
308 }));
309 SkBitmap bitmap;
310 if (image.get()) {
311 bitmap = gfx::NSImageToSkBitmapWithColorSpace(
312 image.get(), /*is_opaque=*/ false, base::mac::GetSystemColorSpace());
313 }
314 return bitmap;
315 }
316
317 void ClipboardMac::ReadCustomData(ClipboardType clipboard_type,
318 const base::string16& type,
319 base::string16* result) const {
320 DCHECK(CalledOnValidThread());
321 DCHECK_EQ(clipboard_type, CLIPBOARD_TYPE_COPY_PASTE);
322
323 NSPasteboard* pb = GetPasteboard();
324 if ([[pb types] containsObject:kWebCustomDataPboardType]) {
325 NSData* data = [pb dataForType:kWebCustomDataPboardType];
326 if ([data length])
327 ReadCustomDataForType([data bytes], [data length], type, result);
328 }
329 }
330
331 void ClipboardMac::ReadBookmark(base::string16* title, std::string* url) const {
332 DCHECK(CalledOnValidThread());
333 NSPasteboard* pb = GetPasteboard();
334
335 if (title) {
336 NSString* contents = [pb stringForType:kUTTypeURLName];
337 *title = base::SysNSStringToUTF16(contents);
338 }
339
340 if (url) {
341 NSString* url_string = [[NSURL URLFromPasteboard:pb] absoluteString];
342 if (!url_string)
343 url->clear();
344 else
345 url->assign([url_string UTF8String]);
346 }
347 }
348
349 void ClipboardMac::ReadData(const FormatType& format,
350 std::string* result) const {
351 DCHECK(CalledOnValidThread());
352 NSPasteboard* pb = GetPasteboard();
353 NSData* data = [pb dataForType:format.ToNSString()];
354 if ([data length])
355 result->assign(static_cast<const char*>([data bytes]), [data length]);
356 }
357
358 void ClipboardMac::WriteObjects(ClipboardType type, const ObjectMap& objects) {
359 DCHECK(CalledOnValidThread());
360 DCHECK_EQ(type, CLIPBOARD_TYPE_COPY_PASTE);
361
362 NSPasteboard* pb = GetPasteboard();
363 [pb declareTypes:[NSArray array] owner:nil];
364
365 for (ObjectMap::const_iterator iter = objects.begin(); iter != objects.end();
366 ++iter) {
367 DispatchObject(static_cast<ObjectType>(iter->first), iter->second);
368 }
369 }
370
371 void ClipboardMac::WriteText(const char* text_data, size_t text_len) {
372 std::string text_str(text_data, text_len);
373 NSString* text = base::SysUTF8ToNSString(text_str);
374 NSPasteboard* pb = GetPasteboard();
375 [pb addTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
376 [pb setString:text forType:NSStringPboardType];
377 }
378
379 void ClipboardMac::WriteHTML(const char* markup_data,
380 size_t markup_len,
381 const char* url_data,
382 size_t url_len) {
383 // We need to mark it as utf-8. (see crbug.com/11957)
384 std::string html_fragment_str("<meta charset='utf-8'>");
385 html_fragment_str.append(markup_data, markup_len);
386 NSString* html_fragment = base::SysUTF8ToNSString(html_fragment_str);
387
388 // TODO(avi): url_data?
389 NSPasteboard* pb = GetPasteboard();
390 [pb addTypes:[NSArray arrayWithObject:NSHTMLPboardType] owner:nil];
391 [pb setString:html_fragment forType:NSHTMLPboardType];
392 }
393
394 void ClipboardMac::WriteRTF(const char* rtf_data, size_t data_len) {
395 WriteData(GetRtfFormatType(), rtf_data, data_len);
396 }
397
398 void ClipboardMac::WriteBookmark(const char* title_data,
399 size_t title_len,
400 const char* url_data,
401 size_t url_len) {
402 std::string title_str(title_data, title_len);
403 NSString* title = base::SysUTF8ToNSString(title_str);
404 std::string url_str(url_data, url_len);
405 NSString* url = base::SysUTF8ToNSString(url_str);
406
407 // TODO(playmobil): In the Windows version of this function, an HTML
408 // representation of the bookmark is also added to the clipboard, to support
409 // drag and drop of web shortcuts. I don't think we need to do this on the
410 // Mac, but we should double check later on.
411 NSURL* nsurl = [NSURL URLWithString:url];
412
413 NSPasteboard* pb = GetPasteboard();
414 // passing UTIs into the pasteboard methods is valid >= 10.5
415 [pb addTypes:[NSArray arrayWithObjects:NSURLPboardType, kUTTypeURLName, nil]
416 owner:nil];
417 [nsurl writeToPasteboard:pb];
418 [pb setString:title forType:kUTTypeURLName];
419 }
420
421 void ClipboardMac::WriteBitmap(const SkBitmap& bitmap) {
422 NSImage* image = gfx::SkBitmapToNSImageWithColorSpace(
423 bitmap, base::mac::GetSystemColorSpace());
424 // An API to ask the NSImage to write itself to the clipboard comes in 10.6 :(
425 // For now, spit out the image as a TIFF.
426 NSPasteboard* pb = GetPasteboard();
427 [pb addTypes:[NSArray arrayWithObject:NSTIFFPboardType] owner:nil];
428 NSData* tiff_data = [image TIFFRepresentation];
429 LOG_IF(ERROR, tiff_data == NULL) << "Failed to allocate image for clipboard";
430 if (tiff_data) {
431 [pb setData:tiff_data forType:NSTIFFPboardType];
432 }
433 }
434
435 void ClipboardMac::WriteData(const FormatType& format,
436 const char* data_data,
437 size_t data_len) {
438 NSPasteboard* pb = GetPasteboard();
439 [pb addTypes:[NSArray arrayWithObject:format.ToNSString()] owner:nil];
440 [pb setData:[NSData dataWithBytes:data_data length:data_len]
441 forType:format.ToNSString()];
442 }
443
444 // Write an extra flavor that signifies WebKit was the last to modify the
445 // pasteboard. This flavor has no data.
446 void ClipboardMac::WriteWebSmartPaste() {
447 NSPasteboard* pb = GetPasteboard();
448 NSString* format = GetWebKitSmartPasteFormatType().ToNSString();
449 [pb addTypes:[NSArray arrayWithObject:format] owner:nil];
450 [pb setData:nil forType:format];
451 }
452
453 } // namespace ui
OLDNEW
« no previous file with comments | « ui/base/clipboard/clipboard_mac.h ('k') | ui/base/clipboard/clipboard_types.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698