Refactor Mac platform implementation of the Pasteboard class to use Platform Strategies.
[WebKit-https.git] / Source / WebCore / platform / mac / DragDataMac.mm
1 /*
2  * Copyright (C) 2007 Apple Inc.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
24  */
25
26 #import "config.h"
27 #import "DragData.h"
28
29 #if ENABLE(DRAG_SUPPORT)
30 #import "Document.h"
31 #import "DocumentFragment.h"
32 #import "DOMDocumentFragment.h"
33 #import "DOMDocumentFragmentInternal.h"
34 #import "Editor.h"
35 #import "EditorClient.h"
36 #import "Frame.h"
37 #import "MIMETypeRegistry.h"
38 #import "Pasteboard.h"
39 #import "Range.h"
40
41 namespace WebCore {
42
43 DragData::DragData(DragDataRef data, const IntPoint& clientPosition, const IntPoint& globalPosition, 
44     DragOperation sourceOperationMask, DragApplicationFlags flags)
45     : m_clientPosition(clientPosition)
46     , m_globalPosition(globalPosition)
47     , m_platformDragData(data)
48     , m_draggingSourceOperationMask(sourceOperationMask)
49     , m_applicationFlags(flags)
50     , m_pasteboard([m_platformDragData draggingPasteboard])
51 {
52 }
53
54 DragData::DragData(const String& dragStorageName, const IntPoint& clientPosition, const IntPoint& globalPosition,
55     DragOperation sourceOperationMask, DragApplicationFlags flags)
56     : m_clientPosition(clientPosition)
57     , m_globalPosition(globalPosition)
58     , m_platformDragData(0)
59     , m_draggingSourceOperationMask(sourceOperationMask)
60     , m_applicationFlags(flags)
61     , m_pasteboard([NSPasteboard pasteboardWithName:dragStorageName])
62 {
63 }
64     
65 bool DragData::canSmartReplace() const
66 {
67     //Need to call this so that the various Pasteboard type strings are intialised
68     Pasteboard::generalPasteboard();
69     return [[m_pasteboard.get() types] containsObject:String(WebSmartPastePboardType)];
70 }
71
72 bool DragData::containsColor() const
73 {
74     return [[m_pasteboard.get() types] containsObject:NSColorPboardType];
75 }
76
77 bool DragData::containsFiles() const
78 {
79     return [[m_pasteboard.get() types] containsObject:NSFilenamesPboardType];
80 }
81
82 unsigned DragData::numberOfFiles() const
83 {
84     if (![[m_pasteboard.get() types] containsObject:NSFilenamesPboardType])
85         return 0;
86     return [[m_pasteboard.get() propertyListForType:NSFilenamesPboardType] count];
87 }
88
89 void DragData::asFilenames(Vector<String>& result) const
90 {
91     NSArray *filenames = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
92     NSEnumerator *fileEnumerator = [filenames objectEnumerator];
93     
94     while (NSString *filename = [fileEnumerator nextObject])
95         result.append(filename);
96 }
97
98 bool DragData::containsPlainText() const
99 {
100     NSArray *types = [m_pasteboard.get() types];
101     
102     return [types containsObject:NSStringPboardType] 
103         || [types containsObject:NSRTFDPboardType]
104         || [types containsObject:NSRTFPboardType]
105         || [types containsObject:NSFilenamesPboardType]
106         || [NSURL URLFromPasteboard:m_pasteboard.get()];
107 }
108
109 String DragData::asPlainText(Frame *frame) const
110 {
111     Pasteboard pasteboard([m_pasteboard.get() name]);
112     return pasteboard.plainText(frame);
113 }
114
115 Color DragData::asColor() const
116 {
117     NSColor *color = [NSColor colorFromPasteboard:m_pasteboard.get()];
118     
119     // The color may not be in an RGB colorspace. This commonly occurs when a color is 
120     // dragged from the NSColorPanel grayscale picker.
121     if ([[color colorSpace] colorSpaceModel] != NSRGBColorSpaceModel)
122         color = [color colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
123     
124     return makeRGBA((int)([color redComponent] * 255.0 + 0.5), (int)([color greenComponent] * 255.0 + 0.5), 
125                     (int)([color blueComponent] * 255.0 + 0.5), (int)([color alphaComponent] * 255.0 + 0.5));
126 }
127
128 static NSArray *insertablePasteboardTypes()
129 {
130     static NSArray *types = nil;
131     if (!types) {
132         types = [[NSArray alloc] initWithObjects:String(WebArchivePboardType), NSHTMLPboardType, NSFilenamesPboardType, NSTIFFPboardType, NSPDFPboardType,
133 #ifdef BUILDING_ON_LEOPARD
134                  NSPICTPboardType,
135 #endif
136                  NSURLPboardType, NSRTFDPboardType, NSRTFPboardType, NSStringPboardType, NSColorPboardType, kUTTypePNG, nil];
137         CFRetain(types);
138     }
139     return types;
140 }
141     
142 bool DragData::containsCompatibleContent() const
143 {
144     NSMutableSet *types = [NSMutableSet setWithArray:[m_pasteboard.get() types]];
145     [types intersectSet:[NSSet setWithArray:insertablePasteboardTypes()]];
146     return [types count] != 0;
147 }
148     
149 bool DragData::containsURL(Frame* frame, FilenameConversionPolicy filenamePolicy) const
150 {
151     return !asURL(frame, filenamePolicy).isEmpty();
152 }
153
154 String DragData::asURL(Frame* frame, FilenameConversionPolicy filenamePolicy, String* title) const
155 {
156     // FIXME: Use filenamePolicy.
157     (void)filenamePolicy;
158
159     if (title) {
160         if (NSString *URLTitleString = [m_pasteboard.get() stringForType:String(WebURLNamePboardType)])
161             *title = URLTitleString;
162     }
163     
164     NSArray *types = [m_pasteboard.get() types];
165     
166     // FIXME: using the editorClient to call into WebKit, for now, since 
167     // calling webkit_canonicalize from WebCore involves migrating a sizable amount of 
168     // helper code that should either be done in a separate patch or figured out in another way.
169     
170     if ([types containsObject:NSURLPboardType]) {
171         NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:m_pasteboard.get()];
172         NSString *scheme = [URLFromPasteboard scheme];
173         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
174             return [frame->editor()->client()->canonicalizeURL(URLFromPasteboard) absoluteString];
175         }
176     }
177     
178     if ([types containsObject:NSStringPboardType]) {
179         NSString *URLString = [m_pasteboard.get() stringForType:NSStringPboardType];
180         NSURL *URL = frame->editor()->client()->canonicalizeURLString(URLString);
181         if (URL)
182             return [URL absoluteString];
183     }
184     
185     if ([types containsObject:NSFilenamesPboardType]) {
186         NSArray *files = [m_pasteboard.get() propertyListForType:NSFilenamesPboardType];
187         if ([files count] == 1) {
188             NSString *file = [files objectAtIndex:0];
189             BOOL isDirectory;
190             if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory)
191                 return String();
192             return [frame->editor()->client()->canonicalizeURL([NSURL fileURLWithPath:file]) absoluteString];
193         }
194     }
195     
196     return String();        
197 }
198
199 PassRefPtr<DocumentFragment> DragData::asFragment(Frame* frame, PassRefPtr<Range> range, bool allowPlainText, bool& chosePlainText) const
200 {
201     Pasteboard pasteboard([m_pasteboard.get() name]);
202     
203     return pasteboard.documentFragment(frame, range, allowPlainText, chosePlainText);
204 }
205     
206 } // namespace WebCore
207
208 #endif // ENABLE(DRAG_SUPPORT)