From 3d2b740d9ec5a2dad16fd6b532d93973060629cd Mon Sep 17 00:00:00 2001 From: liulun Date: Wed, 24 Mar 2021 09:10:12 +0800 Subject: [PATCH 01/17] doc: desktopCapturer menu position (#28315) desktopCapturer can be used in both main process and renderer process --- docs/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/README.md b/docs/README.md index e94ca55e245..9db83ed1516 100644 --- a/docs/README.md +++ b/docs/README.md @@ -144,7 +144,6 @@ These individual tutorials expand on topics discussed in the guide above. ### Modules for the Renderer Process (Web Page): * [contextBridge](api/context-bridge.md) -* [desktopCapturer](api/desktop-capturer.md) * [ipcRenderer](api/ipc-renderer.md) * [webFrame](api/web-frame.md) @@ -152,6 +151,7 @@ These individual tutorials expand on topics discussed in the guide above. * [clipboard](api/clipboard.md) * [crashReporter](api/crash-reporter.md) +* [desktopCapturer](api/desktop-capturer.md) * [nativeImage](api/native-image.md) * [shell](api/shell.md) From d93690ccdc8c175eb4b6b5f6bde579e1147e4936 Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Wed, 24 Mar 2021 07:33:32 -0700 Subject: [PATCH 02/17] Bump v14.0.0-nightly.20210324 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 450026c06df..8d07162777f 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -14.0.0-nightly.20210323 \ No newline at end of file +14.0.0-nightly.20210324 \ No newline at end of file diff --git a/package.json b/package.json index b56a254ad0c..172b180c8b3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "14.0.0-nightly.20210323", + "version": "14.0.0-nightly.20210324", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index c54bbbb0361..2e3e7b5896c 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 14,0,0,20210323 - PRODUCTVERSION 14,0,0,20210323 + FILEVERSION 14,0,0,20210324 + PRODUCTVERSION 14,0,0,20210324 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L From 89df6b98da123f847b82eab897e02dadab02a7d4 Mon Sep 17 00:00:00 2001 From: Calvin Date: Wed, 24 Mar 2021 12:11:26 -0600 Subject: [PATCH 03/17] fix: isolate Pepper plugins (#28332) --- shell/renderer/renderer_client_base.cc | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/shell/renderer/renderer_client_base.cc b/shell/renderer/renderer_client_base.cc index ba4676bf787..77e766cd2b4 100644 --- a/shell/renderer/renderer_client_base.cc +++ b/shell/renderer/renderer_client_base.cc @@ -361,11 +361,8 @@ bool RendererClientBase::IsPluginHandledExternally( bool RendererClientBase::IsOriginIsolatedPepperPlugin( const base::FilePath& plugin_path) { -#if BUILDFLAG(ENABLE_PDF_VIEWER) - return plugin_path.value() == kPdfPluginPath; -#else - return false; -#endif + // Isolate all Pepper plugins, including the PDF plugin. + return true; } std::unique_ptr From 7918ddb0260e1a2cdbc863916d0d3d99925f8c6b Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Wed, 24 Mar 2021 11:43:02 -0700 Subject: [PATCH 04/17] perf: do not double-proxy methods being return over the contextBridge (#28285) --- .../api/electron_api_context_bridge.cc | 23 ++++++++++++++++++- spec-main/api-context-bridge-spec.ts | 11 +++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/shell/renderer/api/electron_api_context_bridge.cc b/shell/renderer/api/electron_api_context_bridge.cc index 64b13604fb9..671dcf062ca 100644 --- a/shell/renderer/api/electron_api_context_bridge.cc +++ b/shell/renderer/api/electron_api_context_bridge.cc @@ -41,6 +41,8 @@ namespace context_bridge { const char* const kProxyFunctionPrivateKey = "electron_contextBridge_proxy_fn"; const char* const kSupportsDynamicPropertiesPrivateKey = "electron_contextBridge_supportsDynamicProperties"; +const char* const kOriginalFunctionPrivateKey = + "electron_contextBridge_original_fn"; } // namespace context_bridge @@ -179,9 +181,26 @@ v8::MaybeLocal PassValueToOtherContext( // the global handle at the right time. if (value->IsFunction()) { auto func = v8::Local::Cast(value); + v8::MaybeLocal maybe_original_fn = GetPrivate( + source_context, func, context_bridge::kOriginalFunctionPrivateKey); { v8::Context::Scope destination_scope(destination_context); + v8::Local proxy_func; + + // If this function has already been sent over the bridge, + // then it is being sent _back_ over the bridge and we can + // simply return the original method here for performance reasons + + // For safety reasons we check if the destination context is the + // creation context of the original method. If it's not we proceed + // with the proxy logic + if (maybe_original_fn.ToLocal(&proxy_func) && proxy_func->IsFunction() && + proxy_func.As()->CreationContext() == + destination_context) { + return v8::MaybeLocal(proxy_func); + } + v8::Local state = v8::Object::New(destination_context->GetIsolate()); SetPrivate(destination_context, state, @@ -190,10 +209,12 @@ v8::MaybeLocal PassValueToOtherContext( context_bridge::kSupportsDynamicPropertiesPrivateKey, gin::ConvertToV8(destination_context->GetIsolate(), support_dynamic_properties)); - v8::Local proxy_func; + if (!v8::Function::New(destination_context, ProxyFunctionWrapper, state) .ToLocal(&proxy_func)) return v8::MaybeLocal(); + SetPrivate(destination_context, proxy_func.As(), + context_bridge::kOriginalFunctionPrivateKey, func); object_cache->CacheProxiedObject(value, proxy_func); return v8::MaybeLocal(proxy_func); } diff --git a/spec-main/api-context-bridge-spec.ts b/spec-main/api-context-bridge-spec.ts index 176711af2b9..4007694621c 100644 --- a/spec-main/api-context-bridge-spec.ts +++ b/spec-main/api-context-bridge-spec.ts @@ -353,6 +353,17 @@ describe('contextBridge', () => { expect(result).equal('return-value'); }); + it('should not double-proxy functions when they are returned to their origin side of the bridge', async () => { + await makeBindingWindow(() => { + contextBridge.exposeInMainWorld('example', (fn: any) => fn); + }); + const result = await callWithBindings(async (root: any) => { + const fn = () => null; + return root.example(fn) === fn; + }); + expect(result).equal(true); + }); + it('should proxy methods that are callable multiple times', async () => { await makeBindingWindow(() => { contextBridge.exposeInMainWorld('example', { From b9b734c9c47d526f7bfd8cabc688dae2d0ba045b Mon Sep 17 00:00:00 2001 From: Samuel Maddock Date: Thu, 25 Mar 2021 01:49:53 -0400 Subject: [PATCH 05/17] fix: export patches not retaining CRLF line endings (#28360) When a patch targets a file using CRLF line endings, they need to be retained in the patch file. Otherwise the patch will fail to apply due to being unable to find surrounding lines with matching whitespace. --- script/lib/git.py | 43 ++++++++++++++++++++++++++++--------------- script/lint.js | 2 +- 2 files changed, 29 insertions(+), 16 deletions(-) diff --git a/script/lib/git.py b/script/lib/git.py index cc82ec9c107..0edcd98ea02 100644 --- a/script/lib/git.py +++ b/script/lib/git.py @@ -47,7 +47,7 @@ def get_repo_root(path): def am(repo, patch_data, threeway=False, directory=None, exclude=None, - committer_name=None, committer_email=None): + committer_name=None, committer_email=None, keep_cr=True): args = [] if threeway: args += ['--3way'] @@ -56,6 +56,10 @@ def am(repo, patch_data, threeway=False, directory=None, exclude=None, if exclude is not None: for path_pattern in exclude: args += ['--exclude', path_pattern] + if keep_cr is True: + # Keep the CR of CRLF in case any patches target files with Windows line + # endings. + args += ['--keep-cr'] root_args = ['-C', repo] if committer_name is not None: @@ -230,7 +234,9 @@ def split_patches(patch_data): """Split a concatenated series of patches into N separate patches""" patches = [] patch_start = re.compile('^From [0-9a-f]+ ') - for line in patch_data.splitlines(): + # Keep line endings in case any patches target files with CRLF. + keep_line_endings = True + for line in patch_data.splitlines(keep_line_endings): if patch_start.match(line): patches.append([]) patches[-1].append(line) @@ -246,13 +252,23 @@ def munge_subject_to_filename(subject): def get_file_name(patch): """Return the name of the file to which the patch should be written""" + file_name = None for line in patch: if line.startswith('Patch-Filename: '): - return line[len('Patch-Filename: '):] + file_name = line[len('Patch-Filename: '):] + break # If no patch-filename header, munge the subject. - for line in patch: - if line.startswith('Subject: '): - return munge_subject_to_filename(line[len('Subject: '):]) + if not file_name: + for line in patch: + if line.startswith('Subject: '): + file_name = munge_subject_to_filename(line[len('Subject: '):]) + break + return file_name.rstrip('\n') + + +def join_patch(patch): + """Joins and formats patch contents""" + return ''.join(remove_patch_filename(patch)).rstrip('\n') + '\n' def remove_patch_filename(patch): @@ -294,10 +310,8 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): for patch in patches: filename = get_file_name(patch) filepath = posixpath.join(out_dir, filename) - existing_patch = io.open(filepath, 'r', encoding='utf-8').read() - formatted_patch = ( - '\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n' - ) + existing_patch = io.open(filepath, 'rb').read() + formatted_patch = join_patch(patch) if formatted_patch != existing_patch: patch_count += 1 if patch_count > 0: @@ -322,12 +336,11 @@ def export_patches(repo, out_dir, patch_range=None, dry_run=False): for patch in patches: filename = get_file_name(patch) file_path = posixpath.join(out_dir, filename) - formatted_patch = ( - '\n'.join(remove_patch_filename(patch)).rstrip('\n') + '\n' - ) + formatted_patch = join_patch(patch) + # Write in binary mode to retain mixed line endings on write. with io.open( - file_path, 'w', newline='\n', encoding='utf-8' + file_path, 'wb' ) as f: - f.write(formatted_patch) + f.write(formatted_patch.encode('utf-8')) pl.write(filename + '\n') diff --git a/script/lint.js b/script/lint.js index 70f6a51693f..a194aacb7b7 100755 --- a/script/lint.js +++ b/script/lint.js @@ -207,7 +207,7 @@ const LINTERS = [{ console.warn(`Patch file '${f}' has no description. Every patch must contain a justification for why the patch exists and the plan for its removal.`); return false; } - const trailingWhitespace = patchText.split('\n').filter(line => line.startsWith('+')).some(line => /\s+$/.test(line)); + const trailingWhitespace = patchText.split(/\r?\n/).some(line => line.startsWith('+') && /\s+$/.test(line)); if (trailingWhitespace) { console.warn(`Patch file '${f}' has trailing whitespace on some lines.`); return false; From 1453a8e743f5c4e4e8dfeac7ff4c982295777258 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Thu, 25 Mar 2021 11:02:47 +0000 Subject: [PATCH 06/17] fix: disappearing thumbar after win.hide() (#28366) * fix: disappearing thumbar after win.hide() * Add descriptive comment --- shell/browser/native_window_views.cc | 8 ++++++++ shell/browser/ui/win/taskbar_host.cc | 5 +++-- shell/browser/ui/win/taskbar_host.h | 2 ++ 3 files changed, 13 insertions(+), 2 deletions(-) diff --git a/shell/browser/native_window_views.cc b/shell/browser/native_window_views.cc index 480445142b3..53645b04c3b 100644 --- a/shell/browser/native_window_views.cc +++ b/shell/browser/native_window_views.cc @@ -442,6 +442,14 @@ void NativeWindowViews::Hide() { if (!features::IsUsingOzonePlatform() && global_menu_bar_) global_menu_bar_->OnWindowUnmapped(); #endif + +#if defined(OS_WIN) + // When the window is removed from the taskbar via win.hide(), + // the thumbnail buttons need to be set up again. + // Ensure that when the window is hidden, + // the taskbar host is notified that it should re-add them. + taskbar_host_.SetThumbarButtonsAdded(false); +#endif } bool NativeWindowViews::IsVisible() { diff --git a/shell/browser/ui/win/taskbar_host.cc b/shell/browser/ui/win/taskbar_host.cc index 272cc2fc98d..23d52d6fb85 100644 --- a/shell/browser/ui/win/taskbar_host.cc +++ b/shell/browser/ui/win/taskbar_host.cc @@ -114,11 +114,12 @@ bool TaskbarHost::SetThumbarButtons(HWND window, // Finally add them to taskbar. HRESULT r; - if (thumbar_buttons_added_) + if (thumbar_buttons_added_) { r = taskbar_->ThumbBarUpdateButtons(window, kMaxButtonsCount, thumb_buttons); - else + } else { r = taskbar_->ThumbBarAddButtons(window, kMaxButtonsCount, thumb_buttons); + } thumbar_buttons_added_ = true; last_buttons_ = buttons; diff --git a/shell/browser/ui/win/taskbar_host.h b/shell/browser/ui/win/taskbar_host.h index 2aef64e9054..4d09f232e0e 100644 --- a/shell/browser/ui/win/taskbar_host.h +++ b/shell/browser/ui/win/taskbar_host.h @@ -60,6 +60,8 @@ class TaskbarHost { // Called by the window that there is a button in thumbar clicked. bool HandleThumbarButtonEvent(int button_id); + void SetThumbarButtonsAdded(bool added) { thumbar_buttons_added_ = added; } + private: // Initialize the taskbar object. bool InitializeTaskbar(); From 77365e701f1d15c3daa43129037138f4b7e5f526 Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Thu, 25 Mar 2021 07:34:28 -0700 Subject: [PATCH 07/17] Bump v14.0.0-nightly.20210325 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 8d07162777f..b122520f572 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -14.0.0-nightly.20210324 \ No newline at end of file +14.0.0-nightly.20210325 \ No newline at end of file diff --git a/package.json b/package.json index 172b180c8b3..0fd67e0a46a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "14.0.0-nightly.20210324", + "version": "14.0.0-nightly.20210325", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index 2e3e7b5896c..d8546abc2e8 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 14,0,0,20210324 - PRODUCTVERSION 14,0,0,20210324 + FILEVERSION 14,0,0,20210325 + PRODUCTVERSION 14,0,0,20210325 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L From fb4e99e7297193dc63904f393e17b2a938f21ded Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Thu, 25 Mar 2021 23:41:11 +0900 Subject: [PATCH 08/17] test: load minimal dict for spellchecker (#28386) --- spec-main/spellchecker-spec.ts | 61 ++++++++++++++++++++++++---------- 1 file changed, 44 insertions(+), 17 deletions(-) diff --git a/spec-main/spellchecker-spec.ts b/spec-main/spellchecker-spec.ts index d8f5c6ccb2a..e669e3ebd90 100644 --- a/spec-main/spellchecker-spec.ts +++ b/spec-main/spellchecker-spec.ts @@ -2,6 +2,9 @@ import { BrowserWindow, Session, session } from 'electron/main'; import { expect } from 'chai'; import * as path from 'path'; +import * as fs from 'fs'; +import * as http from 'http'; +import { AddressInfo } from 'net'; import { closeWindow } from './window-helpers'; import { emittedOnce } from './events-helpers'; import { ifit, ifdescribe, delay } from './spec-helpers'; @@ -10,9 +13,7 @@ const features = process._linkedBinding('electron_common_features'); const v8Util = process._linkedBinding('electron_common_v8_util'); ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () { - // TODO(zcbenz): Spellchecker loads really slow on ASan, we should provide - // a small testing dictionary to make the tests load faster. - this.timeout((process.env.IS_ASAN ? 700 : 20) * 1000); + this.timeout((process.env.IS_ASAN ? 100 : 20) * 1000); let w: BrowserWindow; @@ -32,7 +33,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () // to detect spellchecker is to keep checking with a busy loop. async function rightClickUntil (fn: (params: Electron.ContextMenuParams) => boolean) { const now = Date.now(); - const timeout = (process.env.IS_ASAN ? 600 : 10) * 1000; + const timeout = 10 * 1000; let contextMenuParams = await rightClick(); while (!fn(contextMenuParams) && (Date.now() - now < timeout)) { await delay(100); @@ -41,6 +42,26 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () return contextMenuParams; } + // Setup a server to download hunspell dictionary. + const server = http.createServer((req, res) => { + // The provided is minimal dict for testing only, full list of words can + // be found at src/third_party/hunspell_dictionaries/xx_XX.dic. + fs.readFile(path.join(__dirname, '/../../third_party/hunspell_dictionaries/xx-XX-3-0.bdic'), function (err, data) { + if (err) { + console.error('Failed to read dictionary file'); + res.writeHead(404); + res.end(JSON.stringify(err)); + return; + } + res.writeHead(200); + res.end(data); + }); + }); + before((done) => { + server.listen(0, '127.0.0.1', () => done()); + }); + after(() => server.close()); + beforeEach(async () => { w = new BrowserWindow({ show: false, @@ -50,6 +71,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () contextIsolation: false } }); + w.webContents.session.setSpellCheckerDictionaryDownloadURL(`http://127.0.0.1:${(server.address() as AddressInfo).port}/`); w.webContents.session.setSpellCheckerLanguages(['en-US']); await w.loadFile(path.resolve(__dirname, './fixtures/chromium/spellchecker.html')); }); @@ -62,7 +84,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () const shouldRun = process.platform !== 'win32'; ifit(shouldRun)('should detect correctly spelled words as correct', async () => { - await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautiful and lovely"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typography"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.selectionText.length > 0); expect(contextMenuParams.misspelledWord).to.eq(''); @@ -70,10 +92,10 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () }); ifit(shouldRun)('should detect incorrectly spelled words as incorrect', async () => { - await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); - expect(contextMenuParams.misspelledWord).to.eq('Beautifulllll'); + expect(contextMenuParams.misspelledWord).to.eq('typograpy'); expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1); }); @@ -81,24 +103,24 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () w.webContents.session.setSpellCheckerLanguages([]); await delay(500); w.webContents.session.setSpellCheckerLanguages(['en-US']); - await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); const contextMenuParams = await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); - expect(contextMenuParams.misspelledWord).to.eq('Beautifulllll'); + expect(contextMenuParams.misspelledWord).to.eq('typograpy'); expect(contextMenuParams.dictionarySuggestions).to.have.length.of.at.least(1); }); ifit(shouldRun)('should expose webFrame spellchecker correctly', async () => { - await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); const callWebFrameFn = (expr: string) => w.webContents.executeJavaScript('require("electron").webFrame.' + expr); - expect(await callWebFrameFn('isWordMisspelled("test")')).to.equal(false); - expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(true); - expect(await callWebFrameFn('getWordSuggestions("test")')).to.be.empty(); - expect(await callWebFrameFn('getWordSuggestions("testt")')).to.not.be.empty(); + expect(await callWebFrameFn('isWordMisspelled("typography")')).to.equal(false); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true); + expect(await callWebFrameFn('getWordSuggestions("typography")')).to.be.empty(); + expect(await callWebFrameFn('getWordSuggestions("typograpy")')).to.not.be.empty(); }); describe('spellCheckerEnabled', () => { @@ -107,7 +129,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () }); ifit(shouldRun)('can be dynamically changed', async () => { - await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "Beautifulllll asd asd"'); + await w.webContents.executeJavaScript('document.body.querySelector("textarea").value = "typograpy"'); await w.webContents.executeJavaScript('document.body.querySelector("textarea").focus()'); await rightClickUntil((contextMenuParams) => contextMenuParams.misspelledWord.length > 0); @@ -116,12 +138,17 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () w.webContents.session.spellCheckerEnabled = false; v8Util.runUntilIdle(); expect(w.webContents.session.spellCheckerEnabled).to.be.false(); - expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(false); + // spellCheckerEnabled is sent to renderer asynchronously and there is + // no event notifying when it is finished, so wait a little while to + // ensure the setting has been changed in renderer. + await delay(500); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(false); w.webContents.session.spellCheckerEnabled = true; v8Util.runUntilIdle(); expect(w.webContents.session.spellCheckerEnabled).to.be.true(); - expect(await callWebFrameFn('isWordMisspelled("testt")')).to.equal(true); + await delay(500); + expect(await callWebFrameFn('isWordMisspelled("typograpy")')).to.equal(true); }); }); From 521146f71ee62a769a65bee55b448719b576d868 Mon Sep 17 00:00:00 2001 From: Alexander Prinzhorn Date: Fri, 26 Mar 2021 01:46:59 +0100 Subject: [PATCH 09/17] docs: add missing line in web-contents.md (#28376) * Update web-contents.md The text block was rendered as part of the `features` property, not the `handler` * fix linting --- docs/api/web-contents.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/api/web-contents.md b/docs/api/web-contents.md index 9cc07bca670..7897a8c18e9 100644 --- a/docs/api/web-contents.md +++ b/docs/api/web-contents.md @@ -1131,6 +1131,7 @@ Ignore application menu shortcuts while this web contents is focused. * `url` String - The _resolved_ version of the URL passed to `window.open()`. e.g. opening a window with `window.open('foo')` will yield something like `https://the-origin/the/current/path/foo`. * `frameName` String - Name of the window provided in `window.open()` * `features` String - Comma separated list of window features provided to `window.open()`. + Returns `{action: 'deny'} | {action: 'allow', overrideBrowserWindowOptions?: BrowserWindowConstructorOptions}` - `deny` cancels the creation of the new window. `allow` will allow the new window to be created. Specifying `overrideBrowserWindowOptions` allows customization of the created window. Returning an unrecognized value such as a null, undefined, or an object From 2632564ccf20b31e852b57fa767e11b2a46461dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sa=C3=BAl=20Ibarra=20Corretg=C3=A9?= Date: Fri, 26 Mar 2021 01:49:00 +0100 Subject: [PATCH 10/17] feat: initialize field trials from command line arguments (#28305) Fixes: #27877 --- docs/api/command-line-switches.md | 6 ++++++ shell/browser/electron_browser_main_parts.cc | 3 +++ shell/browser/feature_list.cc | 9 +++++++++ shell/browser/feature_list.h | 3 ++- 4 files changed, 20 insertions(+), 1 deletion(-) diff --git a/docs/api/command-line-switches.md b/docs/api/command-line-switches.md index fe8e7c75aeb..be9cac42b60 100644 --- a/docs/api/command-line-switches.md +++ b/docs/api/command-line-switches.md @@ -75,6 +75,12 @@ This switch can not be used in `app.commandLine.appendSwitch` since it is parsed earlier than user's app is loaded, but you can set the `ELECTRON_ENABLE_LOGGING` environment variable to achieve the same effect. +## --force-fieldtrials=`trials` + +Field trials to be forcefully enabled or disabled. + +For example: `WebRTC-Audio-Red-For-Opus/Enabled/` + ### --host-rules=`rules` A comma-separated list of `rules` that control how hostnames are mapped. diff --git a/shell/browser/electron_browser_main_parts.cc b/shell/browser/electron_browser_main_parts.cc index e4ae699c604..8e21a1e5ee6 100644 --- a/shell/browser/electron_browser_main_parts.cc +++ b/shell/browser/electron_browser_main_parts.cc @@ -279,6 +279,9 @@ void ElectronBrowserMainParts::PostEarlyInitialization() { base::FeatureList::ClearInstanceForTesting(); InitializeFeatureList(); + // Initialize field trials. + InitializeFieldTrials(); + // Initialize after user script environment creation. fake_browser_process_->PostEarlyInitialization(); } diff --git a/shell/browser/feature_list.cc b/shell/browser/feature_list.cc index 9e1fbb5213a..59bdd50f6f9 100644 --- a/shell/browser/feature_list.cc +++ b/shell/browser/feature_list.cc @@ -9,6 +9,7 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/feature_list.h" +#include "base/metrics/field_trial.h" #include "content/public/common/content_features.h" #include "electron/buildflags/buildflags.h" #include "media/base/media_switches.h" @@ -49,4 +50,12 @@ void InitializeFeatureList() { base::FeatureList::InitializeInstance(enable_features, disable_features); } +void InitializeFieldTrials() { + auto* cmd_line = base::CommandLine::ForCurrentProcess(); + auto force_fieldtrials = + cmd_line->GetSwitchValueASCII(::switches::kForceFieldTrials); + + base::FieldTrialList::CreateTrialsFromString(force_fieldtrials); +} + } // namespace electron diff --git a/shell/browser/feature_list.h b/shell/browser/feature_list.h index 9048c6913d4..3464bba213c 100644 --- a/shell/browser/feature_list.h +++ b/shell/browser/feature_list.h @@ -7,6 +7,7 @@ namespace electron { void InitializeFeatureList(); -} +void InitializeFieldTrials(); +} // namespace electron #endif // SHELL_BROWSER_FEATURE_LIST_H_ From 5be2183dd7689318c2b4ac34af6d0e748720629a Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Fri, 26 Mar 2021 07:32:17 -0700 Subject: [PATCH 11/17] Bump v14.0.0-nightly.20210326 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index b122520f572..4b8fda48c3f 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -14.0.0-nightly.20210325 \ No newline at end of file +14.0.0-nightly.20210326 \ No newline at end of file diff --git a/package.json b/package.json index 0fd67e0a46a..6391a7089c3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "14.0.0-nightly.20210325", + "version": "14.0.0-nightly.20210326", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index d8546abc2e8..ff19656a2a8 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 14,0,0,20210325 - PRODUCTVERSION 14,0,0,20210325 + FILEVERSION 14,0,0,20210326 + PRODUCTVERSION 14,0,0,20210326 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L From ff96fabe5ef1339d3423a9901d0e3fa013473b5b Mon Sep 17 00:00:00 2001 From: Cheng Zhao Date: Mon, 29 Mar 2021 16:10:09 +0900 Subject: [PATCH 12/17] test: increase timeout for spellchecker (#28427) --- spec-main/spellchecker-spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/spec-main/spellchecker-spec.ts b/spec-main/spellchecker-spec.ts index e669e3ebd90..63d565ecfa8 100644 --- a/spec-main/spellchecker-spec.ts +++ b/spec-main/spellchecker-spec.ts @@ -13,7 +13,7 @@ const features = process._linkedBinding('electron_common_features'); const v8Util = process._linkedBinding('electron_common_v8_util'); ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () { - this.timeout((process.env.IS_ASAN ? 100 : 20) * 1000); + this.timeout((process.env.IS_ASAN ? 200 : 20) * 1000); let w: BrowserWindow; @@ -33,7 +33,7 @@ ifdescribe(features.isBuiltinSpellCheckerEnabled())('spellchecker', function () // to detect spellchecker is to keep checking with a busy loop. async function rightClickUntil (fn: (params: Electron.ContextMenuParams) => boolean) { const now = Date.now(); - const timeout = 10 * 1000; + const timeout = (process.env.IS_ASAN ? 180 : 10) * 1000; let contextMenuParams = await rightClick(); while (!fn(contextMenuParams) && (Date.now() - now < timeout)) { await delay(100); From ae2059eaa10a63359daa33d65c5e262e32bc6565 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Mon, 29 Mar 2021 10:45:08 +0000 Subject: [PATCH 13/17] refactor: remove more uses of v8::Isolate::GetCurrent() (#28369) --- .../api/electron_api_crash_reporter.cc | 3 +- .../browser/api/electron_api_download_item.cc | 10 ++-- .../browser/api/electron_api_download_item.h | 4 +- shell/browser/api/electron_api_menu.cc | 2 +- shell/browser/api/electron_api_session.cc | 49 ++++++++----------- shell/browser/api/electron_api_session.h | 2 + shell/browser/api/electron_api_url_loader.cc | 3 +- shell/browser/native_window_mac.mm | 12 +++-- shell/renderer/api/electron_api_web_frame.cc | 2 +- 9 files changed, 43 insertions(+), 44 deletions(-) diff --git a/shell/browser/api/electron_api_crash_reporter.cc b/shell/browser/api/electron_api_crash_reporter.cc index e0ee0296090..b7bf09a6bfb 100644 --- a/shell/browser/api/electron_api_crash_reporter.cc +++ b/shell/browser/api/electron_api_crash_reporter.cc @@ -190,8 +190,9 @@ namespace { #if defined(MAS_BUILD) void GetUploadedReports( + v8::Isolate* isolate, base::OnceCallback)> callback) { - std::move(callback).Run(v8::Array::New(v8::Isolate::GetCurrent())); + std::move(callback).Run(v8::Array::New(isolate)); } #else scoped_refptr CreateCrashUploadList() { diff --git a/shell/browser/api/electron_api_download_item.cc b/shell/browser/api/electron_api_download_item.cc index 420fe79ac39..e839c7ac889 100644 --- a/shell/browser/api/electron_api_download_item.cc +++ b/shell/browser/api/electron_api_download_item.cc @@ -84,7 +84,7 @@ DownloadItem* DownloadItem::FromDownloadItem( DownloadItem::DownloadItem(v8::Isolate* isolate, download::DownloadItem* download_item) - : download_item_(download_item) { + : download_item_(download_item), isolate_(isolate) { download_item_->AddObserver(this); download_item_->SetUserData( kElectronApiDownloadItemKey, @@ -101,8 +101,8 @@ DownloadItem::~DownloadItem() { bool DownloadItem::CheckAlive() const { if (!download_item_) { - gin_helper::ErrorThrower(v8::Isolate::GetCurrent()) - .ThrowError("DownloadItem used after being destroyed"); + gin_helper::ErrorThrower(isolate_).ThrowError( + "DownloadItem used after being destroyed"); return false; } return true; @@ -200,10 +200,10 @@ const GURL& DownloadItem::GetURL() const { return download_item_->GetURL(); } -v8::Local DownloadItem::GetURLChain(v8::Isolate* isolate) const { +v8::Local DownloadItem::GetURLChain() const { if (!CheckAlive()) return v8::Local(); - return gin::ConvertToV8(isolate, download_item_->GetUrlChain()); + return gin::ConvertToV8(isolate_, download_item_->GetUrlChain()); } download::DownloadItem::DownloadState DownloadItem::GetState() const { diff --git a/shell/browser/api/electron_api_download_item.h b/shell/browser/api/electron_api_download_item.h index e744e584fd6..d63c5ff498e 100644 --- a/shell/browser/api/electron_api_download_item.h +++ b/shell/browser/api/electron_api_download_item.h @@ -66,7 +66,7 @@ class DownloadItem : public gin::Wrappable, std::string GetFilename() const; std::string GetContentDisposition() const; const GURL& GetURL() const; - v8::Local GetURLChain(v8::Isolate*) const; + v8::Local GetURLChain() const; download::DownloadItem::DownloadState GetState() const; bool IsDone() const; void SetSaveDialogOptions(const file_dialog::DialogSettings& options); @@ -78,6 +78,8 @@ class DownloadItem : public gin::Wrappable, file_dialog::DialogSettings dialog_options_; download::DownloadItem* download_item_; + v8::Isolate* isolate_; + base::WeakPtrFactory weak_factory_{this}; DISALLOW_COPY_AND_ASSIGN(DownloadItem); diff --git a/shell/browser/api/electron_api_menu.cc b/shell/browser/api/electron_api_menu.cc index 2ae9d02dce1..5c4758f8de9 100644 --- a/shell/browser/api/electron_api_menu.cc +++ b/shell/browser/api/electron_api_menu.cc @@ -264,7 +264,7 @@ void Menu::OnMenuWillClose() { } void Menu::OnMenuWillShow() { - Pin(v8::Isolate::GetCurrent()); + Pin(JavascriptEnvironment::GetIsolate()); Emit("menu-will-show"); } diff --git a/shell/browser/api/electron_api_session.cc b/shell/browser/api/electron_api_session.cc index 7b904da9d1d..1b42e561c94 100644 --- a/shell/browser/api/electron_api_session.cc +++ b/shell/browser/api/electron_api_session.cc @@ -331,7 +331,8 @@ const void* kElectronApiSessionKey = &kElectronApiSessionKey; gin::WrapperInfo Session::kWrapperInfo = {gin::kEmbedderNativeGin}; Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context) - : network_emulation_token_(base::UnguessableToken::Create()), + : isolate_(isolate), + network_emulation_token_(base::UnguessableToken::Create()), browser_context_(browser_context) { // Observe DownloadManager to get download notifications. content::BrowserContext::GetDownloadManager(browser_context) @@ -379,10 +380,9 @@ void Session::OnDownloadCreated(content::DownloadManager* manager, if (item->IsSavePackageDownload()) return; - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - v8::Locker locker(isolate); - v8::HandleScope handle_scope(isolate); - auto handle = DownloadItem::FromOrCreate(isolate, item); + v8::Locker locker(isolate_); + v8::HandleScope handle_scope(isolate_); + auto handle = DownloadItem::FromOrCreate(isolate_, item); if (item->GetState() == download::DownloadItem::INTERRUPTED) handle->SetSavePath(item->GetTargetFilePath()); content::WebContents* web_contents = @@ -425,8 +425,7 @@ v8::Local Session::ResolveProxy(gin::Arguments* args) { } v8::Local Session::GetCacheSize() { - auto* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); auto handle = promise.GetHandle(); content::BrowserContext::GetDefaultStoragePartition(browser_context_) @@ -449,8 +448,7 @@ v8::Local Session::GetCacheSize() { } v8::Local Session::ClearCache() { - auto* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); auto handle = promise.GetHandle(); content::BrowserContext::GetDefaultStoragePartition(browser_context_) @@ -558,8 +556,7 @@ v8::Local Session::SetProxy(gin::Arguments* args) { } v8::Local Session::ForceReloadProxyConfig() { - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); auto handle = promise.GetHandle(); content::BrowserContext::GetDefaultStoragePartition(browser_context_) @@ -675,8 +672,7 @@ v8::Local Session::ClearHostResolverCache(gin::Arguments* args) { } v8::Local Session::ClearAuthCache() { - auto* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); v8::Local handle = promise.GetHandle(); content::BrowserContext::GetDefaultStoragePartition(browser_context_) @@ -763,15 +759,14 @@ void Session::CreateInterruptedDownload(const gin_helper::Dictionary& options) { options.Get("lastModified", &last_modified); options.Get("eTag", &etag); options.Get("startTime", &start_time); - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); if (path.empty() || url_chain.empty() || length == 0) { - isolate->ThrowException(v8::Exception::Error(gin::StringToV8( - isolate, "Must pass non-empty path, urlChain and length."))); + isolate_->ThrowException(v8::Exception::Error(gin::StringToV8( + isolate_, "Must pass non-empty path, urlChain and length."))); return; } if (offset >= length) { - isolate->ThrowException(v8::Exception::Error(gin::StringToV8( - isolate, "Must pass an offset value less than length."))); + isolate_->ThrowException(v8::Exception::Error(gin::StringToV8( + isolate_, "Must pass an offset value less than length."))); return; } auto* download_manager = @@ -797,8 +792,7 @@ std::vector Session::GetPreloads() const { v8::Local Session::LoadExtension( const base::FilePath& extension_path, gin::Arguments* args) { - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); v8::Local handle = promise.GetHandle(); if (!extension_path.IsAbsolute()) { @@ -833,7 +827,7 @@ v8::Local Session::LoadExtension( if (extension) { if (!error_msg.empty()) { node::Environment* env = - node::Environment::GetCurrent(v8::Isolate::GetCurrent()); + node::Environment::GetCurrent(promise.isolate()); EmitWarning(env, error_msg, "ExtensionLoadWarning"); } promise.Resolve(extension); @@ -856,11 +850,10 @@ v8::Local Session::GetExtension(const std::string& extension_id) { auto* registry = extensions::ExtensionRegistry::Get(browser_context()); const extensions::Extension* extension = registry->GetInstalledExtension(extension_id); - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); if (extension) { - return gin::ConvertToV8(isolate, extension); + return gin::ConvertToV8(isolate_, extension); } else { - return v8::Null(isolate); + return v8::Null(isolate_); } } @@ -872,7 +865,7 @@ v8::Local Session::GetAllExtensions() { if (extension->location() != extensions::Manifest::COMPONENT) extensions_vector.emplace_back(extension.get()); } - return gin::ConvertToV8(v8::Isolate::GetCurrent(), extensions_vector); + return gin::ConvertToV8(isolate_, extensions_vector); } void Session::OnExtensionLoaded(content::BrowserContext* browser_context, @@ -967,8 +960,7 @@ void Session::Preconnect(const gin_helper::Dictionary& options, } v8::Local Session::CloseAllConnections() { - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise promise(isolate); + gin_helper::Promise promise(isolate_); auto handle = promise.GetHandle(); content::BrowserContext::GetDefaultStoragePartition(browser_context_) @@ -1018,8 +1010,7 @@ void SetSpellCheckerDictionaryDownloadURL(gin_helper::ErrorThrower thrower, } v8::Local Session::ListWordsInSpellCheckerDictionary() { - v8::Isolate* isolate = JavascriptEnvironment::GetIsolate(); - gin_helper::Promise> promise(isolate); + gin_helper::Promise> promise(isolate_); v8::Local handle = promise.GetHandle(); SpellcheckService* spellcheck = diff --git a/shell/browser/api/electron_api_session.h b/shell/browser/api/electron_api_session.h index e76d67c0cb9..317c4a2985c 100644 --- a/shell/browser/api/electron_api_session.h +++ b/shell/browser/api/electron_api_session.h @@ -178,6 +178,8 @@ class Session : public gin::Wrappable, v8::Global service_worker_context_; v8::Global web_request_; + v8::Isolate* isolate_; + // The client id to enable the network throttler. base::UnguessableToken network_emulation_token_; diff --git a/shell/browser/api/electron_api_url_loader.cc b/shell/browser/api/electron_api_url_loader.cc index afe48e40cd2..1224be6f216 100644 --- a/shell/browser/api/electron_api_url_loader.cc +++ b/shell/browser/api/electron_api_url_loader.cc @@ -312,7 +312,8 @@ void SimpleURLLoaderWrapper::Pin() { } void SimpleURLLoaderWrapper::PinBodyGetter(v8::Local body_getter) { - pinned_chunk_pipe_getter_.Reset(v8::Isolate::GetCurrent(), body_getter); + pinned_chunk_pipe_getter_.Reset(JavascriptEnvironment::GetIsolate(), + body_getter); } SimpleURLLoaderWrapper::~SimpleURLLoaderWrapper() { diff --git a/shell/browser/native_window_mac.mm b/shell/browser/native_window_mac.mm index 618119a6eb4..99999d2ff12 100644 --- a/shell/browser/native_window_mac.mm +++ b/shell/browser/native_window_mac.mm @@ -22,6 +22,7 @@ #include "content/public/browser/browser_task_traits.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" +#include "shell/browser/javascript_environment.h" #include "shell/browser/native_browser_view_mac.h" #include "shell/browser/ui/cocoa/electron_native_widget_mac.h" #include "shell/browser/ui/cocoa/electron_ns_window.h" @@ -278,10 +279,11 @@ NativeWindowMac::NativeWindowMac(const gin_helper::Dictionary& options, options.Get(options::kVisualEffectState, &visual_effect_state_); if (options.Has(options::kFullscreenWindowTitle)) { - EmitWarning(node::Environment::GetCurrent(v8::Isolate::GetCurrent()), - "\"fullscreenWindowTitle\" option has been deprecated and is " - "no-op now.", - "electron"); + EmitWarning( + node::Environment::GetCurrent(JavascriptEnvironment::GetIsolate()), + "\"fullscreenWindowTitle\" option has been deprecated and is " + "no-op now.", + "electron"); } bool minimizable = true; @@ -1313,7 +1315,7 @@ void NativeWindowMac::SetVibrancy(const std::string& type) { std::string dep_warn = " has been deprecated and removed as of macOS 10.15."; node::Environment* env = - node::Environment::GetCurrent(v8::Isolate::GetCurrent()); + node::Environment::GetCurrent(JavascriptEnvironment::GetIsolate()); NSVisualEffectMaterial vibrancyType; diff --git a/shell/renderer/api/electron_api_web_frame.cc b/shell/renderer/api/electron_api_web_frame.cc index af814a9916d..8c36d450003 100644 --- a/shell/renderer/api/electron_api_web_frame.cc +++ b/shell/renderer/api/electron_api_web_frame.cc @@ -205,7 +205,7 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback { void Completed( const blink::WebVector>& result) override { - v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Isolate* isolate = promise_.isolate(); if (!result.empty()) { if (!result[0].IsEmpty()) { v8::Local value = result[0]; From b6254bfd3615642ae0b51a6fe7022ceda67ae5cb Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Mon, 29 Mar 2021 07:34:14 -0700 Subject: [PATCH 14/17] Bump v14.0.0-nightly.20210329 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 4b8fda48c3f..5a2972a71f0 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -14.0.0-nightly.20210326 \ No newline at end of file +14.0.0-nightly.20210329 \ No newline at end of file diff --git a/package.json b/package.json index 6391a7089c3..08668fa8af0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "14.0.0-nightly.20210326", + "version": "14.0.0-nightly.20210329", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index ff19656a2a8..ee18fd33bb2 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 14,0,0,20210326 - PRODUCTVERSION 14,0,0,20210326 + FILEVERSION 14,0,0,20210329 + PRODUCTVERSION 14,0,0,20210329 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L From 9a7cfc42aa085113fa6f8f1b2051482da704c4c2 Mon Sep 17 00:00:00 2001 From: Jeremy Rose Date: Mon, 29 Mar 2021 15:35:12 -0700 Subject: [PATCH 15/17] fix: put RemoteCertVerifier upstream from the caching and coalescing layers (#28358) --- .../expose_setuseragent_on_networkcontext.patch | 2 +- ...w_remote_certificate_verification_logic.patch | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/patches/chromium/expose_setuseragent_on_networkcontext.patch b/patches/chromium/expose_setuseragent_on_networkcontext.patch index 061806427fd..892a1dc10f8 100644 --- a/patches/chromium/expose_setuseragent_on_networkcontext.patch +++ b/patches/chromium/expose_setuseragent_on_networkcontext.patch @@ -33,7 +33,7 @@ index 0ccfe130f00ec3b6c75cd8ee04d5a2777e1fd00c..653829457d58bf92057cc36aa8a28970 DISALLOW_COPY_AND_ASSIGN(StaticHttpUserAgentSettings); }; diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index 67986e284434115debf6a638b62c9585ac207c1d..ef64b8ab03b39066e1332cb6859c0012dc86e551 100644 +index 1e220456a91ce81a994c611d9ef8efed88846bc0..d2dcb8d7f18e737a75659e103f760e43bb1d7ff3 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc @@ -1128,6 +1128,13 @@ void NetworkContext::SetNetworkConditions( diff --git a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch index 6e02b00ee31..9b2395e9a26 100644 --- a/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch +++ b/patches/chromium/network_service_allow_remote_certificate_verification_logic.patch @@ -7,7 +7,7 @@ This adds a callback from the network service that's used to implement session.setCertificateVerifyCallback. diff --git a/services/network/network_context.cc b/services/network/network_context.cc -index dc1d135df68e8f11619faffb57dfd38b41bc06d1..67986e284434115debf6a638b62c9585ac207c1d 100644 +index dc1d135df68e8f11619faffb57dfd38b41bc06d1..1e220456a91ce81a994c611d9ef8efed88846bc0 100644 --- a/services/network/network_context.cc +++ b/services/network/network_context.cc @@ -117,6 +117,11 @@ @@ -116,16 +116,16 @@ index dc1d135df68e8f11619faffb57dfd38b41bc06d1..67986e284434115debf6a638b62c9585 void NetworkContext::CreateURLLoaderFactory( mojo::PendingReceiver receiver, mojom::URLLoaderFactoryParamsPtr params) { -@@ -1917,6 +2002,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( - std::move(cert_verifier)); - cert_verifier = base::WrapUnique(cert_verifier_with_trust_anchors_); - #endif // BUILDFLAG(IS_CHROMEOS_ASH) +@@ -1900,6 +1985,9 @@ URLRequestContextOwner NetworkContext::MakeURLRequestContext( + std::move(cert_verifier), std::move(ct_verifier)); + } + #endif // BUILDFLAG(IS_CT_SUPPORTED) + auto remote_cert_verifier = std::make_unique(std::move(cert_verifier)); + remote_cert_verifier_ = remote_cert_verifier.get(); -+ cert_verifier = std::make_unique(std::move(remote_cert_verifier)); - } ++ cert_verifier = std::move(remote_cert_verifier); - builder.SetCertVerifier(IgnoreErrorsCertVerifier::MaybeWrapCertVerifier( + // Whether the cert verifier is remote or in-process, we should wrap it in + // caching and coalescing layers to avoid extra verifications and IPCs. diff --git a/services/network/network_context.h b/services/network/network_context.h index 102548a7f132cd1f7d46421fc2ae941dbff7c29d..34281acc5a2dece3b84666b25f4af423a04bf8df 100644 --- a/services/network/network_context.h From 9fecf8369fdc37e50c4631f7f23fbbf2d4e12537 Mon Sep 17 00:00:00 2001 From: Shelley Vohr Date: Tue, 30 Mar 2021 07:26:49 +0000 Subject: [PATCH 16/17] fix: errors thrown in functions over the `contextBridge` (#28346) * fix: errors thrown in functions over the contextBridge * spec: add a test * fix: ensure exception is a v8::Object --- .../api/electron_api_context_bridge.cc | 28 +++++++++++++------ spec-main/api-context-bridge-spec.ts | 14 ++++++++++ 2 files changed, 33 insertions(+), 9 deletions(-) diff --git a/shell/renderer/api/electron_api_context_bridge.cc b/shell/renderer/api/electron_api_context_bridge.cc index 671dcf062ca..9e7f3e55174 100644 --- a/shell/renderer/api/electron_api_context_bridge.cc +++ b/shell/renderer/api/electron_api_context_bridge.cc @@ -429,21 +429,31 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo& info) { v8::MaybeLocal maybe_return_value; bool did_error = false; - std::string error_message; + v8::Local error_message; { v8::TryCatch try_catch(args.isolate()); maybe_return_value = func->Call(func_owning_context, func, proxied_args.size(), proxied_args.data()); if (try_catch.HasCaught()) { did_error = true; - auto message = try_catch.Message(); + v8::Local exception = try_catch.Exception(); - if (message.IsEmpty() || - !gin::ConvertFromV8(args.isolate(), message->Get(), - &error_message)) { - error_message = - "An unknown exception occurred in the isolated context, an error " - "occurred but a valid exception was not thrown."; + const char* err_msg = + "An unknown exception occurred in the isolated context, an error " + "occurred but a valid exception was not thrown."; + + if (!exception->IsNull() && exception->IsObject()) { + v8::MaybeLocal maybe_message = + exception.As()->Get( + func_owning_context, + gin::ConvertToV8(args.isolate(), "message")); + + if (!maybe_message.ToLocal(&error_message) || + !error_message->IsString()) { + error_message = gin::StringToV8(args.isolate(), err_msg); + } + } else { + error_message = gin::StringToV8(args.isolate(), err_msg); } } } @@ -451,7 +461,7 @@ void ProxyFunctionWrapper(const v8::FunctionCallbackInfo& info) { if (did_error) { v8::Context::Scope calling_context_scope(calling_context); args.isolate()->ThrowException( - v8::Exception::Error(gin::StringToV8(args.isolate(), error_message))); + v8::Exception::Error(error_message.As())); return; } diff --git a/spec-main/api-context-bridge-spec.ts b/spec-main/api-context-bridge-spec.ts index 4007694621c..d08a5e66496 100644 --- a/spec-main/api-context-bridge-spec.ts +++ b/spec-main/api-context-bridge-spec.ts @@ -364,6 +364,20 @@ describe('contextBridge', () => { expect(result).equal(true); }); + it('should properly handle errors thrown in proxied functions', async () => { + await makeBindingWindow(() => { + contextBridge.exposeInMainWorld('example', () => { throw new Error('oh no'); }); + }); + const result = await callWithBindings(async (root: any) => { + try { + root.example(); + } catch (e) { + return e.message; + } + }); + expect(result).equal('oh no'); + }); + it('should proxy methods that are callable multiple times', async () => { await makeBindingWindow(() => { contextBridge.exposeInMainWorld('example', { From c9217f07e66446a6c2778a92875e3a2b04beb856 Mon Sep 17 00:00:00 2001 From: Electron Bot Date: Tue, 30 Mar 2021 07:32:11 -0700 Subject: [PATCH 17/17] Bump v14.0.0-nightly.20210330 --- ELECTRON_VERSION | 2 +- package.json | 2 +- shell/browser/resources/win/electron.rc | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ELECTRON_VERSION b/ELECTRON_VERSION index 5a2972a71f0..2034e35f1cb 100644 --- a/ELECTRON_VERSION +++ b/ELECTRON_VERSION @@ -1 +1 @@ -14.0.0-nightly.20210329 \ No newline at end of file +14.0.0-nightly.20210330 \ No newline at end of file diff --git a/package.json b/package.json index 08668fa8af0..13e18aaab07 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "electron", - "version": "14.0.0-nightly.20210329", + "version": "14.0.0-nightly.20210330", "repository": "https://github.com/electron/electron", "description": "Build cross platform desktop apps with JavaScript, HTML, and CSS", "devDependencies": { diff --git a/shell/browser/resources/win/electron.rc b/shell/browser/resources/win/electron.rc index ee18fd33bb2..bdad2b68447 100644 --- a/shell/browser/resources/win/electron.rc +++ b/shell/browser/resources/win/electron.rc @@ -50,8 +50,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 14,0,0,20210329 - PRODUCTVERSION 14,0,0,20210329 + FILEVERSION 14,0,0,20210330 + PRODUCTVERSION 14,0,0,20210330 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L