fix: nativeImage.createThumbnailFromPath and shell.openExternal in renderer (#41909)
		
	* fix: nativeImage.createThumbnailFromPath in renderer Co-authored-by: Jeremy Rose <jeremya@chromium.org> * also fix shell.openExternal Co-authored-by: Jeremy Rose <jeremya@chromium.org> --------- Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com> Co-authored-by: Jeremy Rose <jeremya@chromium.org>
This commit is contained in:
		
					parent
					
						
							
								98c9e20913
							
						
					
				
			
			
				commit
				
					
						91f257044d
					
				
			
		
					 4 changed files with 60 additions and 34 deletions
				
			
		|  | @ -14,6 +14,7 @@ | ||||||
| 
 | 
 | ||||||
| #include "base/apple/foundation_util.h" | #include "base/apple/foundation_util.h" | ||||||
| #include "base/strings/sys_string_conversions.h" | #include "base/strings/sys_string_conversions.h" | ||||||
|  | #include "base/task/bind_post_task.h" | ||||||
| #include "gin/arguments.h" | #include "gin/arguments.h" | ||||||
| #include "shell/common/gin_converters/image_converter.h" | #include "shell/common/gin_converters/image_converter.h" | ||||||
| #include "shell/common/gin_helper/promise.h" | #include "shell/common/gin_helper/promise.h" | ||||||
|  | @ -38,6 +39,23 @@ double safeShift(double in, double def) { | ||||||
|   return def; |   return def; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void ReceivedThumbnailResult(CGSize size, | ||||||
|  |                              gin_helper::Promise<gfx::Image> p, | ||||||
|  |                              QLThumbnailRepresentation* thumbnail, | ||||||
|  |                              NSError* error) { | ||||||
|  |   if (error || !thumbnail) { | ||||||
|  |     std::string err_msg([error.localizedDescription UTF8String]); | ||||||
|  |     p.RejectWithErrorMessage("unable to retrieve thumbnail preview " | ||||||
|  |                              "image for the given path: " + | ||||||
|  |                              err_msg); | ||||||
|  |   } else { | ||||||
|  |     NSImage* result = [[NSImage alloc] initWithCGImage:[thumbnail CGImage] | ||||||
|  |                                                   size:size]; | ||||||
|  |     gfx::Image image(result); | ||||||
|  |     p.Resolve(image); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| // static | // static | ||||||
| v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath( | v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath( | ||||||
|     v8::Isolate* isolate, |     v8::Isolate* isolate, | ||||||
|  | @ -70,31 +88,15 @@ v8::Local<v8::Promise> NativeImage::CreateThumbnailFromPath( | ||||||
|                      size:cg_size |                      size:cg_size | ||||||
|                     scale:[screen backingScaleFactor] |                     scale:[screen backingScaleFactor] | ||||||
|       representationTypes:QLThumbnailGenerationRequestRepresentationTypeAll]); |       representationTypes:QLThumbnailGenerationRequestRepresentationTypeAll]); | ||||||
|   __block gin_helper::Promise<gfx::Image> p = std::move(promise); |   __block auto block_callback = base::BindPostTaskToCurrentDefault( | ||||||
|  |       base::BindOnce(&ReceivedThumbnailResult, cg_size, std::move(promise))); | ||||||
|  |   auto completionHandler = | ||||||
|  |       ^(QLThumbnailRepresentation* thumbnail, NSError* error) { | ||||||
|  |         std::move(block_callback).Run(thumbnail, error); | ||||||
|  |       }; | ||||||
|   [[QLThumbnailGenerator sharedGenerator] |   [[QLThumbnailGenerator sharedGenerator] | ||||||
|       generateBestRepresentationForRequest:request |       generateBestRepresentationForRequest:request | ||||||
|                          completionHandler:^( |                          completionHandler: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]; |  | ||||||
|                              gfx::Image image(result); |  | ||||||
|                              dispatch_async(dispatch_get_main_queue(), ^{ |  | ||||||
|                                p.Resolve(image); |  | ||||||
|                              }); |  | ||||||
|                            } |  | ||||||
|                          }]; |  | ||||||
| 
 | 
 | ||||||
|   return handle; |   return handle; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -15,11 +15,15 @@ | ||||||
| #include "base/apple/osstatus_logging.h" | #include "base/apple/osstatus_logging.h" | ||||||
| #include "base/files/file_path.h" | #include "base/files/file_path.h" | ||||||
| #include "base/files/file_util.h" | #include "base/files/file_util.h" | ||||||
|  | #include "base/functional/bind.h" | ||||||
| #include "base/functional/callback.h" | #include "base/functional/callback.h" | ||||||
| #include "base/logging.h" | #include "base/logging.h" | ||||||
| #include "base/mac/scoped_aedesc.h" | #include "base/mac/scoped_aedesc.h" | ||||||
| #include "base/strings/stringprintf.h" | #include "base/strings/stringprintf.h" | ||||||
| #include "base/strings/sys_string_conversions.h" | #include "base/strings/sys_string_conversions.h" | ||||||
|  | #include "base/task/thread_pool.h" | ||||||
|  | #include "content/public/browser/browser_task_traits.h" | ||||||
|  | #include "content/public/browser/browser_thread.h" | ||||||
| #include "net/base/apple/url_conversions.h" | #include "net/base/apple/url_conversions.h" | ||||||
| #include "ui/views/widget/widget.h" | #include "ui/views/widget/widget.h" | ||||||
| #include "url/gurl.h" | #include "url/gurl.h" | ||||||
|  | @ -183,15 +187,12 @@ void OpenExternal(const GURL& url, | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   bool activate = options.activate; |   base::ThreadPool::PostTaskAndReplyWithResult( | ||||||
|   __block OpenCallback c = std::move(callback); |       FROM_HERE, | ||||||
|   dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), |       {base::MayBlock(), base::WithBaseSyncPrimitives(), | ||||||
|                  ^{ |        base::TaskPriority::USER_BLOCKING, | ||||||
|                    __block std::string error = OpenURL(ns_url, activate); |        base::TaskShutdownBehavior::SKIP_ON_SHUTDOWN}, | ||||||
|                    dispatch_async(dispatch_get_main_queue(), ^{ |       base::BindOnce(&OpenURL, ns_url, options.activate), std::move(callback)); | ||||||
|                      std::move(c).Run(error); |  | ||||||
|                    }); |  | ||||||
|                  }); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool MoveItemToTrashWithError(const base::FilePath& full_path, | bool MoveItemToTrashWithError(const base::FilePath& full_path, | ||||||
|  |  | ||||||
|  | @ -1,6 +1,6 @@ | ||||||
| import { expect } from 'chai'; | import { expect } from 'chai'; | ||||||
| import { nativeImage } from 'electron/common'; | import { nativeImage } from 'electron/common'; | ||||||
| import { ifdescribe, ifit } from './lib/spec-helpers'; | import { ifdescribe, ifit, itremote, useRemoteContext } from './lib/spec-helpers'; | ||||||
| import * as path from 'node:path'; | import * as path from 'node:path'; | ||||||
| 
 | 
 | ||||||
| describe('nativeImage module', () => { | describe('nativeImage module', () => { | ||||||
|  | @ -424,6 +424,8 @@ describe('nativeImage module', () => { | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   ifdescribe(process.platform !== 'linux')('createThumbnailFromPath(path, size)', () => { |   ifdescribe(process.platform !== 'linux')('createThumbnailFromPath(path, size)', () => { | ||||||
|  |     useRemoteContext({ webPreferences: { contextIsolation: false, nodeIntegration: true } }); | ||||||
|  | 
 | ||||||
|     it('throws when invalid size is passed', async () => { |     it('throws when invalid size is passed', async () => { | ||||||
|       const badSize = { width: -1, height: -1 }; |       const badSize = { width: -1, height: -1 }; | ||||||
| 
 | 
 | ||||||
|  | @ -471,6 +473,13 @@ describe('nativeImage module', () => { | ||||||
|       const result = await nativeImage.createThumbnailFromPath(imgPath, maxSize); |       const result = await nativeImage.createThumbnailFromPath(imgPath, maxSize); | ||||||
|       expect(result.getSize()).to.deep.equal(maxSize); |       expect(result.getSize()).to.deep.equal(maxSize); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     itremote('works in the renderer', async (path: string) => { | ||||||
|  |       const { nativeImage } = require('electron'); | ||||||
|  |       const goodSize = { width: 100, height: 100 }; | ||||||
|  |       const result = await nativeImage.createThumbnailFromPath(path, goodSize); | ||||||
|  |       expect(result.isEmpty()).to.equal(false); | ||||||
|  |     }, [path.join(fixturesPath, 'assets', 'logo.png')]); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('addRepresentation()', () => { |   describe('addRepresentation()', () => { | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ describe('shell module', () => { | ||||||
|     }); |     }); | ||||||
|     afterEach(closeAllWindows); |     afterEach(closeAllWindows); | ||||||
| 
 | 
 | ||||||
|     it('opens an external link', async () => { |     async function urlOpened () { | ||||||
|       let url = 'http://127.0.0.1'; |       let url = 'http://127.0.0.1'; | ||||||
|       let requestReceived: Promise<any>; |       let requestReceived: Promise<any>; | ||||||
|       if (process.platform === 'linux') { |       if (process.platform === 'linux') { | ||||||
|  | @ -53,12 +53,26 @@ describe('shell module', () => { | ||||||
|         url = (await listen(server)).url; |         url = (await listen(server)).url; | ||||||
|         requestReceived = new Promise<void>(resolve => server.on('connection', () => resolve())); |         requestReceived = new Promise<void>(resolve => server.on('connection', () => resolve())); | ||||||
|       } |       } | ||||||
|  |       return { url, requestReceived }; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|  |     it('opens an external link', async () => { | ||||||
|  |       const { url, requestReceived } = await urlOpened(); | ||||||
|       await Promise.all<void>([ |       await Promise.all<void>([ | ||||||
|         shell.openExternal(url), |         shell.openExternal(url), | ||||||
|         requestReceived |         requestReceived | ||||||
|       ]); |       ]); | ||||||
|     }); |     }); | ||||||
|  | 
 | ||||||
|  |     it('opens an external link in the renderer', async () => { | ||||||
|  |       const { url, requestReceived } = await urlOpened(); | ||||||
|  |       const w = new BrowserWindow({ show: false, webPreferences: { sandbox: false, contextIsolation: false, nodeIntegration: true } }); | ||||||
|  |       await w.loadURL('about:blank'); | ||||||
|  |       await Promise.all<void>([ | ||||||
|  |         w.webContents.executeJavaScript(`require("electron").shell.openExternal(${JSON.stringify(url)})`), | ||||||
|  |         requestReceived | ||||||
|  |       ]); | ||||||
|  |     }); | ||||||
|   }); |   }); | ||||||
| 
 | 
 | ||||||
|   describe('shell.trashItem()', () => { |   describe('shell.trashItem()', () => { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	![37223003+trop[bot]@users.noreply.github.com](/assets/img/avatar_default.png) trop[bot]
				trop[bot]