Browse Source

refactor: use QuickLookThumbnailing where applicable (#32456)

Shelley Vohr 3 years ago
parent
commit
4c39eb32b0
2 changed files with 79 additions and 26 deletions
  1. 2 0
      BUILD.gn
  2. 77 26
      shell/common/api/electron_api_native_image_mac.mm

+ 2 - 0
BUILD.gn

@@ -501,6 +501,8 @@ source_set("electron_lib") {
       "StoreKit.framework",
     ]
 
+    weak_frameworks = [ "QuickLookThumbnailing.framework" ]
+
     sources += [
       "shell/browser/ui/views/autofill_popup_view.cc",
       "shell/browser/ui/views/autofill_popup_view.h",

+ 77 - 26
shell/common/api/electron_api_native_image_mac.mm

@@ -10,8 +10,10 @@
 
 #import <Cocoa/Cocoa.h>
 #import <QuickLook/QuickLook.h>
+#import <QuickLookThumbnailing/QuickLookThumbnailing.h>
 
 #include "base/mac/foundation_util.h"
+#include "base/mac/scoped_nsobject.h"
 #include "base/strings/sys_string_conversions.h"
 #include "gin/arguments.h"
 #include "shell/common/gin_converters/image_converter.h"
@@ -53,32 +55,81 @@ v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath(
   }
 
   CGSize cg_size = size.ToCGSize();
-  base::ScopedCFTypeRef<CFURLRef> cfurl = base::mac::FilePathToCFURL(path);
-  base::ScopedCFTypeRef<QLThumbnailRef> ql_thumbnail(
-      QLThumbnailCreate(kCFAllocatorDefault, cfurl, cg_size, NULL));
-  __block gin_helper::Promise<gfx::Image> p = std::move(promise);
-  // we do not want to blocking the main thread while waiting for quicklook to
-  // generate the thumbnail
-  QLThumbnailDispatchAsync(
-      ql_thumbnail,
-      dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, /*flags*/ 0), ^{
-        base::ScopedCFTypeRef<CGImageRef> cg_thumbnail(
-            QLThumbnailCopyImage(ql_thumbnail));
-        if (cg_thumbnail) {
-          NSImage* result =
-              [[[NSImage alloc] initWithCGImage:cg_thumbnail
-                                           size:cg_size] autorelease];
-          gfx::Image thumbnail(result);
-          dispatch_async(dispatch_get_main_queue(), ^{
-            p.Resolve(thumbnail);
-          });
-        } else {
-          dispatch_async(dispatch_get_main_queue(), ^{
-            p.RejectWithErrorMessage("unable to retrieve thumbnail preview "
-                                     "image for the given path");
-          });
-        }
-      });
+
+  if (@available(macOS 10.15, *)) {
+    NSURL* nsurl = base::mac::FilePathToNSURL(path);
+
+    // We need to explicitly check if the user has passed an invalid path
+    // because QLThumbnailGenerationRequest will generate a stock file icon
+    // and pass silently if we do not.
+    if (![[NSFileManager defaultManager] fileExistsAtPath:[nsurl path]]) {
+      promise.RejectWithErrorMessage(
+          "unable to retrieve thumbnail preview image for the given path");
+      return handle;
+    }
+
+    NSScreen* screen = [[NSScreen screens] firstObject];
+    base::scoped_nsobject<QLThumbnailGenerationRequest> request(
+        [[QLThumbnailGenerationRequest alloc]
+              initWithFileAtURL:nsurl
+                           size:cg_size
+                          scale:[screen backingScaleFactor]
+            representationTypes:
+                QLThumbnailGenerationRequestRepresentationTypeAll]);
+    __block gin_helper::Promise<gfx::Image> p = std::move(promise);
+    [[QLThumbnailGenerator sharedGenerator]
+        generateBestRepresentationForRequest:request
+                           completionHandler:^(
+                               QLThumbnailRepresentation* thumbnail,
+                               NSError* error) {
+                             if (error || !thumbnail) {
+                               std::string err_msg(
+                                   [error.localizedDescription UTF8String]);
+                               dispatch_async(dispatch_get_main_queue(), ^{
+                                 p.RejectWithErrorMessage(
+                                     "unable to retrieve thumbnail preview "
+                                     "image for the given path: " +
+                                     err_msg);
+                               });
+                             } else {
+                               NSImage* result = [[[NSImage alloc]
+                                   initWithCGImage:[thumbnail CGImage]
+                                              size:cg_size] autorelease];
+                               gfx::Image image(result);
+                               dispatch_async(dispatch_get_main_queue(), ^{
+                                 p.Resolve(image);
+                               });
+                             }
+                           }];
+  } else {
+    base::ScopedCFTypeRef<CFURLRef> cfurl = base::mac::FilePathToCFURL(path);
+    base::ScopedCFTypeRef<QLThumbnailRef> ql_thumbnail(
+        QLThumbnailCreate(kCFAllocatorDefault, cfurl, cg_size, NULL));
+    __block gin_helper::Promise<gfx::Image> p = std::move(promise);
+    // Do not block the main thread waiting for quicklook to generate the
+    // thumbnail.
+    QLThumbnailDispatchAsync(
+        ql_thumbnail,
+        dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, /*flags*/ 0), ^{
+          base::ScopedCFTypeRef<CGImageRef> cg_thumbnail(
+              QLThumbnailCopyImage(ql_thumbnail));
+          if (cg_thumbnail) {
+            NSImage* result =
+                [[[NSImage alloc] initWithCGImage:cg_thumbnail
+                                             size:cg_size] autorelease];
+            gfx::Image thumbnail(result);
+            dispatch_async(dispatch_get_main_queue(), ^{
+              p.Resolve(thumbnail);
+            });
+          } else {
+            dispatch_async(dispatch_get_main_queue(), ^{
+              p.RejectWithErrorMessage("unable to retrieve thumbnail preview "
+                                       "image for the given path");
+            });
+          }
+        });
+  }
+
   return handle;
 }