Skip to content

Commit

Permalink
fix: ensure nativeImage serialization main->renderer (#23759)
Browse files Browse the repository at this point in the history
  • Loading branch information
codebytere committed May 28, 2020
1 parent e5da2ca commit e8ea007
Show file tree
Hide file tree
Showing 3 changed files with 41 additions and 8 deletions.
10 changes: 9 additions & 1 deletion lib/browser/remote/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import * as electron from 'electron';
import { EventEmitter } from 'events';
import objectsRegistry from './objects-registry';
import { ipcMainInternal } from '../ipc-main-internal';
import { isPromise, isSerializableObject, deserialize } from '@electron/internal/common/type-utils';
import { isPromise, isSerializableObject, deserialize, serialize } from '@electron/internal/common/type-utils';
import { Size } from 'electron/main';

const v8Util = process.electronBinding('v8_util');
const eventBinding = process.electronBinding('event');
const features = process.electronBinding('features');
const { NativeImage } = process.electronBinding('native_image');

if (!features.isRemoteModuleEnabled()) {
throw new Error('remote module is disabled');
Expand Down Expand Up @@ -114,6 +115,9 @@ type MetaType = {
} | {
type: 'promise',
then: MetaType
} | {
type: 'nativeimage'
value: electron.NativeImage
}

// Convert a real value into meta data.
Expand All @@ -124,6 +128,8 @@ const valueToMeta = function (sender: electron.WebContents, contextId: string, v
// Recognize certain types of objects.
if (value instanceof Buffer) {
type = 'buffer';
} else if (value instanceof NativeImage) {
type = 'nativeimage';
} else if (Array.isArray(value)) {
type = 'array';
} else if (value instanceof Error) {
Expand All @@ -147,6 +153,8 @@ const valueToMeta = function (sender: electron.WebContents, contextId: string, v
type,
members: value.map((el: any) => valueToMeta(sender, contextId, el, optimizeSimpleObject))
};
} else if (type === 'nativeimage') {
return { type, value: serialize(value) };
} else if (type === 'object' || type === 'function') {
return {
type,
Expand Down
3 changes: 2 additions & 1 deletion lib/renderer/api/remote.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const { hasSwitch } = process.electronBinding('command_line');
const { NativeImage } = process.electronBinding('native_image');

const { CallbacksRegistry } = require('@electron/internal/renderer/remote/callbacks-registry');
const { isPromise, isSerializableObject, serialize } = require('@electron/internal/common/type-utils');
const { isPromise, isSerializableObject, serialize, deserialize } = require('@electron/internal/common/type-utils');
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');

const callbacksRegistry = new CallbacksRegistry();
Expand Down Expand Up @@ -219,6 +219,7 @@ function metaToValue (meta) {
const types = {
value: () => meta.value,
array: () => meta.members.map((member) => metaToValue(member)),
nativeimage: () => deserialize(meta.value),
buffer: () => Buffer.from(meta.value.buffer, meta.value.byteOffset, meta.value.byteLength),
promise: () => Promise.resolve({ then: metaToValue(meta.then) }),
error: () => metaToError(meta),
Expand Down
36 changes: 30 additions & 6 deletions spec-main/api-remote-spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -366,11 +366,11 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
const w = makeWindow();
const remotely = makeRemotely(w);

it('can serialize an empty nativeImage', async () => {
const getEmptyImage = (img: NativeImage) => img.isEmpty();
it('can serialize an empty nativeImage from renderer to main', async () => {
const getImageEmpty = (img: NativeImage) => img.isEmpty();

w().webContents.once('remote-get-global', (event) => {
event.returnValue = getEmptyImage;
event.returnValue = getImageEmpty;
});

await expect(remotely(() => {
Expand All @@ -379,11 +379,23 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
})).to.eventually.be.true();
});

it('can serialize a non-empty nativeImage', async () => {
const getNonEmptyImage = (img: NativeImage) => img.getSize();
it('can serialize an empty nativeImage from main to renderer', async () => {
w().webContents.once('remote-get-global', (event) => {
const emptyImage = require('electron').nativeImage.createEmpty();
event.returnValue = emptyImage;
});

await expect(remotely(() => {
const image = require('electron').remote.getGlobal('someFunction');
return image.isEmpty();
})).to.eventually.be.true();
});

it('can serialize a non-empty nativeImage from renderer to main', async () => {
const getImageSize = (img: NativeImage) => img.getSize();

w().webContents.once('remote-get-global', (event) => {
event.returnValue = getNonEmptyImage;
event.returnValue = getImageSize;
});

await expect(remotely(() => {
Expand All @@ -393,6 +405,18 @@ ifdescribe(features.isRemoteModuleEnabled())('remote module', () => {
})).to.eventually.deep.equal({ width: 2, height: 2 });
});

it('can serialize a non-empty nativeImage from main to renderer', async () => {
w().webContents.once('remote-get-global', (event) => {
const nonEmptyImage = nativeImage.createFromDataURL('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAIAAAD91JpzAAAAFklEQVQYlWP8//8/AwMDEwMDAwMDAwAkBgMBBMzldwAAAABJRU5ErkJggg==');
event.returnValue = nonEmptyImage;
});

await expect(remotely(() => {
const image = require('electron').remote.getGlobal('someFunction');
return image.getSize();
})).to.eventually.deep.equal({ width: 2, height: 2 });
});

it('can properly create a menu with an nativeImage icon in the renderer', async () => {
await expect(remotely(() => {
const { remote, nativeImage } = require('electron');
Expand Down

0 comments on commit e8ea007

Please sign in to comment.