feat: promisify win.capturePage() (#15743)
* feat: promisify win.capturePage * mark optional arg correctly * Add to breaking changes doc * properly deprecate win.capturePage * remove change from api-contract * document both callback and promise versions * address docs feedback * update promisification progress doc
This commit is contained in:
parent
73fbb69c50
commit
41c2685204
9 changed files with 74 additions and 38 deletions
|
@ -255,12 +255,12 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called when CapturePage is done.
|
// Called when CapturePage is done.
|
||||||
void OnCapturePageDone(const base::Callback<void(const gfx::Image&)>& callback,
|
void OnCapturePageDone(scoped_refptr<util::Promise> promise,
|
||||||
const SkBitmap& bitmap) {
|
const SkBitmap& bitmap) {
|
||||||
// Hack to enable transparency in captured image
|
// Hack to enable transparency in captured image
|
||||||
// TODO(nitsakh) Remove hack once fixed in chromium
|
// TODO(nitsakh) Remove hack once fixed in chromium
|
||||||
const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
|
const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
|
||||||
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
|
promise->Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
@ -1756,21 +1756,17 @@ void WebContents::StartDrag(const mate::Dictionary& item,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::CapturePage(mate::Arguments* args) {
|
v8::Local<v8::Promise> WebContents::CapturePage(mate::Arguments* args) {
|
||||||
gfx::Rect rect;
|
gfx::Rect rect;
|
||||||
base::Callback<void(const gfx::Image&)> callback;
|
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
|
||||||
|
|
||||||
if (!(args->Length() == 1 && args->GetNext(&callback)) &&
|
// get rect arguments if they exist
|
||||||
!(args->Length() == 2 && args->GetNext(&rect) &&
|
args->GetNext(&rect);
|
||||||
args->GetNext(&callback))) {
|
|
||||||
args->ThrowError();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto* const view = web_contents()->GetRenderWidgetHostView();
|
auto* const view = web_contents()->GetRenderWidgetHostView();
|
||||||
if (!view) {
|
if (!view) {
|
||||||
callback.Run(gfx::Image());
|
promise->Resolve(gfx::Image());
|
||||||
return;
|
return promise->GetHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Capture full page if user doesn't specify a |rect|.
|
// Capture full page if user doesn't specify a |rect|.
|
||||||
|
@ -1789,7 +1785,8 @@ void WebContents::CapturePage(mate::Arguments* args) {
|
||||||
bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
|
bitmap_size = gfx::ScaleToCeiledSize(view_size, scale);
|
||||||
|
|
||||||
view->CopyFromSurface(gfx::Rect(rect.origin(), view_size), bitmap_size,
|
view->CopyFromSurface(gfx::Rect(rect.origin(), view_size), bitmap_size,
|
||||||
base::BindOnce(&OnCapturePageDone, callback));
|
base::BindOnce(&OnCapturePageDone, promise));
|
||||||
|
return promise->GetHandle();
|
||||||
}
|
}
|
||||||
|
|
||||||
void WebContents::OnCursorChange(const content::WebCursor& cursor) {
|
void WebContents::OnCursorChange(const content::WebCursor& cursor) {
|
||||||
|
|
|
@ -226,7 +226,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
|
||||||
|
|
||||||
// Captures the page with |rect|, |callback| would be called when capturing is
|
// Captures the page with |rect|, |callback| would be called when capturing is
|
||||||
// done.
|
// done.
|
||||||
void CapturePage(mate::Arguments* args);
|
v8::Local<v8::Promise> CapturePage(mate::Arguments* args);
|
||||||
|
|
||||||
// Methods for creating <webview>.
|
// Methods for creating <webview>.
|
||||||
bool IsGuest() const;
|
bool IsGuest() const;
|
||||||
|
|
|
@ -1212,7 +1212,19 @@ Returns `Boolean` - Whether the window's document has been edited.
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `image` [NativeImage](native-image.md)
|
* `image` [NativeImage](native-image.md)
|
||||||
|
|
||||||
Same as `webContents.capturePage([rect, ]callback)`.
|
Captures a snapshot of the page within `rect`. Upon completion `callback` will
|
||||||
|
be called with `callback(image)`. The `image` is an instance of [NativeImage](native-image.md)
|
||||||
|
that stores data of the snapshot. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
#### `win.capturePage([rect])`
|
||||||
|
|
||||||
|
* `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture
|
||||||
|
|
||||||
|
* Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
||||||
|
|
||||||
|
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
#### `win.loadURL(url[, options])`
|
#### `win.loadURL(url[, options])`
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,6 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||||
- [ ] [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
- [ ] [app.getFileIcon(path[, options], callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#getFileIcon)
|
||||||
- [ ] [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
- [ ] [app.importCertificate(options, callback)](https://github.com/electron/electron/blob/master/docs/api/app.md#importCertificate)
|
||||||
- [ ] [win.hookWindowMessage(message, callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#hookWindowMessage)
|
- [ ] [win.hookWindowMessage(message, callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#hookWindowMessage)
|
||||||
- [ ] [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
|
||||||
- [ ] [request.write(chunk[, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#write)
|
- [ ] [request.write(chunk[, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#write)
|
||||||
- [ ] [request.end([chunk][, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#end)
|
- [ ] [request.end([chunk][, encoding][, callback])](https://github.com/electron/electron/blob/master/docs/api/client-request.md#end)
|
||||||
- [ ] [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
- [ ] [contentTracing.getCategories(callback)](https://github.com/electron/electron/blob/master/docs/api/content-tracing.md#getCategories)
|
||||||
|
@ -52,7 +51,6 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||||
- [ ] [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
|
- [ ] [contents.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#executeJavaScript)
|
||||||
- [ ] [contents.getZoomFactor(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#getZoomFactor)
|
- [ ] [contents.getZoomFactor(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#getZoomFactor)
|
||||||
- [ ] [contents.getZoomLevel(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#getZoomLevel)
|
- [ ] [contents.getZoomLevel(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#getZoomLevel)
|
||||||
- [ ] [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
|
||||||
- [ ] [contents.hasServiceWorker(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#hasServiceWorker)
|
- [ ] [contents.hasServiceWorker(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#hasServiceWorker)
|
||||||
- [ ] [contents.unregisterServiceWorker(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#unregisterServiceWorker)
|
- [ ] [contents.unregisterServiceWorker(callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#unregisterServiceWorker)
|
||||||
- [ ] [contents.print([options], [callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#print)
|
- [ ] [contents.print([options], [callback])](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#print)
|
||||||
|
@ -63,8 +61,11 @@ When a majority of affected functions are migrated, this flag will be enabled by
|
||||||
- [ ] [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
|
- [ ] [webFrame.executeJavaScriptInIsolatedWorld(worldId, scripts[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/web-frame.md#executeJavaScriptInIsolatedWorld)
|
||||||
- [ ] [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
|
- [ ] [webviewTag.executeJavaScript(code[, userGesture, callback])](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#executeJavaScript)
|
||||||
- [ ] [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
|
- [ ] [webviewTag.printToPDF(options, callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#printToPDF)
|
||||||
- [ ] [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
|
||||||
- [ ] [webviewTag.getZoomFactor(callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#getZoomFactor)
|
- [ ] [webviewTag.getZoomFactor(callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#getZoomFactor)
|
||||||
- [ ] [webviewTag.getZoomLevel(callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#getZoomLevel)
|
- [ ] [webviewTag.getZoomLevel(callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#getZoomLevel)
|
||||||
|
|
||||||
### Converted Functions
|
### Converted Functions
|
||||||
|
|
||||||
|
- [ ] [win.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/browser-window.md#capturePage)
|
||||||
|
- [ ] [webviewTag.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/webview-tag.md#capturePage)
|
||||||
|
- [ ] [contents.capturePage([rect, ]callback)](https://github.com/electron/electron/blob/master/docs/api/web-contents.md#capturePage)
|
|
@ -1050,14 +1050,23 @@ console.log(requestId)
|
||||||
|
|
||||||
#### `contents.capturePage([rect, ]callback)`
|
#### `contents.capturePage([rect, ]callback)`
|
||||||
|
|
||||||
* `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured.
|
* `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `image` [NativeImage](native-image.md)
|
* `image` [NativeImage](native-image.md)
|
||||||
|
|
||||||
Captures a snapshot of the page within `rect`. Upon completion `callback` will
|
Captures a snapshot of the page within `rect`. Upon completion `callback` will
|
||||||
be called with `callback(image)`. The `image` is an instance of
|
be called with `callback(image)`. The `image` is an instance of [NativeImage](native-image.md)
|
||||||
[NativeImage](native-image.md) that stores data of the snapshot. Omitting
|
that stores data of the snapshot. Omitting `rect` will capture the whole visible page.
|
||||||
`rect` will capture the whole visible page.
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
#### `contents.capturePage([rect])`
|
||||||
|
|
||||||
|
* `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured.
|
||||||
|
|
||||||
|
* Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
||||||
|
|
||||||
|
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
#### `contents.hasServiceWorker(callback)`
|
#### `contents.hasServiceWorker(callback)`
|
||||||
|
|
||||||
|
|
|
@ -540,11 +540,23 @@ Prints `webview`'s web page as PDF, Same as `webContents.printToPDF(options, cal
|
||||||
|
|
||||||
### `<webview>.capturePage([rect, ]callback)`
|
### `<webview>.capturePage([rect, ]callback)`
|
||||||
|
|
||||||
* `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured.
|
* `rect` [Rectangle](structures/rectangle.md) (optional) - The bounds to capture
|
||||||
* `callback` Function
|
* `callback` Function
|
||||||
* `image` [NativeImage](native-image.md)
|
* `image` [NativeImage](native-image.md)
|
||||||
|
|
||||||
Captures a snapshot of the `webview`'s page. Same as `webContents.capturePage([rect, ]callback)`.
|
Captures a snapshot of the page within `rect`. Upon completion `callback` will
|
||||||
|
be called with `callback(image)`. The `image` is an instance of [NativeImage](native-image.md)
|
||||||
|
that stores data of the snapshot. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
|
**[Deprecated Soon](promisification.md)**
|
||||||
|
|
||||||
|
### `<webview>.capturePage([rect])`
|
||||||
|
|
||||||
|
* `rect` [Rectangle](structures/rectangle.md) (optional) - The area of the page to be captured.
|
||||||
|
|
||||||
|
* Returns `Promise<NativeImage>` - Resolves with a [NativeImage](native-image.md)
|
||||||
|
|
||||||
|
Captures a snapshot of the page within `rect`. Omitting `rect` will capture the whole visible page.
|
||||||
|
|
||||||
### `<webview>.send(channel[, arg1][, arg2][, ...])`
|
### `<webview>.send(channel[, arg1][, arg2][, ...])`
|
||||||
|
|
||||||
|
|
|
@ -318,13 +318,19 @@ WebContents.prototype._init = function () {
|
||||||
NavigationController.call(this, this)
|
NavigationController.call(this, this)
|
||||||
|
|
||||||
// Every remote callback from renderer process would add a listenter to the
|
// Every remote callback from renderer process would add a listenter to the
|
||||||
// render-view-deleted event, so ignore the listenters warning.
|
// render-view-deleted event, so ignore the listeners warning.
|
||||||
this.setMaxListeners(0)
|
this.setMaxListeners(0)
|
||||||
|
|
||||||
|
const nativeCapturePage = this.capturePage
|
||||||
|
this.capturePage = function (rect, cb) {
|
||||||
|
return deprecate.promisify(nativeCapturePage.call(this, rect), cb)
|
||||||
|
}
|
||||||
|
|
||||||
// Dispatch IPC messages to the ipc module.
|
// Dispatch IPC messages to the ipc module.
|
||||||
this.on('ipc-message', function (event, [channel, ...args]) {
|
this.on('ipc-message', function (event, [channel, ...args]) {
|
||||||
ipcMain.emit(channel, event, ...args)
|
ipcMain.emit(channel, event, ...args)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.on('ipc-message-sync', function (event, [channel, ...args]) {
|
this.on('ipc-message-sync', function (event, [channel, ...args]) {
|
||||||
Object.defineProperty(event, 'returnValue', {
|
Object.defineProperty(event, 'returnValue', {
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
|
@ -338,6 +344,7 @@ WebContents.prototype._init = function () {
|
||||||
this.on('ipc-internal-message', function (event, [channel, ...args]) {
|
this.on('ipc-internal-message', function (event, [channel, ...args]) {
|
||||||
ipcMainInternal.emit(channel, event, ...args)
|
ipcMainInternal.emit(channel, event, ...args)
|
||||||
})
|
})
|
||||||
|
|
||||||
this.on('ipc-internal-message-sync', function (event, [channel, ...args]) {
|
this.on('ipc-internal-message-sync', function (event, [channel, ...args]) {
|
||||||
Object.defineProperty(event, 'returnValue', {
|
Object.defineProperty(event, 'returnValue', {
|
||||||
set: function (value) {
|
set: function (value) {
|
||||||
|
|
|
@ -68,8 +68,8 @@ const deprecate = {
|
||||||
},
|
},
|
||||||
|
|
||||||
promisify: (promise, cb) => {
|
promisify: (promise, cb) => {
|
||||||
const oldName = `${promise.name} with callbacks`
|
const oldName = `function with callbacks`
|
||||||
const newName = `${promise.name} with Promises`
|
const newName = `function with Promises`
|
||||||
const warn = warnOnce(oldName, newName)
|
const warn = warnOnce(oldName, newName)
|
||||||
|
|
||||||
if (typeof cb !== 'function') return promise
|
if (typeof cb !== 'function') return promise
|
||||||
|
|
|
@ -490,15 +490,13 @@ describe('BrowserWindow module', () => {
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('BrowserWindow.capturePage(rect, callback)', () => {
|
describe('BrowserWindow.capturePage(rect)', () => {
|
||||||
it('calls the callback with a Buffer', async () => {
|
it('returns a Promise with a Buffer', async () => {
|
||||||
const image = await new Promise((resolve) => {
|
const image = await w.capturePage({
|
||||||
w.capturePage({
|
x: 0,
|
||||||
x: 0,
|
y: 0,
|
||||||
y: 0,
|
width: 100,
|
||||||
width: 100,
|
height: 100
|
||||||
height: 100
|
|
||||||
}, resolve)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(image.isEmpty()).to.be.true()
|
expect(image.isEmpty()).to.be.true()
|
||||||
|
@ -515,7 +513,7 @@ describe('BrowserWindow module', () => {
|
||||||
await emittedOnce(w, 'ready-to-show')
|
await emittedOnce(w, 'ready-to-show')
|
||||||
w.show()
|
w.show()
|
||||||
|
|
||||||
const image = await new Promise((resolve) => w.capturePage(resolve))
|
const image = await w.capturePage()
|
||||||
const imgBuffer = image.toPNG()
|
const imgBuffer = image.toPNG()
|
||||||
|
|
||||||
// Check the 25th byte in the PNG.
|
// Check the 25th byte in the PNG.
|
||||||
|
|
Loading…
Add table
Reference in a new issue