| /* |
| * Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * 3. Neither the name of Apple Inc. ("Apple") nor the names of |
| * its contributors may be used to endorse or promote products derived |
| * from this software without specific prior written permission. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
| * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
| * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY |
| * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
| * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
| * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
| * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF |
| * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #if !PLATFORM(IOS_FAMILY) |
| |
| #import "WebNSPasteboardExtras.h" |
| |
| #import "DOMElementInternal.h" |
| #import "WebArchive.h" |
| #import "WebFrameInternal.h" |
| #import "WebHTMLViewInternal.h" |
| #import "WebNSURLExtras.h" |
| #import "WebResourcePrivate.h" |
| #import "WebURLsWithTitles.h" |
| #import "WebViewPrivate.h" |
| #import <WebCore/CachedImage.h> |
| #import <WebCore/Element.h> |
| #import <WebCore/Image.h> |
| #import <WebCore/LegacyNSPasteboardTypes.h> |
| #import <WebCore/MIMETypeRegistry.h> |
| #import <WebCore/PasteboardCustomData.h> |
| #import <WebCore/RenderAttachment.h> |
| #import <WebCore/RenderImage.h> |
| #import <WebKitLegacy/DOMExtensions.h> |
| #import <WebKitLegacy/DOMPrivate.h> |
| #import <wtf/Assertions.h> |
| #import <wtf/RetainPtr.h> |
| #import <wtf/StdLibExtras.h> |
| |
| using namespace WebCore; |
| |
| NSString *WebURLPboardType = @"public.url"; |
| NSString *WebURLNamePboardType = @"public.url-name"; |
| |
| @implementation NSPasteboard (WebExtras) |
| |
| + (NSArray *)_web_writableTypesForURL |
| { |
| static NSArray *types = [[NSArray alloc] initWithObjects: |
| WebURLsWithTitlesPboardType, |
| legacyURLPasteboardType(), |
| WebURLPboardType, |
| WebURLNamePboardType, |
| legacyStringPasteboardType(), |
| nil]; |
| return types; |
| } |
| |
| static NSArray *writableTypesForImageWithoutArchive() |
| { |
| static NeverDestroyed types = [] { |
| auto types = adoptNS([[NSMutableArray alloc] initWithObjects:legacyTIFFPasteboardType(), nil]); |
| [types addObjectsFromArray:[NSPasteboard _web_writableTypesForURL]]; |
| return types; |
| }(); |
| return types.get().get(); |
| } |
| |
| static NSArray *writableTypesForImageWithArchive() |
| { |
| static NeverDestroyed types = [] { |
| auto types = adoptNS([writableTypesForImageWithoutArchive() mutableCopy]); |
| [types addObject:legacyRTFDPasteboardType()]; |
| [types addObject:WebArchivePboardType]; |
| return types; |
| }(); |
| return types.get().get(); |
| } |
| |
| + (NSArray *)_web_writableTypesForImageIncludingArchive:(BOOL)hasArchive |
| { |
| return hasArchive ? writableTypesForImageWithArchive() : writableTypesForImageWithoutArchive(); |
| } |
| |
| + (NSArray *)_web_dragTypesForURL |
| { |
| return @[ |
| WebURLsWithTitlesPboardType, |
| legacyURLPasteboardType(), |
| WebURLPboardType, |
| WebURLNamePboardType, |
| legacyStringPasteboardType(), |
| legacyFilenamesPasteboardType(), |
| legacyFilesPromisePasteboardType(), |
| ]; |
| } |
| |
| - (NSURL *)_web_bestURL |
| { |
| NSArray *types = [self types]; |
| |
| if ([types containsObject:legacyURLPasteboardType()]) { |
| NSURL *URLFromPasteboard = [NSURL URLFromPasteboard:self]; |
| NSString *scheme = [URLFromPasteboard scheme]; |
| if ([scheme isEqualToString:@"http"] || [scheme isEqualToString:@"https"]) { |
| return [URLFromPasteboard _webkit_canonicalize]; |
| } |
| } |
| |
| if ([types containsObject:legacyStringPasteboardType()]) { |
| NSString *URLString = [self stringForType:legacyStringPasteboardType()]; |
| if ([URLString _webkit_looksLikeAbsoluteURL]) { |
| NSURL *URL = [[NSURL _webkit_URLWithUserTypedString:URLString] _webkit_canonicalize]; |
| if (URL) { |
| return URL; |
| } |
| } |
| } |
| |
| if ([types containsObject:legacyFilenamesPasteboardType()]) { |
| NSArray *files = [self propertyListForType:legacyFilenamesPasteboardType()]; |
| // FIXME: Maybe it makes more sense to allow multiple files and only use the first one? |
| if ([files count] == 1) { |
| NSString *file = [files objectAtIndex:0]; |
| // FIXME: We are filtering out directories because that's what the original code used to |
| // do. Without this check, if the URL points to a local directory, Safari will open the |
| // parent directory of the directory in Finder. This check should go away as soon as |
| // possible. |
| BOOL isDirectory; |
| if ([[NSFileManager defaultManager] fileExistsAtPath:file isDirectory:&isDirectory] && isDirectory) |
| return nil; |
| return [[NSURL fileURLWithPath:file] _webkit_canonicalize]; |
| } |
| } |
| |
| return nil; |
| } |
| |
| - (void)_web_writeURL:(NSURL *)URL andTitle:(NSString *)title types:(NSArray *)types |
| { |
| ASSERT(URL); |
| |
| if ([title length] == 0) { |
| title = [[URL path] lastPathComponent]; |
| if ([title length] == 0) |
| title = [URL _web_userVisibleString]; |
| } |
| |
| if ([types containsObject:legacyURLPasteboardType()]) |
| [URL writeToPasteboard:self]; |
| if ([types containsObject:WebURLPboardType]) |
| [self setString:[URL _web_originalDataAsString] forType:WebURLPboardType]; |
| if ([types containsObject:WebURLNamePboardType]) |
| [self setString:title forType:WebURLNamePboardType]; |
| if ([types containsObject:legacyStringPasteboardType()]) |
| [self setString:[URL _web_userVisibleString] forType:legacyStringPasteboardType()]; |
| if ([types containsObject:WebURLsWithTitlesPboardType]) |
| [WebURLsWithTitles writeURLs:@[URL] andTitles:@[title] toPasteboard:self]; |
| } |
| |
| + (int)_web_setFindPasteboardString:(NSString *)string withOwner:(id)owner |
| { |
| ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
| NSPasteboard *findPasteboard = [NSPasteboard pasteboardWithName:NSFindPboard]; |
| ALLOW_DEPRECATED_DECLARATIONS_END |
| [findPasteboard declareTypes:@[legacyStringPasteboardType()] owner:owner]; |
| [findPasteboard setString:string forType:legacyStringPasteboardType()]; |
| return [findPasteboard changeCount]; |
| } |
| |
| - (void)_web_writeFileWrapperAsRTFDAttachment:(NSFileWrapper *)wrapper |
| { |
| auto attachment = adoptNS([[NSTextAttachment alloc] initWithFileWrapper:wrapper]); |
| NSAttributedString *string = [NSAttributedString attributedStringWithAttachment:attachment.get()]; |
| |
| NSData *RTFDData = [string RTFDFromRange:NSMakeRange(0, [string length]) documentAttributes:@{ }]; |
| [self setData:RTFDData forType:legacyRTFDPasteboardType()]; |
| } |
| |
| |
| - (void)_web_writePromisedRTFDFromArchive:(WebArchive*)archive containsImage:(BOOL)containsImage |
| { |
| ASSERT(archive); |
| // This image data is either the only subresource of an archive (HTML image case) |
| // or the main resource (standalone image case). |
| NSArray *subresources = [archive subresources]; |
| WebResource *resource = [archive mainResource]; |
| if (containsImage && [subresources count] > 0) { |
| WebResource *subresource = [subresources objectAtIndex:0]; |
| NSString *subresourceMIMEType = [subresource MIMEType]; |
| if (MIMETypeRegistry::isSupportedImageMIMEType(subresourceMIMEType) || MIMETypeRegistry::isPDFOrPostScriptMIMEType(subresourceMIMEType)) |
| resource = subresource; |
| } |
| ASSERT(resource != nil); |
| |
| ASSERT(!containsImage || MIMETypeRegistry::isSupportedImageMIMEType([resource MIMEType]) || MIMETypeRegistry::isPDFOrPostScriptMIMEType([resource MIMEType])); |
| if (!containsImage || MIMETypeRegistry::isSupportedImageMIMEType([resource MIMEType]) || MIMETypeRegistry::isPDFOrPostScriptMIMEType([resource MIMEType])) |
| [self _web_writeFileWrapperAsRTFDAttachment:[resource _fileWrapperRepresentation]]; |
| |
| } |
| |
| static CachedImage* imageFromElement(DOMElement *domElement) |
| { |
| auto* element = core(domElement); |
| if (!element) |
| return nullptr; |
| auto* renderer = element->renderer(); |
| if (!is<RenderImage>(renderer)) |
| return nullptr; |
| auto* image = downcast<RenderImage>(*renderer).cachedImage(); |
| if (!image || image->errorOccurred()) |
| return nullptr; |
| return image; |
| } |
| |
| - (void)_web_writeImage:(NSImage *)image |
| element:(DOMElement *)element |
| URL:(NSURL *)URL |
| title:(NSString *)title |
| archive:(WebArchive *)archive |
| types:(NSArray *)types |
| source:(WebHTMLView *)source |
| { |
| ASSERT(image || element); |
| ASSERT(URL); |
| |
| [self _web_writeURL:URL andTitle:title types:types]; |
| |
| if ([types containsObject:legacyTIFFPasteboardType()]) { |
| if (image) |
| [self setData:[image TIFFRepresentation] forType:legacyTIFFPasteboardType()]; |
| else if (source && element) |
| [source setPromisedDragTIFFDataSource:imageFromElement(element)]; |
| else if (element) |
| [self setData:[element _imageTIFFRepresentation] forType:legacyTIFFPasteboardType()]; |
| } |
| |
| if (archive) { |
| if ([types containsObject:WebArchivePboardType]) |
| [self setData:[archive data] forType:WebArchivePboardType]; |
| return; |
| } |
| |
| // We should not have declared types that we aren't going to write (4031826). |
| ASSERT(![types containsObject:legacyRTFDPasteboardType()]); |
| ASSERT(![types containsObject:WebArchivePboardType]); |
| } |
| |
| - (id)_web_declareAndWriteDragImageForElement:(DOMElement *)element |
| URL:(NSURL *)URL |
| title:(NSString *)title |
| archive:(WebArchive *)archive |
| source:(WebHTMLView *)source |
| { |
| ALLOW_DEPRECATED_DECLARATIONS_BEGIN |
| ASSERT(self == [NSPasteboard pasteboardWithName:NSDragPboard]); |
| ALLOW_DEPRECATED_DECLARATIONS_END |
| |
| NSString *extension = @""; |
| RetainPtr<NSMutableArray> types = adoptNS([[NSMutableArray alloc] initWithObjects:legacyFilesPromisePasteboardType(), nil]); |
| NSString *originIdentifier = core(element)->document().originIdentifierForPasteboard(); |
| RetainPtr<NSData> customDataBuffer; |
| if (originIdentifier.length) { |
| [types addObject:@(PasteboardCustomData::cocoaType())]; |
| PasteboardCustomData customData; |
| customData.setOrigin(originIdentifier); |
| customDataBuffer = customData.createSharedBuffer()->createNSData(); |
| } |
| |
| if (auto* renderer = core(element)->renderer()) { |
| if (is<RenderImage>(*renderer)) { |
| if (auto* image = downcast<RenderImage>(*renderer).cachedImage()) { |
| // FIXME: This doesn't check errorOccured the way imageFromElement does. |
| extension = image->image()->filenameExtension(); |
| if (![extension length]) |
| return nullptr; |
| [types addObjectsFromArray:[NSPasteboard _web_writableTypesForImageIncludingArchive:(archive != nil)]]; |
| [self declareTypes:types.get() owner:source]; |
| } |
| } |
| #if ENABLE(ATTACHMENT_ELEMENT) |
| else if (is<RenderAttachment>(*renderer)) { |
| extension = URL.pathExtension; |
| [types addObjectsFromArray:[NSPasteboard _web_dragTypesForURL]]; |
| [self declareTypes:types.get() owner:source]; |
| [self setPropertyList:@[title] forType:legacyFilenamesPasteboardType()]; |
| } |
| #endif |
| } |
| |
| [self _web_writeImage:nil element:element URL:URL title:title archive:archive types:types.get() source:source]; |
| if (customDataBuffer) |
| [self setData:customDataBuffer.get() forType:@(PasteboardCustomData::cocoaType())]; |
| |
| [self setPropertyList:@[extension] forType:legacyFilesPromisePasteboardType()]; |
| |
| return source; |
| } |
| |
| @end |
| |
| #endif // !PLATFORM(IOS_FAMILY) |