electron/lib/browser/api/web-contents.ts

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

890 lines
31 KiB
TypeScript
Raw Normal View History

import { app, ipcMain, session, webFrameMain } from 'electron/main';
chore: bump chromium to 90.0.4415.0 (master) (#27694) * chore: bump chromium in DEPS to 520c02b46668fc608927e0fcd79b6a90885a48bf * chore: bump chromium in DEPS to 90.0.4414.0 * resolve chromium conflicts * resolve v8 conflicts * fix node gn files * 2673502: Remove RenderViewCreated use from ExtensionHost. https://chromium-review.googlesource.com/c/chromium/src/+/2673502 * 2676903: [mojo] Remove most legacy Binding classes. https://chromium-review.googlesource.com/c/chromium/src/+/2676903 * 2644847: Move self-deleting URLLoaderFactory base into //services/network. https://chromium-review.googlesource.com/c/chromium/src/+/2644847 * 2664006: Remove from mojo::DataPipe. https://chromium-review.googlesource.com/c/chromium/src/+/2664006 * 2674530: Remove CertVerifierService feature https://chromium-review.googlesource.com/c/chromium/src/+/2674530 * 2668748: Move OnSSLCertificateError to a new interface. https://chromium-review.googlesource.com/c/chromium/src/+/2668748 * 2672923: Remove RAPPOR reporting infrastructure. https://chromium-review.googlesource.com/c/chromium/src/+/2672923 * 2673502: Remove RenderViewCreated use from ExtensionHost. https://chromium-review.googlesource.com/c/chromium/src/+/2673502 * 2655126: Convert FrameHostMsg_ContextMenu and FrameMsg_ContextMenuClosed|CustomContextMenuAction to Mojo https://chromium-review.googlesource.com/c/chromium/src/+/2655126 * 2628705: Window Placement: Implement screen.isExtended and change event https://chromium-review.googlesource.com/c/chromium/src/+/2628705 * 2643161: Refactor storage::kFileSystem*Native* https://chromium-review.googlesource.com/c/chromium/src/+/2643161 * fix build * only remove the biggest subdir of //ios * chore: bump chromium in DEPS to 90.0.4415.0 * update patches * update sysroots * 2686147: Remove WebContentsObserver::RenderViewCreated(). https://chromium-review.googlesource.com/c/chromium/src/+/2686147 * 2596429: Fixing how extension's split and spanning modes affect OriginAccessList. https://chromium-review.googlesource.com/c/chromium/src/+/2596429 * 2686026: [mojo] Delete AssociatedInterfacePtr (replaced by AssociatedRemote) https://chromium-review.googlesource.com/c/chromium/src/+/2686026 * 2651705: Move ui/base/dragdrop/file_info to ui/base/clipboard https://chromium-review.googlesource.com/c/chromium/src/+/2651705 * 358217: drawBitmap is deprecated https://skia-review.googlesource.com/c/skia/+/358217 * fix gn check * 2678098: Use gen/front_end as input to generate_devtools_grd https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2678098 * 2674530: Remove CertVerifierService feature https://chromium-review.googlesource.com/c/chromium/src/+/2674530 * fixup 2664006: Remove from mojo::DataPipe. https://chromium-review.googlesource.com/c/chromium/src/+/2664006 * fixup build_add_electron_tracing_category.patch * 2673415: [base] Prepare CrashReporterClient for string16 switch https://chromium-review.googlesource.com/c/chromium/src/+/2673415 * 2673413: Add CursorFactoryWin to handle Cursors on Windows https://chromium-review.googlesource.com/c/chromium/src/+/2673413 * 2668748: Move OnSSLCertificateError to a new interface. https://chromium-review.googlesource.com/c/chromium/src/+/2668748 * fix mas gn check * update patch after merge * Update node for .mjs files * build: load v8_prof_processor dependencies as ESM * chore: add patch to fix linux 32bit Co-authored-by: Jeremy Rose <nornagon@nornagon.net> Co-authored-by: Jeremy Rose <jeremya@chromium.org> Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
2021-03-04 17:27:05 +00:00
import type { BrowserWindowConstructorOptions, LoadURLOptions } from 'electron/main';
2020-07-06 17:50:03 +00:00
import * as url from 'url';
import * as path from 'path';
import { openGuestWindow, makeWebPreferences, parseContentTypeFormat } from '@electron/internal/browser/guest-window-manager';
import { parseFeatures } from '@electron/internal/browser/parse-features-string';
import { ipcMainInternal } from '@electron/internal/browser/ipc-main-internal';
import * as ipcMainUtils from '@electron/internal/browser/ipc-main-internal-utils';
import { MessagePortMain } from '@electron/internal/browser/message-port-main';
import { IPC_MESSAGES } from '@electron/internal/common/ipc-messages';
2022-08-03 23:55:12 +00:00
import { IpcMainImpl } from '@electron/internal/browser/ipc-main-impl';
import * as deprecate from '@electron/internal/common/deprecate';
// session is not used here, the purpose is to make sure session is initialized
// before the webContents module.
// eslint-disable-next-line no-unused-expressions
session;
2016-01-12 02:40:23 +00:00
2022-08-03 23:55:12 +00:00
const webFrameMainBinding = process._linkedBinding('electron_browser_web_frame_main');
let nextId = 0;
const getNextId = function () {
return ++nextId;
};
2016-01-12 02:40:23 +00:00
type PostData = LoadURLOptions['postData']
2016-06-01 06:24:53 +00:00
// Stock page sizes
const PDFPageSizes: Record<string, ElectronInternal.MediaSize> = {
Letter: {
custom_display_name: 'Letter',
height_microns: 279400,
name: 'NA_LETTER',
width_microns: 215900
2016-01-12 02:40:23 +00:00
},
Legal: {
custom_display_name: 'Legal',
2016-01-12 02:40:23 +00:00
height_microns: 355600,
name: 'NA_LEGAL',
2016-01-12 02:40:23 +00:00
width_microns: 215900
},
Tabloid: {
height_microns: 431800,
name: 'NA_LEDGER',
2016-01-12 02:40:23 +00:00
width_microns: 279400,
custom_display_name: 'Tabloid'
},
A0: {
custom_display_name: 'A0',
height_microns: 1189000,
name: 'ISO_A0',
width_microns: 841000
},
A1: {
custom_display_name: 'A1',
height_microns: 841000,
name: 'ISO_A1',
width_microns: 594000
},
A2: {
custom_display_name: 'A2',
height_microns: 594000,
name: 'ISO_A2',
width_microns: 420000
},
A3: {
custom_display_name: 'A3',
height_microns: 420000,
name: 'ISO_A3',
width_microns: 297000
},
A4: {
custom_display_name: 'A4',
height_microns: 297000,
name: 'ISO_A4',
is_default: 'true',
width_microns: 210000
},
A5: {
custom_display_name: 'A5',
height_microns: 210000,
name: 'ISO_A5',
width_microns: 148000
},
A6: {
custom_display_name: 'A6',
height_microns: 148000,
name: 'ISO_A6',
width_microns: 105000
2016-01-12 02:40:23 +00:00
}
} as const;
2016-01-12 02:40:23 +00:00
const paperFormats: Record<string, ElectronInternal.PageSize> = {
letter: { width: 8.5, height: 11 },
legal: { width: 8.5, height: 14 },
tabloid: { width: 11, height: 17 },
ledger: { width: 17, height: 11 },
a0: { width: 33.1, height: 46.8 },
a1: { width: 23.4, height: 33.1 },
a2: { width: 16.54, height: 23.4 },
a3: { width: 11.7, height: 16.54 },
a4: { width: 8.27, height: 11.7 },
a5: { width: 5.83, height: 8.27 },
a6: { width: 4.13, height: 5.83 }
} as const;
// The minimum micron size Chromium accepts is that where:
// Per printing/units.h:
// * kMicronsPerInch - Length of an inch in 0.001mm unit.
// * kPointsPerInch - Length of an inch in CSS's 1pt unit.
//
// Formula: (kPointsPerInch / kMicronsPerInch) * size >= 1
//
// Practically, this means microns need to be > 352 microns.
// We therefore need to verify this or it will silently fail.
const isValidCustomPageSize = (width: number, height: number) => {
return [width, height].every(x => x > 352);
};
// JavaScript implementations of WebContents.
const binding = process._linkedBinding('electron_browser_web_contents');
const printing = process._linkedBinding('electron_browser_printing');
const { WebContents } = binding as { WebContents: { prototype: Electron.WebContents } };
2016-08-02 11:38:35 +00:00
WebContents.prototype.postMessage = function (...args) {
return this.mainFrame.postMessage(...args);
};
WebContents.prototype.send = function (channel, ...args) {
return this.mainFrame.send(channel, ...args);
};
WebContents.prototype._sendInternal = function (channel, ...args) {
return this.mainFrame._sendInternal(channel, ...args);
};
function getWebFrame (contents: Electron.WebContents, frame: number | [number, number]) {
if (typeof frame === 'number') {
return webFrameMain.fromId(contents.mainFrame.processId, frame);
} else if (Array.isArray(frame) && frame.length === 2 && frame.every(value => typeof value === 'number')) {
return webFrameMain.fromId(frame[0], frame[1]);
} else {
throw new Error('Missing required frame argument (must be number or [processId, frameId])');
}
}
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
const frame = getWebFrame(this, frameId);
if (!frame) return false;
frame.send(channel, ...args);
return true;
};
2016-01-13 03:55:49 +00:00
// Following methods are mapped to webFrame.
const webFrameMethods = [
2016-12-19 23:50:47 +00:00
'insertCSS',
2016-01-13 03:55:49 +00:00
'insertText',
2019-06-17 15:39:36 +00:00
'removeInsertedCSS',
2018-02-20 13:57:48 +00:00
'setVisualZoomLevelLimits'
2020-07-06 17:50:03 +00:00
] as ('insertCSS' | 'insertText' | 'removeInsertedCSS' | 'setVisualZoomLevelLimits')[];
for (const method of webFrameMethods) {
2020-07-06 17:50:03 +00:00
WebContents.prototype[method] = function (...args: any[]): Promise<any> {
return ipcMainUtils.invokeInWebContents(this, IPC_MESSAGES.RENDERER_WEB_FRAME_METHOD, method, ...args);
2016-01-12 02:40:23 +00:00
};
}
2016-01-12 02:40:23 +00:00
const waitTillCanExecuteJavaScript = async (webContents: Electron.WebContents) => {
if (webContents.getURL() && !webContents.isLoadingMainFrame()) return;
return new Promise<void>((resolve) => {
webContents.once('did-stop-loading', () => {
resolve();
});
});
};
// Make sure WebContents::executeJavaScript would run the code only when the
// WebContents has been loaded.
WebContents.prototype.executeJavaScript = async function (code, hasUserGesture) {
await waitTillCanExecuteJavaScript(this);
return ipcMainUtils.invokeInWebContents(this, IPC_MESSAGES.RENDERER_WEB_FRAME_METHOD, 'executeJavaScript', String(code), !!hasUserGesture);
};
WebContents.prototype.executeJavaScriptInIsolatedWorld = async function (worldId, code, hasUserGesture) {
await waitTillCanExecuteJavaScript(this);
return ipcMainUtils.invokeInWebContents(this, IPC_MESSAGES.RENDERER_WEB_FRAME_METHOD, 'executeJavaScriptInIsolatedWorld', worldId, code, !!hasUserGesture);
};
// Translate the options of printToPDF.
chore: bump chromium to 6d130075d378a64187360ba4e7820 (master) (#24256) * chore: bump chromium in DEPS to 7fb9778894d73378bff51087ce869ea5aa6e5d5d * chore: bump chromium in DEPS to 83da426e53d423f0530fc23433b6d2c4d0548442 * update patches * remove chromeos-only TtsControllerDelegate Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2255314 * SharedUserScriptMaster -> SharedUserScriptManager Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2258357 * avoid deprecated DISALLOW_COPY_AND_ASSIGN https://groups.google.com/a/chromium.org/forum/#!msg/cxx/qwH2hxaEjac/TUKq6eqfCwAJ * chore: bump chromium in DEPS to b2eaf9ff4e6b03267bf279583ea20ceb2b25e9d0 * update patches * rename GetHighContrastColorScheme -> GetPlatformHighContrastColorScheme Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2250224 * remove vulkan info collection Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2252818 * add max_xcode_version build var Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2264867 * add missing headers * chore: bump chromium in DEPS to cded18ca1138f7e8efc904f077ddcca34f0135cf * update patches * add empty floc blocklist to BrowserProcessImpl Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2240873 * chore: bump chromium in DEPS to f06602226cd80bf677b2ce013a94a2fb7f6ac58d * chore: bump chromium in DEPS to 747aa4bfc74fc6cf7f08ee72624cd69ae41ae28d * chore: bump chromium in DEPS to 31c0105e50fcc4e94de33e5c8602c755ace4a32b * chore: update patches * Reland "[base] Stop including check.h, notreached.h, etc. in logging.h" https://chromium-review.googlesource.com/c/chromium/src/+/2264297 * X11 and Ozone: make sure gfx::AcceleratedWidget to be uint32_t https://chromium-review.googlesource.com/c/chromium/src/+/2260554 * Move zygote from //services/service_manager back to //content https://chromium-review.googlesource.com/c/chromium/src/+/2252466 * chore: update v8 patches * [XProto] Remove usage of Shape extension https://chromium-review.googlesource.com/c/chromium/src/+/2262113 * fixup! add empty floc blocklist to BrowserProcessImpl * Require macOS 10.15.1 sdk https://chromium-review.googlesource.com/c/chromium/src/+/2238504 * Use newer Xcode version 11.5.0 * update src cache * chore: bump chromium in DEPS to 60a9883e35db3f6f91916f0878e88e1849c17b11 * chore: update patches * Reland "Reland "New toolchain for Windows 10 19041 SDK"" https://chromium-review.googlesource.com/c/chromium/src/+/2255527 * update patches * Convert raw NonClientFrameViews to unique_ptrs https://chromium-review.googlesource.com/c/chromium/src/+/2240417 * [printing] Move PrintHostMsg_DidPreviewDocument_Params to print.mojom https://chromium-review.googlesource.com/c/chromium/src/+/2257035 * chore: bump chromium in DEPS to 12c233c2a85bfa28fb279f390121ba681e52a71b * chore: update patches * Removing oppressive language for the directory chrome/browser/apps https://chromium-review.googlesource.com/c/chromium/src/+/2269822 * Inclusion: rename SpellcheckLanguageBlacklistPolicyHandler https://chromium-review.googlesource.com/c/chromium/src/+/2267646 * Clean up duplicate WebContents "is fullscreen" functions https://chromium-review.googlesource.com/c/chromium/src/+/2275148 * Adds icon loading service with sandbox for Windows. https://chromium-review.googlesource.com/c/chromium/src/+/1987273 * No more Vulkan info collection for UMA on Windows https://chromium-review.googlesource.com/c/chromium/src/+/2252818 * fix lint * chore: update buildflag conditions * chore: bump chromium in DEPS to a837d4c4230ace4f10b2768728f4044b7995dfa5 * update hunspell files * chore: update patches * Make content::FileSelectListener a RefCounted https://chromium-review.googlesource.com/c/chromium/src/+/2275338 * fix build failures on MAS * update patches * fixup! Reland "[base] Stop including check.h, notreached.h, etc. in logging.h" * fix build on windows * Check for GDI exhaustion if window creation fails https://chromium-review.googlesource.com/c/chromium/src/+/2244124 * chore: bump chromium in DEPS to 2c9b2a73be4ef9ec22d8b6da8e174cb80753f125 * chore: update patches * Network Service: Move DeleteCookiePredicate into public folder https://chromium-review.googlesource.com/c/chromium/src/+/2264186 * chore: bump chromium in DEPS to fa2606299bcc02c362528d26b5dcf8c8a0db0735 * chore: bump chromium in DEPS to d9c235d1227204dbae3708daae851573a3566b94 * chore: bump chromium in DEPS to 2f82c284243c035f49a747fd1ead6c44b4b31093 * chore: update patches * Move creating the LayerTreeSettings into blink. https://chromium-review.googlesource.com/c/chromium/src/+/2267720 * chore: bump chromium in DEPS to 914112f1d9af9e4974059dc403da62699a55550f * update patches * chore: bump chromium in DEPS to e0bc1ffae6393fc543a2da94c88167df75859b36 * refactor: match upstream print preview handling (#24452) * update patches * chore: bump chromium in DEPS to 0881423156abe084164b51ab58ce93a8bd380524 * update patches * update patches * give a type to pendingPromise * chore: bump chromium in DEPS to 11a8c1534b16d130075d378a64187360ba4e7820 * update patches * 2272609: Move //services/service_manager/sandbox to //sandbox/policy. https://chromium-review.googlesource.com/c/chromium/src/+/2272609 * update patches * fixup! 2272609: Move //services/service_manager/sandbox to //sandbox/policy. * fixup! 2272609: Move //services/service_manager/sandbox to //sandbox/policy. * 2264511: Cookies: Update SetCanonicalCookie to return CookieAccessResult https://chromium-review.googlesource.com/c/chromium/src/+/2264511 * chore: fix setAlwaysOnTop test The window must be visible for state to be updated properly. * Revert "Migrate modules/desktop_capture and modules/video_capture to webrtc::Mutex." https://webrtc-review.googlesource.com/c/src/+/179080 * update patches Co-authored-by: Andy Locascio <andy@slack-corp.com> Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com> Co-authored-by: John Kleinschmidt <jkleinsc@github.com> Co-authored-by: Electron Bot <anonymous@electronjs.org> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Jeremy Rose <nornagon@nornagon.net> Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2020-07-14 01:13:34 +00:00
let pendingPromise: Promise<any> | undefined;
WebContents.prototype.printToPDF = async function (options) {
const printSettings: Record<string, any> = {
requestID: getNextId(),
landscape: false,
displayHeaderFooter: false,
headerTemplate: '',
footerTemplate: '',
printBackground: false,
scale: 1.0,
paperWidth: 8.5,
paperHeight: 11.0,
marginTop: 0.4,
marginBottom: 0.4,
marginLeft: 0.4,
marginRight: 0.4,
pageRanges: '',
preferCSSPageSize: false,
shouldGenerateTaggedPDF: false
};
if (options.landscape !== undefined) {
if (typeof options.landscape !== 'boolean') {
throw new Error('landscape must be a Boolean');
}
printSettings.landscape = options.landscape;
}
if (options.displayHeaderFooter !== undefined) {
if (typeof options.displayHeaderFooter !== 'boolean') {
throw new Error('displayHeaderFooter must be a Boolean');
}
printSettings.displayHeaderFooter = options.displayHeaderFooter;
}
if (options.printBackground !== undefined) {
if (typeof options.printBackground !== 'boolean') {
throw new Error('printBackground must be a Boolean');
}
printSettings.shouldPrintBackgrounds = options.printBackground;
}
if (options.scale !== undefined) {
if (typeof options.scale !== 'number') {
throw new Error('scale must be a Number');
}
printSettings.scale = options.scale;
}
const { pageSize } = options;
if (pageSize !== undefined) {
if (typeof pageSize === 'string') {
const format = paperFormats[pageSize.toLowerCase()];
if (!format) {
throw new Error(`Invalid pageSize ${pageSize}`);
}
printSettings.paperWidth = format.width;
printSettings.paperHeight = format.height;
} else if (typeof options.pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize');
}
printSettings.paperWidth = pageSize.width;
printSettings.paperHeight = pageSize.height;
} else {
throw new Error('pageSize must be a String or Object');
}
}
const { margins } = options;
if (margins !== undefined) {
if (typeof margins !== 'object') {
throw new Error('margins must be an Object');
}
if (margins.top !== undefined) {
if (typeof margins.top !== 'number') {
throw new Error('margins.top must be a Number');
}
printSettings.marginTop = margins.top;
}
if (margins.bottom !== undefined) {
if (typeof margins.bottom !== 'number') {
throw new Error('margins.bottom must be a Number');
}
printSettings.marginBottom = margins.bottom;
}
if (margins.left !== undefined) {
if (typeof margins.left !== 'number') {
throw new Error('margins.left must be a Number');
}
printSettings.marginLeft = margins.left;
}
if (margins.right !== undefined) {
if (typeof margins.right !== 'number') {
throw new Error('margins.right must be a Number');
}
printSettings.marginRight = margins.right;
}
2016-01-13 03:55:49 +00:00
}
if (options.pageRanges !== undefined) {
if (typeof options.pageRanges !== 'string') {
throw new Error('pageRanges must be a String');
}
printSettings.pageRanges = options.pageRanges;
}
if (options.headerTemplate !== undefined) {
if (typeof options.headerTemplate !== 'string') {
throw new Error('headerTemplate must be a String');
}
printSettings.headerTemplate = options.headerTemplate;
}
if (options.footerTemplate !== undefined) {
if (typeof options.footerTemplate !== 'string') {
throw new Error('footerTemplate must be a String');
}
printSettings.footerTemplate = options.footerTemplate;
}
if (options.preferCSSPageSize !== undefined) {
if (typeof options.preferCSSPageSize !== 'boolean') {
throw new Error('preferCSSPageSize must be a Boolean');
}
printSettings.preferCSSPageSize = options.preferCSSPageSize;
}
2016-02-22 14:00:21 +00:00
if (options.generateTaggedPDF !== undefined) {
if (typeof options.generateTaggedPDF !== 'boolean') {
throw new Error('generateTaggedPDF must be a Boolean');
}
printSettings.shouldGenerateTaggedPDF = options.generateTaggedPDF;
}
if (this._printToPDF) {
chore: bump chromium to 6d130075d378a64187360ba4e7820 (master) (#24256) * chore: bump chromium in DEPS to 7fb9778894d73378bff51087ce869ea5aa6e5d5d * chore: bump chromium in DEPS to 83da426e53d423f0530fc23433b6d2c4d0548442 * update patches * remove chromeos-only TtsControllerDelegate Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2255314 * SharedUserScriptMaster -> SharedUserScriptManager Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2258357 * avoid deprecated DISALLOW_COPY_AND_ASSIGN https://groups.google.com/a/chromium.org/forum/#!msg/cxx/qwH2hxaEjac/TUKq6eqfCwAJ * chore: bump chromium in DEPS to b2eaf9ff4e6b03267bf279583ea20ceb2b25e9d0 * update patches * rename GetHighContrastColorScheme -> GetPlatformHighContrastColorScheme Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2250224 * remove vulkan info collection Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2252818 * add max_xcode_version build var Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2264867 * add missing headers * chore: bump chromium in DEPS to cded18ca1138f7e8efc904f077ddcca34f0135cf * update patches * add empty floc blocklist to BrowserProcessImpl Refs: https://chromium-review.googlesource.com/c/chromium/src/+/2240873 * chore: bump chromium in DEPS to f06602226cd80bf677b2ce013a94a2fb7f6ac58d * chore: bump chromium in DEPS to 747aa4bfc74fc6cf7f08ee72624cd69ae41ae28d * chore: bump chromium in DEPS to 31c0105e50fcc4e94de33e5c8602c755ace4a32b * chore: update patches * Reland "[base] Stop including check.h, notreached.h, etc. in logging.h" https://chromium-review.googlesource.com/c/chromium/src/+/2264297 * X11 and Ozone: make sure gfx::AcceleratedWidget to be uint32_t https://chromium-review.googlesource.com/c/chromium/src/+/2260554 * Move zygote from //services/service_manager back to //content https://chromium-review.googlesource.com/c/chromium/src/+/2252466 * chore: update v8 patches * [XProto] Remove usage of Shape extension https://chromium-review.googlesource.com/c/chromium/src/+/2262113 * fixup! add empty floc blocklist to BrowserProcessImpl * Require macOS 10.15.1 sdk https://chromium-review.googlesource.com/c/chromium/src/+/2238504 * Use newer Xcode version 11.5.0 * update src cache * chore: bump chromium in DEPS to 60a9883e35db3f6f91916f0878e88e1849c17b11 * chore: update patches * Reland "Reland "New toolchain for Windows 10 19041 SDK"" https://chromium-review.googlesource.com/c/chromium/src/+/2255527 * update patches * Convert raw NonClientFrameViews to unique_ptrs https://chromium-review.googlesource.com/c/chromium/src/+/2240417 * [printing] Move PrintHostMsg_DidPreviewDocument_Params to print.mojom https://chromium-review.googlesource.com/c/chromium/src/+/2257035 * chore: bump chromium in DEPS to 12c233c2a85bfa28fb279f390121ba681e52a71b * chore: update patches * Removing oppressive language for the directory chrome/browser/apps https://chromium-review.googlesource.com/c/chromium/src/+/2269822 * Inclusion: rename SpellcheckLanguageBlacklistPolicyHandler https://chromium-review.googlesource.com/c/chromium/src/+/2267646 * Clean up duplicate WebContents "is fullscreen" functions https://chromium-review.googlesource.com/c/chromium/src/+/2275148 * Adds icon loading service with sandbox for Windows. https://chromium-review.googlesource.com/c/chromium/src/+/1987273 * No more Vulkan info collection for UMA on Windows https://chromium-review.googlesource.com/c/chromium/src/+/2252818 * fix lint * chore: update buildflag conditions * chore: bump chromium in DEPS to a837d4c4230ace4f10b2768728f4044b7995dfa5 * update hunspell files * chore: update patches * Make content::FileSelectListener a RefCounted https://chromium-review.googlesource.com/c/chromium/src/+/2275338 * fix build failures on MAS * update patches * fixup! Reland "[base] Stop including check.h, notreached.h, etc. in logging.h" * fix build on windows * Check for GDI exhaustion if window creation fails https://chromium-review.googlesource.com/c/chromium/src/+/2244124 * chore: bump chromium in DEPS to 2c9b2a73be4ef9ec22d8b6da8e174cb80753f125 * chore: update patches * Network Service: Move DeleteCookiePredicate into public folder https://chromium-review.googlesource.com/c/chromium/src/+/2264186 * chore: bump chromium in DEPS to fa2606299bcc02c362528d26b5dcf8c8a0db0735 * chore: bump chromium in DEPS to d9c235d1227204dbae3708daae851573a3566b94 * chore: bump chromium in DEPS to 2f82c284243c035f49a747fd1ead6c44b4b31093 * chore: update patches * Move creating the LayerTreeSettings into blink. https://chromium-review.googlesource.com/c/chromium/src/+/2267720 * chore: bump chromium in DEPS to 914112f1d9af9e4974059dc403da62699a55550f * update patches * chore: bump chromium in DEPS to e0bc1ffae6393fc543a2da94c88167df75859b36 * refactor: match upstream print preview handling (#24452) * update patches * chore: bump chromium in DEPS to 0881423156abe084164b51ab58ce93a8bd380524 * update patches * update patches * give a type to pendingPromise * chore: bump chromium in DEPS to 11a8c1534b16d130075d378a64187360ba4e7820 * update patches * 2272609: Move //services/service_manager/sandbox to //sandbox/policy. https://chromium-review.googlesource.com/c/chromium/src/+/2272609 * update patches * fixup! 2272609: Move //services/service_manager/sandbox to //sandbox/policy. * fixup! 2272609: Move //services/service_manager/sandbox to //sandbox/policy. * 2264511: Cookies: Update SetCanonicalCookie to return CookieAccessResult https://chromium-review.googlesource.com/c/chromium/src/+/2264511 * chore: fix setAlwaysOnTop test The window must be visible for state to be updated properly. * Revert "Migrate modules/desktop_capture and modules/video_capture to webrtc::Mutex." https://webrtc-review.googlesource.com/c/src/+/179080 * update patches Co-authored-by: Andy Locascio <andy@slack-corp.com> Co-authored-by: deepak1556 <hop2deep@gmail.com> Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com> Co-authored-by: John Kleinschmidt <jkleinsc@github.com> Co-authored-by: Electron Bot <anonymous@electronjs.org> Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com> Co-authored-by: Jeremy Rose <nornagon@nornagon.net> Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2020-07-14 01:13:34 +00:00
if (pendingPromise) {
pendingPromise = pendingPromise.then(() => this._printToPDF(printSettings));
} else {
pendingPromise = this._printToPDF(printSettings);
}
return pendingPromise;
} else {
throw new Error('Printing feature is disabled');
}
};
// TODO(codebytere): deduplicate argument sanitization by moving rest of
// print param logic into new file shared between printToPDF and print
WebContents.prototype.print = function (options: ElectronInternal.WebContentsPrintOptions, callback) {
if (typeof options === 'object') {
const pageSize = options.pageSize ?? 'A4';
if (typeof pageSize === 'object') {
if (!pageSize.height || !pageSize.width) {
throw new Error('height and width properties are required for pageSize');
}
// Dimensions in Microns - 1 meter = 10^6 microns
const height = Math.ceil(pageSize.height);
const width = Math.ceil(pageSize.width);
if (!isValidCustomPageSize(width, height)) {
throw new Error('height and width properties must be minimum 352 microns.');
}
options.mediaSize = {
name: 'CUSTOM',
custom_display_name: 'Custom',
height_microns: height,
width_microns: width,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: width,
imageable_area_top_microns: height
};
} else if (typeof pageSize === 'string' && PDFPageSizes[pageSize]) {
const mediaSize = PDFPageSizes[pageSize];
options.mediaSize = {
...mediaSize,
imageable_area_left_microns: 0,
imageable_area_bottom_microns: 0,
imageable_area_right_microns: mediaSize.width_microns,
imageable_area_top_microns: mediaSize.height_microns
};
} else {
throw new Error(`Unsupported pageSize: ${pageSize}`);
}
}
if (this._print) {
if (callback) {
this._print(options, callback);
} else {
this._print(options);
}
} else {
console.error('Error: Printing feature is disabled.');
}
};
WebContents.prototype.getPrintersAsync = async function () {
// TODO(nornagon): this API has nothing to do with WebContents and should be
// moved.
if (printing.getPrinterListAsync) {
return printing.getPrinterListAsync();
} else {
console.error('Error: Printing feature is disabled.');
return [];
}
};
WebContents.prototype.loadFile = function (filePath, options = {}) {
if (typeof filePath !== 'string') {
throw new TypeError('Must pass filePath as a string');
}
2018-09-13 16:10:51 +00:00
const { query, search, hash } = options;
return this.loadURL(url.format({
protocol: 'file',
slashes: true,
pathname: path.resolve(app.getAppPath(), filePath),
query,
search,
hash
}));
};
WebContents.prototype.loadURL = function (url, options) {
const p = new Promise<void>((resolve, reject) => {
const resolveAndCleanup = () => {
removeListeners();
resolve();
};
const rejectAndCleanup = (errorCode: number, errorDescription: string, url: string) => {
const err = new Error(`${errorDescription} (${errorCode}) loading '${typeof url === 'string' ? url.substr(0, 2048) : url}'`);
Object.assign(err, { errno: errorCode, code: errorDescription, url });
removeListeners();
reject(err);
};
const finishListener = () => {
resolveAndCleanup();
};
const failListener = (event: Electron.Event, errorCode: number, errorDescription: string, validatedURL: string, isMainFrame: boolean) => {
if (isMainFrame) {
rejectAndCleanup(errorCode, errorDescription, validatedURL);
}
};
let navigationStarted = false;
let browserInitiatedInPageNavigation = false;
const navigationListener = (event: Electron.Event, url: string, isSameDocument: boolean, isMainFrame: boolean) => {
if (isMainFrame) {
if (navigationStarted && !isSameDocument) {
// the webcontents has started another unrelated navigation in the
// main frame (probably from the app calling `loadURL` again); reject
// the promise
// We should only consider the request aborted if the "navigation" is
// actually navigating and not simply transitioning URL state in the
// current context. E.g. pushState and `location.hash` changes are
// considered navigation events but are triggered with isSameDocument.
// We can ignore these to allow virtual routing on page load as long
// as the routing does not leave the document
return rejectAndCleanup(-3, 'ERR_ABORTED', url);
}
browserInitiatedInPageNavigation = navigationStarted && isSameDocument;
navigationStarted = true;
}
};
const stopLoadingListener = () => {
// By the time we get here, either 'finish' or 'fail' should have fired
// if the navigation occurred. However, in some situations (e.g. when
// attempting to load a page with a bad scheme), loading will stop
// without emitting finish or fail. In this case, we reject the promise
// with a generic failure.
// TODO(jeremy): enumerate all the cases in which this can happen. If
// the only one is with a bad scheme, perhaps ERR_INVALID_ARGUMENT
// would be more appropriate.
rejectAndCleanup(-2, 'ERR_FAILED', url);
};
const finishListenerWhenUserInitiatedNavigation = () => {
if (!browserInitiatedInPageNavigation) {
finishListener();
}
};
const removeListeners = () => {
this.removeListener('did-finish-load', finishListener);
this.removeListener('did-fail-load', failListener);
this.removeListener('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
this.removeListener('did-start-navigation', navigationListener);
this.removeListener('did-stop-loading', stopLoadingListener);
this.removeListener('destroyed', stopLoadingListener);
};
this.on('did-finish-load', finishListener);
this.on('did-fail-load', failListener);
this.on('did-navigate-in-page', finishListenerWhenUserInitiatedNavigation);
this.on('did-start-navigation', navigationListener);
this.on('did-stop-loading', stopLoadingListener);
this.on('destroyed', stopLoadingListener);
});
// Add a no-op rejection handler to silence the unhandled rejection error.
p.catch(() => {});
this._loadURL(url, options ?? {});
return p;
};
WebContents.prototype.setWindowOpenHandler = function (handler: (details: Electron.HandlerDetails) => ({action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions, outlivesOpener?: boolean})) {
this._windowOpenHandler = handler;
};
WebContents.prototype._callWindowOpenHandler = function (event: Electron.Event, details: Electron.HandlerDetails): {browserWindowConstructorOptions: BrowserWindowConstructorOptions | null, outlivesOpener: boolean} {
const defaultResponse = {
browserWindowConstructorOptions: null,
outlivesOpener: false
};
if (!this._windowOpenHandler) {
return defaultResponse;
}
const response = this._windowOpenHandler(details);
if (typeof response !== 'object') {
event.preventDefault();
console.error(`The window open handler response must be an object, but was instead of type '${typeof response}'.`);
return defaultResponse;
}
if (response === null) {
event.preventDefault();
console.error('The window open handler response must be an object, but was instead null.');
return defaultResponse;
}
if (response.action === 'deny') {
event.preventDefault();
return defaultResponse;
} else if (response.action === 'allow') {
return {
browserWindowConstructorOptions: typeof response.overrideBrowserWindowOptions === 'object' ? response.overrideBrowserWindowOptions : null,
outlivesOpener: typeof response.outlivesOpener === 'boolean' ? response.outlivesOpener : false
};
} else {
event.preventDefault();
console.error('The window open handler response must be an object with an \'action\' property of \'allow\' or \'deny\'.');
return defaultResponse;
}
};
const addReplyToEvent = (event: Electron.IpcMainEvent) => {
const { processId, frameId } = event;
event.reply = (channel: string, ...args: any[]) => {
event.sender.sendToFrame([processId, frameId], channel, ...args);
};
};
2023-02-13 21:39:18 +00:00
const addSenderToEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent, sender: Electron.WebContents) => {
event.sender = sender;
const { processId, frameId } = event;
Object.defineProperty(event, 'senderFrame', {
get: () => webFrameMain.fromId(processId, frameId)
});
};
const addReturnValueToEvent = (event: Electron.IpcMainEvent) => {
Object.defineProperty(event, 'returnValue', {
2023-02-13 21:39:18 +00:00
set: (value) => event._replyChannel.sendReply(value),
get: () => {}
});
};
const getWebFrameForEvent = (event: Electron.IpcMainEvent | Electron.IpcMainInvokeEvent) => {
if (!event.processId || !event.frameId) return null;
return webFrameMainBinding.fromIdOrNull(event.processId, event.frameId);
};
const commandLine = process._linkedBinding('electron_common_command_line');
const environment = process._linkedBinding('electron_common_environment');
const loggingEnabled = () => {
return environment.hasVar('ELECTRON_ENABLE_LOGGING') || commandLine.hasSwitch('enable-logging');
};
// Add JavaScript wrappers for WebContents class.
WebContents.prototype._init = function () {
const prefs = this.getLastWebPreferences() || {};
if (!prefs.nodeIntegration && prefs.preload != null && prefs.sandbox == null) {
deprecate.log('The default sandbox option for windows without nodeIntegration is changing. Presently, by default, when a window has a preload script, it defaults to being unsandboxed. In Electron 20, this default will be changing, and all windows that have nodeIntegration: false (which is the default) will be sandboxed by default. If your preload script doesn\'t use Node, no action is needed. If your preload script does use Node, either refactor it to move Node usage to the main process, or specify sandbox: false in your WebPreferences.');
}
// Read off the ID at construction time, so that it's accessible even after
// the underlying C++ WebContents is destroyed.
const id = this.id;
Object.defineProperty(this, 'id', {
value: id,
writable: false
});
this._windowOpenHandler = null;
2022-08-03 23:55:12 +00:00
const ipc = new IpcMainImpl();
Object.defineProperty(this, 'ipc', {
get () { return ipc; },
enumerable: true
});
2016-01-14 18:35:29 +00:00
// Dispatch IPC messages to the ipc module.
this.on('-ipc-message' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
2023-02-13 21:39:18 +00:00
addSenderToEvent(event, this);
if (internal) {
ipcMainInternal.emit(channel, event, ...args);
} else {
addReplyToEvent(event);
this.emit('ipc-message', event, channel, ...args);
const maybeWebFrame = getWebFrameForEvent(event);
2022-08-03 23:55:12 +00:00
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, ...args);
ipc.emit(channel, event, ...args);
ipcMain.emit(channel, event, ...args);
}
});
2023-02-13 21:39:18 +00:00
this.on('-ipc-invoke' as any, async function (this: Electron.WebContents, event: Electron.IpcMainInvokeEvent, internal: boolean, channel: string, args: any[]) {
addSenderToEvent(event, this);
const replyWithResult = (result: any) => event._replyChannel.sendReply({ result });
const replyWithError = (error: Error) => {
console.error(`Error occurred in handler for '${channel}':`, error);
2023-02-13 21:39:18 +00:00
event._replyChannel.sendReply({ error: error.toString() });
};
const maybeWebFrame = getWebFrameForEvent(event);
const targets: (ElectronInternal.IpcMainInternal| undefined)[] = internal ? [ipcMainInternal] : [maybeWebFrame?.ipc, ipc, ipcMain];
2022-08-03 23:55:12 +00:00
const target = targets.find(target => target && (target as any)._invokeHandlers.has(channel));
if (target) {
2023-02-13 21:39:18 +00:00
const handler = (target as any)._invokeHandlers.get(channel);
try {
replyWithResult(await Promise.resolve(handler(event, ...args)));
} catch (err) {
replyWithError(err as Error);
}
} else {
2023-02-13 21:39:18 +00:00
replyWithError(new Error(`No handler registered for '${channel}'`));
}
});
this.on('-ipc-message-sync' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, args: any[]) {
2023-02-13 21:39:18 +00:00
addSenderToEvent(event, this);
addReturnValueToEvent(event);
if (internal) {
ipcMainInternal.emit(channel, event, ...args);
} else {
addReplyToEvent(event);
const maybeWebFrame = getWebFrameForEvent(event);
2022-08-03 23:55:12 +00:00
if (this.listenerCount('ipc-message-sync') === 0 && ipc.listenerCount(channel) === 0 && ipcMain.listenerCount(channel) === 0 && (!maybeWebFrame || maybeWebFrame.ipc.listenerCount(channel) === 0)) {
console.warn(`WebContents #${this.id} called ipcRenderer.sendSync() with '${channel}' channel without listeners.`);
}
this.emit('ipc-message-sync', event, channel, ...args);
2022-08-03 23:55:12 +00:00
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, ...args);
ipc.emit(channel, event, ...args);
ipcMain.emit(channel, event, ...args);
}
});
2023-02-13 21:39:18 +00:00
this.on('-ipc-ports' as any, function (this: Electron.WebContents, event: Electron.IpcMainEvent, internal: boolean, channel: string, message: any, ports: any[]) {
addSenderToEvent(event, this);
event.ports = ports.map(p => new MessagePortMain(p));
const maybeWebFrame = getWebFrameForEvent(event);
2022-08-03 23:55:12 +00:00
maybeWebFrame && maybeWebFrame.ipc.emit(channel, event, message);
ipc.emit(channel, event, message);
ipcMain.emit(channel, event, message);
});
this.on('crashed', (event, ...args) => {
app.emit('renderer-process-crashed', event, this, ...args);
});
this.on('render-process-gone', (event, details) => {
app.emit('render-process-gone', event, this, details);
// Log out a hint to help users better debug renderer crashes.
if (loggingEnabled()) {
console.info(`Renderer process ${details.reason} - see https://www.electronjs.org/docs/tutorial/application-debugging for potential debugging information.`);
}
});
// The devtools requests the webContents to reload.
this.on('devtools-reload-page', function (this: Electron.WebContents) {
2016-08-02 11:38:35 +00:00
this.reload();
});
if (this.getType() !== 'remote') {
// Make new windows requested by links behave like "window.open".
2023-02-13 21:39:18 +00:00
this.on('-new-window' as any, (event: Electron.Event, url: string, frameName: string, disposition: Electron.HandlerDetails['disposition'],
rawFeatures: string, referrer: Electron.Referrer, postData: PostData) => {
const postBody = postData ? {
data: postData,
...parseContentTypeFormat(postData)
} : undefined;
const details: Electron.HandlerDetails = {
url,
frameName,
features: rawFeatures,
referrer,
postBody,
disposition
};
let result: ReturnType<typeof this._callWindowOpenHandler>;
try {
result = this._callWindowOpenHandler(event, details);
} catch (err) {
event.preventDefault();
throw err;
}
const options = result.browserWindowConstructorOptions;
if (!event.defaultPrevented) {
openGuestWindow({
2023-02-13 21:39:18 +00:00
embedder: this,
disposition,
referrer,
postData,
overrideBrowserWindowOptions: options || {},
windowOpenArgs: details,
outlivesOpener: result.outlivesOpener
});
}
});
let windowOpenOverriddenOptions: BrowserWindowConstructorOptions | null = null;
let windowOpenOutlivesOpenerOption: boolean = false;
2023-02-13 21:39:18 +00:00
this.on('-will-add-new-contents' as any, (event: Electron.Event, url: string, frameName: string, rawFeatures: string, disposition: Electron.HandlerDetails['disposition'], referrer: Electron.Referrer, postData: PostData) => {
const postBody = postData ? {
data: postData,
...parseContentTypeFormat(postData)
} : undefined;
const details: Electron.HandlerDetails = {
url,
frameName,
features: rawFeatures,
disposition,
referrer,
postBody
};
let result: ReturnType<typeof this._callWindowOpenHandler>;
try {
result = this._callWindowOpenHandler(event, details);
} catch (err) {
event.preventDefault();
throw err;
}
windowOpenOutlivesOpenerOption = result.outlivesOpener;
windowOpenOverriddenOptions = result.browserWindowConstructorOptions;
if (!event.defaultPrevented) {
const secureOverrideWebPreferences = windowOpenOverriddenOptions ? {
// Allow setting of backgroundColor as a webPreference even though
// it's technically a BrowserWindowConstructorOptions option because
// we need to access it in the renderer at init time.
backgroundColor: windowOpenOverriddenOptions.backgroundColor,
transparent: windowOpenOverriddenOptions.transparent,
...windowOpenOverriddenOptions.webPreferences
} : undefined;
const { webPreferences: parsedWebPreferences } = parseFeatures(rawFeatures);
const webPreferences = makeWebPreferences({
2023-02-13 21:39:18 +00:00
embedder: this,
insecureParsedWebPreferences: parsedWebPreferences,
secureOverrideWebPreferences
});
windowOpenOverriddenOptions = {
...windowOpenOverriddenOptions,
webPreferences
};
this._setNextChildWebPreferences(webPreferences);
}
});
// Create a new browser window for "window.open"
2023-02-13 21:39:18 +00:00
this.on('-add-new-contents' as any, (event: Electron.Event, webContents: Electron.WebContents, disposition: string,
_userGesture: boolean, _left: number, _top: number, _width: number, _height: number, url: string, frameName: string,
referrer: Electron.Referrer, rawFeatures: string, postData: PostData) => {
const overriddenOptions = windowOpenOverriddenOptions || undefined;
const outlivesOpener = windowOpenOutlivesOpenerOption;
windowOpenOverriddenOptions = null;
// false is the default
windowOpenOutlivesOpenerOption = false;
if ((disposition !== 'foreground-tab' && disposition !== 'new-window' &&
disposition !== 'background-tab')) {
event.preventDefault();
return;
}
openGuestWindow({
2023-02-13 21:39:18 +00:00
embedder: this,
guest: webContents,
overrideBrowserWindowOptions: overriddenOptions,
disposition,
referrer,
postData,
windowOpenArgs: {
url,
frameName,
features: rawFeatures
},
outlivesOpener
});
});
}
this.on('login', (event, ...args) => {
app.emit('login', event, this, ...args);
});
this.on('ready-to-show' as any, () => {
const owner = this.getOwnerBrowserWindow();
if (owner && !owner.isDestroyed()) {
process.nextTick(() => {
owner.emit('ready-to-show');
});
}
});
this.on('select-bluetooth-device', (event, devices, callback) => {
if (this.listenerCount('select-bluetooth-device') === 1) {
// Cancel it if there are no handlers
event.preventDefault();
callback('');
}
});
2023-02-13 21:39:18 +00:00
app.emit('web-contents-created', { sender: this, preventDefault () {}, get defaultPrevented () { return false; } }, this);
2016-01-12 02:40:23 +00:00
// Properties
Object.defineProperty(this, 'audioMuted', {
get: () => this.isAudioMuted(),
set: (muted) => this.setAudioMuted(muted)
});
Object.defineProperty(this, 'userAgent', {
get: () => this.getUserAgent(),
set: (agent) => this.setUserAgent(agent)
});
Object.defineProperty(this, 'zoomLevel', {
get: () => this.getZoomLevel(),
set: (level) => this.setZoomLevel(level)
});
Object.defineProperty(this, 'zoomFactor', {
get: () => this.getZoomFactor(),
set: (factor) => this.setZoomFactor(factor)
});
Object.defineProperty(this, 'frameRate', {
get: () => this.getFrameRate(),
set: (rate) => this.setFrameRate(rate)
});
Object.defineProperty(this, 'backgroundThrottling', {
get: () => this.getBackgroundThrottling(),
set: (allowed) => this.setBackgroundThrottling(allowed)
});
};
2016-08-02 11:38:35 +00:00
// Public APIs.
export function create (options = {}): Electron.WebContents {
return new (WebContents as any)(options);
2020-07-06 17:50:03 +00:00
}
2020-07-06 17:50:03 +00:00
export function fromId (id: string) {
return binding.fromId(id);
}
2016-07-14 15:59:49 +00:00
export function fromFrame (frame: Electron.WebFrameMain) {
return binding.fromFrame(frame);
}
export function fromDevToolsTargetId (targetId: string) {
return binding.fromDevToolsTargetId(targetId);
}
2020-07-06 17:50:03 +00:00
export function getFocusedWebContents () {
let focused = null;
for (const contents of binding.getAllWebContents()) {
if (!contents.isFocused()) continue;
if (focused == null) focused = contents;
// Return webview web contents which may be embedded inside another
// web contents that is also reporting as focused
if (contents.getType() === 'webview') return contents;
2016-06-13 15:59:03 +00:00
}
2020-07-06 17:50:03 +00:00
return focused;
}
export function getAllWebContents () {
return binding.getAllWebContents();
}