1/* 2 * Copyright (C) 2009 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 INC. AND ITS CONTRIBUTORS ``AS IS'' 14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 23 * THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26#import "config.h" 27#import "QuickLook.h" 28 29#if USE(QUICK_LOOK) 30 31#import "DocumentLoader.h" 32#import "FileSystemIOS.h" 33#import "Logging.h" 34#import "ResourceError.h" 35#import "ResourceHandle.h" 36#import "ResourceLoader.h" 37#import "RuntimeApplicationChecksIOS.h" 38#import "SoftLinking.h" 39#import "SynchronousResourceHandleCFURLConnectionDelegate.h" 40#import "WebCoreURLResponseIOS.h" 41#import <Foundation/Foundation.h> 42#import <Foundation/NSFileManager_NSURLExtras.h> 43#import <QuickLook/QLPreviewConverter.h> 44#import <QuickLook/QuickLookPrivate.h> 45#import <wtf/NeverDestroyed.h> 46#import <wtf/StdLibExtras.h> 47#import <wtf/Threading.h> 48#import <wtf/Vector.h> 49#import <wtf/text/WTFString.h> 50 51#if USE(CFNETWORK) 52#import <CFNetwork/CFURLConnection.h> 53 54@interface NSURLResponse (QuickLookDetails) 55+(NSURLResponse *)_responseWithCFURLResponse:(CFURLResponseRef)response; 56-(CFURLResponseRef)_CFURLResponse; 57@end 58#endif 59 60SOFT_LINK_FRAMEWORK_OPTIONAL(QuickLook) 61SOFT_LINK_CLASS(QuickLook, QLPreviewConverter) 62SOFT_LINK_MAY_FAIL(QuickLook, QLPreviewGetSupportedMIMETypes, NSSet *, (), ()) 63SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyBestMimeTypeForFileNameAndMimeType, NSString *, (NSString *fileName, NSString *mimeType), (fileName, mimeType)) 64SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyBestMimeTypeForURLAndMimeType, NSString *, (NSURL *url, NSString *mimeType), (url, mimeType)) 65SOFT_LINK_MAY_FAIL(QuickLook, QLTypeCopyUTIForURLAndMimeType, NSString *, (NSURL *url, NSString *mimeType), (url, mimeType)) 66SOFT_LINK_CONSTANT_MAY_FAIL(QuickLook, QLPreviewScheme, NSString *) 67 68namespace WebCore { 69 NSString *QLTypeCopyUTIForURLAndMimeType(NSURL *url, NSString *mimeType); 70} 71 72using namespace WebCore; 73 74Class WebCore::QLPreviewConverterClass() 75{ 76#define QLPreviewConverter getQLPreviewConverterClass() 77 return QLPreviewConverter; 78#undef QLPreviewConverter 79} 80 81NSString *WebCore::QLTypeCopyBestMimeTypeForFileNameAndMimeType(NSString *fileName, NSString *mimeType) 82{ 83 if (!canLoadQLTypeCopyBestMimeTypeForFileNameAndMimeType()) 84 return nil; 85 86 return ::QLTypeCopyBestMimeTypeForFileNameAndMimeType(fileName, mimeType); 87} 88 89NSString *WebCore::QLTypeCopyBestMimeTypeForURLAndMimeType(NSURL *url, NSString *mimeType) 90{ 91 if (!canLoadQLTypeCopyBestMimeTypeForURLAndMimeType()) 92 return nil; 93 94 return ::QLTypeCopyBestMimeTypeForURLAndMimeType(url, mimeType); 95} 96 97NSSet *WebCore::QLPreviewGetSupportedMIMETypesSet() 98{ 99 if (!canLoadQLPreviewGetSupportedMIMETypes()) 100 return nil; 101 102 static NSSet *set = adoptNS(::QLPreviewGetSupportedMIMETypes()).leakRef(); 103 return set; 104} 105 106NSString *WebCore::QLTypeCopyUTIForURLAndMimeType(NSURL *url, NSString *mimeType) 107{ 108 if (!canLoadQLTypeCopyUTIForURLAndMimeType()) 109 return nil; 110 111 return ::QLTypeCopyUTIForURLAndMimeType(url, mimeType); 112} 113 114NSDictionary *WebCore::QLFileAttributes() 115{ 116 // Set file perms to owner read/write only 117 NSNumber *filePOSIXPermissions = [NSNumber numberWithInteger:(WEB_UREAD | WEB_UWRITE)]; 118 static NSDictionary *dictionary = adoptNS([[NSDictionary alloc] initWithObjectsAndKeys: 119 NSUserName(), NSFileOwnerAccountName, 120 filePOSIXPermissions, NSFilePosixPermissions, 121 nullptr]).leakRef(); 122 return dictionary; 123} 124 125NSDictionary *WebCore::QLDirectoryAttributes() 126{ 127 // Set file perms to owner read/write/execute only 128 NSNumber *directoryPOSIXPermissions = [NSNumber numberWithInteger:(WEB_UREAD | WEB_UWRITE | WEB_UEXEC)]; 129 static NSDictionary *dictionary = adoptNS([[NSDictionary alloc] initWithObjectsAndKeys: 130 NSUserName(), NSFileOwnerAccountName, 131 directoryPOSIXPermissions, NSFilePosixPermissions, 132 nullptr]).leakRef(); 133 return dictionary; 134} 135 136static Mutex& qlPreviewConverterDictionaryMutex() 137{ 138 static NeverDestroyed<Mutex> mutex; 139 return mutex; 140} 141 142static NSMutableDictionary *QLPreviewConverterDictionary() 143{ 144 static NSMutableDictionary *dictionary = [[NSMutableDictionary alloc] init]; 145 return dictionary; 146} 147 148static NSMutableDictionary *QLContentDictionary() 149{ 150 static NSMutableDictionary *contentDictionary = [[NSMutableDictionary alloc] init]; 151 return contentDictionary; 152} 153 154void WebCore::addQLPreviewConverterWithFileForURL(NSURL *url, id converter, NSString *fileName) 155{ 156 ASSERT(url); 157 ASSERT(converter); 158 MutexLocker lock(qlPreviewConverterDictionaryMutex()); 159 [QLPreviewConverterDictionary() setObject:converter forKey:url]; 160 [QLContentDictionary() setObject:(fileName ? fileName : @"") forKey:url]; 161} 162 163NSString *WebCore::qlPreviewConverterFileNameForURL(NSURL *url) 164{ 165 return [QLContentDictionary() objectForKey:url]; 166} 167 168NSString *WebCore::qlPreviewConverterUTIForURL(NSURL *url) 169{ 170 id converter = nil; 171 { 172 MutexLocker lock(qlPreviewConverterDictionaryMutex()); 173 converter = [QLPreviewConverterDictionary() objectForKey:url]; 174 } 175 if (!converter) 176 return nil; 177 return [converter previewUTI]; 178} 179 180void WebCore::removeQLPreviewConverterForURL(NSURL *url) 181{ 182 MutexLocker lock(qlPreviewConverterDictionaryMutex()); 183 [QLPreviewConverterDictionary() removeObjectForKey:url]; 184 185 // Delete the file when we remove the preview converter 186 NSString *filename = qlPreviewConverterFileNameForURL(url); 187 if ([filename length]) 188 [[NSFileManager defaultManager] _web_removeFileOnlyAtPath:filename]; 189 [QLContentDictionary() removeObjectForKey:url]; 190} 191 192PassOwnPtr<ResourceRequest> WebCore::registerQLPreviewConverterIfNeeded(NSURL *url, NSString *mimeType, NSData *data) 193{ 194 RetainPtr<NSString> updatedMIMEType = adoptNS(WebCore::QLTypeCopyBestMimeTypeForURLAndMimeType(url, mimeType)); 195 196 if ([WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:updatedMIMEType.get()]) { 197 RetainPtr<NSString> uti = adoptNS(WebCore::QLTypeCopyUTIForURLAndMimeType(url, updatedMIMEType.get())); 198 199 RetainPtr<id> converter = adoptNS([[QLPreviewConverterClass() alloc] initWithData:data name:nil uti:uti.get() options:nil]); 200 NSURLRequest *request = [converter previewRequest]; 201 202 // We use [request URL] here instead of url since it will be 203 // the URL that the WebDataSource will see during -dealloc. 204 addQLPreviewConverterWithFileForURL([request URL], converter.get(), nil); 205 206 return adoptPtr(new ResourceRequest(request)); 207 } 208 209 return nullptr; 210} 211 212const URL WebCore::safeQLURLForDocumentURLAndResourceURL(const URL& documentURL, const String& resourceURL) 213{ 214 id converter = nil; 215 NSURL *nsDocumentURL = documentURL; 216 { 217 MutexLocker lock(qlPreviewConverterDictionaryMutex()); 218 converter = [QLPreviewConverterDictionary() objectForKey:nsDocumentURL]; 219 } 220 221 if (!converter) 222 return URL(ParsedURLString, resourceURL); 223 224 RetainPtr<NSURLRequest> request = adoptNS([[NSURLRequest alloc] initWithURL:[NSURL URLWithString:resourceURL]]); 225 NSURLRequest *safeRequest = [converter safeRequestForRequest:request.get()]; 226 return [safeRequest URL]; 227} 228 229static Vector<char> createQLPreviewProtocol() 230{ 231 Vector<char> previewProtocol; 232#define QLPreviewScheme getQLPreviewScheme() 233 const char* qlPreviewScheme = [QLPreviewScheme UTF8String]; 234#undef QLPreviewScheme 235 previewProtocol.append(qlPreviewScheme, strlen(qlPreviewScheme) + 1); 236 return previewProtocol; 237} 238 239const char* WebCore::QLPreviewProtocol() 240{ 241 if (!canLoadQLPreviewScheme()) 242 return ""; 243 244 static NeverDestroyed<Vector<char>> previewProtocol(createQLPreviewProtocol()); 245 return previewProtocol.get().data(); 246} 247 248#if USE(CFNETWORK) 249// The way QuickLook works is we pass it an NSURLConnectionDelegate callback object at creation 250// time. Then we pass it all the data as we receive it. Once we've downloaded the full URL, 251// QuickLook turns around and send us, through this delegate, the HTML version of the file which we 252// pass on to WebCore. The flag m_finishedLoadingDataIntoConverter in QuickLookHandle decides 253// whether to pass the data to QuickLook or WebCore. 254// 255// This works fine when using NS APIs, but when using CFNetwork, we don't have a NSURLConnectionDelegate. 256// So we create WebQuickLookHandleAsDelegate as an intermediate delegate object and pass it to 257// QLPreviewConverter. The proxy delegate then forwards the messages on to the CFNetwork code. 258@interface WebQuickLookHandleAsDelegate : NSObject <NSURLConnectionDelegate> { 259 RefPtr<SynchronousResourceHandleCFURLConnectionDelegate> m_connectionDelegate; 260} 261 262- (id)initWithConnectionDelegate:(SynchronousResourceHandleCFURLConnectionDelegate*)connectionDelegate; 263- (void)clearHandle; 264@end 265 266@implementation WebQuickLookHandleAsDelegate 267- (id)initWithConnectionDelegate:(SynchronousResourceHandleCFURLConnectionDelegate*)connectionDelegate 268{ 269 self = [super init]; 270 if (!self) 271 return nil; 272 m_connectionDelegate = connectionDelegate; 273 return self; 274} 275 276- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray 277{ 278 UNUSED_PARAM(connection); 279 if (!m_connectionDelegate) 280 return; 281 LOG(Network, "WebQuickLookHandleAsDelegate::didReceiveDataArray()"); 282 m_connectionDelegate->didReceiveDataArray(reinterpret_cast<CFArrayRef>(dataArray)); 283} 284 285- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived 286{ 287 UNUSED_PARAM(connection); 288 if (!m_connectionDelegate) 289 return; 290 LOG(Network, "WebQuickLookHandleAsDelegate::didReceiveData() - data length = %ld", (long)[data length]); 291 292 // QuickLook code sends us a nil data at times. The check below is the same as the one in 293 // ResourceHandleMac.cpp added for a different bug. 294 if (![data length]) 295 return; 296 m_connectionDelegate->didReceiveData(reinterpret_cast<CFDataRef>(data), static_cast<int>(lengthReceived)); 297} 298 299- (void)connectionDidFinishLoading:(NSURLConnection *)connection 300{ 301 UNUSED_PARAM(connection); 302 if (!m_connectionDelegate) 303 return; 304 LOG(Network, "WebQuickLookHandleAsDelegate::didFinishLoading()"); 305 m_connectionDelegate->didFinishLoading(); 306} 307 308- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 309{ 310 UNUSED_PARAM(connection); 311 if (!m_connectionDelegate) 312 return; 313 LOG(Network, "WebQuickLookHandleAsDelegate::didFail()"); 314 m_connectionDelegate->didFail(reinterpret_cast<CFErrorRef>(error)); 315} 316 317- (void)clearHandle 318{ 319 m_connectionDelegate = nullptr; 320} 321@end 322#endif 323 324@interface WebResourceLoaderQuickLookDelegate : NSObject <NSURLConnectionDelegate> { 325 RefPtr<ResourceLoader> _resourceLoader; 326 BOOL _hasSentDidReceiveResponse; 327 BOOL _hasFailed; 328} 329@property (nonatomic) QuickLookHandle* quickLookHandle; 330@end 331 332@implementation WebResourceLoaderQuickLookDelegate 333 334- (id)initWithResourceLoader:(PassRefPtr<ResourceLoader>)resourceLoader 335{ 336 self = [super init]; 337 if (!self) 338 return nil; 339 340 _resourceLoader = resourceLoader; 341 return self; 342} 343 344- (void)_sendDidReceiveResponseIfNecessary 345{ 346 if (_hasSentDidReceiveResponse || _hasFailed || !_quickLookHandle) 347 return; 348 349 // QuickLook might fail to convert a document without calling connection:didFailWithError: (see <rdar://problem/17927972>). 350 // A nil MIME type is an indication of such a failure, so stop loading the resource and ignore subsequent delegate messages. 351 NSURLResponse *previewResponse = _quickLookHandle->nsResponse(); 352 if (![previewResponse MIMEType]) { 353 _hasFailed = YES; 354 _resourceLoader->didFail(_resourceLoader->cannotShowURLError()); 355 return; 356 } 357 358 _hasSentDidReceiveResponse = YES; 359 _resourceLoader->didReceiveResponse(previewResponse); 360} 361 362#if USE(NETWORK_CFDATA_ARRAY_CALLBACK) 363- (void)connection:(NSURLConnection *)connection didReceiveDataArray:(NSArray *)dataArray 364{ 365 UNUSED_PARAM(connection); 366 if (!_resourceLoader) 367 return; 368 369 [self _sendDidReceiveResponseIfNecessary]; 370 if (_hasFailed) 371 return; 372 373 _resourceLoader->didReceiveDataArray(reinterpret_cast<CFArrayRef>(dataArray)); 374} 375#endif 376 377- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data lengthReceived:(long long)lengthReceived 378{ 379 UNUSED_PARAM(connection); 380 if (!_resourceLoader) 381 return; 382 383 [self _sendDidReceiveResponseIfNecessary]; 384 if (_hasFailed) 385 return; 386 387 // QuickLook code sends us a nil data at times. The check below is the same as the one in 388 // ResourceHandleMac.cpp added for a different bug. 389 if (![data length]) 390 return; 391 _resourceLoader->didReceiveData(reinterpret_cast<const char*>([data bytes]), [data length], lengthReceived, DataPayloadBytes); 392} 393 394- (void)connectionDidFinishLoading:(NSURLConnection *)connection 395{ 396 UNUSED_PARAM(connection); 397 if (!_resourceLoader || _hasFailed) 398 return; 399 400 ASSERT(_hasSentDidReceiveResponse); 401 _resourceLoader->didFinishLoading(0); 402} 403 404- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error 405{ 406 UNUSED_PARAM(connection); 407 408 [self _sendDidReceiveResponseIfNecessary]; 409 if (_hasFailed) 410 return; 411 412 _resourceLoader->didFail(ResourceError(error)); 413} 414 415- (void)clearHandle 416{ 417 _resourceLoader = nullptr; 418 _quickLookHandle = nullptr; 419} 420 421@end 422 423namespace WebCore { 424 425NSString *createTemporaryFileForQuickLook(NSString *fileName) 426{ 427 NSString *downloadDirectory = createTemporaryDirectory(@"QuickLookContent"); 428 if (!downloadDirectory) 429 return nil; 430 431 NSString *contentPath = [downloadDirectory stringByAppendingPathComponent:fileName]; 432 NSFileManager *fileManager = [NSFileManager defaultManager]; 433 NSString *uniqueContentPath = [fileManager _web_pathWithUniqueFilenameForPath:contentPath]; 434 435 BOOL success = [fileManager _web_createFileAtPathWithIntermediateDirectories:uniqueContentPath 436 contents:nil 437 attributes:QLFileAttributes() 438 directoryAttributes:QLDirectoryAttributes()]; 439 440 return success ? uniqueContentPath : nil; 441} 442 443static inline QuickLookHandleClient* emptyClient() 444{ 445 static NeverDestroyed<QuickLookHandleClient> emptyClient; 446 return &emptyClient.get(); 447} 448 449QuickLookHandle::QuickLookHandle(NSURL *firstRequestURL, NSURLConnection *connection, NSURLResponse *nsResponse, id delegate) 450 : m_firstRequestURL(firstRequestURL) 451 , m_converter(adoptNS([[QLPreviewConverterClass() alloc] initWithConnection:connection delegate:delegate response:nsResponse options:nil])) 452 , m_delegate(delegate) 453 , m_finishedLoadingDataIntoConverter(false) 454 , m_nsResponse([m_converter previewResponse]) 455 , m_client(emptyClient()) 456{ 457 LOG(Network, "QuickLookHandle::QuickLookHandle() - previewFileName: %s", [m_converter previewFileName]); 458} 459 460std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceHandle* handle, NSURLConnection *connection, NSURLResponse *nsResponse, id delegate) 461{ 462 ASSERT_ARG(handle, handle); 463 if (!handle->firstRequest().deprecatedIsMainResourceRequest() || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:[nsResponse MIMEType]]) 464 return nullptr; 465 466 std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([handle->firstRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], connection, nsResponse, delegate)); 467 handle->client()->didCreateQuickLookHandle(*quickLookHandle); 468 return WTF::move(quickLookHandle); 469} 470 471#if USE(CFNETWORK) 472std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceHandle* handle, SynchronousResourceHandleCFURLConnectionDelegate* connectionDelegate, CFURLResponseRef cfResponse) 473{ 474 ASSERT_ARG(handle, handle); 475 if (!handle->firstRequest().deprecatedIsMainResourceRequest() || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:(NSString *)CFURLResponseGetMIMEType(cfResponse)]) 476 return nullptr; 477 478 NSURLResponse *nsResponse = [NSURLResponse _responseWithCFURLResponse:cfResponse]; 479 WebQuickLookHandleAsDelegate *delegate = [[[WebQuickLookHandleAsDelegate alloc] initWithConnectionDelegate:connectionDelegate] autorelease]; 480 std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([handle->firstRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], nil, nsResponse, delegate)); 481 handle->client()->didCreateQuickLookHandle(*quickLookHandle); 482 return WTF::move(quickLookHandle); 483} 484 485CFURLResponseRef QuickLookHandle::cfResponse() 486{ 487 return [m_nsResponse _CFURLResponse]; 488} 489#endif 490 491static inline bool isMainResourceLoader(ResourceLoader* loader) 492{ 493 return loader->documentLoader()->mainResourceLoader() == loader; 494} 495 496std::unique_ptr<QuickLookHandle> QuickLookHandle::create(ResourceLoader* loader, NSURLResponse *response) 497{ 498 ASSERT_ARG(loader, loader); 499 if (!isMainResourceLoader(loader) || ![WebCore::QLPreviewGetSupportedMIMETypesSet() containsObject:[response MIMEType]]) 500 return nullptr; 501 502 RetainPtr<WebResourceLoaderQuickLookDelegate> delegate = adoptNS([[WebResourceLoaderQuickLookDelegate alloc] initWithResourceLoader:loader]); 503 std::unique_ptr<QuickLookHandle> quickLookHandle(new QuickLookHandle([loader->originalRequest().nsURLRequest(DoNotUpdateHTTPBody) URL], nil, response, delegate.get())); 504 [delegate setQuickLookHandle:quickLookHandle.get()]; 505 loader->didCreateQuickLookHandle(*quickLookHandle); 506 return WTF::move(quickLookHandle); 507} 508 509NSURLResponse *QuickLookHandle::nsResponse() 510{ 511 return m_nsResponse.get(); 512} 513 514bool QuickLookHandle::didReceiveDataArray(CFArrayRef cfDataArray) 515{ 516 if (m_finishedLoadingDataIntoConverter) 517 return false; 518 519 LOG(Network, "QuickLookHandle::didReceiveDataArray()"); 520 [m_converter appendDataArray:(NSArray *)cfDataArray]; 521 m_client->didReceiveDataArray(cfDataArray); 522 return true; 523} 524 525bool QuickLookHandle::didReceiveData(CFDataRef cfData) 526{ 527 if (m_finishedLoadingDataIntoConverter) 528 return false; 529 530 return didReceiveDataArray(adoptCF(CFArrayCreate(kCFAllocatorDefault, (const void**)&cfData, 1, &kCFTypeArrayCallBacks)).get()); 531} 532 533bool QuickLookHandle::didFinishLoading() 534{ 535 if (m_finishedLoadingDataIntoConverter) 536 return false; 537 538 LOG(Network, "QuickLookHandle::didFinishLoading()"); 539 m_finishedLoadingDataIntoConverter = YES; 540 [m_converter finishedAppendingData]; 541 m_client->didFinishLoading(); 542 return true; 543} 544 545void QuickLookHandle::didFail() 546{ 547 LOG(Network, "QuickLookHandle::didFail()"); 548 m_client->didFail(); 549 [m_converter finishConverting]; 550 m_converter = nullptr; 551} 552 553QuickLookHandle::~QuickLookHandle() 554{ 555 LOG(Network, "QuickLookHandle::~QuickLookHandle()"); 556 m_converter = nullptr; 557 558 [m_delegate clearHandle]; 559} 560 561String QuickLookHandle::previewFileName() const 562{ 563 return [m_converter previewFileName]; 564} 565 566String QuickLookHandle::previewUTI() const 567{ 568 return [m_converter previewUTI]; 569} 570 571NSURL *QuickLookHandle::previewRequestURL() const 572{ 573 return [[m_converter previewRequest] URL]; 574} 575 576} 577 578#endif // USE(QUICK_LOOK) 579