blob: e5b444bfa5c28728387c723328291a8203d1b254 [file] [log] [blame]
/*
* 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)