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:
Shelley Vohr 2018-11-27 23:50:53 -05:00 committed by GitHub
parent 73fbb69c50
commit 41c2685204
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 74 additions and 38 deletions

View file

@ -255,12 +255,12 @@ content::ServiceWorkerContext* GetServiceWorkerContext(
}
// 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) {
// Hack to enable transparency in captured image
// TODO(nitsakh) Remove hack once fixed in chromium
const_cast<SkBitmap&>(bitmap).setAlphaType(kPremul_SkAlphaType);
callback.Run(gfx::Image::CreateFrom1xBitmap(bitmap));
promise->Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
}
} // 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;
base::Callback<void(const gfx::Image&)> callback;
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
if (!(args->Length() == 1 && args->GetNext(&callback)) &&
!(args->Length() == 2 && args->GetNext(&rect) &&
args->GetNext(&callback))) {
args->ThrowError();
return;
}
// get rect arguments if they exist
args->GetNext(&rect);
auto* const view = web_contents()->GetRenderWidgetHostView();
if (!view) {
callback.Run(gfx::Image());
return;
promise->Resolve(gfx::Image());
return promise->GetHandle();
}
// 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);
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) {

View file

@ -226,7 +226,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Captures the page with |rect|, |callback| would be called when capturing is
// done.
void CapturePage(mate::Arguments* args);
v8::Local<v8::Promise> CapturePage(mate::Arguments* args);
// Methods for creating <webview>.
bool IsGuest() const;

View file

@ -1212,7 +1212,19 @@ Returns `Boolean` - Whether the window's document has been edited.
* `callback` Function
* `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])`

View file

@ -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.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.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.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)
@ -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.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.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.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)
@ -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)
- [ ] [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.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.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)

View file

@ -1050,14 +1050,23 @@ console.log(requestId)
#### `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
* `image` [NativeImage](native-image.md)
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.
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)**
#### `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)`

View file

@ -540,11 +540,23 @@ Prints `webview`'s web page as PDF, Same as `webContents.printToPDF(options, cal
### `<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
* `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][, ...])`

View file

@ -318,13 +318,19 @@ WebContents.prototype._init = function () {
NavigationController.call(this, this)
// 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)
const nativeCapturePage = this.capturePage
this.capturePage = function (rect, cb) {
return deprecate.promisify(nativeCapturePage.call(this, rect), cb)
}
// Dispatch IPC messages to the ipc module.
this.on('ipc-message', function (event, [channel, ...args]) {
ipcMain.emit(channel, event, ...args)
})
this.on('ipc-message-sync', function (event, [channel, ...args]) {
Object.defineProperty(event, 'returnValue', {
set: function (value) {
@ -338,6 +344,7 @@ WebContents.prototype._init = function () {
this.on('ipc-internal-message', function (event, [channel, ...args]) {
ipcMainInternal.emit(channel, event, ...args)
})
this.on('ipc-internal-message-sync', function (event, [channel, ...args]) {
Object.defineProperty(event, 'returnValue', {
set: function (value) {

View file

@ -68,8 +68,8 @@ const deprecate = {
},
promisify: (promise, cb) => {
const oldName = `${promise.name} with callbacks`
const newName = `${promise.name} with Promises`
const oldName = `function with callbacks`
const newName = `function with Promises`
const warn = warnOnce(oldName, newName)
if (typeof cb !== 'function') return promise

View file

@ -490,15 +490,13 @@ describe('BrowserWindow module', () => {
})
})
describe('BrowserWindow.capturePage(rect, callback)', () => {
it('calls the callback with a Buffer', async () => {
const image = await new Promise((resolve) => {
w.capturePage({
x: 0,
y: 0,
width: 100,
height: 100
}, resolve)
describe('BrowserWindow.capturePage(rect)', () => {
it('returns a Promise with a Buffer', async () => {
const image = await w.capturePage({
x: 0,
y: 0,
width: 100,
height: 100
})
expect(image.isEmpty()).to.be.true()
@ -515,7 +513,7 @@ describe('BrowserWindow module', () => {
await emittedOnce(w, 'ready-to-show')
w.show()
const image = await new Promise((resolve) => w.capturePage(resolve))
const image = await w.capturePage()
const imgBuffer = image.toPNG()
// Check the 25th byte in the PNG.