/* * Copyright (C) 2020 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. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. 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 INC. 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. */ #import "config.h" #import "QuickLookThumbnailLoader.h" #if HAVE(QUICKLOOK_THUMBNAILING) #import #import "QuickLookThumbnailingSoftLink.h" @implementation WKQLThumbnailQueueManager - (instancetype)init { self = [super init]; if (self) _queue = [[NSOperationQueue alloc] init]; return self; } - (void)dealloc { [_queue release]; [super dealloc]; } + (WKQLThumbnailQueueManager *)sharedInstance { static WKQLThumbnailQueueManager *sharedInstance = [[WKQLThumbnailQueueManager alloc] init]; return sharedInstance; } @end @interface WKQLThumbnailLoadOperation () @property (atomic, readwrite, getter=isExecuting) BOOL executing; @property (atomic, readwrite, getter=isFinished) BOOL finished; @end @implementation WKQLThumbnailLoadOperation { RetainPtr _filePath; RetainPtr _identifier; RetainPtr _fileWrapper; RetainPtr _thumbnail; BOOL _shouldWrite; } - (instancetype)initWithAttachment:(NSFileWrapper *)fileWrapper identifier:(NSString *)identifier { if (self = [super init]) { _fileWrapper = fileWrapper; _identifier = adoptNS([identifier copy]); _shouldWrite = YES; } return self; } - (instancetype)initWithURL:(NSString *)fileURL identifier:(NSString *)identifier { if (self = [super init]) { _identifier = adoptNS([identifier copy]); _filePath = [NSURL fileURLWithPath:fileURL]; } return self; } - (void)start { self.executing = YES; if (_shouldWrite) { NSString *temporaryDirectory = FileSystem::createTemporaryDirectory(@"QLTempFileData"); NSString *filePath = [temporaryDirectory stringByAppendingPathComponent:[_fileWrapper preferredFilename]]; NSFileWrapperWritingOptions options = 0; NSError *error = nil; auto fileURLPath = [NSURL fileURLWithPath:filePath]; [_fileWrapper writeToURL:fileURLPath options:options originalContentsURL:nil error:&error]; _filePath = WTFMove(fileURLPath); if (error) return; } auto request = adoptNS([WebKit::allocQLThumbnailGenerationRequestInstance() initWithFileAtURL:_filePath.get() size:CGSizeMake(400, 400) scale:1 representationTypes:QLThumbnailGenerationRequestRepresentationTypeThumbnail]); [request setIconMode:YES]; [[WebKit::getQLThumbnailGeneratorClass() sharedGenerator] generateBestRepresentationForRequest:request.get() completionHandler:^(QLThumbnailRepresentation *thumbnail, NSError *error) { if (error) return; if (_thumbnail) return; #if USE(APPKIT) _thumbnail = thumbnail.NSImage; #else _thumbnail = thumbnail.UIImage; #endif if (_shouldWrite) [[NSFileManager defaultManager] removeItemAtURL:_filePath.get() error:nullptr]; self.executing = NO; self.finished = YES; }]; } - (CocoaImage *)thumbnail { return _thumbnail.get(); } - (NSString *)identifier { return _identifier.get(); } - (BOOL)isAsynchronous { return YES; } @synthesize executing = _executing; - (BOOL)isExecuting { @synchronized(self) { return _executing; } } - (void)setExecuting:(BOOL)executing { @synchronized(self) { if (executing != _executing) { [self willChangeValueForKey:@"isExecuting"]; _executing = executing; [self didChangeValueForKey:@"isExecuting"]; } } } @synthesize finished = _finished; - (BOOL)isFinished { @synchronized(self) { return _finished; } } - (void)setFinished:(BOOL)finished { @synchronized(self) { if (finished != _finished) { [self willChangeValueForKey:@"isFinished"]; _finished = finished; [self didChangeValueForKey:@"isFinished"]; } } } @end #endif // HAVE(QUICKLOOK_THUMBNAILING)