~oif-team/ubuntu/natty/qt4-x11/xi2.1

« back to all changes in this revision

Viewing changes to src/3rdparty/webkit/WebCore/platform/mac/ClipboardMac.mm

  • Committer: Bazaar Package Importer
  • Author(s): Alessandro Ghersi
  • Date: 2009-11-02 18:30:08 UTC
  • mfrom: (1.2.2 upstream)
  • mto: (15.2.5 experimental)
  • mto: This revision was merged to the branch mainline in revision 88.
  • Revision ID: james.westby@ubuntu.com-20091102183008-b6a4gcs128mvfb3m
Tags: upstream-4.6.0~beta1
ImportĀ upstreamĀ versionĀ 4.6.0~beta1

Show diffs side-by-side

added added

removed removed

Lines of Context:
31
31
#import "DragController.h"
32
32
#import "Editor.h"
33
33
#import "FoundationExtras.h"
 
34
#import "FileList.h"
34
35
#import "Frame.h"
35
36
#import "Image.h"
36
37
#import "Page.h"
37
38
#import "Pasteboard.h"
38
39
#import "RenderImage.h"
 
40
#import "SecurityOrigin.h"
39
41
#import "WebCoreSystemInterface.h"
40
42
 
 
43
#ifdef BUILDING_ON_TIGER
 
44
typedef unsigned NSUInteger;
 
45
#endif
 
46
 
41
47
namespace WebCore {
42
48
 
43
49
ClipboardMac::ClipboardMac(bool forDragging, NSPasteboard *pasteboard, ClipboardAccessPolicy policy, Frame *frame)
57
63
    return m_pasteboard && [m_pasteboard.get() types] && [[m_pasteboard.get() types] count] > 0;
58
64
}
59
65
    
60
 
static NSString *cocoaTypeFromMIMEType(const String& type)
 
66
static NSString *cocoaTypeFromHTMLClipboardType(const String& type)
61
67
{
62
68
    String qType = type.stripWhiteSpace();
63
69
 
76
82
    
77
83
    // Try UTI now
78
84
    NSString *mimeType = qType;
79
 
    CFStringRef UTIType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mimeType, NULL);
80
 
    if (UTIType) {
81
 
        CFStringRef pbType = UTTypeCopyPreferredTagWithClass(UTIType, kUTTagClassNSPboardType);
82
 
        CFRelease(UTIType);
 
85
    RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (CFStringRef)mimeType, NULL));
 
86
    if (utiType) {
 
87
        CFStringRef pbType = UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassNSPboardType);
83
88
        if (pbType)
84
89
            return HardAutorelease(pbType);
85
90
    }
88
93
    return qType;
89
94
}
90
95
 
91
 
static String MIMETypeFromCocoaType(NSString *type)
 
96
static String utiTypeFromCocoaType(NSString *type)
 
97
{
 
98
    RetainPtr<CFStringRef> utiType(AdoptCF, UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL));
 
99
    if (utiType) {
 
100
        RetainPtr<CFStringRef> mimeType(AdoptCF, UTTypeCopyPreferredTagWithClass(utiType.get(), kUTTagClassMIMEType));
 
101
        if (mimeType)
 
102
            return String(mimeType.get());
 
103
    }
 
104
    return String();
 
105
}
 
106
 
 
107
static void addHTMLClipboardTypesForCocoaType(HashSet<String>& resultTypes, NSString *cocoaType, NSPasteboard *pasteboard)
92
108
{
93
109
    // UTI may not do these right, so make sure we get the right, predictable result
94
 
    if ([type isEqualToString:NSStringPboardType])
95
 
        return "text/plain";
96
 
    if ([type isEqualToString:NSURLPboardType] || [type isEqualToString:NSFilenamesPboardType])
97
 
        return "text/uri-list";
98
 
    
99
 
    // Now try the general UTI mechanism
100
 
    CFStringRef UTIType = UTTypeCreatePreferredIdentifierForTag(kUTTagClassNSPboardType, (CFStringRef)type, NULL);
101
 
    if (UTIType) {
102
 
        CFStringRef mimeType = UTTypeCopyPreferredTagWithClass(UTIType, kUTTagClassMIMEType);
103
 
        CFRelease(UTIType);
104
 
        if (mimeType) {
105
 
            String result = mimeType;
106
 
            CFRelease(mimeType);
107
 
            return result;
 
110
    if ([cocoaType isEqualToString:NSStringPboardType])
 
111
        resultTypes.add("text/plain");
 
112
    else if ([cocoaType isEqualToString:NSURLPboardType])
 
113
        resultTypes.add("text/uri-list");
 
114
    else if ([cocoaType isEqualToString:NSFilenamesPboardType]) {
 
115
        // If file list is empty, add nothing.
 
116
        // Note that there is a chance that the file list count could have changed since we grabbed the types array.
 
117
        // However, this is not really an issue for us doing a sanity check here.
 
118
        NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType];
 
119
        if ([fileList count]) {
 
120
            // It is unknown if NSFilenamesPboardType always implies NSURLPboardType in Cocoa,
 
121
            // but NSFilenamesPboardType should imply both 'text/uri-list' and 'Files'
 
122
            resultTypes.add("text/uri-list");
 
123
            resultTypes.add("Files");
108
124
        }
 
125
    } else if (String utiType = utiTypeFromCocoaType(cocoaType))
 
126
        resultTypes.add(utiType);
 
127
    else {
 
128
        // No mapping, just pass the whole string though
 
129
        resultTypes.add(cocoaType);
109
130
    }
110
 
 
111
 
    // No mapping, just pass the whole string though
112
 
    return type;
113
131
}
114
132
 
115
133
void ClipboardMac::clearData(const String& type)
119
137
 
120
138
    // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner
121
139
 
122
 
    NSString *cocoaType = cocoaTypeFromMIMEType(type);
123
 
    if (cocoaType) {
 
140
    NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type);
 
141
    if (cocoaType)
124
142
        [m_pasteboard.get() setString:@"" forType:cocoaType];
125
 
    }
126
143
}
127
144
 
128
145
void ClipboardMac::clearAllData()
135
152
    [m_pasteboard.get() declareTypes:[NSArray array] owner:nil];
136
153
}
137
154
 
 
155
static NSArray *absoluteURLsFromPasteboardFilenames(NSPasteboard* pasteboard, bool onlyFirstURL = false)
 
156
{
 
157
    NSArray *fileList = [pasteboard propertyListForType:NSFilenamesPboardType];
 
158
 
 
159
    // FIXME: Why does this code need to guard against bad values on the pasteboard?
 
160
    ASSERT(!fileList || [fileList isKindOfClass:[NSArray class]]);
 
161
    if (!fileList || ![fileList isKindOfClass:[NSArray class]] || ![fileList count])
 
162
        return nil;
 
163
 
 
164
    NSUInteger count = onlyFirstURL ? 1 : [fileList count];
 
165
    NSMutableArray *urls = [NSMutableArray array];
 
166
    for (NSUInteger i = 0; i < count; i++) {
 
167
        NSString *string = [fileList objectAtIndex:i];
 
168
 
 
169
        ASSERT([string isKindOfClass:[NSString class]]);  // Added to understand why this if code is here
 
170
        if (![string isKindOfClass:[NSString class]])
 
171
            return nil; // Non-string object in the list, bail out!  FIXME: When can this happen?
 
172
 
 
173
        NSURL *url = [NSURL fileURLWithPath:string];
 
174
        [urls addObject:[url absoluteString]];
 
175
    }
 
176
    return urls;
 
177
}
 
178
 
 
179
static NSArray *absoluteURLsFromPasteboard(NSPasteboard* pasteboard, bool onlyFirstURL = false)
 
180
{
 
181
    // NOTE: We must always check [availableTypes containsObject:] before accessing pasteboard data
 
182
    // or CoreFoundation will printf when there is not data of the corresponding type.
 
183
    NSArray *availableTypes = [pasteboard types];
 
184
 
 
185
    // Try NSFilenamesPboardType because it contains a list
 
186
    if ([availableTypes containsObject:NSFilenamesPboardType]) {
 
187
        if (NSArray* absoluteURLs = absoluteURLsFromPasteboardFilenames(pasteboard, onlyFirstURL))
 
188
            return absoluteURLs;
 
189
    }
 
190
 
 
191
    // Fallback to NSURLPboardType (which is a single URL)
 
192
    if ([availableTypes containsObject:NSURLPboardType]) {
 
193
        if (NSURL *url = [NSURL URLFromPasteboard:pasteboard])
 
194
            return [NSArray arrayWithObject:[url absoluteString]];
 
195
    }
 
196
 
 
197
    // No file paths on the pasteboard, return nil
 
198
    return nil;
 
199
}
 
200
 
138
201
String ClipboardMac::getData(const String& type, bool& success) const
139
202
{
140
203
    success = false;
141
204
    if (policy() != ClipboardReadable)
142
205
        return String();
143
 
    
144
 
    NSString *cocoaType = cocoaTypeFromMIMEType(type);
 
206
 
 
207
    NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type);
145
208
    NSString *cocoaValue = nil;
146
 
    NSArray *availableTypes = [m_pasteboard.get() types];
147
 
 
148
 
    // Fetch the data in different ways for the different Cocoa types
149
 
 
 
209
 
 
210
    // Grab the value off the pasteboard corresponding to the cocoaType
150
211
    if ([cocoaType isEqualToString:NSURLPboardType]) {
151
 
        // When both URL and filenames are present, filenames is superior since it can contain a list.
152
 
        // must check this or we get a printf from CF when there's no data of this type
153
 
        if ([availableTypes containsObject:NSFilenamesPboardType]) {
154
 
            NSArray *fileList = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
155
 
            if (fileList && [fileList isKindOfClass:[NSArray class]]) {
156
 
                unsigned count = [fileList count];
157
 
                if (count > 0) {
158
 
                    if (type != "text/uri-list")
159
 
                        count = 1;
160
 
                    NSMutableString *urls = [NSMutableString string];
161
 
                    unsigned i;
162
 
                    for (i = 0; i < count; i++) {
163
 
                        if (i > 0) {
164
 
                            [urls appendString:@"\n"];
165
 
                        }
166
 
                        NSString *string = [fileList objectAtIndex:i];
167
 
                        if (![string isKindOfClass:[NSString class]])
168
 
                            break;
169
 
                        NSURL *url = [NSURL fileURLWithPath:string];
170
 
                        [urls appendString:[url absoluteString]];
171
 
                    }
172
 
                    if (i == count)
173
 
                        cocoaValue = urls;
174
 
                }
175
 
            }
176
 
        }
177
 
        if (!cocoaValue) {
178
 
            // must check this or we get a printf from CF when there's no data of this type
179
 
            if ([availableTypes containsObject:NSURLPboardType]) {
180
 
                NSURL *url = [NSURL URLFromPasteboard:m_pasteboard.get()];
181
 
                if (url) {
182
 
                    cocoaValue = [url absoluteString];
183
 
                }
184
 
            }
185
 
        }
186
 
    } else if (cocoaType) {        
 
212
        // "URL" and "text/url-list" both map to NSURLPboardType in cocoaTypeFromHTMLClipboardType(), "URL" only wants the first URL
 
213
        bool onlyFirstURL = (type == "URL");
 
214
        NSArray *absoluteURLs = absoluteURLsFromPasteboard(m_pasteboard.get(), onlyFirstURL);
 
215
        cocoaValue = [absoluteURLs componentsJoinedByString:@"\n"];
 
216
    } else if ([cocoaType isEqualToString:NSStringPboardType]) {
 
217
        cocoaValue = [[m_pasteboard.get() stringForType:cocoaType] precomposedStringWithCanonicalMapping];
 
218
    } else if (cocoaType)
187
219
        cocoaValue = [m_pasteboard.get() stringForType:cocoaType];
188
 
    }
189
220
 
190
221
    // Enforce changeCount ourselves for security.  We check after reading instead of before to be
191
222
    // sure it doesn't change between our testing the change count and accessing the data.
203
234
        return false;
204
235
    // note NSPasteboard enforces changeCount itself on writing - can't write if not the owner
205
236
 
206
 
    NSString *cocoaType = cocoaTypeFromMIMEType(type);
 
237
    NSString *cocoaType = cocoaTypeFromHTMLClipboardType(type);
207
238
    NSString *cocoaData = data;
208
239
 
209
240
    if ([cocoaType isEqualToString:NSURLPboardType]) {
211
242
        NSURL *url = [[NSURL alloc] initWithString:cocoaData];
212
243
        [url writeToPasteboard:m_pasteboard.get()];
213
244
 
214
 
        if ([url isFileURL]) {
 
245
        if ([url isFileURL] && m_frame->document()->securityOrigin()->canLoadLocalResources()) {
215
246
            [m_pasteboard.get() addTypes:[NSArray arrayWithObject:NSFilenamesPboardType] owner:nil];
216
247
            NSArray *fileList = [NSArray arrayWithObject:[url path]];
217
248
            [m_pasteboard.get() setPropertyList:fileList forType:NSFilenamesPboardType];
243
274
        return HashSet<String>();
244
275
 
245
276
    HashSet<String> result;
246
 
    if (types) {
247
 
        unsigned count = [types count];
248
 
        unsigned i;
249
 
        for (i = 0; i < count; i++) {
250
 
            NSString *pbType = [types objectAtIndex:i];
251
 
            if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"])
252
 
                continue;   // skip this ancient type that gets auto-supplied by some system conversion
 
277
    NSUInteger count = [types count];
 
278
    // FIXME: This loop could be split into two stages. One which adds all the HTML5 specified types
 
279
    // and a second which adds all the extra types from the cocoa clipboard (which is Mac-only behavior).
 
280
    for (NSUInteger i = 0; i < count; i++) {
 
281
        NSString *pbType = [types objectAtIndex:i];
 
282
        if ([pbType isEqualToString:@"NeXT plain ascii pasteboard type"])
 
283
            continue;   // skip this ancient type that gets auto-supplied by some system conversion
253
284
 
254
 
            String str = MIMETypeFromCocoaType(pbType);
255
 
            if (!result.contains(str))
256
 
                result.add(str);
257
 
        }
 
285
        addHTMLClipboardTypesForCocoaType(result, pbType, m_pasteboard.get());
258
286
    }
 
287
 
259
288
    return result;
260
289
}
261
290
 
 
291
// FIXME: We could cache the computed fileList if necessary
 
292
// Currently each access gets a new copy, setData() modifications to the
 
293
// clipboard are not reflected in any FileList objects the page has accessed and stored
 
294
PassRefPtr<FileList> ClipboardMac::files() const
 
295
{
 
296
    if (policy() != ClipboardReadable)
 
297
        return FileList::create();
 
298
 
 
299
    NSArray *absoluteURLs = absoluteURLsFromPasteboardFilenames(m_pasteboard.get());
 
300
    NSUInteger count = [absoluteURLs count];
 
301
 
 
302
    RefPtr<FileList> fileList = FileList::create();
 
303
    for (NSUInteger x = 0; x < count; x++) {
 
304
        NSURL *absoluteURL = [NSURL URLWithString:[absoluteURLs objectAtIndex:x]];
 
305
        ASSERT([absoluteURL isFileURL]);
 
306
        fileList->append(File::create([absoluteURL path]));
 
307
    }
 
308
    return fileList.release(); // We will always return a FileList, sometimes empty
 
309
}
 
310
 
262
311
// The rest of these getters don't really have any impact on security, so for now make no checks
263
312
 
264
313
void ClipboardMac::setDragImage(CachedImage* img, const IntPoint &loc)
319
368
    Pasteboard::writeURL(m_pasteboard.get(), nil, url, title, frame);
320
369
}
321
370
    
 
371
#if ENABLE(DRAG_SUPPORT)
322
372
void ClipboardMac::declareAndWriteDragImage(Element* element, const KURL& url, const String& title, Frame* frame)
323
373
{
324
374
    ASSERT(frame);
325
375
    if (Page* page = frame->page())
326
 
        page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), [DOMElement _wrapElement:element], url, title, frame);
 
376
        page->dragController()->client()->declareAndWriteDragImage(m_pasteboard.get(), kit(element), url, title, frame);
327
377
}
 
378
#endif // ENABLE(DRAG_SUPPORT)
328
379
    
329
380
DragImageRef ClipboardMac::createDragImage(IntPoint& loc) const
330
381
{