refactor: use typeutils for nativeImage serialization (#23693)
This commit is contained in:
parent
75847a0c5b
commit
762f7bcca2
3 changed files with 65 additions and 43 deletions
|
@ -4,7 +4,7 @@ import * as electron from 'electron';
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import objectsRegistry from './objects-registry';
|
import objectsRegistry from './objects-registry';
|
||||||
import { ipcMainInternal } from '../ipc-main-internal';
|
import { ipcMainInternal } from '../ipc-main-internal';
|
||||||
import { isPromise, isSerializableObject } from '@electron/internal/common/type-utils';
|
import { isPromise, isSerializableObject, deserialize } from '@electron/internal/common/type-utils';
|
||||||
import { Size } from 'electron/main';
|
import { Size } from 'electron/main';
|
||||||
|
|
||||||
const v8Util = process.electronBinding('v8_util');
|
const v8Util = process.electronBinding('v8_util');
|
||||||
|
@ -234,7 +234,10 @@ type MetaTypeFromRenderer = {
|
||||||
} | {
|
} | {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
name: string,
|
name: string,
|
||||||
members: { name: string, value: MetaTypeFromRenderer }[]
|
members: {
|
||||||
|
name: string,
|
||||||
|
value: MetaTypeFromRenderer
|
||||||
|
}[]
|
||||||
} | {
|
} | {
|
||||||
type: 'function-with-return-value',
|
type: 'function-with-return-value',
|
||||||
value: MetaTypeFromRenderer
|
value: MetaTypeFromRenderer
|
||||||
|
@ -245,7 +248,12 @@ type MetaTypeFromRenderer = {
|
||||||
length: number
|
length: number
|
||||||
} | {
|
} | {
|
||||||
type: 'nativeimage',
|
type: 'nativeimage',
|
||||||
value: { size: Size, buffer: Buffer, scaleFactor: number, dataURL: string }[]
|
value: {
|
||||||
|
size: Size,
|
||||||
|
buffer: Buffer,
|
||||||
|
scaleFactor: number,
|
||||||
|
dataURL: string
|
||||||
|
}[]
|
||||||
}
|
}
|
||||||
|
|
||||||
const fakeConstructor = (constructor: Function, name: string) =>
|
const fakeConstructor = (constructor: Function, name: string) =>
|
||||||
|
@ -263,15 +271,8 @@ const fakeConstructor = (constructor: Function, name: string) =>
|
||||||
const unwrapArgs = function (sender: electron.WebContents, frameId: number, contextId: string, args: any[]) {
|
const unwrapArgs = function (sender: electron.WebContents, frameId: number, contextId: string, args: any[]) {
|
||||||
const metaToValue = function (meta: MetaTypeFromRenderer): any {
|
const metaToValue = function (meta: MetaTypeFromRenderer): any {
|
||||||
switch (meta.type) {
|
switch (meta.type) {
|
||||||
case 'nativeimage': {
|
case 'nativeimage':
|
||||||
const image = electron.nativeImage.createEmpty();
|
return deserialize(meta.value);
|
||||||
for (const rep of meta.value) {
|
|
||||||
const { size, scaleFactor, dataURL } = rep;
|
|
||||||
const { width, height } = size;
|
|
||||||
image.addRepresentation({ dataURL, scaleFactor, width, height });
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
case 'value':
|
case 'value':
|
||||||
return meta.value;
|
return meta.value;
|
||||||
case 'remote-object':
|
case 'remote-object':
|
||||||
|
|
|
@ -20,10 +20,10 @@ const serializableTypes = [
|
||||||
Date,
|
Date,
|
||||||
Error,
|
Error,
|
||||||
RegExp,
|
RegExp,
|
||||||
ArrayBuffer,
|
ArrayBuffer
|
||||||
NativeImage
|
|
||||||
];
|
];
|
||||||
|
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Structured_clone_algorithm#Supported_types
|
||||||
export function isSerializableObject (value: any) {
|
export function isSerializableObject (value: any) {
|
||||||
return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type);
|
return value === null || ArrayBuffer.isView(value) || serializableTypes.some(type => value instanceof type);
|
||||||
}
|
}
|
||||||
|
@ -34,18 +34,55 @@ const objectMap = function (source: Object, mapper: (value: any) => any) {
|
||||||
return Object.fromEntries(targetEntries);
|
return Object.fromEntries(targetEntries);
|
||||||
};
|
};
|
||||||
|
|
||||||
export function serialize (value: any): any {
|
function serializeNativeImage (image: any) {
|
||||||
if (value instanceof NativeImage) {
|
const representations = [];
|
||||||
const representations = [];
|
const scaleFactors = image.getScaleFactors();
|
||||||
for (const scaleFactor of value.getScaleFactors()) {
|
|
||||||
const size = value.getSize(scaleFactor);
|
// Use Buffer when there's only one representation for better perf.
|
||||||
const dataURL = value.toDataURL({ scaleFactor });
|
// This avoids compressing to/from PNG where it's not necessary to
|
||||||
|
// ensure uniqueness of dataURLs (since there's only one).
|
||||||
|
if (scaleFactors.length === 1) {
|
||||||
|
const scaleFactor = scaleFactors[0];
|
||||||
|
const size = image.getSize(scaleFactor);
|
||||||
|
const buffer = image.toBitmap({ scaleFactor });
|
||||||
|
representations.push({ scaleFactor, size, buffer });
|
||||||
|
} else {
|
||||||
|
// Construct from dataURLs to ensure that they are not lost in creation.
|
||||||
|
for (const scaleFactor of scaleFactors) {
|
||||||
|
const size = image.getSize(scaleFactor);
|
||||||
|
const dataURL = image.toDataURL({ scaleFactor });
|
||||||
representations.push({ scaleFactor, size, dataURL });
|
representations.push({ scaleFactor, size, dataURL });
|
||||||
}
|
}
|
||||||
return { __ELECTRON_SERIALIZED_NativeImage__: true, representations };
|
}
|
||||||
} else if (value instanceof Buffer) {
|
return { __ELECTRON_SERIALIZED_NativeImage__: true, representations };
|
||||||
return { __ELECTRON_SERIALIZED_Buffer__: true, data: value };
|
}
|
||||||
} else if (Array.isArray(value)) {
|
|
||||||
|
function deserializeNativeImage (value: any) {
|
||||||
|
const image = nativeImage.createEmpty();
|
||||||
|
|
||||||
|
// Use Buffer when there's only one representation for better perf.
|
||||||
|
// This avoids compressing to/from PNG where it's not necessary to
|
||||||
|
// ensure uniqueness of dataURLs (since there's only one).
|
||||||
|
if (value.representations.length === 1) {
|
||||||
|
const { buffer, size, scaleFactor } = value.representations[0];
|
||||||
|
const { width, height } = size;
|
||||||
|
image.addRepresentation({ buffer, scaleFactor, width, height });
|
||||||
|
} else {
|
||||||
|
// Construct from dataURLs to ensure that they are not lost in creation.
|
||||||
|
for (const rep of value.representations) {
|
||||||
|
const { dataURL, size, scaleFactor } = rep;
|
||||||
|
const { width, height } = size;
|
||||||
|
image.addRepresentation({ dataURL, scaleFactor, width, height });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function serialize (value: any): any {
|
||||||
|
if (value instanceof NativeImage) {
|
||||||
|
return serializeNativeImage(value);
|
||||||
|
} if (Array.isArray(value)) {
|
||||||
return value.map(serialize);
|
return value.map(serialize);
|
||||||
} else if (isSerializableObject(value)) {
|
} else if (isSerializableObject(value)) {
|
||||||
return value;
|
return value;
|
||||||
|
@ -58,16 +95,7 @@ export function serialize (value: any): any {
|
||||||
|
|
||||||
export function deserialize (value: any): any {
|
export function deserialize (value: any): any {
|
||||||
if (value && value.__ELECTRON_SERIALIZED_NativeImage__) {
|
if (value && value.__ELECTRON_SERIALIZED_NativeImage__) {
|
||||||
const image = nativeImage.createEmpty();
|
return deserializeNativeImage(value);
|
||||||
for (const rep of value.representations) {
|
|
||||||
const { size, scaleFactor, dataURL } = rep;
|
|
||||||
const { width, height } = size;
|
|
||||||
image.addRepresentation({ dataURL, scaleFactor, width, height });
|
|
||||||
}
|
|
||||||
return image;
|
|
||||||
} else if (value && value.__ELECTRON_SERIALIZED_Buffer__) {
|
|
||||||
const { buffer, byteOffset, byteLength } = value.data;
|
|
||||||
return Buffer.from(buffer, byteOffset, byteLength);
|
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
return value.map(deserialize);
|
return value.map(deserialize);
|
||||||
} else if (isSerializableObject(value)) {
|
} else if (isSerializableObject(value)) {
|
||||||
|
|
|
@ -5,7 +5,7 @@ const { hasSwitch } = process.electronBinding('command_line');
|
||||||
const { NativeImage } = process.electronBinding('native_image');
|
const { NativeImage } = process.electronBinding('native_image');
|
||||||
|
|
||||||
const { CallbacksRegistry } = require('@electron/internal/renderer/remote/callbacks-registry');
|
const { CallbacksRegistry } = require('@electron/internal/renderer/remote/callbacks-registry');
|
||||||
const { isPromise, isSerializableObject } = require('@electron/internal/common/type-utils');
|
const { isPromise, isSerializableObject, serialize } = require('@electron/internal/common/type-utils');
|
||||||
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');
|
const { ipcRendererInternal } = require('@electron/internal/renderer/ipc-renderer-internal');
|
||||||
|
|
||||||
const callbacksRegistry = new CallbacksRegistry();
|
const callbacksRegistry = new CallbacksRegistry();
|
||||||
|
@ -37,14 +37,7 @@ function wrapArgs (args, visited = new Set()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value instanceof NativeImage) {
|
if (value instanceof NativeImage) {
|
||||||
const images = [];
|
return { type: 'nativeimage', value: serialize(value) };
|
||||||
for (const scaleFactor of value.getScaleFactors()) {
|
|
||||||
const size = value.getSize(scaleFactor);
|
|
||||||
const buffer = value.toBitmap({ scaleFactor });
|
|
||||||
const dataURL = value.toDataURL({ scaleFactor });
|
|
||||||
images.push({ buffer, scaleFactor, size, dataURL });
|
|
||||||
}
|
|
||||||
return { type: 'nativeimage', value: images };
|
|
||||||
} else if (Array.isArray(value)) {
|
} else if (Array.isArray(value)) {
|
||||||
visited.add(value);
|
visited.add(value);
|
||||||
const meta = {
|
const meta = {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue