ASSERTION FAILED: ASSERT(!containsImage || MIMETypeRegistry::isSupportedImageResource...
[WebKit-https.git] / Source / WebKitLegacy / mac / Misc / WebNSPasteboardExtras.mm
1 /*
2  * Copyright (C) 2005, 2006, 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  *
8  * 1.  Redistributions of source code must retain the above copyright
9  *     notice, this list of conditions and the following disclaimer. 
10  * 2.  Redistributions in binary form must reproduce the above copyright
11  *     notice, this list of conditions and the following disclaimer in the
12  *     documentation and/or other materials provided with the distribution. 
13  * 3.  Neither the name of Apple Inc. ("Apple") nor the names of
14  *     its contributors may be used to endorse or promote products derived
15  *     from this software without specific prior written permission. 
16  *
17  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
18  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28
29 #if !PLATFORM(IOS)
30
31 #import "WebNSPasteboardExtras.h"
32
33 #import "DOMElementInternal.h"
34 #import "WebArchive.h"
35 #import "WebFrameInternal.h"
36 #import "WebHTMLViewInternal.h"
37 #import "WebNSURLExtras.h"
38 #import "WebResourcePrivate.h"
39 #import "WebURLsWithTitles.h"
40 #import "WebViewPrivate.h"
41 #import <WebCore/CachedImage.h>
42 #import <WebCore/Element.h>
43 #import <WebCore/Image.h>
44 #import <WebCore/LegacyNSPasteboardTypes.h>
45 #import <WebCore/MIMETypeRegistry.h>
46 #import <WebCore/RenderAttachment.h>
47 #import <WebCore/RenderImage.h>
48 #import <WebKitLegacy/DOMExtensions.h>
49 #import <WebKitLegacy/DOMPrivate.h>
50 #import <wtf/Assertions.h>
51 #import <wtf/RetainPtr.h>
52 #import <wtf/StdLibExtras.h>
53
54 using namespace WebCore;
55
56 NSString *WebURLPboardType = @"public.url";
57 NSString *WebURLNamePboardType = @"public.url-name";
58
59 @implementation NSPasteboard (WebExtras)
60
61 + (NSArray *)_web_writableTypesForURL
62 {
63     static NSArray *types = [[NSArray alloc] initWithObjects:
64         WebURLsWithTitlesPboardType,
65         legacyURLPasteboardType(),
66         WebURLPboardType,
67         WebURLNamePboardType,
68         legacyStringPasteboardType(),
69         nil];
70     return types;
71 }
72
73 static inline NSArray *_createWritableTypesForImageWithoutArchive()
74 {
75     NSMutableArray *types = [[NSMutableArray alloc] initWithObjects:legacyTIFFPasteboardType(), nil];
76     [types addObjectsFromArray:[NSPasteboard _web_writableTypesForURL]];
77     return types;
78 }
79
80 static NSArray *_writableTypesForImageWithoutArchive (void)
81 {
82     static NSArray *types = _createWritableTypesForImageWithoutArchive();
83     return types;
84 }
85
86 static inline NSArray *_createWritableTypesForImageWithArchive()
87 {
88     NSMutableArray *types = [_writableTypesForImageWithoutArchive() mutableCopy];
89     [types addObject:legacyRTFDPasteboardType()];
90     [types addObject:WebArchivePboardType];
91     return types;
92 }
93
94 static NSArray *_writableTypesForImageWithArchive (void)
95 {
96     static NSArray *types = _createWritableTypesForImageWithArchive();
97     return types;
98 }
99
100 + (NSArray *)_web_writableTypesForImageIncludingArchive:(BOOL)hasArchive
101 {
102     return hasArchive 
103         ? _writableTypesForImageWithArchive()
104         : _writableTypesForImageWithoutArchive();
105 }
106
107 + (NSArray *)_web_dragTypesForURL
108 {
109     return [NSArray arrayWithObjects:
110         WebURLsWithTitlesPboardType,
111         legacyURLPasteboardType(),
112         WebURLPboardType,
113         WebURLNamePboardType,
114         legacyStringPasteboardType(),
115         legacyFilenamesPasteboardType(),
116 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
117         legacyFilesPromisePasteboardType(),
118 #endif
119         nil];
120 }
121
122 - (NSURL *)_web_bestURL
123 {
124     NSArray *types = [self types];
125
126     if ([types containsObject:legacyURLPasteboardType()]) {
127         NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:self];
128         NSString *scheme = [URLFromPasteboard scheme];
129         if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) {
130             return [URLFromPasteboard _webkit_canonicalize];
131         }
132     }
133
134     if ([types containsObject:legacyStringPasteboardType()]) {
135         NSString *URLString = [self stringForType:legacyStringPasteboardType()];
136         if ([URLString _webkit_looksLikeAbsoluteURL]) {
137             NSURL *URL = [[NSURL _webkit_URLWithUserTypedString:URLString] _webkit_canonicalize];
138             if (URL) {
139                 return URL;
140             }
141         }
142     }
143
144     if ([types containsObject:legacyFilenamesPasteboardType()]) {
145         NSArray *files = [self propertyListForType:legacyFilenamesPasteboardType()];
146         // FIXME: Maybe it makes more sense to allow multiple files and only use the first one?
147         if ([files count] == 1) {
148             NSString *file = [files objectAtIndex:0];
149             // FIXME: We are filtering out directories because that's what the original code used to
150             // do. Without this check, if the URL points to a local directory, Safari will open the
151             // parent directory of the directory in Finder. This check should go away as soon as
152             // possible.
153             BOOL isDirectory;
154             if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory)
155                 return nil;
156             return [[NSURL fileURLWithPath:file] _webkit_canonicalize];
157         }
158     }
159
160     return nil;
161 }
162
163 - (void)_web_writeURL:(NSURL *)URL andTitle:(NSString *)title types:(NSArray *)types
164 {
165     ASSERT(URL);
166
167     if ([title length] == 0) {
168         title = [[URL path] lastPathComponent];
169         if ([title length] == 0)
170             title = [URL _web_userVisibleString];
171     }
172     
173     if ([types containsObject:legacyURLPasteboardType()])
174         [URL writeToPasteboard:self];
175     if ([types containsObject:WebURLPboardType])
176         [self setString:[URL _web_originalDataAsString] forType:WebURLPboardType];
177     if ([types containsObject:WebURLNamePboardType])
178         [self setString:title forType:WebURLNamePboardType];
179     if ([types containsObject:legacyStringPasteboardType()])
180         [self setString:[URL _web_userVisibleString] forType:legacyStringPasteboardType()];
181     if ([types containsObject:WebURLsWithTitlesPboardType])
182         [WebURLsWithTitles writeURLs:[NSArray arrayWithObject:URL] andTitles:[NSArray arrayWithObject:title] toPasteboard:self];
183 }
184
185 + (int)_web_setFindPasteboardString:(NSString *)string withOwner:(id)owner
186 {
187 #pragma clang diagnostic push
188 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
189     NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard];
190 #pragma clang diagnostic pop
191     [findPasteboard declareTypes:[NSArray arrayWithObject:legacyStringPasteboardType()] owner:owner];
192     [findPasteboard setString:string forType:legacyStringPasteboardType()];
193     return [findPasteboard changeCount];
194 }
195
196 - (void)_web_writeFileWrapperAsRTFDAttachment:(NSFileWrapper *)wrapper
197 {
198     NSTextAttachment *attachment = [[NSTextAttachment alloc] initWithFileWrapper:wrapper];
199     
200     NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment];
201     [attachment release];
202     
203     NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:@{ }];
204     [self setData:RTFDData forType:legacyRTFDPasteboardType()];
205 }
206
207
208 - (void)_web_writePromisedRTFDFromArchive:(WebArchive*)archive containsImage:(BOOL)containsImage
209 {
210     ASSERT(archive);
211     // This image data is either the only subresource of an archive (HTML image case)
212     // or the main resource (standalone image case).
213     NSArray *subresources = [archive subresources];
214     WebResource *resource = [archive mainResource];
215     if (containsImage && [subresources count] > 0) {
216         WebResource *subresource = [subresources objectAtIndex:0];
217         NSString *subresourceMIMEType = [subresource MIMEType];
218         if (MIMETypeRegistry::isSupportedImageResourceMIMEType(subresourceMIMEType) || MIMETypeRegistry::isPDFOrPostScriptMIMEType(subresourceMIMEType))
219             resource = subresource;
220     }
221     ASSERT(resource != nil);
222     
223     ASSERT(!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType]) || MIMETypeRegistry::isPDFOrPostScriptMIMEType([resource MIMEType]));
224     if (!containsImage || MIMETypeRegistry::isSupportedImageResourceMIMEType([resource MIMEType]) || MIMETypeRegistry::isPDFOrPostScriptMIMEType([resource MIMEType]))
225         [self _web_writeFileWrapperAsRTFDAttachment:[resource _fileWrapperRepresentation]];
226     
227 }
228
229 static CachedImage* imageFromElement(DOMElement *domElement)
230 {
231     auto* element = core(domElement);
232     if (!element)
233         return nullptr;
234     auto* renderer = element->renderer();
235     if (!is<RenderImage>(renderer))
236         return nullptr;
237     auto* image = downcast<RenderImage>(*renderer).cachedImage();
238     if (!image || image->errorOccurred())
239         return nullptr;
240     return image;
241 }
242
243 - (void)_web_writeImage:(NSImage *)image
244                 element:(DOMElement *)element
245                     URL:(NSURL *)URL 
246                   title:(NSString *)title
247                 archive:(WebArchive *)archive
248                   types:(NSArray *)types
249                  source:(WebHTMLView *)source
250 {
251     ASSERT(image || element);
252     ASSERT(URL);
253
254     [self _web_writeURL:URL andTitle:title types:types];
255     
256     if ([types containsObject:legacyTIFFPasteboardType()]) {
257         if (image)
258             [self setData:[image TIFFRepresentation] forType:legacyTIFFPasteboardType()];
259         else if (source && element)
260             [source setPromisedDragTIFFDataSource:imageFromElement(element)];
261         else if (element)
262             [self setData:[element _imageTIFFRepresentation] forType:legacyTIFFPasteboardType()];
263     }
264     
265     if (archive) {
266         if ([types containsObject:WebArchivePboardType])
267             [self setData:[archive data] forType:WebArchivePboardType];
268         return;
269     }
270
271     // We should not have declared types that we aren't going to write (4031826).
272     ASSERT(![types containsObject:legacyRTFDPasteboardType()]);
273     ASSERT(![types containsObject:WebArchivePboardType]);
274 }
275
276 - (id)_web_declareAndWriteDragImageForElement:(DOMElement *)element
277                                        URL:(NSURL *)URL 
278                                      title:(NSString *)title
279                                    archive:(WebArchive *)archive
280                                     source:(WebHTMLView *)source
281 {
282 #pragma clang diagnostic push
283 #pragma clang diagnostic ignored "-Wdeprecated-declarations"
284     ASSERT(self == [NSPasteboard pasteboardWithName:NSDragPboard]);
285 #pragma clang diagnostic pop
286
287     NSString *extension = @"";
288     RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:legacyFilesPromisePasteboardType(), nil]);
289     if (auto* renderer = core(element)->renderer()) {
290         if (is<RenderImage>(*renderer)) {
291             if (auto* image = downcast<RenderImage>(*renderer).cachedImage()) {
292                 // FIXME: This doesn't check errorOccured the way imageFromElement does.
293                 extension = image->image()->filenameExtension();
294                 if (![extension length])
295                     return nullptr;
296                 [types addObjectsFromArray:[NSPasteboard _web_writableTypesForImageIncludingArchive:(archive != nil)]];
297                 [self declareTypes:types.get() owner:source];
298             }
299         }
300 #if ENABLE(ATTACHMENT_ELEMENT)
301         else if (is<RenderAttachment>(*renderer)) {
302             extension = URL.pathExtension;
303             [types addObjectsFromArray:[NSPasteboard _web_dragTypesForURL]];
304             [self declareTypes:types.get() owner:source];
305             RetainPtr<NSMutableArray> paths = adoptNS([[NSMutableArray alloc] init]);
306             [paths.get() addObject:title];
307             [self setPropertyList:paths.get() forType:legacyFilenamesPasteboardType()];
308         }
309 #endif
310     }
311
312     [self _web_writeImage:nil element:element URL:URL title:title archive:archive types:types.get() source:source];
313
314     NSArray *extensions = [[NSArray alloc] initWithObjects:extension, nil];
315     [self setPropertyList:extensions forType:legacyFilesPromisePasteboardType()];
316     [extensions release];
317
318     return source;
319 }
320
321 @end
322
323 #endif // !PLATFORM(IOS)