Compare commits

..

78 Commits

Author SHA1 Message Date
trop[bot]
1eb0d77b46 fix: emit will-navigate for links in chrome: pages (#40524)
* fix: emit will-navigate for links in chrome: pages

Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>

* test: will-navigate emitted from chrome: pages

Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>

* Update shell/browser/electron_navigation_throttle.cc

Co-authored-by: Charles Kerr <charles@charleskerr.com>

Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Maddock <smaddock@slack-corp.com>
Co-authored-by: Samuel Maddock <samuel.maddock@gmail.com>
2023-11-15 11:20:22 +01:00
electron-roller[bot]
03acfc9bed chore: bump chromium to 118.0.5993.144 (27-x-y) (#40522)
chore: bump chromium in DEPS to 118.0.5993.144

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-11-15 11:12:16 +01:00
trop[bot]
8472c6a3d7 fix: chrome.action API registration (#40513)
* fix: chrome.action API registration

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: browser_action implemented_in

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-13 12:57:16 +01:00
trop[bot]
efeaabc62a build: allow overriding electron version (#40508)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2023-11-12 19:50:58 -08:00
trop[bot]
99fb3d1922 feat: keyboard.lock() should use permissions helper (#40459)
feat: keyboard.lock should use permissions helper

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-09 10:41:36 -08:00
electron-roller[bot]
fc2d896b8e chore: bump chromium to 118.0.5993.136 (27-x-y) (#40483)
chore: bump chromium in DEPS to 118.0.5993.136

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-11-09 10:32:28 -08:00
trop[bot]
206364dd8d fix: broken shader cache due to compilation error (#40467)
* fix: broken shader cache due to compilation error

Refs https://chromium-review.googlesource.com/c/chromium/src/+/4988290

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-11-08 11:17:51 +09:00
trop[bot]
f9702ca0da docs: fix hid-device-{added|removed|revoked} event types (#40477)
docs: fix hid-device-{added|removed|revoked} types

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-07 18:09:45 -08:00
trop[bot]
3148a2a874 fix: crash when unloading some WebViews (#40444)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-06 11:48:08 -08:00
electron-roller[bot]
272b371be8 chore: bump chromium to 118.0.5993.129 (27-x-y) (#40417)
chore: bump chromium in DEPS to 118.0.5993.129

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-11-02 11:56:49 -04:00
trop[bot]
bbc12f6688 docs: add bypassCustomProtocolHandlers to ses.fetch (#40423)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Brandon Fowler <brandfowl@gmail.com>
2023-11-02 10:10:12 -04:00
trop[bot]
a6a35f12b0 docs: document our Node.js versioning policy (#40415)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-01 20:17:27 -04:00
electron-roller[bot]
0beed97bb0 chore: bump chromium to 118.0.5993.120 (27-x-y) (#40404)
chore: bump chromium in DEPS to 118.0.5993.120

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-11-01 11:15:59 -04:00
trop[bot]
a22f6118dd build: actually show github upload output if verbose is true. (#40399)
* build: actually show github upload output if verbose is true.

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

* chore: fixup lint

Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-11-01 10:01:15 -04:00
trop[bot]
4487ff5368 fix: navigator.keyboard.lock() fullscreen exit handling (#40388)
fix: navigator.keyboard.lock() fullscreen exit handling

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-11-01 10:00:56 -04:00
electron-roller[bot]
6b87170c24 chore: bump chromium to 118.0.5993.119 (27-x-y) (#40355)
chore: bump chromium in DEPS to 118.0.5993.119

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-10-29 20:57:45 -04:00
Milan Burda
1e24b130bb build: fix ":electron_lib_arc" / "chromium_src:chrome_lib_arc" dependencies (#40349) 2023-10-26 16:24:32 -04:00
trop[bot]
ef2745ff29 fix: prevent PopUpButtonHandler premature dealloc (#40347)
fix: prevent PopUpButtonHandler dealloc

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-26 14:12:53 -04:00
trop[bot]
8f90a408c8 build: upload slow, more time good (#40337)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <marshallofsound@electronjs.org>
2023-10-26 00:20:55 -07:00
electron-roller[bot]
e43beaeec0 chore: bump chromium to 118.0.5993.117 (27-x-y) (#40326)
* chore: bump chromium in DEPS to 118.0.5993.117

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-25 16:25:08 -04:00
Milan Burda
7ac2e49d2e test: add spec for app.getAppMetrics() for utility process (#40317)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
2023-10-24 13:32:20 -07:00
trop[bot]
301f3da15d test: add spec for child-process-gone event for utility process (#40305)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-10-24 11:15:36 -04:00
Samuel Attard
416c6dcb39 chore: cherry-pick 0c2d9659ccc1 from chromium (#40280)
* chore: cherry-pick 0c2d9659ccc1 from chromium

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-20 10:29:17 +02:00
trop[bot]
79876b72b1 docs: fix represented file fiddle (#40251)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2023-10-19 11:13:24 +02:00
trop[bot]
54d9958a49 chore: Show FIDO devices in the chooser if allowed (#40274)
* chore: Show FIDO devices in the chooser if allowed

* chore: tweak HidChooserContext::IsFidoAllowedForOrigin

* chore: feedback from review

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-19 11:13:09 +02:00
trop[bot]
db99feb7c3 chore: implement no-op chrome.action extension APIs (#40260)
chore: implement no-op chrome.action extension APIs

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-18 19:19:22 -04:00
trop[bot]
64318df509 fix: correctly track receiver for methods called via ctx bridge (#40262)
* fix: correctly track receiver for methods called via ctx bridge

Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>

* spec: test for correct contextBridge passage

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Samuel Attard <samuel.r.attard@gmail.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-18 21:38:25 +02:00
electron-roller[bot]
4ceb644723 chore: bump chromium to 118.0.5993.89 (27-x-y) (#40240)
chore: bump chromium in DEPS to 118.0.5993.89

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-10-18 10:19:01 -04:00
trop[bot]
ae212f41ab fix: Windows Toast notification dismissal from Action Center (#40244)
* fix: Windows Toast notification dismissal from Action Center

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* docs: note Toast behavior in event

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: address feedback from review

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-18 10:03:54 +02:00
trop[bot]
1f64b7869c refactor: partition HidDelegate observers by browser context (#40237)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-17 18:58:59 -04:00
electron-roller[bot]
f282bdac65 chore: bump chromium to 118.0.5993.71 (27-x-y) (#40235)
chore: bump chromium in DEPS to 118.0.5993.71

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
2023-10-17 18:58:40 -04:00
trop[bot]
c0ad9e154f docs: Update docs on testing Electron apps with WebdriverIO (#40226)
* docs: Updated docs on testing Electron using WebdriverIO

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Felix Rieseberg <fr@makenotion.com>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* more updates

Co-authored-by: Christian Bromann <git@bromann.dev>

* address PR comments

Co-authored-by: Christian Bromann <git@bromann.dev>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

* Update docs/tutorial/automated-testing.md

Co-authored-by: Erick Zhao <erick@hotmail.ca>

Co-authored-by: Christian Bromann <github@christian-bromann.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Christian Bromann <github@christian-bromann.com>
Co-authored-by: Christian Bromann <git@bromann.dev>
2023-10-17 16:54:45 +02:00
trop[bot]
6304ea53ef fix: incorrect wco bounds in macOS fullscreen (#40217)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-16 13:11:37 +02:00
David Sanders
4c1e53dfa6 docs: fix some string union typings (#40202) 2023-10-16 14:10:10 +09:00
trop[bot]
96f9cc5157 fix: store portal restore token under the right source ID (#40193)
XDG Desktop Portal provides restore tokens to restore a previously
selected PipeWire stream instead of prompting the user again. This
restore token is single use only and it has to be replaced when the
stream is completed/stopped.

BaseCapturerPipewire maintains two source IDs: one is initialized by
the constructor for new sources (source_id_) and another is for
capturing previously selected sources (selected_source_id_). The
restore token was always being stored under `source_id_`, even if the
capture was ongoing for `selected_source_id_`. This prevents a stream
from being restored more than once. Fix that by storing the restore
token under the selected source ID if it exists.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Athul Iddya <athul@iddya.com>
2023-10-13 22:09:05 +02:00
trop[bot]
8890ab5119 fix: webContents.capturePage() for hidden windows on Windows/Linux (#40188)
fix: capturePage for hidden windows on Windows/Linux

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-12 13:54:48 +02:00
electron-roller[bot]
4bb80df378 chore: bump chromium to 118.0.5993.70 (27-x-y) (#40175)
* chore: bump chromium in DEPS to 118.0.5993.70

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-11 14:34:43 -04:00
trop[bot]
3d10512399 docs: update dates for E28 (#40168)
* docs: update dates for E28

Co-authored-by: VerteDinde <vertedinde@electronjs.org>

* docs: update node version

Co-authored-by: David Sanders <dsanders11@ucsbalum.com>

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: VerteDinde <vertedinde@electronjs.org>
2023-10-11 09:27:21 -07:00
trop[bot]
30305e4f2b test: make capturePage color matching timeouts consistent (#40166)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-10 19:26:20 -04:00
trop[bot]
40c21e02da fix: crash when calling non-reentrant function in loadURL (#40162)
fix: crash when calling non-reentrant function in loadURL

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-10 11:49:22 -04:00
trop[bot]
6de96fb83b ci: fixup diagnose_goma_log.py call (#40149)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-09 18:44:51 -04:00
trop[bot]
cf0e974ce1 fix: failing build with enable_electron_extensions=false (#40087)
* fix: ENABLE_EXTENSIONS -> ENABLE_ELECTRON_EXTENSIONS

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* fix: extension guard fixes

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: fix linker errors

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-09 18:43:40 -04:00
trop[bot]
7e2073226a fix: crashed events deprecation (#40111)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-10-09 15:19:53 +02:00
trop[bot]
8f370cd2e3 fix: fix vibrancy applying without transparency on MacOS (#40130)
* fix: fix vibrancy applying without transparency

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

* fix: initiate backgroundMaterial and vibrancy earlier in native window

Co-authored-by: samuelmaddock <samuelmaddock@electronjs.org>

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2023-10-09 15:19:30 +02:00
Milan Burda
82d4e9427f test: fix "crashed event does not crash main process when destroying WebContents in it" (#40144) 2023-10-09 15:18:46 +02:00
trop[bot]
f0b742f2d6 test: add back smoke test for removed API (#40139)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: David Sanders <dsanders11@ucsbalum.com>
2023-10-09 15:41:39 +09:00
trop[bot]
2bc07b098b chore: cherry-pick c03569f from libuv (#40126)
* chore: cherry-pick c03569f from libuv

Refs c03569f0df

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: update .patches

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-09 08:45:34 +09:00
trop[bot]
d95f28c194 fix: toggling DevTools while minimized on Windows (#40116)
fix: toggling devtools while minimized on Windows

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-06 11:46:55 -04:00
trop[bot]
22ea11175b fix: error using webcrypto.subtle.importKey() (#40100)
* fix: error using webcrypto.subtle.importKey()

Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>

* chore: update .patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-06 10:42:49 -04:00
trop[bot]
5b44e82eb4 fix: all children showing when showing child window (#40105)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-06 09:56:23 -04:00
electron-roller[bot]
4c4a3e7594 chore: bump chromium to 118.0.5993.54 (27-x-y) (#40103)
* chore: bump chromium in DEPS to 118.0.5993.54

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-10-05 19:53:06 -04:00
trop[bot]
bf7474d3f4 feat: add tabbingIdentifier property to BrowserWindow (#40082)
feat: add tabbingIdentifier property to BrowserWindow

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-05 09:13:05 -04:00
George Xu
3f142ad039 feat: expose app accessibility transparency settings api (#40074)
feat: expose app accessibility transparency settings api (#39631)

* feat: expose app accessibility transparency settings api

* docs: fix typo

* chore: add doc

* change to property

* add as property instead of method

* chore: fix lint

* rename function name in header

---------

Co-authored-by: Keeley Hammond <vertedinde@electronjs.org>
2023-10-04 16:36:04 -07:00
electron-roller[bot]
10db23828e chore: bump chromium to 118.0.5993.32 (27-x-y) (#40044)
* chore: bump chromium in DEPS to 118.0.5993.32

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-10-02 14:37:40 -04:00
trop[bot]
43ba54e61f docs: add PipeWire integration instructions for snaps (#40068)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Athul Iddya <athul@iddya.com>
2023-10-02 11:05:52 -04:00
trop[bot]
3fdfcbb5dd chore: update extensions url handling to match upstream (#40063)
- https://chromium-review.googlesource.com/c/chromium/src/+/4772028
- https://chromium-review.googlesource.com/c/chromium/src/+/4264656
- https://chromium-review.googlesource.com/c/chromium/src/+/4712150

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-02 13:12:47 +02:00
trop[bot]
9e8cba981a fix: BroadcastChannel initialization location (#40067)
fix: `BroadcastChannel` initialization location (#37421)

* fix: BroadcastChannel initialization location

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-10-02 13:10:46 +02:00
trop[bot]
a85c6cf0e5 fix: detect screen readers by testing their existences (#40065)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2023-10-02 13:07:27 +02:00
trop[bot]
7e536dfd8e fix: propagate layout call to all children of InspectableWebContentsViewViews (#40037)
Propagate layout call to all children of InspectableWebContentsViewViews.

When BrowserView bounds are set from js, those might not trigger layout
immediately, sometimes propagating InvalidateLayout call to parent.
View is marked as needing layout, expecting to receive it from parent on
next layout call. The problem is that BrowserView's view is added as child
of InspectableWebContentsViews which does not call setBounds (which
would trigger layout) on all of it's children when doing it's layout,
so it skips propagating Layout call to its children BrowserViews views,
even though those were marked as needing layout.
Call base class View::Layout which will iterate over views' children
and call Layout on those that were marked as needing them.

Fixes #39993.

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Marek Haranczyk <marek@openfin.co>
2023-09-28 18:55:24 -04:00
trop[bot]
7d21d113d2 fix: failure on immutable webContents.print(options) (#40030)
fix: failure on immutable webContents.print(options)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-28 12:48:44 -04:00
Samuel Attard
7ed33db12e chore: cherry-pick 3fbd1dca6a4d from libvpx (#40022)
* chore: cherry-pick 3fbd1dca6a4d from libvpx

* build: update patches config

* chore: update patches

* chore: update patches

---------

Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-09-28 03:31:46 -07:00
trop[bot]
66c4f9cb6f fix: rounded corners on vibrant macOS modals (#39996)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-28 10:33:39 +02:00
trop[bot]
a00155dcfc fix: set window contents as opaque to decrease DWM GPU usage (#40003)
* set window contents as opaque to decrease DWM GPU usage

Co-authored-by: brhenrique <bruno.d@miro.com>

* chore: add more context to ShouldWindowContentsBeTransparent

Co-authored-by: brhenrique <bruno.d@miro.com>

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: brhenrique <bruno.d@miro.com>
2023-09-28 10:33:29 +02:00
trop[bot]
3e4adb91c5 feat: enable dark mode on GTK UIs (#40010)
feat: port DarkModeManagerLinux

This is needed after https://bugs.chromium.org/p/chromium/issues/detail?id=998903
and replaces the previous workaround to detect dark mode on GTK.
Detect system dark theme preference via xdg settings portal:
https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Settings

Closes: https://github.com/electron/electron/issues/38961
Closes: https://github.com/electron/electron/issues/28838

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Robert Günzler <r@gnzler.io>
2023-09-27 16:44:34 -04:00
trop[bot]
f63f02fbb2 docs: document type-specific module aliases (#40005)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Erick Zhao <erick@hotmail.ca>
2023-09-27 16:35:32 -04:00
trop[bot]
a3a6e8ff26 build: fix with enable_pdf_viewer = false (#40001)
build: fix with enable_pdf_viewer = false

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Shelley Vohr <shelley.vohr@gmail.com>
2023-09-27 19:57:48 +02:00
trop[bot]
e70a25d5a3 fix: apply size constraints to NSWindow (#39992)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Cheng Zhao <zcbenz@gmail.com>
2023-09-27 16:54:19 +02:00
Keeley Hammond
8e2cf54f29 fix: revert SameParty cookie attribute removal (#39976) 2023-09-26 14:17:23 -07:00
trop[bot]
a3614983de chore: add deprecated app.runningUnderRosettaTranslation to breaking-changes.md (#39984)
chore: add deprecated app.runningUnderRosettaTranslation to breaking-changes.md

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-09-26 16:57:42 -04:00
David Sanders
686adf9d15 chore: remove deprecated systemPreferences APIs (#39804)
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-26 14:45:49 +09:00
John Kleinschmidt
25dccaa1b1 test: fixup parallel/test-node-output-error test (#39973) 2023-09-25 17:03:41 -04:00
trop[bot]
175cd9111e refactor: use type enum in file stats for asar archive (#39968)
refactor: use type enum in file stats for asar archive (#39889)

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-09-25 11:14:05 -04:00
trop[bot]
70236258cf docs: correct v24 Alpha date (#39966)
docs: correct v27 Alpha date

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Leon <xuminjieleon@163.com>
2023-09-25 12:43:16 +02:00
electron-roller[bot]
d0d9011fc9 chore: bump chromium to 118.0.5993.18 (27-x-y) (#39943)
* chore: bump chromium in DEPS to 118.0.5993.18

* chore: update patches

---------

Co-authored-by: electron-roller[bot] <84116207+electron-roller[bot]@users.noreply.github.com>
Co-authored-by: PatchUp <73610968+patchup[bot]@users.noreply.github.com>
2023-09-22 10:04:12 +02:00
trop[bot]
8423a014ed chore: cherry-pick tls shutdown crash fix from upstream (#39947)
* chore: cherry-pick tls shutdown crash fix from upstream

Co-authored-by: deepak1556 <hop2deep@gmail.com>

* chore: update patches

---------

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: deepak1556 <hop2deep@gmail.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-21 19:39:21 +02:00
trop[bot]
4ba1b219a5 fix: app.runningUnderARM64Translation() always returning true on Windows ARM64 (#39931)
fix: app.runningUnderARM64Translation() always returning true on ARM64

Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: Milan Burda <milan.burda@gmail.com>
2023-09-21 10:09:17 -04:00
trop[bot]
e721b683bf ci: fix linux builds of forks (#39940)
Co-authored-by: trop[bot] <37223003+trop[bot]@users.noreply.github.com>
Co-authored-by: John Kleinschmidt <jkleinsc@electronjs.org>
2023-09-21 10:07:51 -04:00
John Kleinschmidt
271be9c8e4 chore: fixup node flakes (#39917)
(cherry picked from commit 80a9b9d654)
2023-09-19 15:29:00 -04:00
136 changed files with 6537 additions and 852 deletions

View File

@@ -660,6 +660,7 @@ step-nodejs-headers-build: &step-nodejs-headers-build
step-electron-publish: &step-electron-publish
run:
name: Publish Electron Dist
no_output_timeout: 30m
command: |
if [ "`uname`" == "Darwin" ]; then
rm -rf src/out/Default/obj
@@ -754,8 +755,8 @@ step-show-goma-stats: &step-show-goma-stats
command: |
set +e
set +o pipefail
$GOMA_DIR/goma_ctl.py stat
$GOMA_DIR/diagnose_goma_log.py
python3 $GOMA_DIR/goma_ctl.py stat
python3 $GOMA_DIR/diagnose_goma_log.py
true
when: always
background: true
@@ -1074,7 +1075,7 @@ commands:
condition:
or:
- equal: [<< parameters.could-be-aks >>, false]
- equal: [<< pipeline.parameters.large-linux-executor >>, xlarge]
- equal: [<< pipeline.parameters.large-linux-executor >>, 2xlarge]
steps: << parameters.circle >>
- when:
condition:
@@ -1914,7 +1915,8 @@ jobs:
steps:
- electron-build:
persist: true
checkout: true
checkout: false
checkout-and-assume-cache: true
build-nonproprietary-ffmpeg: false
artifact-key: 'linux-x64-asan'
build-type: 'Linux'

View File

@@ -103,14 +103,26 @@ branding = read_file("shell/app/BRANDING.json", "json")
electron_project_name = branding.project_name
electron_product_name = branding.product_name
electron_mac_bundle_id = branding.mac_bundle_id
electron_version = exec_script("script/print-version.py",
[],
"trim string",
[
".git/packed-refs",
".git/HEAD",
"script/lib/get-version.js",
])
if (override_electron_version != "") {
electron_version = override_electron_version
} else {
# When building from source code tarball there is no git tag available and
# builders must explicitly pass override_electron_version in gn args.
# This read_file call will assert if there is no git information, without it
# gn will generate a malformed build configuration and ninja will get into
# infinite loop.
read_file(".git/packed-refs", "string")
# Set electron version from git tag.
electron_version = exec_script("script/get-git-version.py",
[],
"trim string",
[
".git/packed-refs",
".git/HEAD",
])
}
if (is_mas_build) {
assert(is_mac,
@@ -787,6 +799,7 @@ if (is_mac) {
"buildflags",
"shell/common/api:mojo",
"//base",
"//content/public/browser",
"//skia",
"//third_party/electron_node:node_lib",
"//third_party/webrtc_overrides:webrtc_component",

2
DEPS
View File

@@ -2,7 +2,7 @@ gclient_gn_args_from = 'src'
vars = {
'chromium_version':
'118.0.5993.11',
'118.0.5993.144',
'node_version':
'v18.17.1',
'nan_version':

View File

@@ -18,4 +18,9 @@ declare_args() {
# Enable Spellchecker support
enable_builtin_spellchecker = true
# The version of Electron.
# Packagers and vendor builders should set this in gn args to avoid running
# the script that reads git tag.
override_electron_version = ""
}

View File

@@ -202,6 +202,10 @@ static_library("chrome") {
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.cc",
"//chrome/browser/ui/views/status_icons/status_icon_linux_dbus.h",
]
sources += [
"//chrome/browser/ui/views/dark_mode_manager_linux.cc",
"//chrome/browser/ui/views/dark_mode_manager_linux.h",
]
public_deps += [
"//components/dbus/menu",
"//components/dbus/thread_linux",
@@ -319,6 +323,34 @@ static_library("chrome") {
"//components/pdf/renderer",
]
}
} else {
# These are required by the webRequest module.
sources += [
"//extensions/browser/api/declarative_net_request/request_action.cc",
"//extensions/browser/api/declarative_net_request/request_action.h",
"//extensions/browser/api/web_request/form_data_parser.cc",
"//extensions/browser/api/web_request/form_data_parser.h",
"//extensions/browser/api/web_request/upload_data_presenter.cc",
"//extensions/browser/api/web_request/upload_data_presenter.h",
"//extensions/browser/api/web_request/web_request_api_constants.cc",
"//extensions/browser/api/web_request/web_request_api_constants.h",
"//extensions/browser/api/web_request/web_request_info.cc",
"//extensions/browser/api/web_request/web_request_info.h",
"//extensions/browser/api/web_request/web_request_resource_type.cc",
"//extensions/browser/api/web_request/web_request_resource_type.h",
"//extensions/browser/extension_api_frame_id_map.cc",
"//extensions/browser/extension_api_frame_id_map.h",
"//extensions/browser/extension_navigation_ui_data.cc",
"//extensions/browser/extension_navigation_ui_data.h",
"//extensions/browser/extensions_browser_client.cc",
"//extensions/browser/extensions_browser_client.h",
"//extensions/browser/guest_view/web_view/web_view_renderer_state.cc",
"//extensions/browser/guest_view/web_view/web_view_renderer_state.h",
]
public_deps += [
"//extensions/browser/api/declarative_net_request/flat:extension_ruleset",
]
}
if (!is_mas_build) {
@@ -353,6 +385,7 @@ if (is_mac) {
deps = [
"//base",
"//content/public/browser",
"//skia",
"//third_party/electron_node:node_lib",
"//third_party/webrtc_overrides:webrtc_component",

View File

@@ -1134,11 +1134,11 @@ indicates success while any other value indicates failure according to Chromium
resolver will attempt to use the system's DNS settings to do DNS lookups
itself. Enabled by default on macOS, disabled by default on Windows and
Linux.
* `secureDnsMode` string (optional) - Can be "off", "automatic" or "secure".
Configures the DNS-over-HTTP mode. When "off", no DoH lookups will be
performed. When "automatic", DoH lookups will be performed first if DoH is
* `secureDnsMode` string (optional) - Can be 'off', 'automatic' or 'secure'.
Configures the DNS-over-HTTP mode. When 'off', no DoH lookups will be
performed. When 'automatic', DoH lookups will be performed first if DoH is
available, and insecure DNS lookups will be performed as a fallback. When
"secure", only DoH lookups will be performed. Defaults to "automatic".
'secure', only DoH lookups will be performed. Defaults to 'automatic'.
* `secureDnsServers` string[]&#32;(optional) - A list of DNS-over-HTTP
server templates. See [RFC8484 § 3][] for details on the template format.
Most servers support the POST method; the template for such servers is

View File

@@ -505,6 +505,10 @@ events.
A `Integer` property representing the unique ID of the window. Each ID is unique among all `BrowserWindow` instances of the entire Electron application.
#### `win.tabbingIdentifier` _macOS_ _Readonly_
A `string` (optional) property that is equal to the `tabbingIdentifier` passed to the `BrowserWindow` constructor or `undefined` if none was set.
#### `win.autoHideMenuBar`
A `boolean` property that determines whether the window menu bar should hide itself automatically. Once set, the menu bar will only show when users press the single `Alt` key.

View File

@@ -85,6 +85,8 @@ Emitted when the notification is closed by manual intervention from the user.
This event is not guaranteed to be emitted in all cases where the notification
is closed.
On Windows, the `close` event can be emitted in one of three ways: programmatic dismissal with `notification.close()`, by the user closing the notification, or via system timeout. If a notification is in the Action Center after the initial `close` event is emitted, a call to `notification.close()` will remove the notification from the action center but the `close` event will not be emitted again.
#### Event: 'reply' _macOS_
Returns:
@@ -127,6 +129,8 @@ shown notification and create a new one with identical properties.
Dismisses the notification.
On Windows, calling `notification.close()` while the notification is visible on screen will dismiss the notification and remove it from the Action Center. If `notification.close()` is called after the notification is no longer visible on screen, calling `notification.close()` will try remove it from the Action Center.
### Instance Properties
#### `notification.title`

View File

@@ -266,7 +266,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `navigator.hid.requestDevice` has been called and
@@ -281,7 +281,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `frame` [WebFrameMain](web-frame-main.md)
Emitted after `navigator.hid.requestDevice` has been called and
@@ -296,7 +296,7 @@ Returns:
* `event` Event
* `details` Object
* `device` [HIDDevice[]](structures/hid-device.md)
* `device` [HIDDevice](structures/hid-device.md)
* `origin` string (optional) - The origin that the device has been revoked from.
Emitted after `HIDDevice.forget()` has been called. This event can be used
@@ -785,7 +785,7 @@ Returns `Promise<void>` - Resolves when all connections are closed.
#### `ses.fetch(input[, init])`
* `input` string | [GlobalRequest](https://nodejs.org/api/globals.html#request)
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) (optional)
* `init` [RequestInit](https://developer.mozilla.org/en-US/docs/Web/API/fetch#options) & { bypassCustomProtocolHandlers?: boolean } (optional)
Returns `Promise<GlobalResponse>` - see [Response](https://developer.mozilla.org/en-US/docs/Web/API/Response).
@@ -901,6 +901,7 @@ win.webContents.session.setCertificateVerifyProc((request, callback) => {
* `midiSysex` - Request the use of system exclusive messages in the [Web MIDI API](https://developer.mozilla.org/en-US/docs/Web/API/Web_MIDI_API).
* `notifications` - Request notification creation and the ability to display them in the user's system tray using the [Notifications API](https://developer.mozilla.org/en-US/docs/Web/API/notification)
* `pointerLock` - Request to directly interpret mouse movements as an input method via the [Pointer Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Pointer_Lock_API). These requests always appear to originate from the main frame.
* `keyboardLock` - Request capture of keypresses for any or all of the keys on the physical keyboard via the [Keyboard Lock API](https://developer.mozilla.org/en-US/docs/Web/API/Keyboard/lock). These requests always appear to originate from the main frame.
* `openExternal` - Request to open links in external applications.
* `window-management` - Request access to enumerate screens using the [`getScreenDetails`](https://developer.chrome.com/en/articles/multi-screen-window-placement/) API.
* `unknown` - An unrecognized permission request.

View File

@@ -273,7 +273,6 @@ This API is only available on macOS 10.14 Mojave or newer.
* `window-frame` - Window frame.
* `window-text` - Text in windows.
* On **macOS**
* `alternate-selected-control-text` - The text on a selected surface in a list or table. _Deprecated_
* `control-background` - The background of a large interface element, such as a browser or table.
* `control` - The surface of a control.
* `control-text` -The text of a control that isnt disabled.
@@ -339,21 +338,6 @@ Returns `string` - Can be `dark`, `light` or `unknown`.
Gets the macOS appearance setting that is currently applied to your application,
maps to [NSApplication.effectiveAppearance](https://developer.apple.com/documentation/appkit/nsapplication/2967171-effectiveappearance?language=objc)
### `systemPreferences.getAppLevelAppearance()` _macOS_ _Deprecated_
Returns `string` | `null` - Can be `dark`, `light` or `unknown`.
Gets the macOS appearance setting that you have declared you want for
your application, maps to [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc).
You can use the `setAppLevelAppearance` API to set this value.
### `systemPreferences.setAppLevelAppearance(appearance)` _macOS_ _Deprecated_
* `appearance` string | null - Can be `dark` or `light`
Sets the appearance setting for your application, this should override the
system default and override the value of `getEffectiveAppearance`.
### `systemPreferences.canPromptTouchID()` _macOS_
Returns `boolean` - whether or not this device has the ability to use Touch ID.
@@ -417,15 +401,9 @@ Returns an object with system animation settings.
## Properties
### `systemPreferences.appLevelAppearance` _macOS_ _Deprecated_
### `systemPreferences.accessibilityDisplayShouldReduceTransparency()` _macOS_
A `string` property that can be `dark`, `light` or `unknown`. It determines the macOS appearance setting for
your application. This maps to values in: [NSApplication.appearance](https://developer.apple.com/documentation/appkit/nsapplication/2967170-appearance?language=objc). Setting this will override the
system default as well as the value of `getEffectiveAppearance`.
Possible values that can be set are `dark` and `light`, and possible return values are `dark`, `light`, and `unknown`.
This property is only available on macOS 10.14 Mojave or newer.
A `boolean` property which determines whether the app avoids using semitransparent backgrounds. This maps to [NSWorkspace.accessibilityDisplayShouldReduceTransparency](https://developer.apple.com/documentation/appkit/nsworkspace/1533006-accessibilitydisplayshouldreduce)
### `systemPreferences.effectiveAppearance` _macOS_ _Readonly_

View File

@@ -29,7 +29,7 @@ Process: [Main](../glossary.md#main-process)<br />
* `inherit`: equivalent to \['ignore', 'inherit', 'inherit']
* `serviceName` string (optional) - Name of the process that will appear in `name` property of
[`child-process-gone` event of `app`](app.md#event-child-process-gone).
Default is `node.mojom.NodeService`.
Default is `Node Utility Process`.
* `allowLoadingUnsignedLibraries` boolean (optional) _macOS_ - With this flag, the utility process will be
launched via the `Electron Helper (Plugin).app` helper executable on macOS, which can be
codesigned with `com.apple.security.cs.disable-library-validation` and

View File

@@ -1211,7 +1211,7 @@ Returns `string` - The user agent for this web page.
* `css` string
* `options` Object (optional)
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
Returns `Promise<string>` - A promise that resolves with a key for the inserted CSS that can later be used to remove the CSS via `contents.removeInsertedCSS(key)`.

View File

@@ -113,7 +113,7 @@ webFrame.setSpellCheckProvider('en-US', {
* `css` string
* `options` Object (optional)
* `cssOrigin` string (optional) - Can be either 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
* `cssOrigin` string (optional) - Can be 'user' or 'author'. Sets the [cascade origin](https://www.w3.org/TR/css3-cascade/#cascade-origin) of the inserted stylesheet. Default is 'author'.
Returns `string` - A key for the inserted CSS that can later be used to remove
the CSS via `webFrame.removeInsertedCSS(key)`.

View File

@@ -61,6 +61,41 @@ w.webContents.getPrintersAsync().then((printers) => {
})
```
### Removed: `systemPreferences.{get,set}AppLevelAppearance` and `systemPreferences.appLevelAppearance`
The `systemPreferences.getAppLevelAppearance` and `systemPreferences.setAppLevelAppearance`
methods have been removed, as well as the `systemPreferences.appLevelAppearance` property.
Use the `nativeTheme` module instead.
```js
// Removed
systemPreferences.getAppLevelAppearance()
// Replace with
nativeTheme.shouldUseDarkColors
// Removed
systemPreferences.appLevelAppearance
// Replace with
nativeTheme.shouldUseDarkColors
// Removed
systemPreferences.setAppLevelAppearance('dark')
// Replace with
nativeTheme.themeSource = 'dark'
```
### Removed: `alternate-selected-control-text` value for `systemPreferences.getColor`
The `alternate-selected-control-text` value for `systemPreferences.getColor`
has been removed. Use `selected-content-background` instead.
```js
// Removed
systemPreferences.getColor('alternate-selected-control-text')
// Replace with
systemPreferences.getColor('selected-content-background')
```
## Planned Breaking API Changes (26.0)
### Deprecated: `webContents.getPrinters`
@@ -635,6 +670,18 @@ to open synchronously scriptable child windows, among other incompatibilities.
See the documentation for [window.open in Electron](api/window-open.md)
for more details.
### Deprecated: `app.runningUnderRosettaTranslation`
The `app.runningUnderRosettaTranslation` property has been deprecated.
Use `app.runningUnderARM64Translation` instead.
```js
// Deprecated
console.log(app.runningUnderRosettaTranslation)
// Replace with
console.log(app.runningUnderARM64Translation)
```
## Planned Breaking API Changes (14.0)
### Removed: `remote` module

View File

@@ -7,14 +7,20 @@ function createWindow () {
height: 600
})
win.setRepresentedFilename(os.homedir())
win.setDocumentEdited(true)
win.loadFile('index.html')
}
app.whenReady().then(() => {
const win = new BrowserWindow()
createWindow()
win.setRepresentedFilename(os.homedir())
win.setDocumentEdited(true)
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
@@ -22,9 +28,3 @@ app.on('window-all-closed', () => {
app.quit()
}
})
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})

View File

@@ -22,34 +22,101 @@ There are a few ways that you can set up testing using WebDriver.
Node.js package for testing with WebDriver. Its ecosystem also includes various plugins
(e.g. reporter and services) that can help you put together your test setup.
If you already have an existing WebdriverIO setup, it is recommended to update your dependencies and validate your existing configuration with how it is [outlined in the docs](https://webdriver.io/docs/desktop-testing/electron#configuration).
#### Install the test runner
First you need to run the WebdriverIO starter toolkit in your project root directory:
If you don't use WebdriverIO in your project yet, you can add it by running the starter toolkit in your project root directory:
```sh npm2yarn
npx wdio . --yes
npm init wdio@latest ./
```
This installs all necessary packages for you and generates a `wdio.conf.js` configuration file.
This starts a configuration wizard that helps you put together the right setup, installs all necessary packages, and generates a `wdio.conf.js` configuration file. Make sure to select _"Desktop Testing - of Electron Applications"_ on one of the first questions asking _"What type of testing would you like to do?"_.
#### Connect WDIO to your Electron app
Update the capabilities in your configuration file to point to your Electron app binary:
After running the configuration wizard, your `wdio.conf.js` should include roughly the following content:
```javascript title='wdio.conf.js'
exports.config = {
```js title='wdio.conf.js' @ts-nocheck
export const config = {
// ...
services: ['electron'],
capabilities: [{
browserName: 'chrome',
'goog:chromeOptions': {
binary: '/path/to/your/electron/binary', // Path to your Electron binary.
args: [/* cli arguments */] // Optional, perhaps 'app=' + /path/to/your/app/
browserName: 'electron',
'wdio:electronServiceOptions': {
// WebdriverIO can automatically find your bundled application
// if you use Electron Forge or electron-builder, otherwise you
// can define it here, e.g.:
// appBinaryPath: './path/to/bundled/application.exe',
appArgs: ['foo', 'bar=baz']
}
}]
// ...
}
```
#### Write your tests
Use the [WebdriverIO API](https://webdriver.io/docs/api) to interact with elements on the screen. The framework provides custom "matchers" that make asserting the state of your application easy, e.g.:
```js @ts-nocheck
import { browser, $, expect } from '@wdio/globals'
describe('keyboard input', () => {
it('should detect keyboard input', async () => {
await browser.keys(['y', 'o'])
await expect($('keypress-count')).toHaveText('YO')
})
})
```
Furthermore, WebdriverIO allows you to access Electron APIs to get static information about your application:
```js @ts-nocheck
import { browser, $, expect } from '@wdio/globals'
describe('when the make smaller button is clicked', () => {
it('should decrease the window height and width by 10 pixels', async () => {
const boundsBefore = await browser.electron.browserWindow('getBounds')
expect(boundsBefore.width).toEqual(210)
expect(boundsBefore.height).toEqual(310)
await $('.make-smaller').click()
const boundsAfter = await browser.electron.browserWindow('getBounds')
expect(boundsAfter.width).toEqual(200)
expect(boundsAfter.height).toEqual(300)
})
})
```
or to retrieve other Electron process information:
```js @ts-nocheck
import fs from 'node:fs'
import path from 'node:path'
import { browser, expect } from '@wdio/globals'
const packageJson = JSON.parse(fs.readFileSync(path.join(__dirname, '..', 'package.json'), { encoding: 'utf-8' }))
const { name, version } = packageJson
describe('electron APIs', () => {
it('should retrieve app metadata through the electron API', async () => {
const appName = await browser.electron.app('getName')
expect(appName).toEqual(name)
const appVersion = await browser.electron.app('getVersion')
expect(appVersion).toEqual(version)
})
it('should pass args through to the launched application', async () => {
// custom args are set in the wdio.conf.js file as they need to be set before WDIO starts
const argv = await browser.electron.mainProcess('argv')
expect(argv).toContain('--foo')
expect(argv).toContain('--bar=baz')
})
})
```
#### Run your tests
To run your tests:
@@ -58,6 +125,12 @@ To run your tests:
$ npx wdio run wdio.conf.js
```
WebdriverIO helps launch and shut down the application for you.
#### More documentation
Find more documentation on Mocking Electron APIs and other useful resources in the [official WebdriverIO documentation](https://webdriver.io/docs/desktop-testing/electron).
### With Selenium
[Selenium](https://www.selenium.dev/) is a web automation framework that

View File

@@ -9,12 +9,13 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
| Electron | Alpha | Beta | Stable | EOL | Chrome | Node | Supported |
| ------- | ----- | ------- | ------ | ------ | ---- | ---- | ---- |
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | TBD | M118 | TBD | ✅ |
| 28.0.0 | 2023-Oct-11 | 2023-Nov-6 | 2023-Dec-5 | TBD | M120 | TBD | ✅ |
| 27.0.0 | 2023-Aug-17 | 2023-Sep-13 | 2023-Oct-10 | 2024-Apr-16 | M118 | v18.17 | ✅ |
| 26.0.0 | 2023-Jun-01 | 2023-Jun-27 | 2023-Aug-15 | 2024-Feb-27 | M116 | v18.16 | ✅ |
| 25.0.0 | 2023-Apr-10 | 2023-May-02 | 2023-May-30 | 2024-Jan-02 | M114 | v18.15 | ✅ |
| 24.0.0 | 2022-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | |
| 24.0.0 | 2023-Feb-09 | 2023-Mar-07 | 2023-Apr-04 | 2023-Oct-10 | M112 | v18.14 | 🚫 |
| 23.0.0 | 2022-Dec-01 | 2023-Jan-10 | 2023-Feb-07 | 2023-Aug-15 | M110 | v18.12 | 🚫 |
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-Oct-10 | M108 | v16.17 | |
| 22.0.0 | 2022-Sep-29 | 2022-Oct-25 | 2022-Nov-29 | 2023-Oct-10 | M108 | v16.17 | 🚫 |
| 21.0.0 | 2022-Aug-04 | 2022-Aug-30 | 2022-Sep-27 | 2023-Apr-04 | M106 | v16.16 | 🚫 |
| 20.0.0 | 2022-May-26 | 2022-Jun-21 | 2022-Aug-02 | 2023-Feb-07 | M104 | v16.15 | 🚫 |
| 19.0.0 | 2022-Mar-31 | 2022-Apr-26 | 2022-May-24 | 2022-Nov-29 | M102 | v16.14 | 🚫 |
@@ -48,12 +49,6 @@ check out our [Electron Versioning](./electron-versioning.md) doc.
* Since Electron 6, Electron major versions have been targeting every other Chromium major version. Each Electron stable should happen on the same day as Chrome stable ([see blog post](https://www.electronjs.org/blog/12-week-cadence)).
* Since Electron 16, Electron has been releasing major versions on an 8-week cadence in accordance to Chrome's change to a 4-week release cadence ([see blog post](https://www.electronjs.org/blog/8-week-cadence)).
:::info Chrome release dates
Chromium has the own public release schedule [here](https://chromiumdash.appspot.com/schedule).
:::
## Version support policy
:::info
@@ -78,6 +73,38 @@ and the version prior to that receives the vast majority of those fixes
as time and bandwidth warrants. The oldest supported release line will receive
only security fixes directly.
### Chromium version support
:::info Chromium release schedule
Chromium's public release schedule is [here](https://chromiumdash.appspot.com/schedule).
:::
Electron targets Chromium even-number versions, releasing every 8 weeks in concert
with Chromium's 4-week release schedule. For example, Electron 26 uses Chromium 116, while Electron 27 uses Chromium 118.
### Node.js version support
Electron upgrades its `main` branch to even-number versions of Node.js when they enter Active LTS. The schedule
is as follows:
<img src="https://raw.githubusercontent.com/nodejs/Release/main/schedule.svg?sanitize=true" alt="Releases">
As a rule, stable branches of Electron do not receive Node.js upgrades after they have been cut.
If Electron has recently updated its `main` branch to a new major version of Node.js, the next stable
branch to be cut will be released with the new version.
Patch upgrades of Node that contain significant security or bug fixes, and are submitted
more than 2 weeks prior to a stable release date, will be accepted into an Electron alpha
or beta release branch.
Minor upgrades of Node that contain significant security or bug fixes, and are submitted
more than 2 weeks prior to a stable release date may be accepted into an Electron alpha or
beta release branch on a case-by-case basis. These requests will be reviewed and voted on
by the [Releases Working Group](https://github.com/electron/governance/tree/main/wg-releases),
to ensure minimal disruption for developers who may be consuming alpha or beta releases.
### Breaking API changes
When an API is changed or removed in a way that breaks existing functionality, the

View File

@@ -228,6 +228,23 @@ channel with a renderer process using [`MessagePort`][]s. An Electron app can
always prefer the [UtilityProcess][] API over Node.js [`child_process.fork`][] API when
there is need to fork a child process from the main process.
## Process-specific module aliases (TypeScript)
Electron's npm package also exports subpaths that contain a subset of
Electron's TypeScript type definitions.
- `electron/main` includes types for all main process modules.
- `electron/renderer` includes types for all renderer process modules.
- `electron/common` includes types for modules that can run in main and renderer processes.
These aliases have no impact on runtime, but can be used for typechecking
and autocomplete.
```js title="Usage example"
const { app } = require('electron/main')
const { shell } = require('electron/common')
```
[window-mdn]: https://developer.mozilla.org/en-US/docs/Web/API/Window
[`MessagePort`]: https://developer.mozilla.org/en-US/docs/Web/API/MessagePort
[`child_process.fork`]: https://nodejs.org/dist/latest-v16.x/docs/api/child_process.html#child_processforkmodulepath-args-options

View File

@@ -91,14 +91,14 @@ version: '0.1'
summary: Hello World Electron app
description: |
Simple Hello World Electron app as an example
base: core18
base: core22
confinement: strict
grade: stable
apps:
electron-packager-hello-world:
command: electron-quick-start/electron-quick-start --no-sandbox
extensions: [gnome-3-34]
extensions: [gnome]
plugs:
- browser-support
- network
@@ -237,6 +237,34 @@ apps:
desktop: usr/share/applications/desktop.desktop
```
## Optional: Enabling desktop capture
Capturing the desktop requires PipeWire library in some Linux configurations that use
the Wayland protocol. To bundle PipeWire with your application, ensure that the base
snap is set to `core22` or newer. Next, create a part called `pipewire` and add it to
the `after` section of your application:
```yaml
pipewire:
plugin: nil
build-packages: [libpipewire-0.3-dev]
stage-packages: [pipewire]
prime:
- usr/lib/*/pipewire-*
- usr/lib/*/spa-*
- usr/lib/*/libpipewire*.so*
- usr/share/pipewire
```
Finally, configure your application's environment for PipeWire:
```yaml
environment:
SPA_PLUGIN_DIR: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/spa-0.2
PIPEWIRE_CONFIG_NAME: $SNAP/usr/share/pipewire/pipewire.conf
PIPEWIRE_MODULE_DIR: $SNAP/usr/lib/$CRAFT_ARCH_TRIPLET/pipewire-0.3
```
[snapcraft-syntax]: https://docs.snapcraft.io/build-snaps/syntax
[electron-packager]: https://github.com/electron/electron-packager
[electron-forge]: https://github.com/electron/forge

View File

@@ -222,14 +222,26 @@ with CommonJS module syntax:
- [app][app], which controls your application's event lifecycle.
- [BrowserWindow][browser-window], which creates and manages app windows.
:::info Capitalization conventions
<details><summary>Module capitalization conventions</summary>
You might have noticed the capitalization difference between the **a**pp
and **B**rowser**W**indow modules. Electron follows typical JavaScript conventions here,
where PascalCase modules are instantiable class constructors (e.g. BrowserWindow, Tray,
Notification) whereas camelCase modules are not instantiable (e.g. app, ipcRenderer, webContents).
:::
</details>
<details><summary>Typed import aliases</summary>
For better type checking when writing TypeScript code, you can choose to import
main process modules from <code>electron/main</code>.
```js
const { app, BrowserWindow } = require('electron/main')
```
For more information, see the [Process Model docs](../tutorial/process-model.md#process-specific-module-aliases-typescript).
</details>
:::warning ES Modules in Electron

View File

@@ -676,6 +676,8 @@ filenames = {
]
lib_sources_extensions = [
"shell/browser/extensions/api/extension_action/extension_action_api.cc",
"shell/browser/extensions/api/extension_action/extension_action_api.h",
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
"shell/browser/extensions/api/resources_private/resources_private_api.cc",

View File

@@ -1,4 +1,5 @@
import { Buffer } from 'buffer';
import { constants } from 'fs';
import * as path from 'path';
import * as util from 'util';
import type * as Crypto from 'crypto';
@@ -67,18 +68,22 @@ const gid = process.getgid?.() ?? 0;
const fakeTime = new Date();
enum AsarFileType {
kFile = (constants as any).UV_DIRENT_FILE,
kDirectory = (constants as any).UV_DIRENT_DIR,
kLink = (constants as any).UV_DIRENT_LINK,
}
const fileTypeToMode = new Map<AsarFileType, number>([
[AsarFileType.kFile, constants.S_IFREG],
[AsarFileType.kDirectory, constants.S_IFDIR],
[AsarFileType.kLink, constants.S_IFLNK]
]);
const asarStatsToFsStats = function (stats: NodeJS.AsarFileStat) {
const { Stats, constants } = require('fs');
const { Stats } = require('fs');
let mode = constants.S_IROTH ^ constants.S_IRGRP ^ constants.S_IRUSR ^ constants.S_IWUSR;
if (stats.isFile) {
mode ^= constants.S_IFREG;
} else if (stats.isDirectory) {
mode ^= constants.S_IFDIR;
} else if (stats.isLink) {
mode ^= constants.S_IFLNK;
}
const mode = constants.S_IROTH | constants.S_IRGRP | constants.S_IRUSR | constants.S_IWUSR | fileTypeToMode.get(stats.type)!;
return new Stats(
1, // dev
@@ -241,7 +246,6 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
const logASARAccess = (asarPath: string, filePath: string, offset: number) => {
if (!process.env.ELECTRON_LOG_ASAR_READS) return;
if (!logFDs.has(asarPath)) {
const path = require('path');
const logFilename = `${path.basename(asarPath, '.asar')}-access-log.txt`;
const logPath = path.join(require('os').tmpdir(), logFilename);
logFDs.set(asarPath, fs.openSync(logPath, 'a'));
@@ -657,13 +661,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
nextTick(callback!, [error]);
return;
}
if (stats.isFile) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
} else if (stats.isDirectory) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
} else if (stats.isLink) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
}
dirents.push(new fs.Dirent(file, stats.type));
}
nextTick(callback!, [null, dirents]);
return;
@@ -700,13 +698,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
if (!stats) {
throw createError(AsarError.NOT_FOUND, { asarPath, filePath: childPath });
}
if (stats.isFile) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_FILE));
} else if (stats.isDirectory) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_DIR));
} else if (stats.isLink) {
dirents.push(new fs.Dirent(file, fs.constants.UV_DIRENT_LINK));
}
dirents.push(new fs.Dirent(file, stats.type));
}
return dirents;
}
@@ -757,7 +749,7 @@ export const wrapFsWithAsar = (fs: Record<string, any>) => {
const stats = archive.stat(filePath);
if (!stats) return -34;
return (stats.isDirectory) ? 1 : 0;
return (stats.type === AsarFileType.kDirectory) ? 1 : 0;
};
// Calling mkdir for directory inside asar archive should throw ENOTDIR

View File

@@ -114,5 +114,11 @@ for (const name of events) {
}
// Deprecation.
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone');
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone');
deprecate.event(app, 'gpu-process-crashed', 'child-process-gone', () => {
// the old event is still emitted by App::OnGpuProcessCrashed()
return undefined;
});
deprecate.event(app, 'renderer-process-crashed', 'render-process-gone', (event: Electron.Event, webContents: Electron.WebContents, details: Electron.RenderProcessGoneDetails) => {
return [event, webContents, details.reason === 'killed'];
});

View File

@@ -1,33 +1,5 @@
import * as deprecate from '@electron/internal/common/deprecate';
const { systemPreferences } = process._linkedBinding('electron_browser_system_preferences');
if ('getAppLevelAppearance' in systemPreferences) {
const nativeALAGetter = systemPreferences.getAppLevelAppearance;
const nativeALASetter = systemPreferences.setAppLevelAppearance;
const warnALA = deprecate.warnOnce('appLevelAppearance');
const warnALAGetter = deprecate.warnOnce('getAppLevelAppearance function');
const warnALASetter = deprecate.warnOnce('setAppLevelAppearance function');
Object.defineProperty(systemPreferences, 'appLevelAppearance', {
get: () => {
warnALA();
return nativeALAGetter.call(systemPreferences);
},
set: (appearance) => {
warnALA();
nativeALASetter.call(systemPreferences, appearance);
}
});
systemPreferences.getAppLevelAppearance = () => {
warnALAGetter();
return nativeALAGetter.call(systemPreferences);
};
systemPreferences.setAppLevelAppearance = (appearance) => {
warnALASetter();
nativeALASetter.call(systemPreferences, appearance);
};
}
if ('getEffectiveAppearance' in systemPreferences) {
const nativeEAGetter = systemPreferences.getEffectiveAppearance;
Object.defineProperty(systemPreferences, 'effectiveAppearance', {

View File

@@ -337,49 +337,53 @@ WebContents.prototype.printToPDF = async function (options) {
// 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');
}
if (typeof options !== 'object') {
throw new Error('webContents.print(): Invalid print settings specified.');
}
// 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.');
}
const printSettings: Record<string, any> = { ...options };
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}`);
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.');
}
printSettings.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];
printSettings.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);
this._print(printSettings, callback);
} else {
this._print(options);
this._print(printSettings);
}
} else {
console.error('Error: Printing feature is disabled.');
@@ -653,8 +657,8 @@ WebContents.prototype._init = function () {
ipcMain.emit(channel, event, message);
});
this.on('crashed', (event, ...args) => {
app.emit('renderer-process-crashed', event, this, ...args);
deprecate.event(this, 'crashed', 'render-process-gone', (event: Electron.Event, details: Electron.RenderProcessGoneDetails) => {
return [event, details.reason === 'killed'];
});
this.on('render-process-gone', (event, details) => {

View File

@@ -66,14 +66,17 @@ export function renameFunction<T extends Function> (fn: T, newName: string): T {
}
// change the name of an event
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string) {
export function event (emitter: NodeJS.EventEmitter, oldName: string, newName: string, transformer: (...args: any[]) => any[] | undefined = (...args) => args) {
const warn = newName.startsWith('-') /* internal event */
? warnOnce(`${oldName} event`)
: warnOnce(`${oldName} event`, `${newName} event`);
return emitter.on(newName, function (this: NodeJS.EventEmitter, ...args) {
if (this.listenerCount(oldName) !== 0) {
warn();
this.emit(oldName, ...args);
const transformedArgs = transformer(...args);
if (transformedArgs) {
this.emit(oldName, ...transformedArgs);
}
}
});
}

View File

@@ -131,3 +131,5 @@ build_remove_ent_content_analysis_assert.patch
fix_activate_background_material_on_windows.patch
fix_move_autopipsettingshelper_behind_branding_buildflag.patch
revert_remove_the_allowaggressivethrottlingwithwebsocket_feature.patch
revert_same_party_cookie_attribute_removal.patch
crash_gpu_process_and_clear_shader_cache_when_skia_reports.patch

View File

@@ -33,10 +33,10 @@ index 41ce32113ec2679b76d5a4fd69a7109c832ac7a1..1cd35794bf78f3d92b42634d9494c85a
"//base",
"//build:branding_buildflags",
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 139ade66fbaf20f7c41275f5f84acf81afcc03f7..f7272dea8af27026a9094bdc9a3c5a3b10eee42b 100644
index 31bf3d854d9a672e535f747fb8734d66ac0c37e9..cad2387217a73ec5a7533fc121ea7b77cd6995ae 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -4724,7 +4724,7 @@ static_library("browser") {
@@ -4726,7 +4726,7 @@ static_library("browser") {
# On Windows, the hashes are embedded in //chrome:chrome_initial rather
# than here in :chrome_dll.
@@ -46,10 +46,10 @@ index 139ade66fbaf20f7c41275f5f84acf81afcc03f7..f7272dea8af27026a9094bdc9a3c5a3b
sources += [ "certificate_viewer_stub.cc" ]
}
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index fff07e866add0af2c395412ad80fb6a447ac801e..2dc1c74310fae6324e9997023c7f5ba5d7a32ca2 100644
index a315f817a8977d36e52b8f7c81d9e6778d3dcca2..dc046a004d6f4b2e9f1ec4b9423f293cfecaff8d 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -6839,7 +6839,6 @@ test("unit_tests") {
@@ -6841,7 +6841,6 @@ test("unit_tests") {
deps += [
"//chrome:other_version",
@@ -57,7 +57,7 @@ index fff07e866add0af2c395412ad80fb6a447ac801e..2dc1c74310fae6324e9997023c7f5ba5
"//chrome//services/util_win:unit_tests",
"//chrome/app:chrome_dll_resources",
"//chrome/app:win_unit_tests",
@@ -6865,6 +6864,10 @@ test("unit_tests") {
@@ -6867,6 +6866,10 @@ test("unit_tests") {
"//ui/resources",
]
@@ -68,7 +68,7 @@ index fff07e866add0af2c395412ad80fb6a447ac801e..2dc1c74310fae6324e9997023c7f5ba5
ldflags = [
"/DELAYLOAD:api-ms-win-core-winrt-error-l1-1-0.dll",
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
@@ -7832,7 +7835,6 @@ test("unit_tests") {
@@ -7834,7 +7837,6 @@ test("unit_tests") {
}
deps += [
@@ -76,7 +76,7 @@ index fff07e866add0af2c395412ad80fb6a447ac801e..2dc1c74310fae6324e9997023c7f5ba5
"//chrome/browser/apps:icon_standardizer",
"//chrome/browser/apps/app_service",
"//chrome/browser/apps/app_service:app_registry_cache_waiter",
@@ -7919,6 +7921,10 @@ test("unit_tests") {
@@ -7921,6 +7923,10 @@ test("unit_tests") {
"//ui/webui/resources/js/browser_command:mojo_bindings",
]

View File

@@ -9,10 +9,10 @@ potentially prevent a window from being created.
TODO(loc): this patch is currently broken.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 50d873e238b04eb6d461dc929d98dfe171cc491c..586aa87098bd3db10440fe865a02c05e7b3be14f 100644
index af16b1053e1f42887bf0fde97bba30a377857872..ef79bf0e27bd0c5eb9fe5f0aef1cf6c6a2900e13 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -8206,6 +8206,7 @@ void RenderFrameHostImpl::CreateNewWindow(
@@ -8224,6 +8224,7 @@ void RenderFrameHostImpl::CreateNewWindow(
last_committed_origin_, params->window_container_type,
params->target_url, params->referrer.To<Referrer>(),
params->frame_name, params->disposition, *params->features,

View File

@@ -14,7 +14,7 @@ This change patches it out to prevent the DCHECK.
It can be removed once/if we see a better solution to the problem.
diff --git a/content/browser/site_instance_impl.cc b/content/browser/site_instance_impl.cc
index a478ec236b193a42296aa30be384b54973f2ff89..e65c53f1ad3f0b79bd820970436788ae4e5b61fe 100644
index 36cead8ff426f915afbdb0e4650effb4454edb64..cecabbaa8aa49a887b4f2b26c2d7d92ceeee34e9 100644
--- a/content/browser/site_instance_impl.cc
+++ b/content/browser/site_instance_impl.cc
@@ -205,7 +205,7 @@ scoped_refptr<SiteInstanceImpl> SiteInstanceImpl::CreateForGuest(

View File

@@ -6,7 +6,7 @@ Subject: chore: patch out Profile methods in titlebar_config
Make this code linkable in Electron by removing Profile references.
diff --git a/chrome/browser/win/titlebar_config.cc b/chrome/browser/win/titlebar_config.cc
index 92d0e8165a264c7ef2701a66e0f7179f0d080f47..b0c91778399f811a5d1b0f208488667cb38459e1 100644
index f088a7071b1e0e1e05aee5637484b1dea3e2a6fa..8d411e550f6a8ca1a4070bf5d5719703f90b3dfa 100644
--- a/chrome/browser/win/titlebar_config.cc
+++ b/chrome/browser/win/titlebar_config.cc
@@ -19,8 +19,10 @@ BASE_FEATURE(kWindows11MicaTitlebar,

View File

@@ -0,0 +1,70 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Le Hoang Quyen <lehoangquyen@chromium.org>
Date: Tue, 31 Oct 2023 08:52:25 +0000
Subject: Crash GPU process and clear shader cache when skia reports
compileError.
Sometimes Skia failed to compile the cached GLSL because the driver had
been changed but GL_RENDERER was still the same. In this case, we better
crash the GPU process and signal the browser to clear the cache & let
Skia regenerate the GLSL in the next run.
Even if the compile failure wasn't caused by the cached GLSL. It's still
better to crash the GPU process and let the shaders be re-generated.
Because a failed compilation would have resulted in wrong rendering
even if we had allowed the process to continue its execution.
Bug: 1442633
Change-Id: Ia0e36bd4674877de5be451a6ea9c4e7fa5e34e8e
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4988290
Reviewed-by: Sunny Sachanandani <sunnyps@chromium.org>
Commit-Queue: Quyen Le <lehoangquyen@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1217461}
diff --git a/gpu/command_buffer/service/shared_context_state.cc b/gpu/command_buffer/service/shared_context_state.cc
index f675b3b4fb0c1892f7ddbec7aa4e2284ff3dfcba..f5d1c60ee99b84641a46fbefa9915eb409690098 100644
--- a/gpu/command_buffer/service/shared_context_state.cc
+++ b/gpu/command_buffer/service/shared_context_state.cc
@@ -4,6 +4,7 @@
#include "gpu/command_buffer/service/shared_context_state.h"
+#include "base/immediate_crash.h"
#include "base/observer_list.h"
#include "base/strings/stringprintf.h"
#include "base/system/sys_info.h"
@@ -99,6 +100,13 @@ void SharedContextState::compileError(const char* shader, const char* errors) {
<< "------------------------\n"
<< shader << "\nErrors:\n"
<< errors;
+
+ // Increase shader cache shm count and crash the GPU process so that the
+ // browser process would clear the cache.
+ GpuProcessShmCount::ScopedIncrement increment(
+ use_shader_cache_shm_count_.get());
+
+ base::ImmediateCrash();
}
}
@@ -294,6 +302,7 @@ bool SharedContextState::InitializeGanesh(
gl::ProgressReporter* progress_reporter) {
progress_reporter_ = progress_reporter;
gr_shader_cache_ = cache;
+ use_shader_cache_shm_count_ = use_shader_cache_shm_count;
size_t max_resource_cache_bytes;
size_t glyph_cache_max_texture_bytes;
diff --git a/gpu/command_buffer/service/shared_context_state.h b/gpu/command_buffer/service/shared_context_state.h
index 00aab5227f30a3f56b2b5c63ee5f627aa2a6c03b..4b9cf8ac797f6d5f9146fb1be43ff78a756d4ee5 100644
--- a/gpu/command_buffer/service/shared_context_state.h
+++ b/gpu/command_buffer/service/shared_context_state.h
@@ -391,6 +391,8 @@ class GPU_GLES2_EXPORT SharedContextState
std::vector<uint8_t> scratch_deserialization_buffer_;
raw_ptr<gpu::raster::GrShaderCache, DanglingUntriaged> gr_shader_cache_ =
nullptr;
+ raw_ptr<GpuProcessShmCount, DanglingUntriaged> use_shader_cache_shm_count_ =
+ nullptr;
// |need_context_state_reset| is set whenever Skia may have altered the
// driver's GL state.

View File

@@ -6,10 +6,10 @@ Subject: disable_hidden.patch
Electron uses this to disable background throttling for hidden windows.
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 9e946e02bca276a877defacf6cf6cb54f882ceba..149ead7bbf52ad127747c5f80f0e35a13203502a 100644
index 916c3f324ed2161d1f9ad1a023cc0318a1b72628..2d946e29c94a07a1aa4f4b6018ab1b564440f55d 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -801,6 +801,9 @@ void RenderWidgetHostImpl::WasHidden() {
@@ -807,6 +807,9 @@ void RenderWidgetHostImpl::WasHidden() {
return;
}

View File

@@ -13,10 +13,10 @@ uses internally for things like menus and devtools.
We can remove this patch once it has in some shape been upstreamed.
diff --git a/ui/native_theme/native_theme.cc b/ui/native_theme/native_theme.cc
index f6556e141a76b0766f672bfa5819256e635c60af..06c7ac178cefc149732294ed790f2b7cbb328d34 100644
index af49c133fb2b176139263553d2afff33e96a94b1..699c38b2046e267619eef103c83eff258887e0c0 100644
--- a/ui/native_theme/native_theme.cc
+++ b/ui/native_theme/native_theme.cc
@@ -153,6 +153,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
@@ -156,6 +156,8 @@ NativeTheme::NativeTheme(bool should_use_dark_colors,
NativeTheme::~NativeTheme() = default;
bool NativeTheme::ShouldUseDarkColors() const {
@@ -26,7 +26,7 @@ index f6556e141a76b0766f672bfa5819256e635c60af..06c7ac178cefc149732294ed790f2b7c
}
diff --git a/ui/native_theme/native_theme.h b/ui/native_theme/native_theme.h
index 6f51a8ffec973d6c2acacabb951c7cc4e36b639c..889e655fccc115faae932236cc28c6386cf19c1e 100644
index 341248a6b15b280c382c965009540fbdb64b0978..c9bead90658ac0e2d503c90c6ce380a318fee457 100644
--- a/ui/native_theme/native_theme.h
+++ b/ui/native_theme/native_theme.h
@@ -433,6 +433,23 @@ class NATIVE_THEME_EXPORT NativeTheme {
@@ -53,7 +53,7 @@ index 6f51a8ffec973d6c2acacabb951c7cc4e36b639c..889e655fccc115faae932236cc28c638
// Returns a shared instance of the native theme that should be used for web
// rendering. Do not use it in a normal application context (i.e. browser).
// The returned object should not be deleted by the caller. This function is
@@ -643,6 +660,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
@@ -654,6 +671,7 @@ class NATIVE_THEME_EXPORT NativeTheme {
bool inverted_colors_ = false;
PreferredColorScheme preferred_color_scheme_ = PreferredColorScheme::kLight;
PreferredContrast preferred_contrast_ = PreferredContrast::kNoPreference;
@@ -62,10 +62,10 @@ index 6f51a8ffec973d6c2acacabb951c7cc4e36b639c..889e655fccc115faae932236cc28c638
SEQUENCE_CHECKER(sequence_checker_);
};
diff --git a/ui/native_theme/native_theme_win.cc b/ui/native_theme/native_theme_win.cc
index faa15be0b3e08360c702b32968d3b1633038d776..7a6c284143e873b408333fa2052e05863935cb89 100644
index 595b7185832126dd3d8ca85c445b835e5969adcb..58c64b98a0f94b0be7e7819999cf81dedf9bbe08 100644
--- a/ui/native_theme/native_theme_win.cc
+++ b/ui/native_theme/native_theme_win.cc
@@ -658,6 +658,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
@@ -663,6 +663,8 @@ bool NativeThemeWin::ShouldUseDarkColors() const {
// ...unless --force-dark-mode was specified in which case caveat emptor.
if (InForcedColorsMode() && !IsForcedDarkMode())
return false;

View File

@@ -514,7 +514,7 @@ index 796ae2688436eb07f19909641d1620dd02f10cdb..c9e0eee0b329caf46669b419b1cd10cf
waiting_on_draw_ack_ = true;
diff --git a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
index c70b0af70a68386c5d36833e621dd1b5cdc1522a..17e5c96cbb4ef2f575fd5ba7bd8b0c7bd58da5e7 100644
index 1c59eb0cdf1786a19f74f165acc3fb071dcf2fa1..ddb2389f548a8558f79d7cf32ffd6ce0a7751553 100644
--- a/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
+++ b/components/viz/service/frame_sinks/root_compositor_frame_sink_impl.cc
@@ -97,7 +97,8 @@ RootCompositorFrameSinkImpl::Create(

View File

@@ -17,7 +17,7 @@ policy->CanCommitOriginAndUrl.
Upstreamed at https://chromium-review.googlesource.com/c/chromium/src/+/3856266.
diff --git a/content/browser/renderer_host/navigation_request.cc b/content/browser/renderer_host/navigation_request.cc
index e91fb6b203b55d4937e9f4b4ed8fd5e8efb5aa10..855cb90260de04b90b8bbf4a8733e0869cda551d 100644
index 5cf177fc73dd2b3038754b11d23ad637e7709f88..72103151867a9c1154b83da83b52a5b3b7b988ed 100644
--- a/content/browser/renderer_host/navigation_request.cc
+++ b/content/browser/renderer_host/navigation_request.cc
@@ -7543,10 +7543,11 @@ NavigationRequest::GetOriginForURLLoaderFactoryAfterResponseWithDebugInfo() {

View File

@@ -25,10 +25,10 @@ index c9a13aee1e64f359cd1d5c2e440b4df204420997..7790c311400fc84bfda6c99e1ebd8da7
// Returns true if duplex mode is set.
bool SetDuplexModeInPrintSettings(mojom::DuplexMode mode);
diff --git a/printing/printing_context_mac.mm b/printing/printing_context_mac.mm
index ee900c7541af99c61844920433ae39e2648ae90b..59137008aeddc03d60c58a463206dc91a0ef5c1f 100644
index 7c9204db9b4c8f36e4c7405e3bd9c8b311753f04..4bff296ea2c55175416aaa778856e6182866664f 100644
--- a/printing/printing_context_mac.mm
+++ b/printing/printing_context_mac.mm
@@ -464,7 +464,8 @@ void ApplySystemPrintDialogData(
@@ -473,7 +473,8 @@ void ApplySystemPrintDialogData(
!SetCollateInPrintSettings(settings_->collate()) ||
!SetDuplexModeInPrintSettings(settings_->duplex_mode()) ||
!SetOutputColor(static_cast<int>(settings_->color())) ||
@@ -38,7 +38,7 @@ index ee900c7541af99c61844920433ae39e2648ae90b..59137008aeddc03d60c58a463206dc91
return OnError();
}
}
@@ -617,6 +618,22 @@ void ApplySystemPrintDialogData(
@@ -626,6 +627,22 @@ void ApplySystemPrintDialogData(
return PMSetCopies(print_settings, copies, false) == noErr;
}
@@ -100,10 +100,10 @@ index 07847521e7217c78480205812a73cc89503c00d2..586e866ca7ec0eb0b573d23e3bd95792
} else {
// No need to bother, we don't know how many pages are available.
diff --git a/ui/gtk/printing/print_dialog_gtk.cc b/ui/gtk/printing/print_dialog_gtk.cc
index e270fa36d775333aaa30f1ff0104062c544d1058..e4a6213e19e4f23834802784a43db22c9d02d891 100644
index dcabfdab6cc5a0f0a79f797d3660118b780bd110..bcbfeef775e40c1b0c1bbac49dd520e602bc4cb9 100644
--- a/ui/gtk/printing/print_dialog_gtk.cc
+++ b/ui/gtk/printing/print_dialog_gtk.cc
@@ -245,6 +245,24 @@ void PrintDialogGtk::UpdateSettings(
@@ -248,6 +248,24 @@ void PrintDialogGtk::UpdateSettings(
gtk_print_settings_set_n_copies(gtk_settings_, settings->copies());
gtk_print_settings_set_collate(gtk_settings_, settings->collate());

View File

@@ -75,7 +75,7 @@ index 3a815ebf505bd95fa7f6b61ba433d98fbfe20225..dbbebbdc1735bc14224dfcde0b7fe3a6
+
@end
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
index 94ac4fa8db42cb70fa5032a0c1eeb10ad94b8d9a..048cfe7b16d74845492c9317f1ed9790fed36250 100644
index 085d9821933390c781fe11d441910501bf22d601..6c79434e2a5b59267c9801ac23c318c9c320f019 100644
--- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
+++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.h
@@ -17,6 +17,7 @@ class NativeWidgetNSWindowBridge;
@@ -95,10 +95,10 @@ index 94ac4fa8db42cb70fa5032a0c1eeb10ad94b8d9a..048cfe7b16d74845492c9317f1ed9790
// The NSWindow used by BridgedNativeWidget. Provides hooks into AppKit that
// can only be accomplished by overriding methods.
diff --git a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
index 517333705c9b68706159bff2396c3ba1f8dc1f55..f11ce18fb4d1567eb53e6b9272424eecb40e51e1 100644
index 6e837d66209e6322324227bc596e40e56fccc495..3c3c5db57cfaba8e59867e74b81b4fad1cf7a8ed 100644
--- a/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
+++ b/components/remote_cocoa/app_shim/native_widget_mac_nswindow.mm
@@ -113,7 +113,9 @@ void OrderChildWindow(NSWindow* child_window,
@@ -101,7 +101,9 @@ void OrderChildWindow(NSWindow* child_window,
} // namespace
@interface NSWindow (Private)
@@ -108,7 +108,7 @@ index 517333705c9b68706159bff2396c3ba1f8dc1f55..f11ce18fb4d1567eb53e6b9272424eec
- (BOOL)hasKeyAppearance;
- (long long)_resizeDirectionForMouseLocation:(CGPoint)location;
- (BOOL)_isConsideredOpenForPersistentState;
@@ -161,6 +163,8 @@ - (void)cr_mouseDownOnFrameView:(NSEvent*)event {
@@ -139,6 +141,8 @@ - (void)cr_mouseDownOnFrameView:(NSEvent*)event {
}
@end
@@ -117,7 +117,7 @@ index 517333705c9b68706159bff2396c3ba1f8dc1f55..f11ce18fb4d1567eb53e6b9272424eec
@implementation NativeWidgetMacNSWindowTitledFrame
- (void)mouseDown:(NSEvent*)event {
if (self.window.isMovable)
@@ -187,6 +191,8 @@ - (BOOL)usesCustomDrawing {
@@ -165,6 +169,8 @@ - (BOOL)usesCustomDrawing {
}
@end
@@ -126,7 +126,7 @@ index 517333705c9b68706159bff2396c3ba1f8dc1f55..f11ce18fb4d1567eb53e6b9272424eec
@implementation NativeWidgetMacNSWindow {
@private
CommandDispatcher* __strong _commandDispatcher;
@@ -396,6 +402,8 @@ - (NSAccessibilityRole)accessibilityRole {
@@ -353,6 +359,8 @@ - (NSAccessibilityRole)accessibilityRole {
// NSWindow overrides.
@@ -135,7 +135,7 @@ index 517333705c9b68706159bff2396c3ba1f8dc1f55..f11ce18fb4d1567eb53e6b9272424eec
+ (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle {
if (windowStyle & NSWindowStyleMaskTitled) {
if (Class customFrame = [NativeWidgetMacNSWindowTitledFrame class])
@@ -407,6 +415,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle {
@@ -364,6 +372,8 @@ + (Class)frameViewClassForStyleMask:(NSWindowStyleMask)windowStyle {
return [super frameViewClassForStyleMask:windowStyle];
}

View File

@@ -43,10 +43,10 @@ index 5a096477c123a782341115f964c4975301ccaf9a..ecfbb3b405425af346a6ba6788fc1d8f
} // namespace
diff --git a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
index 5855f1272c65fb5b6c0e6a5493aded657d2eb2e9..4b175b312907cce2b6ef8b6eaf05f84c2aefba5b 100644
index 7c702f140281faea37bf60094e7bb78104d9c1ad..07796eb52e7d64d6be9b5e32fba53bba21fef8d7 100644
--- a/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
+++ b/components/remote_cocoa/app_shim/native_widget_ns_window_bridge.mm
@@ -609,10 +609,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) {
@@ -599,10 +599,12 @@ NSUInteger CountBridgedWindows(NSArray* child_windows) {
// this should be treated as an error and caught early.
CHECK(bridged_view_);
@@ -238,7 +238,7 @@ index 835cce73b7ab8b38c37d3e2650e12303d9d918e3..4460a00497dfaee0ba90cd5d14888055
+
#endif // UI_BASE_COCOA_REMOTE_ACCESSIBILITY_API_H_
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.h b/ui/views/cocoa/native_widget_mac_ns_window_host.h
index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d463ee5c8e 100644
index 6c2761b68d895fb1964e98865dd96cc37226fce0..563ee4da217ff4aabf2ef3452322da9e9ccefe4f 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.h
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.h
@@ -30,7 +30,9 @@
@@ -251,7 +251,7 @@ index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d4
@class NSView;
namespace remote_cocoa {
@@ -454,10 +456,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost
@@ -456,10 +458,12 @@ class VIEWS_EXPORT NativeWidgetMacNSWindowHost
mojo::AssociatedRemote<remote_cocoa::mojom::NativeWidgetNSWindow>
remote_ns_window_remote_;
@@ -265,10 +265,10 @@ index 2daaf2b78b7a60d340c2ff1651f8b5450db4af0f..3080adea0402f9d57cbde5d4350605d4
// Used to force the NSApplication's focused accessibility element to be the
// views::Views accessibility tree when the NSView for this is focused.
diff --git a/ui/views/cocoa/native_widget_mac_ns_window_host.mm b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38a60026b0 100644
index 6e0f07f5e1107341d0232e4a76b7332620315c04..0135aada72ef0c3a85ab8d134462754eb31ad2df 100644
--- a/ui/views/cocoa/native_widget_mac_ns_window_host.mm
+++ b/ui/views/cocoa/native_widget_mac_ns_window_host.mm
@@ -339,7 +339,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -352,7 +352,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
NativeWidgetMacNSWindowHost::GetNativeViewAccessibleForNSView() const {
if (in_process_ns_window_bridge_)
return in_process_ns_window_bridge_->ns_view();
@@ -280,7 +280,7 @@ index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38
}
gfx::NativeViewAccessible
@@ -354,7 +358,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -367,7 +371,11 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
return [in_process_ns_window_bridge_->ns_view() window];
}
@@ -292,7 +292,7 @@ index 53bdb4d62294f128b8f4b7bdcddf1052e15f331f..d052f5bb619bf4092810c6d5dd489a38
}
remote_cocoa::mojom::NativeWidgetNSWindow*
@@ -1353,20 +1361,24 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
@@ -1382,20 +1390,24 @@ void HandleAccelerator(const ui::Accelerator& accelerator,
void NativeWidgetMacNSWindowHost::SetRemoteAccessibilityTokens(
const std::vector<uint8_t>& window_token,
const std::vector<uint8_t>& view_token) {

View File

@@ -61,10 +61,10 @@ index f1aadfefe2b35ff4f292a04d834679e1c3fe89e9..7cb39e4059719a4fc323586e83aba47d
}
diff --git a/ui/color/win/native_color_mixers_win.cc b/ui/color/win/native_color_mixers_win.cc
index d9df0c0be6abf72c4756fb8e0f1e4b8c308a09f3..07ad3bf7e422272f017695c8b0e0aebedb8d8330 100644
index a0eb66d2a28b19ee92e2c3c23fd3eff5d64d502d..1d3b62d504884e036365256443c1a1b4f0c796ab 100644
--- a/ui/color/win/native_color_mixers_win.cc
+++ b/ui/color/win/native_color_mixers_win.cc
@@ -202,6 +202,10 @@ void AddNativeUiColorMixer(ColorProvider* provider,
@@ -205,6 +205,10 @@ void AddNativeUiColorMixer(ColorProvider* provider,
SetAlpha(kColorNotificationInputForeground, gfx::kGoogleGreyAlpha700);
mixer[kColorSliderTrack] = AlphaBlend(
kColorNativeHighlight, kColorNativeWindow, gfx::kGoogleGreyAlpha400);
@@ -75,7 +75,7 @@ index d9df0c0be6abf72c4756fb8e0f1e4b8c308a09f3..07ad3bf7e422272f017695c8b0e0aebe
// Window Background
mixer[kColorBubbleFooterBackground] = {kColorNativeWindow};
@@ -211,6 +215,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
@@ -214,6 +218,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
mixer[kColorFrameInactive] = {kColorNativeWindow};
mixer[kColorPrimaryBackground] = {kColorNativeWindow};
mixer[kColorTooltipBackground] = {kColorNativeWindow};
@@ -83,7 +83,7 @@ index d9df0c0be6abf72c4756fb8e0f1e4b8c308a09f3..07ad3bf7e422272f017695c8b0e0aebe
// Window Text
mixer[kColorAlertLowSeverity] = {kColorNativeWindowText};
@@ -225,6 +230,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
@@ -228,6 +233,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
mixer[kColorTableGroupingIndicator] = {kColorNativeWindowText};
mixer[kColorThrobber] = {kColorNativeWindowText};
mixer[kColorTooltipForeground] = {kColorNativeWindowText};
@@ -91,7 +91,7 @@ index d9df0c0be6abf72c4756fb8e0f1e4b8c308a09f3..07ad3bf7e422272f017695c8b0e0aebe
// Hyperlinks
mixer[kColorForcedHotlight] = {kColorNativeHotlight};
@@ -271,6 +277,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
@@ -274,6 +280,7 @@ void AddNativeUiColorMixer(ColorProvider* provider,
mixer[kColorTextfieldForeground] = {kColorNativeBtnText};
mixer[kColorTextfieldForegroundPlaceholder] = {kColorNativeBtnText};
mixer[kColorTextfieldForegroundDisabled] = {kColorNativeBtnText};

View File

@@ -706,7 +706,7 @@ index 3f9a514fb41d72c5d06de6ac989f9d7c0513a4e7..0e7ada9df962808dad7caf074a08ebde
// Tells the browser printing failed.
PrintingFailed(int32 cookie, PrintFailureReason reason);
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc86a1777cd 100644
index 5a58210461222ed431624bf161b32770c5ae97e6..aec69c525cefd73e50f50883ac0dc8bee94e78c0 100644
--- a/components/printing/renderer/print_render_frame_helper.cc
+++ b/components/printing/renderer/print_render_frame_helper.cc
@@ -45,6 +45,7 @@
@@ -717,7 +717,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
#include "printing/units.h"
#include "services/metrics/public/cpp/ukm_source_id.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_provider.h"
@@ -1322,14 +1323,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
@@ -1237,14 +1238,14 @@ void PrintRenderFrameHelper::ScriptedPrint(bool user_initiated) {
}
print_in_progress_ = true;
@@ -734,7 +734,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
if (!weak_this) {
return;
}
@@ -1360,7 +1361,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver(
@@ -1275,7 +1276,7 @@ void PrintRenderFrameHelper::BindPrintRenderFrameReceiver(
receivers_.Add(this, std::move(receiver));
}
@@ -743,7 +743,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
ScopedIPC scoped_ipc(weak_ptr_factory_.GetWeakPtr());
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
return;
@@ -1375,7 +1376,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() {
@@ -1290,7 +1291,7 @@ void PrintRenderFrameHelper::PrintRequestedPages() {
// plugin node and print that instead.
auto plugin = delegate_->GetPdfElement(frame);
@@ -752,7 +752,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
if (render_frame_gone_) {
return;
@@ -1462,7 +1463,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
@@ -1377,7 +1378,8 @@ void PrintRenderFrameHelper::PrintForSystemDialog() {
}
Print(frame, print_preview_context_.source_node(),
@@ -762,7 +762,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
if (render_frame_gone_) {
return;
}
@@ -1525,6 +1527,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
@@ -1440,6 +1442,8 @@ void PrintRenderFrameHelper::PrintPreview(base::Value::Dict settings) {
if (ipc_nesting_level_ > kAllowedIpcDepthForPrint)
return;
@@ -771,7 +771,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
print_preview_context_.OnPrintPreview();
#if BUILDFLAG(IS_CHROMEOS_ASH)
@@ -2158,7 +2162,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
@@ -2065,7 +2069,8 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
}
Print(duplicate_node.GetDocument().GetFrame(), duplicate_node,
@@ -781,7 +781,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
// Check if `this` is still valid.
if (!weak_this) {
return;
@@ -2174,7 +2179,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
@@ -2081,7 +2086,9 @@ void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
const blink::WebNode& node,
@@ -792,7 +792,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
// If still not finished with earlier print request simply ignore.
if (prep_frame_view_)
return;
@@ -2182,7 +2189,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
@@ -2089,7 +2096,7 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
FrameReference frame_ref(frame);
uint32_t expected_page_count = 0;
@@ -801,7 +801,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
DidFinishPrinting(PrintingResult::kFailPrintInit);
return; // Failed to init print page settings.
}
@@ -2201,8 +2208,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
@@ -2108,8 +2115,15 @@ void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
print_pages_params_->params->print_scaling_option;
auto self = weak_ptr_factory_.GetWeakPtr();
@@ -818,7 +818,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
// Check if `this` is still valid.
if (!self)
return;
@@ -2446,35 +2460,47 @@ void PrintRenderFrameHelper::IPCProcessed() {
@@ -2349,35 +2363,47 @@ void PrintRenderFrameHelper::IPCProcessed() {
}
}
@@ -876,7 +876,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
return false;
}
@@ -2579,7 +2605,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser(
@@ -2482,7 +2508,7 @@ mojom::PrintPagesParamsPtr PrintRenderFrameHelper::GetPrintSettingsFromUser(
std::move(params),
base::BindOnce(
[](base::OnceClosure quit_closure, mojom::PrintPagesParamsPtr* output,
@@ -886,7 +886,7 @@ index 658a3c59993ac30feaea4d86148ed5adc9dcbdb1..afa788bbefc8f814af9b70ff5b5ebbc8
std::move(quit_closure).Run();
},
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
index 8d65b7b6440c8e653eb1b3f9c50b40944b7ae61b..eb6b4a42d507ff216fc07328c1907815a082ef19 100644
index 5cbb2940f83af329ea38efca5bf3216056269654..8cf783d37589fdca88592eeb9b8cc91b6ae60203 100644
--- a/components/printing/renderer/print_render_frame_helper.h
+++ b/components/printing/renderer/print_render_frame_helper.h
@@ -247,7 +247,7 @@ class PrintRenderFrameHelper

View File

@@ -30,10 +30,10 @@ index fe010b1f001130fbdeaf4ef9ce7798e4baf958b5..28f1305f439be7f669e482ac0e4804c0
// RenderWidgetHost on the primary main frame, and false otherwise.
virtual bool IsWidgetForPrimaryMainFrame(RenderWidgetHostImpl*);
diff --git a/content/browser/renderer_host/render_widget_host_impl.cc b/content/browser/renderer_host/render_widget_host_impl.cc
index 149ead7bbf52ad127747c5f80f0e35a13203502a..0f2a73f990fd41112d18ab6a9ed5bc43b90c235a 100644
index 2d946e29c94a07a1aa4f4b6018ab1b564440f55d..b013e7eaa4a5db79d19378e437d8d3d18dd1b2aa 100644
--- a/content/browser/renderer_host/render_widget_host_impl.cc
+++ b/content/browser/renderer_host/render_widget_host_impl.cc
@@ -2121,6 +2121,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
@@ -2127,6 +2127,9 @@ void RenderWidgetHostImpl::SetCursor(const ui::Cursor& cursor) {
if (view_) {
view_->UpdateCursor(cursor);
}

File diff suppressed because it is too large Load Diff

View File

@@ -15,10 +15,10 @@ Note that we also need to manually update embedder's
`api::WebContents::IsFullscreenForTabOrPending` value.
diff --git a/content/browser/renderer_host/render_frame_host_impl.cc b/content/browser/renderer_host/render_frame_host_impl.cc
index 586aa87098bd3db10440fe865a02c05e7b3be14f..cb372df065f83614ff6c2954035795e67eb69d0c 100644
index ef79bf0e27bd0c5eb9fe5f0aef1cf6c6a2900e13..f121a6b0395d9ee1cf5d5c03ee1dc8968167428a 100644
--- a/content/browser/renderer_host/render_frame_host_impl.cc
+++ b/content/browser/renderer_host/render_frame_host_impl.cc
@@ -7417,6 +7417,17 @@ void RenderFrameHostImpl::EnterFullscreen(
@@ -7435,6 +7435,17 @@ void RenderFrameHostImpl::EnterFullscreen(
}
}

0
patches/libvpx/.patches Normal file
View File

View File

@@ -42,3 +42,10 @@ fix_isurl_implementation.patch
ci_ensure_node_tests_set_electron_run_as_node.patch
chore_update_fixtures_errors_force_colors_snapshot.patch
fix_assert_module_in_the_renderer_process.patch
tls_ensure_tls_sockets_are_closed_if_the_underlying_wrap_closes.patch
test_deflake_test-tls-socket-close.patch
net_fix_crash_due_to_simultaneous_close_shutdown_on_js_stream.patch
net_use_asserts_in_js_socket_stream_to_catch_races_in_future.patch
lib_fix_broadcastchannel_initialization_location.patch
fix_handle_possible_disabled_sharedarraybuffer.patch
win_process_avoid_assert_after_spawning_store_app_4152.patch

View File

@@ -11,7 +11,7 @@ trying to see whether or not the lines are greyed out. One possibility
would be to upstream a changed test that doesn't hardcode line numbers.
diff --git a/test/fixtures/errors/force_colors.snapshot b/test/fixtures/errors/force_colors.snapshot
index 0334a0b4faa3633aa8617b9538873e7f3540513b..7f85ddc507c9c38ce85ed2a48f8152eef168717b 100644
index 0334a0b4faa3633aa8617b9538873e7f3540513b..fa9989f55980aeddd3fa944318488c0289e3ab6e 100644
--- a/test/fixtures/errors/force_colors.snapshot
+++ b/test/fixtures/errors/force_colors.snapshot
@@ -4,11 +4,12 @@ throw new Error('Should include grayed stack trace')
@@ -27,7 +27,7 @@ index 0334a0b4faa3633aa8617b9538873e7f3540513b..7f85ddc507c9c38ce85ed2a48f8152ee
+ at Object..js (node:internal*modules*cjs*loader:1326:10)
+ at Module.load (node:internal*modules*cjs*loader:1126:32)
+ at node:internal*modules*cjs*loader:967:12
+ at Function._load (node:electron*js2c*asar_bundle:757:32)
+ at Function._load (node:electron*js2c*asar_bundle:743:32)
+ at Function.executeUserEntryPoint [as runMain] (node:internal*modules*run_main:96:12)
 at node:internal*main*run_main_module:23:47

View File

@@ -0,0 +1,37 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 2 Oct 2023 16:03:43 +0200
Subject: fix: handle possible disabled SharedArrayBuffer
It's possible for SharedArrayBuffer to be disabled with the -no-harmony-sharedarraybuffer
flag, and so we should guard uses with a check for potential undefined-ness.
This should be upstreamed to Node.js.
diff --git a/lib/internal/crypto/webidl.js b/lib/internal/crypto/webidl.js
index 9f5340c223902c5ff61def05e8a4f470b4f328e8..d6dbfa482f9ebff3f99fb810e072cf9a03d1cd4d 100644
--- a/lib/internal/crypto/webidl.js
+++ b/lib/internal/crypto/webidl.js
@@ -183,7 +183,10 @@ function isNonSharedArrayBuffer(V) {
return ObjectPrototypeIsPrototypeOf(ArrayBufferPrototype, V);
}
+// SharedArrayBuffers can be disabled with --no-harmony-sharedarraybuffer.
function isSharedArrayBuffer(V) {
+ if (SharedArrayBuffer === undefined)
+ return false;
return ObjectPrototypeIsPrototypeOf(SharedArrayBuffer.prototype, V);
}
diff --git a/lib/internal/main/worker_thread.js b/lib/internal/main/worker_thread.js
index be4d82086199855a10108528b3dacc663b839454..10c33bacc0529e12f52aaf1baf6d42489b2a75a7 100644
--- a/lib/internal/main/worker_thread.js
+++ b/lib/internal/main/worker_thread.js
@@ -108,6 +108,7 @@ port.on('message', (message) => {
require('internal/worker').assignEnvironmentData(environmentData);
+ // SharedArrayBuffers can be disabled with --no-harmony-sharedarraybuffer.
if (SharedArrayBuffer !== undefined) {
// The counter is only passed to the workers created by the main thread,
// not to workers created by other workers.

View File

@@ -0,0 +1,44 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Shelley Vohr <shelley.vohr@gmail.com>
Date: Mon, 27 Feb 2023 12:56:15 +0100
Subject: lib: fix BroadcastChannel initialization location
Refs https://github.com/nodejs/node/pull/40532.
Fixes a bug in the above, wherein BroadcastChannel should have been
initialized in bootstrap/browser instead of bootstrap/node. That
inadvertently made it such that there was incorrect handling of the
DOM vs Node.js implementations of BroadcastChannel.
This will be upstreamed.
diff --git a/lib/internal/bootstrap/browser.js b/lib/internal/bootstrap/browser.js
index 5be4dd6176482c724455cbbeeaa9680e849a091b..29ccee75d77da072735032f0a25363ac88a023ba 100644
--- a/lib/internal/bootstrap/browser.js
+++ b/lib/internal/bootstrap/browser.js
@@ -12,6 +12,10 @@ const {
} = require('internal/util');
const config = internalBinding('config');
+// Non-standard extensions:
+const { BroadcastChannel } = require('internal/worker/io');
+exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
+
// https://console.spec.whatwg.org/#console-namespace
exposeNamespace(globalThis, 'console',
createGlobalConsole());
diff --git a/lib/internal/bootstrap/node.js b/lib/internal/bootstrap/node.js
index 13ea68c96fd415f976aab0f291a1b7c688db1c58..0ca3de08fffb344c0330ce0f8d28b2d3d0b24350 100644
--- a/lib/internal/bootstrap/node.js
+++ b/lib/internal/bootstrap/node.js
@@ -238,10 +238,6 @@ const {
queueMicrotask,
} = require('internal/process/task_queues');
-// Non-standard extensions:
-const { BroadcastChannel } = require('internal/worker/io');
-exposeInterface(globalThis, 'BroadcastChannel', BroadcastChannel);
-
defineOperation(globalThis, 'queueMicrotask', queueMicrotask);
const timers = require('timers');

View File

@@ -0,0 +1,171 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tim Perry <pimterry@gmail.com>
Date: Thu, 24 Aug 2023 16:05:02 +0100
Subject: net: fix crash due to simultaneous close/shutdown on JS Stream
Sockets
A JS stream socket wraps a stream, exposing it as a socket for something
on top which needs a socket specifically (e.g. an HTTP server).
If the internal stream is closed in the same tick as the layer on top
attempts to close this stream, the race between doShutdown and doClose
results in an uncatchable exception. A similar race can happen with
doClose and doWrite.
It seems legitimate these can happen in parallel, so this resolves that
by explicitly detecting and handling that situation: if a close is in
progress, both doShutdown & doWrite allow doClose to run
finishShutdown/Write for them, cancelling the operation, without trying
to use this._handle (which will be null) in the meantime.
PR-URL: https://github.com/nodejs/node/pull/49400
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
diff --git a/lib/internal/js_stream_socket.js b/lib/internal/js_stream_socket.js
index 8bc19296620b3fd0e5487165743f0f1bc2d342e7..68e1802a63b012b59418b79a0e68de5147543a23 100644
--- a/lib/internal/js_stream_socket.js
+++ b/lib/internal/js_stream_socket.js
@@ -21,6 +21,7 @@ const { ERR_STREAM_WRAP } = require('internal/errors').codes;
const kCurrentWriteRequest = Symbol('kCurrentWriteRequest');
const kCurrentShutdownRequest = Symbol('kCurrentShutdownRequest');
const kPendingShutdownRequest = Symbol('kPendingShutdownRequest');
+const kPendingClose = Symbol('kPendingClose');
function isClosing() { return this[owner_symbol].isClosing(); }
@@ -94,6 +95,7 @@ class JSStreamSocket extends Socket {
this[kCurrentWriteRequest] = null;
this[kCurrentShutdownRequest] = null;
this[kPendingShutdownRequest] = null;
+ this[kPendingClose] = false;
this.readable = stream.readable;
this.writable = stream.writable;
@@ -135,10 +137,17 @@ class JSStreamSocket extends Socket {
this[kPendingShutdownRequest] = req;
return 0;
}
+
assert(this[kCurrentWriteRequest] === null);
assert(this[kCurrentShutdownRequest] === null);
this[kCurrentShutdownRequest] = req;
+ if (this[kPendingClose]) {
+ // If doClose is pending, the stream & this._handle are gone. We can't do
+ // anything. doClose will call finishShutdown with ECANCELED for us shortly.
+ return 0;
+ }
+
const handle = this._handle;
process.nextTick(() => {
@@ -164,6 +173,13 @@ class JSStreamSocket extends Socket {
assert(this[kCurrentWriteRequest] === null);
assert(this[kCurrentShutdownRequest] === null);
+ if (this[kPendingClose]) {
+ // If doClose is pending, the stream & this._handle are gone. We can't do
+ // anything. doClose will call finishWrite with ECANCELED for us shortly.
+ this[kCurrentWriteRequest] = req; // Store req, for doClose to cancel
+ return 0;
+ }
+
const handle = this._handle;
const self = this;
@@ -217,6 +233,8 @@ class JSStreamSocket extends Socket {
}
doClose(cb) {
+ this[kPendingClose] = true;
+
const handle = this._handle;
// When sockets of the "net" module destroyed, they will call
@@ -234,6 +252,8 @@ class JSStreamSocket extends Socket {
this.finishWrite(handle, uv.UV_ECANCELED);
this.finishShutdown(handle, uv.UV_ECANCELED);
+ this[kPendingClose] = false;
+
cb();
});
}
diff --git a/test/parallel/test-http2-client-connection-tunnelling.js b/test/parallel/test-http2-client-connection-tunnelling.js
new file mode 100644
index 0000000000000000000000000000000000000000..6e04121ca71ea81f49c7f50ec11d7fac735c80a9
--- /dev/null
+++ b/test/parallel/test-http2-client-connection-tunnelling.js
@@ -0,0 +1,71 @@
+'use strict';
+
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+const assert = require('assert');
+const net = require('net');
+const tls = require('tls');
+const h2 = require('http2');
+
+// This test sets up an H2 proxy server, and tunnels a request over one of its streams
+// back to itself, via TLS, and then closes the TLS connection. On some Node versions
+// (v18 & v20 up to 20.5.1) the resulting JS Stream Socket fails to shutdown correctly
+// in this case, and crashes due to a null pointer in finishShutdown.
+
+const tlsOptions = {
+ key: fixtures.readKey('agent1-key.pem'),
+ cert: fixtures.readKey('agent1-cert.pem'),
+ ALPNProtocols: ['h2']
+};
+
+const netServer = net.createServer((socket) => {
+ socket.allowHalfOpen = false;
+ // ^ This allows us to trigger this reliably, but it's not strictly required
+ // for the bug and crash to happen, skipping this just fails elsewhere later.
+
+ h2Server.emit('connection', socket);
+});
+
+const h2Server = h2.createSecureServer(tlsOptions, (req, res) => {
+ res.writeHead(200);
+ res.end();
+});
+
+h2Server.on('connect', (req, res) => {
+ res.writeHead(200, {});
+ netServer.emit('connection', res.stream);
+});
+
+netServer.listen(0, common.mustCall(() => {
+ const proxyClient = h2.connect(`https://localhost:${netServer.address().port}`, {
+ rejectUnauthorized: false
+ });
+
+ const proxyReq = proxyClient.request({
+ ':method': 'CONNECT',
+ ':authority': 'example.com:443'
+ });
+
+ proxyReq.on('response', common.mustCall((response) => {
+ assert.strictEqual(response[':status'], 200);
+
+ // Create a TLS socket within the tunnel, and start sending a request:
+ const tlsSocket = tls.connect({
+ socket: proxyReq,
+ ALPNProtocols: ['h2'],
+ rejectUnauthorized: false
+ });
+
+ proxyReq.on('close', common.mustCall(() => {
+ proxyClient.close();
+ netServer.close();
+ }));
+
+ // Forcibly kill the TLS socket
+ tlsSocket.destroy();
+
+ // This results in an async error in affected Node versions, before the 'close' event
+ }));
+}));

View File

@@ -0,0 +1,30 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tim Perry <pimterry@gmail.com>
Date: Fri, 25 Aug 2023 14:16:35 +0100
Subject: net: use asserts in JS Socket Stream to catch races in future
PR-URL: https://github.com/nodejs/node/pull/49400
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
diff --git a/lib/internal/js_stream_socket.js b/lib/internal/js_stream_socket.js
index 68e1802a63b012b59418b79a0e68de5147543a23..70d6d03069f3f1e85e66864c6c1e6de6084f5ea6 100644
--- a/lib/internal/js_stream_socket.js
+++ b/lib/internal/js_stream_socket.js
@@ -149,6 +149,7 @@ class JSStreamSocket extends Socket {
}
const handle = this._handle;
+ assert(handle !== null);
process.nextTick(() => {
// Ensure that write is dispatched asynchronously.
@@ -181,6 +182,8 @@ class JSStreamSocket extends Socket {
}
const handle = this._handle;
+ assert(handle !== null);
+
const self = this;
let pending = bufs.length;

View File

@@ -0,0 +1,28 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Luigi Pinca <luigipinca@gmail.com>
Date: Wed, 13 Sep 2023 08:04:39 +0200
Subject: test: deflake test-tls-socket-close
Move the check for the destroyed state of the remote socket to the inner
`setImmediate()`.
Refs: https://github.com/nodejs/node/pull/49327#issuecomment-1712525257
PR-URL: https://github.com/nodejs/node/pull/49575
Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
Reviewed-By: Moshe Atlow <moshe@atlow.co.il>
diff --git a/test/parallel/test-tls-socket-close.js b/test/parallel/test-tls-socket-close.js
index 667b291309a4c5636a2c658fa8204b32c2e4df46..70af760d53bb4ddab62c99180d505e943ec269f6 100644
--- a/test/parallel/test-tls-socket-close.js
+++ b/test/parallel/test-tls-socket-close.js
@@ -44,9 +44,9 @@ function connectClient(server) {
setImmediate(() => {
assert.strictEqual(netSocket.destroyed, true);
- assert.strictEqual(clientTlsSocket.destroyed, true);
setImmediate(() => {
+ assert.strictEqual(clientTlsSocket.destroyed, true);
assert.strictEqual(serverTlsSocket.destroyed, true);
tlsServer.close();

View File

@@ -7,10 +7,10 @@ Instead of disabling the tests, flag them as flaky so they still run
but don't cause CI failures on flakes.
diff --git a/test/parallel/parallel.status b/test/parallel/parallel.status
index 913ae4b0b10a7d508d864539cf075fa9c2f9362c..985f1c0d0c0c6afc049bf1d89f91412ecf431215 100644
index 913ae4b0b10a7d508d864539cf075fa9c2f9362c..0539a599e57d40c5da650dcf5ffe9a67763506e1 100644
--- a/test/parallel/parallel.status
+++ b/test/parallel/parallel.status
@@ -5,6 +5,12 @@ prefix parallel
@@ -5,6 +5,13 @@ prefix parallel
# sample-test : PASS,FLAKY
[true] # This section applies to all platforms
@@ -20,6 +20,7 @@ index 913ae4b0b10a7d508d864539cf075fa9c2f9362c..985f1c0d0c0c6afc049bf1d89f91412e
+test-fetch: PASS, FLAKY
+test-cluster-bind-privileged-port: PASS, FLAKY
+test-cluster-shared-handle-bind-privileged-port: PASS, FLAKY
+test-debugger-random-port-with-inspect-port: PASS, FLAKY
[$system==win32]
# https://github.com/nodejs/node/issues/24497

View File

@@ -0,0 +1,204 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Tim Perry <1526883+pimterry@users.noreply.github.com>
Date: Fri, 1 Sep 2023 09:00:05 +0200
Subject: tls: ensure TLS Sockets are closed if the underlying wrap closes
This fixes a potential segfault, among various other likely-related
issues, which all occur because TLSSockets were not informed if their
underlying stream was closed in many cases.
This also significantly modifies an existing TLS test. With this change
in place, that test no longer works, as it tries to mess with internals
to trigger a race, and those internals are now cleaned up earlier. This
test has been simplified to a more general TLS shutdown test.
PR-URL: https://github.com/nodejs/node/pull/49327
Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
Reviewed-By: Debadree Chatterjee <debadree333@gmail.com>
diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js
index 1eff3b3fba8a05d5fade43c6cb00b6621daa8c3d..5bed23e1355e5e5a1965f15ca270fb372f751d66 100644
--- a/lib/_tls_wrap.js
+++ b/lib/_tls_wrap.js
@@ -629,6 +629,9 @@ TLSSocket.prototype._wrapHandle = function(wrap, handle) {
defineHandleReading(this, handle);
this.on('close', onSocketCloseDestroySSL);
+ if (wrap) {
+ wrap.on('close', () => this.destroy());
+ }
return res;
};
diff --git a/test/parallel/test-http2-socket-close.js b/test/parallel/test-http2-socket-close.js
new file mode 100644
index 0000000000000000000000000000000000000000..02db77bcf8480c79c77175ba802f9fe10ffc4efe
--- /dev/null
+++ b/test/parallel/test-http2-socket-close.js
@@ -0,0 +1,67 @@
+'use strict';
+
+const common = require('../common');
+const fixtures = require('../common/fixtures');
+if (!common.hasCrypto)
+ common.skip('missing crypto');
+const assert = require('assert');
+const net = require('net');
+const h2 = require('http2');
+
+const tlsOptions = {
+ key: fixtures.readKey('agent1-key.pem'),
+ cert: fixtures.readKey('agent1-cert.pem'),
+ ALPNProtocols: ['h2']
+};
+
+// Create a net server that upgrades sockets to HTTP/2 manually, handles the
+// request, and then shuts down via a short socket timeout and a longer H2 session
+// timeout. This is an unconventional way to shut down a session (the underlying
+// socket closing first) but it should work - critically, it shouldn't segfault
+// (as it did until Node v20.5.1).
+
+let serverRawSocket;
+let serverH2Session;
+
+const netServer = net.createServer((socket) => {
+ serverRawSocket = socket;
+ h2Server.emit('connection', socket);
+});
+
+const h2Server = h2.createSecureServer(tlsOptions, (req, res) => {
+ res.writeHead(200);
+ res.end();
+});
+
+h2Server.on('session', (session) => {
+ serverH2Session = session;
+});
+
+netServer.listen(0, common.mustCall(() => {
+ const proxyClient = h2.connect(`https://localhost:${netServer.address().port}`, {
+ rejectUnauthorized: false
+ });
+
+ proxyClient.on('close', common.mustCall(() => {
+ netServer.close();
+ }));
+
+ const req = proxyClient.request({
+ ':method': 'GET',
+ ':path': '/'
+ });
+
+ req.on('response', common.mustCall((response) => {
+ assert.strictEqual(response[':status'], 200);
+
+ // Asynchronously shut down the server's connections after the response,
+ // but not in the order it typically expects:
+ setTimeout(() => {
+ serverRawSocket.destroy();
+
+ setTimeout(() => {
+ serverH2Session.close();
+ }, 10);
+ }, 10);
+ }));
+}));
diff --git a/test/parallel/test-tls-socket-close.js b/test/parallel/test-tls-socket-close.js
index 87355cf8d7bd2d07bb0fab59491b68f3963f8809..667b291309a4c5636a2c658fa8204b32c2e4df46 100644
--- a/test/parallel/test-tls-socket-close.js
+++ b/test/parallel/test-tls-socket-close.js
@@ -8,37 +8,18 @@ const tls = require('tls');
const net = require('net');
const fixtures = require('../common/fixtures');
-// Regression test for https://github.com/nodejs/node/issues/8074
-//
-// This test has a dependency on the order in which the TCP connection is made,
-// and TLS server handshake completes. It assumes those server side events occur
-// before the client side write callback, which is not guaranteed by the TLS
-// API. It usually passes with TLS1.3, but TLS1.3 didn't exist at the time the
-// bug existed.
-//
-// Pin the test to TLS1.2, since the test shouldn't be changed in a way that
-// doesn't trigger a segfault in Node.js 7.7.3:
-// https://github.com/nodejs/node/issues/13184#issuecomment-303700377
-tls.DEFAULT_MAX_VERSION = 'TLSv1.2';
-
const key = fixtures.readKey('agent2-key.pem');
const cert = fixtures.readKey('agent2-cert.pem');
-let tlsSocket;
-// tls server
+let serverTlsSocket;
const tlsServer = tls.createServer({ cert, key }, (socket) => {
- tlsSocket = socket;
- socket.on('error', common.mustCall((error) => {
- assert.strictEqual(error.code, 'EINVAL');
- tlsServer.close();
- netServer.close();
- }));
+ serverTlsSocket = socket;
});
+// A plain net server, that manually passes connections to the TLS
+// server to be upgraded
let netSocket;
-// plain tcp server
const netServer = net.createServer((socket) => {
- // If client wants to use tls
tlsServer.emit('connection', socket);
netSocket = socket;
@@ -46,35 +27,32 @@ const netServer = net.createServer((socket) => {
connectClient(netServer);
}));
+// A client that connects, sends one message, and closes the raw connection:
function connectClient(server) {
- const tlsConnection = tls.connect({
+ const clientTlsSocket = tls.connect({
host: 'localhost',
port: server.address().port,
rejectUnauthorized: false
});
- tlsConnection.write('foo', 'utf8', common.mustCall(() => {
+ clientTlsSocket.write('foo', 'utf8', common.mustCall(() => {
assert(netSocket);
netSocket.setTimeout(common.platformTimeout(10), common.mustCall(() => {
- assert(tlsSocket);
- // This breaks if TLSSocket is already managing the socket:
+ assert(serverTlsSocket);
+
netSocket.destroy();
- const interval = setInterval(() => {
- // Checking this way allows us to do the write at a time that causes a
- // segmentation fault (not always, but often) in Node.js 7.7.3 and
- // earlier. If we instead, for example, wait on the `close` event, then
- // it will not segmentation fault, which is what this test is all about.
- if (tlsSocket._handle._parent.bytesRead === 0) {
- tlsSocket.write('bar');
- clearInterval(interval);
- }
- }, 1);
+
+ setImmediate(() => {
+ assert.strictEqual(netSocket.destroyed, true);
+ assert.strictEqual(clientTlsSocket.destroyed, true);
+
+ setImmediate(() => {
+ assert.strictEqual(serverTlsSocket.destroyed, true);
+
+ tlsServer.close();
+ netServer.close();
+ });
+ });
}));
}));
- tlsConnection.on('error', (e) => {
- // Tolerate the occasional ECONNRESET.
- // Ref: https://github.com/nodejs/node/issues/13184
- if (e.code !== 'ECONNRESET')
- throw e;
- });
}

View File

@@ -0,0 +1,85 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jameson Nash <vtjnash@gmail.com>
Date: Mon, 2 Oct 2023 15:15:18 +0200
Subject: win,process: avoid assert after spawning Store app (#4152)
Make sure this handle is functional. The Windows kernel seems to have a
bug that if the first use of AssignProcessToJobObject is for a Windows
Store program, subsequent attempts to use the handle with fail with
INVALID_PARAMETER (87). This is possilby because all uses of the handle
must be for the same Terminal Services session. We can ensure it is
tied to our current session now by adding ourself to it. We could
remove ourself afterwards, but there doesn't seem to be a reason to.
Secondly, we start the process suspended so that we can make sure we
added it to the job control object before it does anything itself (such
as launch more jobs or exit).
Fixes: https://github.com/JuliaLang/julia/issues/51461
diff --git a/deps/uv/src/win/process.c b/deps/uv/src/win/process.c
index 24c633393fd15dcf87726b174d6b027a969e0f0d..4ad9fec900fa66b0e8c6894701e94f420de903a8 100644
--- a/deps/uv/src/win/process.c
+++ b/deps/uv/src/win/process.c
@@ -102,6 +102,21 @@ static void uv__init_global_job_handle(void) {
&info,
sizeof info))
uv_fatal_error(GetLastError(), "SetInformationJobObject");
+
+
+ if (!AssignProcessToJobObject(uv_global_job_handle_, GetCurrentProcess())) {
+ /* Make sure this handle is functional. The Windows kernel has a bug that
+ * if the first use of AssignProcessToJobObject is for a Windows Store
+ * program, subsequent attempts to use the handle with fail with
+ * INVALID_PARAMETER (87). This is possibly because all uses of the handle
+ * must be for the same Terminal Services session. We can ensure it is tied
+ * to our current session now by adding ourself to it. We could remove
+ * ourself afterwards, but there doesn't seem to be a reason to.
+ */
+ DWORD err = GetLastError();
+ if (err != ERROR_ACCESS_DENIED)
+ uv_fatal_error(err, "AssignProcessToJobObject");
+ }
}
@@ -1098,6 +1113,7 @@ int uv_spawn(uv_loop_t* loop,
* breakaway.
*/
process_flags |= DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP;
+ process_flags |= CREATE_SUSPENDED;
}
if (!CreateProcessW(application_path,
@@ -1115,11 +1131,6 @@ int uv_spawn(uv_loop_t* loop,
goto done;
}
- /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
-
- process->process_handle = info.hProcess;
- process->pid = info.dwProcessId;
-
/* If the process isn't spawned as detached, assign to the global job object
* so windows will kill it when the parent process dies. */
if (!(options->flags & UV_PROCESS_DETACHED)) {
@@ -1142,6 +1153,19 @@ int uv_spawn(uv_loop_t* loop,
}
}
+ if (process_flags & CREATE_SUSPENDED) {
+ if (ResumeThread(info.hThread) == ((DWORD)-1)) {
+ err = GetLastError();
+ TerminateProcess(info.hProcess, 1);
+ goto done;
+ }
+ }
+
+ /* Spawn succeeded. Beyond this point, failure is reported asynchronously. */
+
+ process->process_handle = info.hProcess;
+ process->pid = info.dwProcessId;
+
/* Set IPC pid to all IPC pipes. */
for (i = 0; i < options->stdio_count; i++) {
const uv_stdio_container_t* fdopt = &options->stdio[i];

View File

@@ -1,3 +1,4 @@
fix_fallback_to_x11_capturer_on_wayland.patch
fix_mark_pipewire_capturer_as_failed_after_session_is_closed.patch
fix_check_pipewire_init_before_creating_generic_capturer.patch
pipewire_capturer_make_restore_tokens_re-usable_more_than_one_time.patch

View File

@@ -0,0 +1,73 @@
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
From: Jan Grulich <grulja@gmail.com>
Date: Mon, 9 Oct 2023 18:54:31 +0200
Subject: PipeWire capturer: make restore tokens re-usable more than one time
Do not automatically remove all tokens once we attempt to use them. This
mitigates an issue with Google Meet where an additional instance of a
DesktopCapturer is created and destroyed right away, taking away the
token we would use otherwise. Also save the token under same SourceId
once we get a new (but could be same) token from the restored session.
Bug: webrtc:15544
Change-Id: I565b22f5bf6a4d8a3b7d6d757f9c1046c7a0557d
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/322621
Commit-Queue: Jan Grulich <grulja@gmail.com>
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
Cr-Commit-Position: refs/heads/main@{#40892}
diff --git a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
index 5a67c18c1d1f62aa5e3162d9778ca665bac4a1bb..a5df76b0cdecd1e2e68f2f25c80c6b17de8bc808 100644
--- a/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
+++ b/modules/desktop_capture/linux/wayland/base_capturer_pipewire.cc
@@ -82,8 +82,10 @@ void BaseCapturerPipeWire::OnScreenCastRequestResult(RequestResponse result,
<< static_cast<uint>(result);
} else if (ScreenCastPortal* screencast_portal = GetScreenCastPortal()) {
if (!screencast_portal->RestoreToken().empty()) {
+ const SourceId token_id =
+ selected_source_id_ ? selected_source_id_ : source_id_;
RestoreTokenManager::GetInstance().AddToken(
- source_id_, screencast_portal->RestoreToken());
+ token_id, screencast_portal->RestoreToken());
}
}
@@ -138,7 +140,7 @@ void BaseCapturerPipeWire::Start(Callback* callback) {
ScreenCastPortal::PersistMode::kTransient);
if (selected_source_id_) {
screencast_portal->SetRestoreToken(
- RestoreTokenManager::GetInstance().TakeToken(selected_source_id_));
+ RestoreTokenManager::GetInstance().GetToken(selected_source_id_));
}
}
diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.cc b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
index 5ca9b957a9e4f436bc09d4bc16019b169ae9ba9f..a17d9a49bb031efa340bfd61b4a6f8f5a86d09da 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.cc
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.cc
@@ -23,10 +23,8 @@ void RestoreTokenManager::AddToken(DesktopCapturer::SourceId id,
restore_tokens_.insert({id, token});
}
-std::string RestoreTokenManager::TakeToken(DesktopCapturer::SourceId id) {
- std::string token = restore_tokens_[id];
- // Remove the token as it cannot be used anymore
- restore_tokens_.erase(id);
+std::string RestoreTokenManager::GetToken(DesktopCapturer::SourceId id) {
+ const std::string token = restore_tokens_[id];
return token;
}
diff --git a/modules/desktop_capture/linux/wayland/restore_token_manager.h b/modules/desktop_capture/linux/wayland/restore_token_manager.h
index 174bef121f74b7b2b529d681b86c4fb4218586ea..ad4f74790f2a5cfba304fc11d47c9924db9013d8 100644
--- a/modules/desktop_capture/linux/wayland/restore_token_manager.h
+++ b/modules/desktop_capture/linux/wayland/restore_token_manager.h
@@ -27,7 +27,7 @@ class RestoreTokenManager {
static RestoreTokenManager& GetInstance();
void AddToken(DesktopCapturer::SourceId id, const std::string& token);
- std::string TakeToken(DesktopCapturer::SourceId id);
+ std::string GetToken(DesktopCapturer::SourceId id);
// Returns a source ID which does not have any token associated with it yet.
DesktopCapturer::SourceId GetUnusedId();

34
script/get-git-version.py Executable file
View File

@@ -0,0 +1,34 @@
#!/usr/bin/env python3
import subprocess
import os
# Find the nearest tag to the current HEAD.
# This is equivalent to our old logic of "use a value in package.json" for the
# following reasons:
#
# 1. Whenever we updated the package.json we ALSO pushed a tag with the same
# version.
# 2. Whenever we _reverted_ a bump all we actually did was push a commit that
# deleted the tag and changed the version number back.
#
# The only difference in the "git describe" technique is that technically a
# commit can "change" its version number if a tag is created / removed
# retroactively. i.e. the first time a commit is pushed it will be 1.2.3
# and after the tag is made rebuilding the same commit will result in it being
# 1.2.4.
try:
output = subprocess.check_output(
['git', 'describe', '--tags', '--abbrev=0'],
cwd=os.path.abspath(os.path.join(os.path.dirname(__file__), '..')),
stderr=subprocess.PIPE,
universal_newlines=True)
version = output.strip().replace('v', '')
print(version)
except Exception:
# When there is error we print a null version string instead of throwing an
# exception, this is because for linux/bsd packages and some vendor builds
# electron is built from a source code tarball and there is no git information
# there.
print('0.0.0-no-git-tag-found')

View File

@@ -1,22 +1,30 @@
const { spawnSync } = require('node:child_process');
const fs = require('node:fs');
const path = require('node:path');
const { ELECTRON_DIR, getOutDir } = require('./utils');
// Print the value of electron_version set in gn config.
module.exports.getElectronVersion = () => {
// Find the nearest tag to the current HEAD
// This is equivilant to our old logic of "use a value in package.json" for the following reasons
//
// 1. Whenever we updated the package.json we ALSO pushed a tag with the same version
// 2. Whenever we _reverted_ a bump all we actually did was push a commit that deleted the tag and changed the version number back
//
// The only difference in the "git describe" technique is that technically a commit can "change" it's version
// number if a tag is created / removed retroactively. i.e. the first time a commit is pushed it will be 1.2.3
// and after the tag is made rebuilding the same commit will result in it being 1.2.4
const output = spawnSync('git', ['describe', '--tags', '--abbrev=0'], {
cwd: path.resolve(__dirname, '..', '..')
});
if (output.status !== 0) {
console.error(output.stderr);
throw new Error('Failed to get current electron version');
// Read the override_electron_version from args.gn file.
try {
const outDir = path.resolve(ELECTRON_DIR, '..', 'out', getOutDir());
const content = fs.readFileSync(path.join(outDir, 'args.gn'));
const regex = /override_electron_version\s*=\s*["']([^"']+)["']/;
const match = content.toString().match(regex);
if (match) {
return match[1];
}
} catch (error) {
// Error may happen when trying to get version before running gn, which is a
// valid case and error will be ignored.
}
return output.stdout.toString().trim().replace(/^v/g, '');
// Most win32 machines have python.exe but no python3.exe.
const python = process.platform === 'win32' ? 'python.exe' : 'python3';
// Get the version from git tag if it is not defined in gn args.
const output = spawnSync(python, [path.join(ELECTRON_DIR, 'script', 'get-git-version.py')]);
if (output.status !== 0) {
throw new Error(`Failed to get git tag, script quit with ${output.status}: ${output.stdout}`);
}
return output.stdout.toString().trim();
};

View File

@@ -1,3 +0,0 @@
from lib.util import get_electron_version
print(get_electron_version())

View File

@@ -363,8 +363,10 @@ def upload_io_to_github(release, filename, filepath, version):
(filename))
script_path = os.path.join(
ELECTRON_DIR, 'script', 'release', 'uploaders', 'upload-to-github.ts')
execute([TS_NODE, script_path, filepath, filename, str(release['id']),
version])
upload_gh_output = execute([TS_NODE, script_path, filepath, filename,
str(release['id']), version])
if is_verbose_mode():
print(upload_gh_output)
def upload_sha256_checksum(version, file_path, key_prefix=None):

View File

@@ -19,6 +19,7 @@
#include "base/path_service.h"
#include "base/system/sys_info.h"
#include "base/values.h"
#include "base/win/windows_version.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/icon_manager.h"
#include "chrome/common/chrome_features.h"
@@ -1478,23 +1479,8 @@ void App::SetUserAgentFallback(const std::string& user_agent) {
}
#if BUILDFLAG(IS_WIN)
bool App::IsRunningUnderARM64Translation() const {
USHORT processMachine = 0;
USHORT nativeMachine = 0;
auto IsWow64Process2 = reinterpret_cast<decltype(&::IsWow64Process2)>(
GetProcAddress(GetModuleHandle(L"kernel32.dll"), "IsWow64Process2"));
if (IsWow64Process2 == nullptr) {
return false;
}
if (!IsWow64Process2(GetCurrentProcess(), &processMachine, &nativeMachine)) {
return false;
}
return nativeMachine == IMAGE_FILE_MACHINE_ARM64;
return base::win::OSInfo::IsRunningEmulatedOnArm64();
}
#endif

View File

@@ -953,6 +953,14 @@ void BaseWindow::AddTabbedWindow(NativeWindow* window,
args->ThrowError("AddTabbedWindow cannot be called by a window on itself.");
}
v8::Local<v8::Value> BaseWindow::GetTabbingIdentifier() {
auto tabbing_id = window_->GetTabbingIdentifier();
if (!tabbing_id.has_value())
return v8::Undefined(isolate());
return gin::ConvertToV8(isolate(), tabbing_id.value());
}
void BaseWindow::SetAutoHideMenuBar(bool auto_hide) {
window_->SetAutoHideMenuBar(auto_hide);
}
@@ -1305,6 +1313,7 @@ void BaseWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("moveTabToNewWindow", &BaseWindow::MoveTabToNewWindow)
.SetMethod("toggleTabBar", &BaseWindow::ToggleTabBar)
.SetMethod("addTabbedWindow", &BaseWindow::AddTabbedWindow)
.SetProperty("tabbingIdentifier", &BaseWindow::GetTabbingIdentifier)
.SetMethod("setWindowButtonVisibility",
&BaseWindow::SetWindowButtonVisibility)
.SetMethod("_getWindowButtonVisibility",

View File

@@ -198,9 +198,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
bool GetWindowButtonVisibility() const;
void SetWindowButtonPosition(absl::optional<gfx::Point> position);
absl::optional<gfx::Point> GetWindowButtonPosition() const;
#endif
#if BUILDFLAG(IS_MAC)
bool IsHiddenInMissionControl();
void SetHiddenInMissionControl(bool hidden);
#endif
@@ -215,6 +213,7 @@ class BaseWindow : public gin_helper::TrackableObject<BaseWindow>,
void MoveTabToNewWindow();
void ToggleTabBar();
void AddTabbedWindow(NativeWindow* window, gin_helper::Arguments* args);
v8::Local<v8::Value> GetTabbingIdentifier();
void SetAutoHideMenuBar(bool auto_hide);
bool IsMenuBarAutoHide();
void SetMenuBarVisibility(bool visible);

View File

@@ -216,7 +216,11 @@ void Notification::NotificationClosed() {
void Notification::Close() {
if (notification_) {
notification_->Dismiss();
if (notification_->is_dismissed()) {
notification_->Remove();
} else {
notification_->Dismiss();
}
notification_->set_delegate(nullptr);
notification_.reset();
}

View File

@@ -90,16 +90,15 @@ gin::ObjectTemplateBuilder SystemPreferences::GetObjectTemplateBuilder(
&SystemPreferences::IsSwipeTrackingFromScrollEventsEnabled)
.SetMethod("getEffectiveAppearance",
&SystemPreferences::GetEffectiveAppearance)
.SetMethod("getAppLevelAppearance",
&SystemPreferences::GetAppLevelAppearance)
.SetMethod("setAppLevelAppearance",
&SystemPreferences::SetAppLevelAppearance)
.SetMethod("getSystemColor", &SystemPreferences::GetSystemColor)
.SetMethod("canPromptTouchID", &SystemPreferences::CanPromptTouchID)
.SetMethod("promptTouchID", &SystemPreferences::PromptTouchID)
.SetMethod("isTrustedAccessibilityClient",
&SystemPreferences::IsTrustedAccessibilityClient)
.SetMethod("askForMediaAccess", &SystemPreferences::AskForMediaAccess)
.SetProperty(
"accessibilityDisplayShouldReduceTransparency",
&SystemPreferences::AccessibilityDisplayShouldReduceTransparency)
#endif
.SetMethod("getAnimationSettings",
&SystemPreferences::GetAnimationSettings);

View File

@@ -96,6 +96,7 @@ class SystemPreferences
gin::Arguments* args);
void RemoveUserDefault(const std::string& name);
bool IsSwipeTrackingFromScrollEventsEnabled();
bool AccessibilityDisplayShouldReduceTransparency();
std::string GetSystemColor(gin_helper::ErrorThrower thrower,
const std::string& color);
@@ -112,8 +113,6 @@ class SystemPreferences
// TODO(MarshallOfSound): Write tests for these methods once we
// are running tests on a Mojave machine
v8::Local<v8::Value> GetEffectiveAppearance(v8::Isolate* isolate);
v8::Local<v8::Value> GetAppLevelAppearance(v8::Isolate* isolate);
void SetAppLevelAppearance(gin::Arguments* args);
#endif
v8::Local<v8::Value> GetAnimationSettings(v8::Isolate* isolate);

View File

@@ -475,14 +475,7 @@ bool SystemPreferences::IsTrustedAccessibilityClient(bool prompt) {
std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
const std::string& color) {
NSColor* sysColor = nil;
if (color == "alternate-selected-control-text") {
sysColor = [NSColor alternateSelectedControlTextColor];
EmitWarning(
node::Environment::GetCurrent(thrower.isolate()),
"'alternate-selected-control-text' is deprecated as an input to "
"getColor. Use 'selected-content-background' instead.",
"electron");
} else if (color == "control-background") {
if (color == "control-background") {
sysColor = [NSColor controlBackgroundColor];
} else if (color == "control") {
sysColor = [NSColor controlColor];
@@ -609,19 +602,9 @@ v8::Local<v8::Value> SystemPreferences::GetEffectiveAppearance(
isolate, [NSApplication sharedApplication].effectiveAppearance);
}
v8::Local<v8::Value> SystemPreferences::GetAppLevelAppearance(
v8::Isolate* isolate) {
return gin::ConvertToV8(isolate,
[NSApplication sharedApplication].appearance);
}
void SystemPreferences::SetAppLevelAppearance(gin::Arguments* args) {
NSAppearance* appearance;
if (args->GetNext(&appearance)) {
[[NSApplication sharedApplication] setAppearance:appearance];
} else {
args->ThrowError();
}
bool SystemPreferences::AccessibilityDisplayShouldReduceTransparency() {
return [[NSWorkspace sharedWorkspace]
accessibilityDisplayShouldReduceTransparency];
}
} // namespace electron::api

View File

@@ -33,6 +33,7 @@
#include "components/security_state/content/content_utils.h"
#include "components/security_state/core/security_state.h"
#include "content/browser/renderer_host/frame_tree_node.h" // nogncheck
#include "content/browser/renderer_host/navigation_controller_impl.h" // nogncheck
#include "content/browser/renderer_host/render_frame_host_manager.h" // nogncheck
#include "content/browser/renderer_host/render_widget_host_impl.h" // nogncheck
#include "content/browser/renderer_host/render_widget_host_view_base.h" // nogncheck
@@ -468,9 +469,16 @@ base::IDMap<WebContents*>& GetAllWebContents() {
void OnCapturePageDone(gin_helper::Promise<gfx::Image> promise,
base::ScopedClosureRunner capture_handle,
const SkBitmap& bitmap) {
auto ui_task_runner = content::GetUIThreadTaskRunner({});
if (!ui_task_runner->RunsTasksInCurrentSequence()) {
ui_task_runner->PostTask(
FROM_HERE, base::BindOnce(&OnCapturePageDone, std::move(promise),
std::move(capture_handle), bitmap));
return;
}
// Hack to enable transparency in captured image
promise.Resolve(gfx::Image::CreateFrom1xBitmap(bitmap));
capture_handle.RunAndReset();
}
@@ -1324,12 +1332,6 @@ bool WebContents::HandleKeyboardEvent(
bool WebContents::PlatformHandleKeyboardEvent(
content::WebContents* source,
const content::NativeWebKeyboardEvent& event) {
// Escape exits tabbed fullscreen mode.
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen()) {
ExitFullscreenModeForTab(source);
return true;
}
// Check if the webContents has preferences and to ignore shortcuts
auto* web_preferences = WebContentsPreferences::From(source);
if (web_preferences && web_preferences->ShouldIgnoreMenuShortcuts())
@@ -1507,11 +1509,10 @@ void WebContents::FindReply(content::WebContents* web_contents,
Emit("found-in-page", result.GetHandle());
}
void WebContents::RequestExclusivePointerAccess(
content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed) {
void WebContents::OnRequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed) {
if (allowed) {
exclusive_access_manager_.mouse_lock_controller()->RequestToLockMouse(
web_contents, user_gesture, last_unlocked_by_target);
@@ -1528,7 +1529,7 @@ void WebContents::RequestToLockMouse(content::WebContents* web_contents,
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestPointerLockPermission(
user_gesture, last_unlocked_by_target,
base::BindOnce(&WebContents::RequestExclusivePointerAccess,
base::BindOnce(&WebContents::OnRequestToLockMouse,
base::Unretained(this)));
}
@@ -1536,10 +1537,24 @@ void WebContents::LostMouseLock() {
exclusive_access_manager_.mouse_lock_controller()->LostMouseLock();
}
void WebContents::OnRequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked,
bool allowed) {
if (allowed) {
exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
web_contents, esc_key_locked);
} else {
web_contents->GotResponseToKeyboardLockRequest(false);
}
}
void WebContents::RequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked) {
exclusive_access_manager_.keyboard_lock_controller()->RequestKeyboardLock(
web_contents, esc_key_locked);
auto* permission_helper =
WebContentsPermissionHelper::FromWebContents(web_contents);
permission_helper->RequestKeyboardLockPermission(
esc_key_locked, base::BindOnce(&WebContents::OnRequestKeyboardLock,
base::Unretained(this)));
}
void WebContents::CancelKeyboardLockRequest(
@@ -1726,13 +1741,6 @@ void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
void WebContents::PrimaryMainFrameRenderProcessGone(
base::TerminationStatus status) {
auto weak_this = GetWeakPtr();
Emit("crashed", status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED);
// User might destroy WebContents in the crashed event.
if (!weak_this || !web_contents())
return;
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope handle_scope(isolate);
gin_helper::Dictionary details = gin_helper::Dictionary::CreateEmpty(isolate);
@@ -2406,8 +2414,20 @@ void WebContents::LoadURL(const GURL& url,
params.transition_type = ui::PageTransitionFromInt(
ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR);
params.override_user_agent = content::NavigationController::UA_OVERRIDE_TRUE;
// Discard non-committed entries to ensure that we don't re-use a pending
// entry
// It's not safe to start a new navigation or otherwise discard the current
// one while the call that started it is still on the stack. See
// http://crbug.com/347742.
auto& ctrl_impl = static_cast<content::NavigationControllerImpl&>(
web_contents()->GetController());
if (ctrl_impl.in_navigate_to_pending_entry()) {
Emit("did-fail-load", static_cast<int>(net::ERR_FAILED),
net::ErrorToShortString(net::ERR_FAILED), url.possibly_invalid_spec(),
true);
return;
}
// Discard non-committed entries to ensure we don't re-use a pending entry.
web_contents()->GetController().DiscardNonCommittedEntries();
web_contents()->GetController().LoadURLWithParams(params);
@@ -3427,22 +3447,16 @@ v8::Local<v8::Promise> WebContents::CapturePage(gin::Arguments* args) {
}
auto* const view = web_contents()->GetRenderWidgetHostView();
if (!view) {
if (!view || view->GetViewBounds().size().IsEmpty()) {
promise.Resolve(gfx::Image());
return handle;
}
#if !BUILDFLAG(IS_MAC)
// If the view's renderer is suspended this may fail on Windows/Linux -
// bail if so. See CopyFromSurface in
// content/public/browser/render_widget_host_view.h.
auto* rfh = web_contents()->GetPrimaryMainFrame();
if (rfh &&
rfh->GetVisibilityState() == blink::mojom::PageVisibilityState::kHidden) {
promise.Resolve(gfx::Image());
if (!view->IsSurfaceAvailableForCopy()) {
promise.RejectWithErrorMessage(
"Current display surface not available for capture");
return handle;
}
#endif // BUILDFLAG(IS_MAC)
auto capture_handle = web_contents()->IncrementCapturerCount(
rect.size(), stay_hidden, stay_awake);

View File

@@ -568,14 +568,17 @@ class WebContents : public ExclusiveAccessContext,
const gfx::Rect& selection_rect,
int active_match_ordinal,
bool final_update) override;
void RequestExclusivePointerAccess(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed);
void OnRequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target,
bool allowed);
void RequestToLockMouse(content::WebContents* web_contents,
bool user_gesture,
bool last_unlocked_by_target) override;
void LostMouseLock() override;
void OnRequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked,
bool allowed);
void RequestKeyboardLock(content::WebContents* web_contents,
bool esc_key_locked) override;
void CancelKeyboardLockRequest(content::WebContents* web_contents) override;

View File

@@ -42,12 +42,6 @@ bool WebContents::PlatformHandleKeyboardEvent(
event.GetType() == content::NativeWebKeyboardEvent::Type::kChar)
return false;
// Escape exits tabbed fullscreen mode.
if (event.windows_key_code == ui::VKEY_ESCAPE && is_html_fullscreen()) {
ExitFullscreenModeForTab(source);
return true;
}
// Check if the webContents has preferences and to ignore shortcuts
auto* web_preferences = WebContentsPreferences::From(source);
if (web_preferences && web_preferences->ShouldIgnoreMenuShortcuts())

View File

@@ -57,7 +57,7 @@
#include "crypto/crypto_buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "electron/shell/common/api/api.mojom.h"
#include "extensions/browser/api/messaging/messaging_api_message_filter.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "mojo/public/cpp/bindings/binder_map.h"
#include "net/ssl/ssl_cert_request_info.h"
#include "net/ssl/ssl_private_key.h"
@@ -114,6 +114,7 @@
#include "shell/common/options_switches.h"
#include "shell/common/platform_util.h"
#include "shell/common/thread_restrictions.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#include "third_party/blink/public/common/loader/url_loader_throttle.h"
#include "third_party/blink/public/common/renderer_preferences/renderer_preferences.h"
#include "third_party/blink/public/common/tokens/tokens.h"
@@ -147,6 +148,7 @@
#include "content/public/browser/child_process_security_policy.h"
#include "content/public/browser/file_url_loader.h"
#include "content/public/browser/web_ui_url_loader_factory.h"
#include "extensions/browser/api/messaging/messaging_api_message_filter.h"
#include "extensions/browser/api/mime_handler_private/mime_handler_private.h"
#include "extensions/browser/api/web_request/web_request_api.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
@@ -154,7 +156,6 @@
#include "extensions/browser/extension_host.h"
#include "extensions/browser/extension_message_filter.h"
#include "extensions/browser/extension_navigation_throttle.h"
#include "extensions/browser/extension_navigation_ui_data.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_protocols.h"
#include "extensions/browser/extension_registry.h"
@@ -172,7 +173,6 @@
#include "shell/browser/extensions/electron_extension_message_filter.h"
#include "shell/browser/extensions/electron_extension_system.h"
#include "shell/browser/extensions/electron_extension_web_contents_observer.h"
#include "third_party/blink/public/common/associated_interfaces/associated_interface_registry.h"
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
@@ -1220,12 +1220,12 @@ void ElectronBrowserClient::
protocol_registry->RegisterURLLoaderFactories(factories,
false /* allow_file_access */);
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
factories->emplace(
extensions::kExtensionScheme,
extensions::CreateExtensionServiceWorkerScriptURLLoaderFactory(
browser_context));
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
}
bool ElectronBrowserClient::ShouldTreatURLSchemeAsFirstPartyWhenTopLevel(
@@ -1413,9 +1413,10 @@ void ElectronBrowserClient::OverrideURLLoaderFactoryParams(
factory_params->disable_web_security = true;
}
}
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
extensions::URLLoaderFactoryManager::OverrideURLLoaderFactoryParams(
browser_context, origin, is_for_isolated_world, factory_params);
#endif
}
void ElectronBrowserClient::
@@ -1473,7 +1474,7 @@ void ElectronBrowserClient::
},
&render_frame_host));
#endif
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
associated_registry.AddInterface<extensions::mojom::LocalFrameHost>(
base::BindRepeating(
[](content::RenderFrameHost* render_frame_host,

View File

@@ -79,12 +79,12 @@
#if BUILDFLAG(IS_LINUX)
#include "base/environment.h"
#include "chrome/browser/ui/views/dark_mode_manager_linux.h"
#include "device/bluetooth/bluetooth_adapter_factory.h"
#include "device/bluetooth/dbus/dbus_bluez_manager_wrapper_linux.h"
#include "electron/electron_gtk_stubs.h"
#include "ui/base/cursor/cursor_factory.h"
#include "ui/base/ime/linux/linux_input_method_context_factory.h"
#include "ui/gfx/color_utils.h"
#include "ui/gtk/gtk_compat.h" // nogncheck
#include "ui/gtk/gtk_util.h" // nogncheck
#include "ui/linux/linux_ui.h"
@@ -169,36 +169,8 @@ std::u16string MediaStringProvider(media::MessageId id) {
}
}
#if BUILDFLAG(IS_LINUX)
// GTK does not provide a way to check if current theme is dark, so we compare
// the text and background luminosity to get a result.
// This trick comes from FireFox.
void UpdateDarkThemeSetting() {
float bg = color_utils::GetRelativeLuminance(gtk::GetBgColor("GtkLabel"));
float fg = color_utils::GetRelativeLuminance(gtk::GetFgColor("GtkLabel"));
bool is_dark = fg > bg;
// Pass it to NativeUi theme, which is used by the nativeTheme module and most
// places in Electron.
ui::NativeTheme::GetInstanceForNativeUi()->set_use_dark_colors(is_dark);
// Pass it to Web Theme, to make "prefers-color-scheme" media query work.
ui::NativeTheme::GetInstanceForWeb()->set_use_dark_colors(is_dark);
}
#endif
} // namespace
#if BUILDFLAG(IS_LINUX)
class DarkThemeObserver : public ui::NativeThemeObserver {
public:
DarkThemeObserver() = default;
// ui::NativeThemeObserver:
void OnNativeThemeUpdated(ui::NativeTheme* observed_theme) override {
UpdateDarkThemeSetting();
}
};
#endif
// static
ElectronBrowserMainParts* ElectronBrowserMainParts::self_ = nullptr;
@@ -432,17 +404,10 @@ void ElectronBrowserMainParts::ToolkitInitialized() {
CHECK(electron::IsElectron_gdk_pixbufInitialized())
<< "Failed to initialize libgdk_pixbuf-2.0.so.0";
// Chromium does not respect GTK dark theme setting, but they may change
// in future and this code might be no longer needed. Check the Chromium
// issue to keep updated:
// https://bugs.chromium.org/p/chromium/issues/detail?id=998903
UpdateDarkThemeSetting();
// Update the native theme when GTK theme changes. The GetNativeTheme
// here returns a NativeThemeGtk, which monitors GTK settings.
dark_theme_observer_ = std::make_unique<DarkThemeObserver>();
auto* linux_ui_theme = ui::LinuxUiTheme::GetForProfile(nullptr);
CHECK(linux_ui_theme);
linux_ui_theme->GetNativeTheme()->AddObserver(dark_theme_observer_.get());
// source theme changes from system settings, including settings portal:
// https://flatpak.github.io/xdg-desktop-portal/#gdbus-org.freedesktop.portal.Settings
dark_mode_manager_ = std::make_unique<ui::DarkModeManagerLinux>();
ui::LinuxUi::SetInstance(linux_ui);
// Cursor theme changes are tracked by LinuxUI (via a CursorThemeManager

View File

@@ -43,7 +43,8 @@ class Environment;
namespace ui {
class LinuxUiGetter;
}
class DarkModeManagerLinux;
} // namespace ui
namespace electron {
@@ -65,10 +66,6 @@ class ViewsDelegate;
class ViewsDelegateMac;
#endif
#if BUILDFLAG(IS_LINUX)
class DarkThemeObserver;
#endif
class ElectronBrowserMainParts : public content::BrowserMainParts {
public:
ElectronBrowserMainParts();
@@ -145,9 +142,7 @@ class ElectronBrowserMainParts : public content::BrowserMainParts {
#endif
#if BUILDFLAG(IS_LINUX)
// Used to notify the native theme of changes to dark mode.
std::unique_ptr<DarkThemeObserver> dark_theme_observer_;
std::unique_ptr<ui::DarkModeManagerLinux> dark_mode_manager_;
std::unique_ptr<ui::LinuxUiGetter> linux_ui_getter_;
#endif

View File

@@ -4,9 +4,11 @@
#include "shell/browser/electron_navigation_throttle.h"
#include "content/browser/renderer_host/render_frame_host_impl.h" // nogncheck
#include "content/public/browser/navigation_handle.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/javascript_environment.h"
#include "ui/base/page_transition_types.h"
namespace electron {
@@ -37,11 +39,24 @@ ElectronNavigationThrottle::WillStartRequest() {
return PROCEED;
}
if (handle->IsRendererInitiated() &&
bool is_renderer_initiated = handle->IsRendererInitiated();
// Chrome's internal pages always mark navigation as browser-initiated. Let's
// ignore that.
// https://source.chromium.org/chromium/chromium/src/+/main:content/browser/renderer_host/navigator.cc;l=883-892;drc=0c8ffbe78dc0ef2047849e45cefb3f621043e956
if (!is_renderer_initiated &&
ui::PageTransitionIsWebTriggerable(handle->GetPageTransition())) {
auto* render_frame_host = contents->GetPrimaryMainFrame();
auto* rfh_impl =
static_cast<content::RenderFrameHostImpl*>(render_frame_host);
is_renderer_initiated = rfh_impl && rfh_impl->web_ui();
}
if (is_renderer_initiated &&
api_contents->EmitNavigationEvent("will-frame-navigate", handle)) {
return CANCEL;
}
if (handle->IsRendererInitiated() && handle->IsInMainFrame() &&
if (is_renderer_initiated && handle->IsInMainFrame() &&
api_contents->EmitNavigationEvent("will-navigate", handle)) {
return CANCEL;
}

View File

@@ -11,6 +11,7 @@ assert(enable_extensions,
function_registration("api_registration") {
sources = [
"//electron/shell/common/extensions/api/action.json",
"//electron/shell/common/extensions/api/extension.json",
"//electron/shell/common/extensions/api/resources_private.idl",
"//electron/shell/common/extensions/api/scripting.idl",

View File

@@ -0,0 +1,197 @@
// Copyright (c) 2023 Microsoft, GmbH
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "shell/browser/extensions/api/extension_action/extension_action_api.h"
#include <stddef.h>
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/lazy_instance.h"
#include "base/observer_list.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/browser/extension_util.h"
#include "extensions/common/mojom/view_type.mojom.h"
using content::WebContents;
namespace extensions {
//
// ExtensionActionAPI::Observer
//
void ExtensionActionAPI::Observer::OnExtensionActionUpdated(
ExtensionAction* extension_action,
content::WebContents* web_contents,
content::BrowserContext* browser_context) {}
void ExtensionActionAPI::Observer::OnExtensionActionAPIShuttingDown() {}
ExtensionActionAPI::Observer::~Observer() {}
//
// ExtensionActionAPI
//
static base::LazyInstance<BrowserContextKeyedAPIFactory<ExtensionActionAPI>>::
DestructorAtExit g_extension_action_api_factory = LAZY_INSTANCE_INITIALIZER;
ExtensionActionAPI::ExtensionActionAPI(content::BrowserContext* context)
: browser_context_(context), extension_prefs_(nullptr) {}
ExtensionActionAPI::~ExtensionActionAPI() {}
// static
BrowserContextKeyedAPIFactory<ExtensionActionAPI>*
ExtensionActionAPI::GetFactoryInstance() {
return g_extension_action_api_factory.Pointer();
}
// static
ExtensionActionAPI* ExtensionActionAPI::Get(content::BrowserContext* context) {
return BrowserContextKeyedAPIFactory<ExtensionActionAPI>::Get(context);
}
ExtensionPrefs* ExtensionActionAPI::GetExtensionPrefs() {
return nullptr;
}
void ExtensionActionAPI::Shutdown() {}
//
// ExtensionActionFunction
//
ExtensionActionFunction::ExtensionActionFunction() {}
ExtensionActionFunction::~ExtensionActionFunction() {}
ExtensionFunction::ResponseAction ExtensionActionFunction::Run() {
return RunExtensionAction();
}
ExtensionFunction::ResponseAction
ExtensionActionShowFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.show is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionHideFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.hide is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ActionIsEnabledFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.isEnabled is not supported in Electron";
return RespondNow(WithArguments(false));
}
ExtensionFunction::ResponseAction
ExtensionActionSetIconFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.setIcon is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionSetTitleFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.setTitle is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionSetPopupFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.setPopup is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionSetBadgeTextFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.setBadgeText is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() {
LOG(INFO)
<< "chrome.action.setBadgeBackgroundColor is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ActionSetBadgeTextColorFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.setBadgeTextColor is not supported in Electron";
return RespondNow(NoArguments());
}
ExtensionFunction::ResponseAction
ExtensionActionGetTitleFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.getTitle is not supported in Electron";
return RespondNow(WithArguments(""));
}
ExtensionFunction::ResponseAction
ExtensionActionGetPopupFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.getPopup is not supported in Electron";
return RespondNow(WithArguments(""));
}
ExtensionFunction::ResponseAction
ExtensionActionGetBadgeTextFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.getBadgeText is not supported in Electron";
return RespondNow(WithArguments(""));
}
ExtensionFunction::ResponseAction
ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() {
LOG(INFO)
<< "chrome.action.getBadgeBackgroundColor is not supported in Electron";
base::Value::List list;
return RespondNow(WithArguments(std::move(list)));
}
ExtensionFunction::ResponseAction
ActionGetBadgeTextColorFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.getBadgeTextColor is not supported in Electron";
base::Value::List list;
return RespondNow(WithArguments(std::move(list)));
}
ActionGetUserSettingsFunction::ActionGetUserSettingsFunction() = default;
ActionGetUserSettingsFunction::~ActionGetUserSettingsFunction() = default;
ExtensionFunction::ResponseAction ActionGetUserSettingsFunction::Run() {
LOG(INFO) << "chrome.action.getUserSettings is not supported in Electron";
base::Value::Dict ui_settings;
return RespondNow(WithArguments(std::move(ui_settings)));
}
ExtensionFunction::ResponseAction
ActionOpenPopupFunction::RunExtensionAction() {
LOG(INFO) << "chrome.action.openPopup is not supported in Electron";
return RespondNow(NoArguments());
}
} // namespace extensions

View File

@@ -0,0 +1,520 @@
// Copyright (c) 2023 Microsoft, GmbH
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef SHELL_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_
#define SHELL_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_
#include <string>
#include "base/memory/raw_ptr.h"
#include "base/observer_list.h"
#include "base/values.h"
#include "extensions/browser/browser_context_keyed_api_factory.h"
#include "extensions/browser/extension_action.h"
#include "extensions/browser/extension_function.h"
#include "extensions/browser/extension_host_registry.h"
namespace content {
class BrowserContext;
class WebContents;
} // namespace content
namespace extensions {
class ExtensionHost;
class ExtensionPrefs;
class ExtensionActionAPI : public BrowserContextKeyedAPI {
public:
class Observer {
public:
virtual void OnExtensionActionUpdated(
ExtensionAction* extension_action,
content::WebContents* web_contents,
content::BrowserContext* browser_context);
virtual void OnExtensionActionAPIShuttingDown();
protected:
virtual ~Observer();
};
explicit ExtensionActionAPI(content::BrowserContext* context);
ExtensionActionAPI(const ExtensionActionAPI&) = delete;
ExtensionActionAPI& operator=(const ExtensionActionAPI&) = delete;
~ExtensionActionAPI() override;
// Convenience method to get the instance for a profile.
static ExtensionActionAPI* Get(content::BrowserContext* context);
static BrowserContextKeyedAPIFactory<ExtensionActionAPI>*
GetFactoryInstance();
// Add or remove observers.
void AddObserver(Observer* observer) {}
void RemoveObserver(Observer* observer) {}
// Notifies that there has been a change in the given |extension_action|.
void NotifyChange(ExtensionAction* extension_action,
content::WebContents* web_contents,
content::BrowserContext* browser_context) {}
// Dispatches the onClicked event for extension that owns the given action.
void DispatchExtensionActionClicked(const ExtensionAction& extension_action,
content::WebContents* web_contents,
const Extension* extension) {}
// Clears the values for all ExtensionActions for the tab associated with the
// given |web_contents| (and signals that page actions changed).
void ClearAllValuesForTab(content::WebContents* web_contents) {}
private:
friend class BrowserContextKeyedAPIFactory<ExtensionActionAPI>;
ExtensionPrefs* GetExtensionPrefs();
// BrowserContextKeyedAPI implementation.
void Shutdown() override;
static const char* service_name() { return "ExtensionActionAPI"; }
static const bool kServiceRedirectedInIncognito = true;
raw_ptr<content::BrowserContext> browser_context_;
raw_ptr<ExtensionPrefs> extension_prefs_;
};
// Implementation of the browserAction and pageAction APIs.
class ExtensionActionFunction : public ExtensionFunction {
protected:
ExtensionActionFunction();
~ExtensionActionFunction() override;
ResponseAction Run() override;
virtual ResponseAction RunExtensionAction() = 0;
};
//
// Implementations of each extension action API.
//
// pageAction and browserAction bindings are created for these by extending them
// then declaring an EXTENSION_FUNCTION_NAME.
//
// show
class ExtensionActionShowFunction : public ExtensionActionFunction {
protected:
~ExtensionActionShowFunction() override {}
ResponseAction RunExtensionAction() override;
};
// hide
class ExtensionActionHideFunction : public ExtensionActionFunction {
protected:
~ExtensionActionHideFunction() override {}
ResponseAction RunExtensionAction() override;
};
// setIcon
class ExtensionActionSetIconFunction : public ExtensionActionFunction {
public:
static void SetReportErrorForInvisibleIconForTesting(bool value);
protected:
~ExtensionActionSetIconFunction() override {}
ResponseAction RunExtensionAction() override;
};
// setTitle
class ExtensionActionSetTitleFunction : public ExtensionActionFunction {
protected:
~ExtensionActionSetTitleFunction() override {}
ResponseAction RunExtensionAction() override;
};
// setPopup
class ExtensionActionSetPopupFunction : public ExtensionActionFunction {
protected:
~ExtensionActionSetPopupFunction() override {}
ResponseAction RunExtensionAction() override;
};
// setBadgeText
class ExtensionActionSetBadgeTextFunction : public ExtensionActionFunction {
protected:
~ExtensionActionSetBadgeTextFunction() override {}
ResponseAction RunExtensionAction() override;
};
// setBadgeBackgroundColor
class ExtensionActionSetBadgeBackgroundColorFunction
: public ExtensionActionFunction {
protected:
~ExtensionActionSetBadgeBackgroundColorFunction() override {}
ResponseAction RunExtensionAction() override;
};
// getTitle
class ExtensionActionGetTitleFunction : public ExtensionActionFunction {
protected:
~ExtensionActionGetTitleFunction() override {}
ResponseAction RunExtensionAction() override;
};
// getPopup
class ExtensionActionGetPopupFunction : public ExtensionActionFunction {
protected:
~ExtensionActionGetPopupFunction() override {}
ResponseAction RunExtensionAction() override;
};
// openPopup
class ExtensionActionOpenPopupFunction : public ExtensionActionFunction {
protected:
~ExtensionActionOpenPopupFunction() override {}
ResponseAction RunExtensionAction() override;
};
// getBadgeText
class ExtensionActionGetBadgeTextFunction : public ExtensionActionFunction {
protected:
~ExtensionActionGetBadgeTextFunction() override {}
ResponseAction RunExtensionAction() override;
};
// getBadgeBackgroundColor
class ExtensionActionGetBadgeBackgroundColorFunction
: public ExtensionActionFunction {
protected:
~ExtensionActionGetBadgeBackgroundColorFunction() override {}
ResponseAction RunExtensionAction() override;
};
//
// action.* aliases for supported action APIs.
//
class ActionSetIconFunction : public ExtensionActionSetIconFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setIcon", ACTION_SETICON)
protected:
~ActionSetIconFunction() override {}
};
class ActionGetPopupFunction : public ExtensionActionGetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getPopup", ACTION_GETPOPUP)
protected:
~ActionGetPopupFunction() override {}
};
class ActionSetPopupFunction : public ExtensionActionSetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setPopup", ACTION_SETPOPUP)
protected:
~ActionSetPopupFunction() override {}
};
class ActionGetTitleFunction : public ExtensionActionGetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getTitle", ACTION_GETTITLE)
protected:
~ActionGetTitleFunction() override {}
};
class ActionSetTitleFunction : public ExtensionActionSetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setTitle", ACTION_SETTITLE)
protected:
~ActionSetTitleFunction() override {}
};
class ActionGetBadgeTextFunction : public ExtensionActionGetBadgeTextFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getBadgeText", ACTION_GETBADGETEXT)
protected:
~ActionGetBadgeTextFunction() override {}
};
class ActionSetBadgeTextFunction : public ExtensionActionSetBadgeTextFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setBadgeText", ACTION_SETBADGETEXT)
protected:
~ActionSetBadgeTextFunction() override {}
};
class ActionGetBadgeBackgroundColorFunction
: public ExtensionActionGetBadgeBackgroundColorFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getBadgeBackgroundColor",
ACTION_GETBADGEBACKGROUNDCOLOR)
protected:
~ActionGetBadgeBackgroundColorFunction() override {}
};
class ActionSetBadgeBackgroundColorFunction
: public ExtensionActionSetBadgeBackgroundColorFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setBadgeBackgroundColor",
ACTION_SETBADGEBACKGROUNDCOLOR)
protected:
~ActionSetBadgeBackgroundColorFunction() override {}
};
class ActionGetBadgeTextColorFunction : public ExtensionActionFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getBadgeTextColor",
ACTION_GETBADGETEXTCOLOR)
protected:
~ActionGetBadgeTextColorFunction() override = default;
ResponseAction RunExtensionAction() override;
};
class ActionSetBadgeTextColorFunction : public ExtensionActionFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.setBadgeTextColor",
ACTION_SETBADGETEXTCOLOR)
protected:
~ActionSetBadgeTextColorFunction() override = default;
ResponseAction RunExtensionAction() override;
};
class ActionEnableFunction : public ExtensionActionShowFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.enable", ACTION_ENABLE)
protected:
~ActionEnableFunction() override {}
};
class ActionDisableFunction : public ExtensionActionHideFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.disable", ACTION_DISABLE)
protected:
~ActionDisableFunction() override {}
};
class ActionIsEnabledFunction : public ExtensionActionFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.isEnabled", ACTION_ISENABLED)
protected:
~ActionIsEnabledFunction() override = default;
ResponseAction RunExtensionAction() override;
};
class ActionGetUserSettingsFunction : public ExtensionFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.getUserSettings", ACTION_GETUSERSETTINGS)
ActionGetUserSettingsFunction();
ActionGetUserSettingsFunction(const ActionGetUserSettingsFunction&) = delete;
ActionGetUserSettingsFunction& operator=(
const ActionGetUserSettingsFunction&) = delete;
ResponseAction Run() override;
protected:
~ActionGetUserSettingsFunction() override;
};
class ActionOpenPopupFunction : public ExtensionActionOpenPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("action.openPopup", ACTION_OPENPOPUP)
protected:
~ActionOpenPopupFunction() override = default;
ResponseAction RunExtensionAction() override;
};
//
// browserAction.* aliases for supported browserAction APIs.
//
class BrowserActionSetIconFunction : public ExtensionActionSetIconFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.setIcon", BROWSERACTION_SETICON)
protected:
~BrowserActionSetIconFunction() override {}
};
class BrowserActionSetTitleFunction : public ExtensionActionSetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.setTitle", BROWSERACTION_SETTITLE)
protected:
~BrowserActionSetTitleFunction() override {}
};
class BrowserActionSetPopupFunction : public ExtensionActionSetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.setPopup", BROWSERACTION_SETPOPUP)
protected:
~BrowserActionSetPopupFunction() override {}
};
class BrowserActionGetTitleFunction : public ExtensionActionGetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.getTitle", BROWSERACTION_GETTITLE)
protected:
~BrowserActionGetTitleFunction() override {}
};
class BrowserActionGetPopupFunction : public ExtensionActionGetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.getPopup", BROWSERACTION_GETPOPUP)
protected:
~BrowserActionGetPopupFunction() override {}
};
class BrowserActionSetBadgeTextFunction
: public ExtensionActionSetBadgeTextFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.setBadgeText",
BROWSERACTION_SETBADGETEXT)
protected:
~BrowserActionSetBadgeTextFunction() override {}
};
class BrowserActionSetBadgeBackgroundColorFunction
: public ExtensionActionSetBadgeBackgroundColorFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.setBadgeBackgroundColor",
BROWSERACTION_SETBADGEBACKGROUNDCOLOR)
protected:
~BrowserActionSetBadgeBackgroundColorFunction() override {}
};
class BrowserActionGetBadgeTextFunction
: public ExtensionActionGetBadgeTextFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.getBadgeText",
BROWSERACTION_GETBADGETEXT)
protected:
~BrowserActionGetBadgeTextFunction() override {}
};
class BrowserActionGetBadgeBackgroundColorFunction
: public ExtensionActionGetBadgeBackgroundColorFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.getBadgeBackgroundColor",
BROWSERACTION_GETBADGEBACKGROUNDCOLOR)
protected:
~BrowserActionGetBadgeBackgroundColorFunction() override {}
};
class BrowserActionEnableFunction : public ExtensionActionShowFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.enable", BROWSERACTION_ENABLE)
protected:
~BrowserActionEnableFunction() override {}
};
class BrowserActionDisableFunction : public ExtensionActionHideFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.disable", BROWSERACTION_DISABLE)
protected:
~BrowserActionDisableFunction() override {}
};
class BrowserActionOpenPopupFunction : public ExtensionActionOpenPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("browserAction.openPopup",
BROWSERACTION_OPEN_POPUP)
protected:
~BrowserActionOpenPopupFunction() override {}
};
} // namespace extensions
//
// pageAction.* aliases for supported pageAction APIs.
//
class PageActionShowFunction : public extensions::ExtensionActionShowFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.show", PAGEACTION_SHOW)
protected:
~PageActionShowFunction() override {}
};
class PageActionHideFunction : public extensions::ExtensionActionHideFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.hide", PAGEACTION_HIDE)
protected:
~PageActionHideFunction() override {}
};
class PageActionSetIconFunction
: public extensions::ExtensionActionSetIconFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.setIcon", PAGEACTION_SETICON)
protected:
~PageActionSetIconFunction() override {}
};
class PageActionSetTitleFunction
: public extensions::ExtensionActionSetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.setTitle", PAGEACTION_SETTITLE)
protected:
~PageActionSetTitleFunction() override {}
};
class PageActionSetPopupFunction
: public extensions::ExtensionActionSetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.setPopup", PAGEACTION_SETPOPUP)
protected:
~PageActionSetPopupFunction() override {}
};
class PageActionGetTitleFunction
: public extensions::ExtensionActionGetTitleFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.getTitle", PAGEACTION_GETTITLE)
protected:
~PageActionGetTitleFunction() override {}
};
class PageActionGetPopupFunction
: public extensions::ExtensionActionGetPopupFunction {
public:
DECLARE_EXTENSION_FUNCTION("pageAction.getPopup", PAGEACTION_GETPOPUP)
protected:
~PageActionGetPopupFunction() override {}
};
#endif // SHELL_BROWSER_EXTENSIONS_API_EXTENSION_ACTION_EXTENSION_ACTION_API_H_

View File

@@ -13,15 +13,15 @@
#include "chrome/grit/generated_resources.h"
#include "components/strings/grit/components_strings.h"
#include "components/zoom/page_zoom_constants.h"
#include "pdf/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "printing/buildflags/buildflags.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/webui/web_ui_util.h"
#if BUILDFLAG(ENABLE_PDF)
#if BUILDFLAG(ENABLE_PDF_VIEWER)
#include "chrome/browser/pdf/pdf_extension_util.h"
#include "pdf/pdf_features.h"
#endif // BUILDFLAG(ENABLE_PDF)
#endif // BUILDFLAG(ENABLE_PDF_VIEWER)
// To add a new component to this API, simply:
// 1. Add your component to the Component enum in
@@ -48,7 +48,7 @@ ExtensionFunction::ResponseAction ResourcesPrivateGetStringsFunction::Run() {
switch (component) {
case api::resources_private::COMPONENT_PDF:
#if BUILDFLAG(ENABLE_PDF)
#if BUILDFLAG(ENABLE_PDF_VIEWER)
pdf_extension_util::AddStrings(
pdf_extension_util::PdfViewerContext::kPdfViewer, &dict);
pdf_extension_util::AddAdditionalData(true, false, &dict);

View File

@@ -7,20 +7,27 @@
#include <memory>
#include <utility>
#include "base/command_line.h"
#include "base/strings/pattern.h"
#include "base/types/expected_macros.h"
#include "chrome/common/url_constants.h"
#include "components/url_formatter/url_fixer.h"
#include "content/public/browser/navigation_entry.h"
#include "extensions/browser/extension_api_frame_id_map.h"
#include "extensions/browser/extension_prefs.h"
#include "extensions/common/error_utils.h"
#include "extensions/common/extension_features.h"
#include "extensions/common/feature_switch.h"
#include "extensions/common/manifest_constants.h"
#include "extensions/common/mojom/host_id.mojom.h"
#include "extensions/common/permissions/permissions_data.h"
#include "extensions/common/switches.h"
#include "shell/browser/api/electron_api_web_contents.h"
#include "shell/browser/native_window.h"
#include "shell/browser/web_contents_zoom_controller.h"
#include "shell/browser/window_list.h"
#include "shell/common/extensions/api/tabs.h"
#include "third_party/blink/public/common/chrome_debug_urls.h"
#include "third_party/blink/public/common/page/page_zoom.h"
#include "url/gurl.h"
@@ -468,17 +475,25 @@ bool IsKillURL(const GURL& url) {
DCHECK(url.IsAboutBlank() || url.IsAboutSrcdoc());
#endif
static const char* const kill_hosts[] = {
chrome::kChromeUICrashHost, chrome::kChromeUIDelayedHangUIHost,
chrome::kChromeUIHangUIHost, chrome::kChromeUIKillHost,
// Disallow common renderer debug URLs.
// Note: this would also disallow JavaScript URLs, but we already explicitly
// check for those before calling into here from PrepareURLForNavigation.
if (blink::IsRendererDebugURL(url)) {
return true;
}
if (!url.SchemeIs(content::kChromeUIScheme)) {
return false;
}
// Also disallow a few more hosts which are not covered by the check above.
static const char* const kKillHosts[] = {
chrome::kChromeUIDelayedHangUIHost, chrome::kChromeUIHangUIHost,
chrome::kChromeUIQuitHost, chrome::kChromeUIRestartHost,
content::kChromeUIBrowserCrashHost, content::kChromeUIMemoryExhaustHost,
};
if (!url.SchemeIs(content::kChromeUIScheme))
return false;
return base::Contains(kill_hosts, url.host_piece());
return base::Contains(kKillHosts, url.host_piece());
}
GURL ResolvePossiblyRelativeURL(const std::string& url_string,
@@ -489,10 +504,18 @@ GURL ResolvePossiblyRelativeURL(const std::string& url_string,
return url;
}
bool PrepareURLForNavigation(const std::string& url_string,
const Extension* extension,
GURL* return_url,
std::string* error) {
bool AllowFileAccess(const ExtensionId& extension_id,
content::BrowserContext* context) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableExtensionsFileAccessCheck) ||
ExtensionPrefs::Get(context)->AllowFileAccess(extension_id);
}
base::expected<GURL, std::string> PrepareURLForNavigation(
const std::string& url_string,
const Extension* extension,
content::BrowserContext* browser_context) {
GURL url = ResolvePossiblyRelativeURL(url_string, extension);
// Ideally, the URL would only be "fixed" for user input (e.g. for URLs
@@ -504,34 +527,62 @@ bool PrepareURLForNavigation(const std::string& url_string,
// Reject invalid URLs.
if (!url.is_valid()) {
const char kInvalidUrlError[] = "Invalid url: \"*\".";
*error = ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string);
return false;
return base::unexpected(
ErrorUtils::FormatErrorMessage(kInvalidUrlError, url_string));
}
// Don't let the extension use JavaScript URLs in API triggered navigations.
if (url.SchemeIs(url::kJavaScriptScheme)) {
const char kJavaScriptUrlsNotAllowedInExtensionNavigations[] =
"JavaScript URLs are not allowed in API based extension navigations. "
"Use "
"chrome.scripting.executeScript instead.";
return base::unexpected(kJavaScriptUrlsNotAllowedInExtensionNavigations);
}
// Don't let the extension crash the browser or renderers.
if (IsKillURL(url)) {
const char kNoCrashBrowserError[] =
"I'm sorry. I'm afraid I can't do that.";
*error = kNoCrashBrowserError;
return false;
return base::unexpected(kNoCrashBrowserError);
}
// Don't let the extension navigate directly to devtools scheme pages, unless
// they have applicable permissions.
if (url.SchemeIs(content::kChromeDevToolsScheme) &&
!(extension->permissions_data()->HasAPIPermission(
extensions::mojom::APIPermissionID::kDevtools) ||
extension->permissions_data()->HasAPIPermission(
extensions::mojom::APIPermissionID::kDebugger))) {
const char kCannotNavigateToDevtools[] =
"Cannot navigate to a devtools:// page without either the devtools or "
"debugger permission.";
*error = kCannotNavigateToDevtools;
return false;
if (url.SchemeIs(content::kChromeDevToolsScheme)) {
bool has_permission =
extension && (extension->permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kDevtools) ||
extension->permissions_data()->HasAPIPermission(
mojom::APIPermissionID::kDebugger));
if (!has_permission) {
const char kCannotNavigateToDevtools[] =
"Cannot navigate to a devtools:// page without either the devtools "
"or "
"debugger permission.";
return base::unexpected(kCannotNavigateToDevtools);
}
}
return_url->Swap(&url);
return true;
// Don't let the extension navigate directly to chrome-untrusted scheme pages.
if (url.SchemeIs(content::kChromeUIUntrustedScheme)) {
const char kCannotNavigateToChromeUntrusted[] =
"Cannot navigate to a chrome-untrusted:// page.";
return base::unexpected(kCannotNavigateToChromeUntrusted);
}
// Don't let the extension navigate directly to file scheme pages, unless
// they have file access.
if (url.SchemeIsFile() &&
!AllowFileAccess(extension->id(), browser_context) &&
base::FeatureList::IsEnabled(
extensions_features::kRestrictFileURLNavigation)) {
const char kFileUrlsNotAllowedInExtensionNavigations[] =
"Cannot navigate to a file URL without local file access.";
return base::unexpected(kFileUrlsNotAllowedInExtensionNavigations);
}
return url;
}
TabsUpdateFunction::TabsUpdateFunction() : web_contents_(nullptr) {}
@@ -566,22 +617,14 @@ ExtensionFunction::ResponseAction TabsUpdateFunction::Run() {
bool TabsUpdateFunction::UpdateURL(const std::string& url_string,
int tab_id,
std::string* error) {
GURL url;
if (!PrepareURLForNavigation(url_string, extension(), &url, error)) {
auto url =
PrepareURLForNavigation(url_string, extension(), browser_context());
if (!url.has_value()) {
*error = std::move(url.error());
return false;
}
const bool is_javascript_scheme = url.SchemeIs(url::kJavaScriptScheme);
// JavaScript URLs are forbidden in chrome.tabs.update().
if (is_javascript_scheme) {
const char kJavaScriptUrlsNotAllowedInTabsUpdate[] =
"JavaScript URLs are not allowed in chrome.tabs.update. Use "
"chrome.tabs.executeScript instead.";
*error = kJavaScriptUrlsNotAllowedInTabsUpdate;
return false;
}
content::NavigationController::LoadURLParams load_params(url);
content::NavigationController::LoadURLParams load_params(*url);
// Treat extension-initiated navigations as renderer-initiated so that the URL
// does not show in the omnibox until it commits. This avoids URL spoofs

View File

@@ -6,6 +6,7 @@
#include "extensions/browser/api/i18n/i18n_api.h"
#include "extensions/browser/extension_function_registry.h"
#include "shell/browser/extensions/api/extension_action/extension_action_api.h"
#include "shell/browser/extensions/api/generated_api_registration.h"
#include "shell/browser/extensions/api/scripting/scripting_api.h"
#include "shell/browser/extensions/api/tabs/tabs_api.h"

View File

@@ -9,8 +9,10 @@
#include "base/command_line.h"
#include "base/containers/contains.h"
#include "base/scoped_observation.h"
#include "chrome/common/chrome_features.h"
#include "content/public/browser/web_contents.h"
#include "electron/buildflags/buildflags.h"
#include "services/device/public/cpp/hid/hid_switches.h"
#include "shell/browser/electron_permission_manager.h"
#include "shell/browser/hid/hid_chooser_context.h"
@@ -19,14 +21,16 @@
#include "shell/browser/web_contents_permission_helper.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "extensions/common/constants.h"
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
namespace {
electron::HidChooserContext* GetChooserContext(
content::BrowserContext* browser_context) {
if (!browser_context)
return nullptr;
return electron::HidChooserContextFactory::GetForBrowserContext(
browser_context);
}
@@ -35,6 +39,70 @@ electron::HidChooserContext* GetChooserContext(
namespace electron {
// Manages the HidDelegate observers for a single browser context.
class ElectronHidDelegate::ContextObservation
: public HidChooserContext::DeviceObserver {
public:
ContextObservation(ElectronHidDelegate* parent,
content::BrowserContext* browser_context)
: parent_(parent), browser_context_(browser_context) {
auto* chooser_context = GetChooserContext(browser_context_);
device_observation_.Observe(chooser_context);
}
ContextObservation(ContextObservation&) = delete;
ContextObservation& operator=(ContextObservation&) = delete;
~ContextObservation() override = default;
// HidChooserContext::DeviceObserver:
void OnDeviceAdded(const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceAdded(device_info);
}
void OnDeviceRemoved(
const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceRemoved(device_info);
}
void OnDeviceChanged(
const device::mojom::HidDeviceInfo& device_info) override {
for (auto& observer : observer_list_)
observer.OnDeviceChanged(device_info);
}
void OnHidManagerConnectionError() override {
for (auto& observer : observer_list_)
observer.OnHidManagerConnectionError();
}
void OnHidChooserContextShutdown() override {
parent_->observations_.erase(browser_context_);
// Return since `this` is now deleted.
}
void AddObserver(content::HidDelegate::Observer* observer) {
observer_list_.AddObserver(observer);
}
void RemoveObserver(content::HidDelegate::Observer* observer) {
observer_list_.RemoveObserver(observer);
}
private:
// Safe because `parent_` owns `this`.
const raw_ptr<ElectronHidDelegate> parent_;
// Safe because `this` is destroyed when the context is lost.
const raw_ptr<content::BrowserContext> browser_context_;
base::ScopedObservation<HidChooserContext, HidChooserContext::DeviceObserver>
device_observation_{this};
base::ObserverList<content::HidDelegate::Observer> observer_list_;
};
ElectronHidDelegate::ElectronHidDelegate() = default;
ElectronHidDelegate::~ElectronHidDelegate() = default;
@@ -45,10 +113,11 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
content::HidChooser::Callback callback) {
DCHECK(render_frame_host);
auto* chooser_context =
GetChooserContext(render_frame_host->GetBrowserContext());
if (!device_observation_.IsObserving())
device_observation_.Observe(chooser_context);
auto* browser_context = render_frame_host->GetBrowserContext();
// Start observing HidChooserContext for permission and device events.
GetContextObserver(browser_context);
DCHECK(base::Contains(observations_, browser_context));
HidChooserController* controller = ControllerForFrame(render_frame_host);
if (controller) {
@@ -67,6 +136,9 @@ std::unique_ptr<content::HidChooser> ElectronHidDelegate::RunChooser(
bool ElectronHidDelegate::CanRequestDevicePermission(
content::BrowserContext* browser_context,
const url::Origin& origin) {
if (!browser_context)
return false;
base::Value::Dict details;
details.Set("securityOrigin", origin.GetURL().spec());
auto* permission_manager = static_cast<ElectronPermissionManager*>(
@@ -81,91 +153,79 @@ bool ElectronHidDelegate::HasDevicePermission(
content::BrowserContext* browser_context,
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device) {
return GetChooserContext(browser_context)
->HasDevicePermission(origin, device);
return browser_context && GetChooserContext(browser_context)
->HasDevicePermission(origin, device);
}
void ElectronHidDelegate::RevokeDevicePermission(
content::BrowserContext* browser_context,
const url::Origin& origin,
const device::mojom::HidDeviceInfo& device) {
return GetChooserContext(browser_context)
->RevokeDevicePermission(origin, device);
if (browser_context) {
GetChooserContext(browser_context)->RevokeDevicePermission(origin, device);
}
}
device::mojom::HidManager* ElectronHidDelegate::GetHidManager(
content::BrowserContext* browser_context) {
if (!browser_context)
return nullptr;
return GetChooserContext(browser_context)->GetHidManager();
}
void ElectronHidDelegate::AddObserver(content::BrowserContext* browser_context,
Observer* observer) {
observer_list_.AddObserver(observer);
auto* chooser_context = GetChooserContext(browser_context);
if (!device_observation_.IsObserving())
device_observation_.Observe(chooser_context);
if (!browser_context)
return;
GetContextObserver(browser_context)->AddObserver(observer);
}
void ElectronHidDelegate::RemoveObserver(
content::BrowserContext* browser_context,
content::HidDelegate::Observer* observer) {
observer_list_.RemoveObserver(observer);
if (!browser_context)
return;
DCHECK(base::Contains(observations_, browser_context));
GetContextObserver(browser_context)->RemoveObserver(observer);
}
const device::mojom::HidDeviceInfo* ElectronHidDelegate::GetDeviceInfo(
content::BrowserContext* browser_context,
const std::string& guid) {
auto* chooser_context = GetChooserContext(browser_context);
if (!chooser_context)
return nullptr;
return chooser_context->GetDeviceInfo(guid);
}
bool ElectronHidDelegate::IsFidoAllowedForOrigin(
content::BrowserContext* browser_context,
const url::Origin& origin) {
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHidBlocklist);
auto* chooser_context = GetChooserContext(browser_context);
return chooser_context && chooser_context->IsFidoAllowedForOrigin(origin);
}
bool ElectronHidDelegate::IsServiceWorkerAllowedForOrigin(
const url::Origin& origin) {
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// WebHID is only available on extension service workers with feature flag
// enabled for now.
if (base::FeatureList::IsEnabled(
features::kEnableWebHidOnExtensionServiceWorker) &&
origin.scheme() == extensions::kExtensionScheme)
return true;
#endif // BUILDFLAG(ENABLE_EXTENSIONS)
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
return false;
}
void ElectronHidDelegate::OnDeviceAdded(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceAdded(device_info);
}
void ElectronHidDelegate::OnDeviceRemoved(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceRemoved(device_info);
}
void ElectronHidDelegate::OnDeviceChanged(
const device::mojom::HidDeviceInfo& device_info) {
for (auto& observer : observer_list_)
observer.OnDeviceChanged(device_info);
}
void ElectronHidDelegate::OnHidManagerConnectionError() {
device_observation_.Reset();
for (auto& observer : observer_list_)
observer.OnHidManagerConnectionError();
}
void ElectronHidDelegate::OnHidChooserContextShutdown() {
device_observation_.Reset();
ElectronHidDelegate::ContextObservation*
ElectronHidDelegate::GetContextObserver(
content::BrowserContext* browser_context) {
if (!base::Contains(observations_, browser_context)) {
observations_.emplace(browser_context, std::make_unique<ContextObservation>(
this, browser_context));
}
return observations_[browser_context].get();
}
HidChooserController* ElectronHidDelegate::ControllerForFrame(

View File

@@ -10,17 +10,24 @@
#include <unordered_map>
#include <vector>
#include "base/observer_list.h"
#include "base/scoped_observation.h"
#include "base/containers/flat_map.h"
#include "content/public/browser/hid_chooser.h"
#include "content/public/browser/hid_delegate.h"
#include "services/device/public/mojom/hid.mojom-forward.h"
#include "shell/browser/hid/hid_chooser_context.h"
#include "third_party/blink/public/mojom/hid/hid.mojom-forward.h"
#include "url/origin.h"
namespace content {
class BrowserContext;
class RenderFrameHost;
} // namespace content
namespace electron {
class HidChooserController;
class ElectronHidDelegate : public content::HidDelegate,
public HidChooserContext::DeviceObserver {
class ElectronHidDelegate : public content::HidDelegate {
public:
ElectronHidDelegate();
ElectronHidDelegate(ElectronHidDelegate&) = delete;
@@ -54,13 +61,6 @@ class ElectronHidDelegate : public content::HidDelegate,
bool IsFidoAllowedForOrigin(content::BrowserContext* browser_context,
const url::Origin& origin) override;
bool IsServiceWorkerAllowedForOrigin(const url::Origin& origin) override;
// HidChooserContext::DeviceObserver:
void OnDeviceAdded(const device::mojom::HidDeviceInfo&) override;
void OnDeviceRemoved(const device::mojom::HidDeviceInfo&) override;
void OnDeviceChanged(const device::mojom::HidDeviceInfo&) override;
void OnHidManagerConnectionError() override;
void OnHidChooserContextShutdown() override;
void IncrementConnectionCount(content::BrowserContext* browser_context,
const url::Origin& origin) override {}
void DecrementConnectionCount(content::BrowserContext* browser_context,
@@ -69,6 +69,14 @@ class ElectronHidDelegate : public content::HidDelegate,
void DeleteControllerForFrame(content::RenderFrameHost* render_frame_host);
private:
class ContextObservation;
ContextObservation* GetContextObserver(
content::BrowserContext* browser_context);
base::flat_map<content::BrowserContext*, std::unique_ptr<ContextObservation>>
observations_;
HidChooserController* ControllerForFrame(
content::RenderFrameHost* render_frame_host);
@@ -78,10 +86,6 @@ class ElectronHidDelegate : public content::HidDelegate,
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters,
content::HidChooser::Callback callback);
base::ScopedObservation<HidChooserContext, HidChooserContext::DeviceObserver>
device_observation_{this};
base::ObserverList<content::HidDelegate::Observer> observer_list_;
std::unordered_map<content::RenderFrameHost*,
std::unique_ptr<HidChooserController>>
controller_map_;
@@ -91,23 +95,4 @@ class ElectronHidDelegate : public content::HidDelegate,
} // namespace electron
namespace base {
template <>
struct ScopedObservationTraits<electron::HidChooserContext,
electron::HidChooserContext::DeviceObserver> {
static void AddObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->AddDeviceObserver(observer);
}
static void RemoveObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->RemoveDeviceObserver(observer);
}
};
} // namespace base
#endif // ELECTRON_SHELL_BROWSER_HID_ELECTRON_HID_DELEGATE_H_

View File

@@ -29,9 +29,14 @@
#include "shell/common/gin_converters/value_converter.h"
#include "shell/common/gin_helper/dictionary.h"
#include "third_party/blink/public/common/permissions/permission_utils.h"
#include "ui/base/l10n/l10n_util.h"
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "base/containers/fixed_flat_set.h"
#include "base/strings/string_piece.h"
#include "extensions/common/constants.h"
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
namespace electron {
const char kHidDeviceNameKey[] = "name";
@@ -182,6 +187,26 @@ bool HidChooserContext::HasDevicePermission(
origin, DeviceInfoToValue(device), browser_context_);
}
bool HidChooserContext::IsFidoAllowedForOrigin(const url::Origin& origin) {
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
static constexpr auto kPrivilegedExtensionIds =
base::MakeFixedFlatSet<base::StringPiece>({
"ckcendljdlmgnhghiaomidhiiclmapok", // gnubbyd-v3 dev
"lfboplenmmjcmpbkeemecobbadnmpfhi", // gnubbyd-v3 prod
});
if (origin.scheme() == extensions::kExtensionScheme &&
base::Contains(kPrivilegedExtensionIds, origin.host())) {
return true;
}
#endif // BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
// This differs from upstream - we want to allow users greater
// ability to communicate with FIDO devices in Electron.
return base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHidBlocklist);
}
void HidChooserContext::AddDeviceObserver(DeviceObserver* observer) {
EnsureHidManagerConnection();
device_observer_list_.AddObserver(observer);

View File

@@ -14,6 +14,7 @@
#include "base/memory/raw_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/observer_list.h"
#include "base/scoped_observation_traits.h"
#include "base/unguessable_token.h"
#include "components/keyed_service/core/keyed_service.h"
#include "content/public/browser/web_contents.h"
@@ -77,6 +78,9 @@ class HidChooserContext : public KeyedService,
bool HasDevicePermission(const url::Origin& origin,
const device::mojom::HidDeviceInfo& device);
// Returns true if `origin` is allowed to access FIDO reports.
bool IsFidoAllowedForOrigin(const url::Origin& origin);
// For ScopedObserver.
void AddDeviceObserver(DeviceObserver* observer);
void RemoveDeviceObserver(DeviceObserver* observer);
@@ -138,4 +142,23 @@ class HidChooserContext : public KeyedService,
} // namespace electron
namespace base {
template <>
struct ScopedObservationTraits<electron::HidChooserContext,
electron::HidChooserContext::DeviceObserver> {
static void AddObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->AddDeviceObserver(observer);
}
static void RemoveObserver(
electron::HidChooserContext* source,
electron::HidChooserContext::DeviceObserver* observer) {
source->RemoveDeviceObserver(observer);
}
};
} // namespace base
#endif // ELECTRON_SHELL_BROWSER_HID_HID_CHOOSER_CONTEXT_H_

View File

@@ -85,12 +85,16 @@ HidChooserController::HidChooserController(
filters_(std::move(filters)),
exclusion_filters_(std::move(exclusion_filters)),
callback_(std::move(callback)),
initiator_document_(render_frame_host->GetWeakDocumentPtr()),
origin_(content::WebContents::FromRenderFrameHost(render_frame_host)
->GetPrimaryMainFrame()
->GetLastCommittedOrigin()),
frame_tree_node_id_(render_frame_host->GetFrameTreeNodeId()),
hid_delegate_(hid_delegate),
render_frame_host_id_(render_frame_host->GetGlobalId()) {
// The use above of GetMainFrame is safe as content::HidService instances are
// not created for fenced frames.
DCHECK(!render_frame_host->IsNestedWithinFencedFrame());
chooser_context_ = HidChooserContextFactory::GetForBrowserContext(
web_contents->GetBrowserContext())
->AsWeakPtr();
@@ -129,6 +133,7 @@ void HidChooserController::OnDeviceAdded(
const device::mojom::HidDeviceInfo& device) {
if (!DisplayDevice(device))
return;
if (AddDeviceInfo(device)) {
api::Session* session = GetSession();
if (session) {
@@ -142,8 +147,6 @@ void HidChooserController::OnDeviceAdded(
session->Emit("hid-device-added", details);
}
}
return;
}
void HidChooserController::OnDeviceRemoved(
@@ -151,7 +154,8 @@ void HidChooserController::OnDeviceRemoved(
if (!base::Contains(items_, PhysicalDeviceIdFromDeviceInfo(device)))
return;
if (api::Session* session = GetSession(); session != nullptr) {
api::Session* session = GetSession();
if (session) {
auto* rfh = content::RenderFrameHost::FromID(render_frame_host_id_);
v8::Isolate* isolate = JavascriptEnvironment::GetIsolate();
v8::HandleScope scope(isolate);
@@ -223,9 +227,8 @@ void HidChooserController::OnGotDevices(
for (auto& device : devices) {
if (DisplayDevice(*device)) {
if (AddDeviceInfo(*device)) {
if (AddDeviceInfo(*device))
devicesToDisplay.push_back(device->Clone());
}
}
}
@@ -233,6 +236,7 @@ void HidChooserController::OnGotDevices(
// enumeration.
if (chooser_context_)
observation_.Observe(chooser_context_.get());
bool prevent_default = false;
api::Session* session = GetSession();
if (session) {
@@ -255,26 +259,41 @@ void HidChooserController::OnGotDevices(
bool HidChooserController::DisplayDevice(
const device::mojom::HidDeviceInfo& device) const {
if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHidBlocklist)) {
// Do not pass the device to the chooser if it is excluded by the blocklist.
if (device.is_excluded_by_blocklist)
return false;
// Check if `device` has a top-level collection with a FIDO usage. FIDO
// devices may be displayed if the origin is privileged or the blocklist is
// disabled.
const bool has_fido_collection =
base::Contains(device.collections, device::mojom::kPageFido,
[](const auto& c) { return c->usage->usage_page; });
// Do not pass the device to the chooser if it has a top-level collection
// with the FIDO usage page.
//
// Note: The HID blocklist also blocks top-level collections with the FIDO
// usage page, but will not block the device if it has other (non-FIDO)
// collections. The check below will exclude the device from the chooser
// if it has any top-level FIDO collection.
auto find_it =
std::find_if(device.collections.begin(), device.collections.end(),
[](const device::mojom::HidCollectionInfoPtr& c) {
return c->usage->usage_page == device::mojom::kPageFido;
});
if (find_it != device.collections.end())
return false;
if (has_fido_collection) {
if (base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kDisableHidBlocklist) ||
(chooser_context_ &&
chooser_context_->IsFidoAllowedForOrigin(origin_))) {
return FilterMatchesAny(device) && !IsExcluded(device);
}
AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kInfo,
base::StringPrintf(
"Chooser dialog is not displaying a FIDO HID device: vendorId=%d, "
"productId=%d, name='%s', serial='%s'",
device.vendor_id, device.product_id, device.product_name.c_str(),
device.serial_number.c_str()));
return false;
}
if (device.is_excluded_by_blocklist) {
AddMessageToConsole(
blink::mojom::ConsoleMessageLevel::kInfo,
base::StringPrintf(
"Chooser dialog is not displaying a device excluded by "
"the HID blocklist: vendorId=%d, "
"productId=%d, name='%s', serial='%s'",
device.vendor_id, device.product_id, device.product_name.c_str(),
device.serial_number.c_str()));
return false;
}
return FilterMatchesAny(device) && !IsExcluded(device);
@@ -303,6 +322,15 @@ bool HidChooserController::IsExcluded(
return false;
}
void HidChooserController::AddMessageToConsole(
blink::mojom::ConsoleMessageLevel level,
const std::string& message) const {
if (content::RenderFrameHost* rfh =
initiator_document_.AsRenderFrameHostIfValid()) {
rfh->AddMessageToConsole(level, message);
}
}
bool HidChooserController::AddDeviceInfo(
const device::mojom::HidDeviceInfo& device) {
const auto& id = PhysicalDeviceIdFromDeviceInfo(device);
@@ -340,10 +368,8 @@ void HidChooserController::UpdateDeviceInfo(
auto physical_device_it = device_map_.find(id);
DCHECK(physical_device_it != device_map_.end());
auto& device_infos = physical_device_it->second;
auto device_it = base::ranges::find_if(
device_infos, [&device](const device::mojom::HidDeviceInfoPtr& d) {
return d->guid == device.guid;
});
auto device_it = base::ranges::find(device_infos, device.guid,
&device::mojom::HidDeviceInfo::guid);
DCHECK(device_it != device_infos.end());
*device_it = device.Clone();
}

View File

@@ -10,8 +10,10 @@
#include <vector>
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "content/public/browser/global_routing_id.h"
#include "content/public/browser/hid_chooser.h"
#include "content/public/browser/weak_document_ptr.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "services/device/public/mojom/hid.mojom-forward.h"
@@ -19,6 +21,7 @@
#include "shell/browser/hid/electron_hid_delegate.h"
#include "shell/browser/hid/hid_chooser_context.h"
#include "shell/common/gin_converters/frame_converter.h"
#include "third_party/blink/public/mojom/devtools/console_message.mojom.h"
#include "third_party/blink/public/mojom/hid/hid.mojom.h"
namespace content {
@@ -75,6 +78,8 @@ class HidChooserController
bool DisplayDevice(const device::mojom::HidDeviceInfo& device) const;
bool FilterMatchesAny(const device::mojom::HidDeviceInfo& device) const;
bool IsExcluded(const device::mojom::HidDeviceInfo& device) const;
void AddMessageToConsole(blink::mojom::ConsoleMessageLevel level,
const std::string& message) const;
// Add |device_info| to |device_map_|. The device is added to the chooser item
// representing the physical device. If the chooser item does not yet exist, a
@@ -97,8 +102,8 @@ class HidChooserController
std::vector<blink::mojom::HidDeviceFilterPtr> filters_;
std::vector<blink::mojom::HidDeviceFilterPtr> exclusion_filters_;
content::HidChooser::Callback callback_;
content::WeakDocumentPtr initiator_document_;
const url::Origin origin_;
const int frame_tree_node_id_;
// The lifetime of the chooser context is tied to the browser context used to
// create it, and may be destroyed while the chooser is still active.

View File

@@ -99,6 +99,11 @@ NativeWindow::NativeWindow(const gin_helper::Dictionary& options,
options.Get(options::kTransparent, &transparent_);
options.Get(options::kEnableLargerThanScreen, &enable_larger_than_screen_);
options.Get(options::kTitleBarStyle, &title_bar_style_);
#if BUILDFLAG(IS_WIN)
options.Get(options::kBackgroundMaterial, &background_material_);
#elif BUILDFLAG(IS_MAC)
options.Get(options::kVibrancyType, &vibrancy_);
#endif
v8::Local<v8::Value> titlebar_overlay;
if (options.Get(options::ktitleBarOverlay, &titlebar_overlay)) {
@@ -352,10 +357,14 @@ void NativeWindow::SetContentSizeConstraints(
size_constraints_.reset();
}
// Windows/Linux:
// The return value of GetContentSizeConstraints will be passed to Chromium
// to set min/max sizes of window. Note that we are returning content size
// instead of window size because that is what Chromium expects, see the
// comment of |WidgetSizeIsClientSize| in Chromium's codebase to learn more.
//
// macOS:
// The min/max sizes are set directly by calling NSWindow's methods.
extensions::SizeConstraints NativeWindow::GetContentSizeConstraints() const {
if (content_size_constraints_)
return *content_size_constraints_;
@@ -475,6 +484,10 @@ bool NativeWindow::AddTabbedWindow(NativeWindow* window) {
return true; // for non-Mac platforms
}
absl::optional<std::string> NativeWindow::GetTabbingIdentifier() const {
return ""; // for non-Mac platforms
}
void NativeWindow::SetVibrancy(const std::string& type) {
vibrancy_ = type;
}
@@ -522,7 +535,7 @@ void NativeWindow::PreviewFile(const std::string& path,
void NativeWindow::CloseFilePreview() {}
gfx::Rect NativeWindow::GetWindowControlsOverlayRect() {
absl::optional<gfx::Rect> NativeWindow::GetWindowControlsOverlayRect() {
return overlay_rect_;
}
@@ -650,6 +663,7 @@ void NativeWindow::NotifyWindowMoved() {
}
void NativeWindow::NotifyWindowEnterFullScreen() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowEnterFullScreen();
}
@@ -675,6 +689,7 @@ void NativeWindow::NotifyWindowSheetEnd() {
}
void NativeWindow::NotifyWindowLeaveFullScreen() {
NotifyLayoutWindowControlsOverlay();
for (NativeWindowObserver& observer : observers_)
observer.OnWindowLeaveFullScreen();
}
@@ -718,10 +733,10 @@ void NativeWindow::NotifyWindowSystemContextMenu(int x,
}
void NativeWindow::NotifyLayoutWindowControlsOverlay() {
gfx::Rect bounding_rect = GetWindowControlsOverlayRect();
if (!bounding_rect.IsEmpty()) {
auto bounding_rect = GetWindowControlsOverlayRect();
if (bounding_rect.has_value()) {
for (NativeWindowObserver& observer : observers_)
observer.UpdateWindowControlsOverlay(bounding_rect);
observer.UpdateWindowControlsOverlay(bounding_rect.value());
}
}

View File

@@ -255,6 +255,7 @@ class NativeWindow : public base::SupportsUserData,
virtual void MoveTabToNewWindow();
virtual void ToggleTabBar();
virtual bool AddTabbedWindow(NativeWindow* window);
virtual absl::optional<std::string> GetTabbingIdentifier() const;
// Toggle the menu bar.
virtual void SetAutoHideMenuBar(bool auto_hide);
@@ -284,7 +285,7 @@ class NativeWindow : public base::SupportsUserData,
return weak_factory_.GetWeakPtr();
}
virtual gfx::Rect GetWindowControlsOverlayRect();
virtual absl::optional<gfx::Rect> GetWindowControlsOverlayRect();
virtual void SetWindowControlsOverlayRect(const gfx::Rect& overlay_rect);
// Methods called by the WebContents.

View File

@@ -58,6 +58,8 @@ class NativeWindowMac : public NativeWindow,
gfx::Rect GetBounds() override;
bool IsNormal() override;
gfx::Rect GetNormalBounds() override;
void SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) override;
void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) override;
void SetResizable(bool resizable) override;
@@ -143,6 +145,7 @@ class NativeWindowMac : public NativeWindow,
void MoveTabToNewWindow() override;
void ToggleTabBar() override;
bool AddTabbedWindow(NativeWindow* window) override;
absl::optional<std::string> GetTabbingIdentifier() const override;
void SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) override;
void PreviewFile(const std::string& path,
@@ -150,7 +153,7 @@ class NativeWindowMac : public NativeWindow,
void CloseFilePreview() override;
gfx::Rect ContentBoundsToWindowBounds(const gfx::Rect& bounds) const override;
gfx::Rect WindowBoundsToContentBounds(const gfx::Rect& bounds) const override;
gfx::Rect GetWindowControlsOverlayRect() override;
absl::optional<gfx::Rect> GetWindowControlsOverlayRect() override;
void NotifyWindowEnterFullScreen() override;
void NotifyWindowLeaveFullScreen() override;
void SetActive(bool is_key) override;
@@ -186,6 +189,9 @@ class NativeWindowMac : public NativeWindow,
has_deferred_window_close_ = defer_close;
}
void set_wants_to_be_visible(bool visible) { wants_to_be_visible_ = visible; }
bool wants_to_be_visible() const { return wants_to_be_visible_; }
enum class VisualEffectState {
kFollowWindow,
kActive,
@@ -252,6 +258,10 @@ class NativeWindowMac : public NativeWindow,
// transition is complete.
bool has_deferred_window_close_ = false;
// If true, the window is either visible, or wants to be visible but is
// currently hidden due to having a hidden parent.
bool wants_to_be_visible_ = false;
NSInteger attention_request_id_ = 0; // identifier from requestUserAttention
// The presentation options before entering kiosk mode.

View File

@@ -496,6 +496,8 @@ void NativeWindowMac::Show() {
return;
}
set_wants_to_be_visible(true);
// Reattach the window to the parent to actually show it.
if (parent())
InternalSetParentWindow(parent(), true);
@@ -528,6 +530,10 @@ void NativeWindowMac::Hide() {
return;
}
// If the window wants to be visible and has a parent, then the parent may
// order it back in (in the period between orderOut: and close).
set_wants_to_be_visible(false);
DetachChildren();
// Detach the window from the parent before.
@@ -663,6 +669,9 @@ void NativeWindowMac::RemoveChildFromParentWindow() {
void NativeWindowMac::AttachChildren() {
for (auto* child : child_windows_) {
if (!static_cast<NativeWindowMac*>(child)->wants_to_be_visible())
continue;
auto* child_nswindow = child->GetNativeWindow().GetNativeNSWindow();
if ([child_nswindow parentWindow] == window_)
continue;
@@ -676,8 +685,6 @@ void NativeWindowMac::AttachChildren() {
}
void NativeWindowMac::DetachChildren() {
DCHECK(child_windows_.size() == [[window_ childWindows] count]);
// Hide all children before hiding/minimizing the window.
// NativeWidgetNSWindowBridge::NotifyVisibilityChangeDown()
// will DCHECK otherwise.
@@ -774,6 +781,16 @@ gfx::Rect NativeWindowMac::GetNormalBounds() {
// return widget()->GetRestoredBounds();
}
void NativeWindowMac::SetSizeConstraints(
const extensions::SizeConstraints& window_constraints) {
// Apply the size constraints to NSWindow.
if (window_constraints.HasMinimumSize())
[window_ setMinSize:window_constraints.GetMinimumSize().ToCGSize()];
if (window_constraints.HasMaximumSize())
[window_ setMaxSize:window_constraints.GetMaximumSize().ToCGSize()];
NativeWindow::SetSizeConstraints(window_constraints);
}
void NativeWindowMac::SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) {
auto convertSize = [this](const gfx::Size& size) {
@@ -788,6 +805,7 @@ void NativeWindowMac::SetContentSizeConstraints(
}
};
// Apply the size constraints to NSWindow.
NSView* content = [window_ contentView];
if (size_constraints.HasMinimumSize()) {
NSSize min_size = convertSize(size_constraints.GetMinimumSize());
@@ -1422,11 +1440,21 @@ void NativeWindowMac::UpdateVibrancyRadii(bool fullscreen) {
if (vibrantView != nil && !vibrancy_type_.empty()) {
const bool no_rounded_corner = !HasStyleMask(NSWindowStyleMaskTitled);
if (!has_frame() && !is_modal() && !no_rounded_corner) {
const int macos_version = base::mac::MacOSMajorVersion();
// Modal window corners are rounded on macOS >= 11 or higher if the user
// hasn't passed noRoundedCorners.
bool should_round_modal =
!no_rounded_corner && (macos_version >= 11 ? true : !is_modal());
// Nonmodal window corners are rounded if they're frameless and the user
// hasn't passed noRoundedCorners.
bool should_round_nonmodal = !no_rounded_corner && !has_frame();
if (should_round_nonmodal || should_round_modal) {
CGFloat radius;
if (fullscreen) {
radius = 0.0f;
} else if (@available(macOS 11.0, *)) {
} else if (macos_version >= 11) {
radius = 9.0f;
} else {
// Smaller corner radius on versions prior to Big Sur.
@@ -1635,6 +1663,13 @@ bool NativeWindowMac::AddTabbedWindow(NativeWindow* window) {
return true;
}
absl::optional<std::string> NativeWindowMac::GetTabbingIdentifier() const {
if ([window_ tabbingMode] == NSWindowTabbingModeDisallowed)
return absl::nullopt;
return base::SysNSStringToUTF8([window_ tabbingIdentifier]);
}
void NativeWindowMac::SetAspectRatio(double aspect_ratio,
const gfx::Size& extra_size) {
NativeWindow::SetAspectRatio(aspect_ratio, extra_size);
@@ -1875,23 +1910,33 @@ void NativeWindowMac::SetForwardMouseMessages(bool forward) {
[window_ setAcceptsMouseMovedEvents:forward];
}
gfx::Rect NativeWindowMac::GetWindowControlsOverlayRect() {
if (titlebar_overlay_ && buttons_proxy_ &&
window_button_visibility_.value_or(true)) {
absl::optional<gfx::Rect> NativeWindowMac::GetWindowControlsOverlayRect() {
if (!titlebar_overlay_)
return absl::nullopt;
// On macOS, when in fullscreen mode, window controls (the menu bar, title
// bar, and toolbar) are attached to a separate NSView that slides down from
// the top of the screen, independent of, and overlapping the WebContents.
// Disable WCO when in fullscreen, because this space is inaccessible to
// WebContents. https://crbug.com/915110.
if (IsFullscreen())
return gfx::Rect();
if (buttons_proxy_ && window_button_visibility_.value_or(true)) {
NSRect buttons = [buttons_proxy_ getButtonsContainerBounds];
gfx::Rect overlay;
overlay.set_width(GetContentSize().width() - NSWidth(buttons));
if ([buttons_proxy_ useCustomHeight]) {
overlay.set_height(titlebar_overlay_height());
} else {
overlay.set_height(NSHeight(buttons));
}
overlay.set_height([buttons_proxy_ useCustomHeight]
? titlebar_overlay_height()
: NSHeight(buttons));
if (!base::i18n::IsRTL())
overlay.set_x(NSMaxX(buttons));
return overlay;
}
return gfx::Rect();
return absl::nullopt;
}
// static

View File

@@ -7,6 +7,7 @@
#include <wrl/client.h>
#include "base/win/atl.h" // Must be before UIAutomationCore.h
#include "base/win/scoped_handle.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "shell/browser/browser.h"
#include "shell/browser/native_window_views.h"
@@ -165,10 +166,41 @@ gfx::ResizeEdge GetWindowResizeEdge(WPARAM param) {
}
}
bool IsMutexPresent(const wchar_t* name) {
base::win::ScopedHandle mutex_holder(::CreateMutex(nullptr, false, name));
return ::GetLastError() == ERROR_ALREADY_EXISTS;
}
bool IsLibraryLoaded(const wchar_t* name) {
HMODULE hmodule = nullptr;
::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, name,
&hmodule);
return hmodule != nullptr;
}
// The official way to get screen reader status is to call:
// SystemParametersInfo(SPI_GETSCREENREADER) && UiaClientsAreListening()
// However it has false positives (for example when user is using touch screens)
// and will cause performance issues in some apps.
bool IsScreenReaderActive() {
UINT screenReader = 0;
SystemParametersInfo(SPI_GETSCREENREADER, 0, &screenReader, 0);
return screenReader && UiaClientsAreListening();
if (IsMutexPresent(L"NarratorRunning"))
return true;
static const wchar_t* names[] = {// NVDA
L"nvdaHelperRemote.dll",
// JAWS
L"jhook.dll",
// Window-Eyes
L"gwhk64.dll", L"gwmhook.dll",
// ZoomText
L"AiSquared.Infuser.HookLib.dll"};
for (auto* name : names) {
if (IsLibraryLoaded(name))
return true;
}
return false;
}
} // namespace

View File

@@ -27,10 +27,14 @@ void Notification::NotificationClicked() {
Destroy();
}
void Notification::NotificationDismissed() {
void Notification::NotificationDismissed(bool should_destroy) {
if (delegate())
delegate()->NotificationClosed();
Destroy();
set_is_dismissed(true);
if (should_destroy)
Destroy();
}
void Notification::NotificationFailed(const std::string& error) {
@@ -39,6 +43,8 @@ void Notification::NotificationFailed(const std::string& error) {
Destroy();
}
void Notification::Remove() {}
void Notification::Destroy() {
presenter()->RemoveNotification(this);
}

View File

@@ -50,13 +50,19 @@ class Notification {
// Shows the notification.
virtual void Show(const NotificationOptions& options) = 0;
// Closes the notification, this instance will be destroyed after the
// notification gets closed.
// Dismisses the notification. On some platforms this will result in full
// removal and destruction of the notification, but if the initial dismissal
// does not fully get rid of the notification it will be destroyed in Remove.
virtual void Dismiss() = 0;
// Removes the notification if it was not fully removed during dismissal,
// as can happen on some platforms including Windows.
virtual void Remove();
// Should be called by derived classes.
void NotificationClicked();
void NotificationDismissed();
void NotificationDismissed(bool should_destroy = true);
void NotificationFailed(const std::string& error = "");
// delete this.
@@ -68,10 +74,12 @@ class Notification {
void set_delegate(NotificationDelegate* delegate) { delegate_ = delegate; }
void set_notification_id(const std::string& id) { notification_id_ = id; }
void set_is_dismissed(bool dismissed) { is_dismissed_ = dismissed; }
NotificationDelegate* delegate() const { return delegate_; }
NotificationPresenter* presenter() const { return presenter_; }
const std::string& notification_id() const { return notification_id_; }
bool is_dismissed() const { return is_dismissed_; }
// disable copy
Notification(const Notification&) = delete;
@@ -85,6 +93,7 @@ class Notification {
raw_ptr<NotificationDelegate> delegate_;
raw_ptr<NotificationPresenter> presenter_;
std::string notification_id_;
bool is_dismissed_ = false;
base::WeakPtrFactory<Notification> weak_factory_{this};
};

View File

@@ -8,6 +8,8 @@
#include "shell/browser/notifications/win/windows_toast_notification.h"
#include <string_view>
#include <shlobj.h>
#include <wrl\wrappers\corewrappers.h>
@@ -34,6 +36,8 @@ using ABI::Windows::Data::Xml::Dom::IXmlNodeList;
using ABI::Windows::Data::Xml::Dom::IXmlText;
using Microsoft::WRL::Wrappers::HStringReference;
namespace winui = ABI::Windows::UI;
#define RETURN_IF_FAILED(hr) \
do { \
HRESULT _hrTemp = hr; \
@@ -47,8 +51,7 @@ using Microsoft::WRL::Wrappers::HStringReference;
std::string _msgTemp = msg; \
if (FAILED(_hrTemp)) { \
std::string _err = _msgTemp + ",ERROR " + std::to_string(_hrTemp); \
if (IsDebuggingNotifications()) \
LOG(INFO) << _err; \
DebugLog(_err); \
Notification::NotificationFailed(_err); \
return _hrTemp; \
} \
@@ -58,17 +61,23 @@ namespace electron {
namespace {
bool IsDebuggingNotifications() {
return base::Environment::Create()->HasVar("ELECTRON_DEBUG_NOTIFICATIONS");
// This string needs to be max 16 characters to work on Windows 10 prior to
// applying Creators Update (build 15063).
constexpr wchar_t kGroup[] = L"Notifications";
void DebugLog(std::string_view log_msg) {
if (base::Environment::Create()->HasVar("ELECTRON_DEBUG_NOTIFICATIONS"))
LOG(INFO) << log_msg;
}
} // namespace
// static
ComPtr<ABI::Windows::UI::Notifications::IToastNotificationManagerStatics>
ComPtr<winui::Notifications::IToastNotificationManagerStatics>
WindowsToastNotification::toast_manager_;
// static
ComPtr<ABI::Windows::UI::Notifications::IToastNotifier>
ComPtr<winui::Notifications::IToastNotifier>
WindowsToastNotification::toast_notifier_;
// static
@@ -112,17 +121,37 @@ WindowsToastNotification::~WindowsToastNotification() {
void WindowsToastNotification::Show(const NotificationOptions& options) {
if (SUCCEEDED(ShowInternal(options))) {
if (IsDebuggingNotifications())
LOG(INFO) << "Notification created";
DebugLog("Notification created");
if (delegate())
delegate()->NotificationDisplayed();
}
}
void WindowsToastNotification::Remove() {
DebugLog("Removing notification from action center");
ComPtr<winui::Notifications::IToastNotificationManagerStatics2>
toast_manager2;
if (FAILED(toast_manager_.As(&toast_manager2)))
return;
ComPtr<winui::Notifications::IToastNotificationHistory> notification_history;
if (FAILED(toast_manager2->get_History(&notification_history)))
return;
ScopedHString app_id;
if (!GetAppUserModelID(&app_id))
return;
ScopedHString group(kGroup);
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
notification_history->RemoveGroupedTagWithId(tag, group, app_id);
}
void WindowsToastNotification::Dismiss() {
if (IsDebuggingNotifications())
LOG(INFO) << "Hiding notification";
DebugLog("Hiding notification");
toast_notifier_->Hide(toast_notification_.Get());
}
@@ -151,8 +180,7 @@ HRESULT WindowsToastNotification::ShowInternal(
return E_FAIL;
}
ComPtr<ABI::Windows::UI::Notifications::IToastNotificationFactory>
toast_factory;
ComPtr<winui::Notifications::IToastNotificationFactory> toast_factory;
REPORT_AND_RETURN_IF_FAILED(
Windows::Foundation::GetActivationFactory(toast_str, &toast_factory),
"WinAPI: GetActivationFactory failed");
@@ -161,6 +189,19 @@ HRESULT WindowsToastNotification::ShowInternal(
toast_xml.Get(), &toast_notification_),
"WinAPI: CreateToastNotification failed");
ComPtr<winui::Notifications::IToastNotification2> toast2;
REPORT_AND_RETURN_IF_FAILED(
toast_notification_->QueryInterface(IID_PPV_ARGS(&toast2)),
"WinAPI: Getting Notification interface failed");
ScopedHString group(kGroup);
REPORT_AND_RETURN_IF_FAILED(toast2->put_Group(group),
"WinAPI: Setting group failed");
ScopedHString tag(base::as_wcstr(base::UTF8ToUTF16(notification_id())));
REPORT_AND_RETURN_IF_FAILED(toast2->put_Tag(tag),
"WinAPI: Setting tag failed");
REPORT_AND_RETURN_IF_FAILED(SetupCallbacks(toast_notification_.Get()),
"WinAPI: SetupCallbacks failed");
@@ -170,22 +211,20 @@ HRESULT WindowsToastNotification::ShowInternal(
}
HRESULT WindowsToastNotification::GetToastXml(
ABI::Windows::UI::Notifications::IToastNotificationManagerStatics*
toastManager,
winui::Notifications::IToastNotificationManagerStatics* toastManager,
const std::u16string& title,
const std::u16string& msg,
const std::wstring& icon_path,
const std::u16string& timeout_type,
bool silent,
IXmlDocument** toast_xml) {
ABI::Windows::UI::Notifications::ToastTemplateType template_type;
winui::Notifications::ToastTemplateType template_type;
if (title.empty() || msg.empty()) {
// Single line toast.
template_type =
icon_path.empty()
? ABI::Windows::UI::Notifications::ToastTemplateType_ToastText01
: ABI::Windows::UI::Notifications::
ToastTemplateType_ToastImageAndText01;
? winui::Notifications::ToastTemplateType_ToastText01
: winui::Notifications::ToastTemplateType_ToastImageAndText01;
REPORT_AND_RETURN_IF_FAILED(
toast_manager_->GetTemplateContent(template_type, toast_xml),
"XML: Fetching XML ToastImageAndText01 template failed");
@@ -199,9 +238,8 @@ HRESULT WindowsToastNotification::GetToastXml(
// Title and body toast.
template_type =
icon_path.empty()
? ABI::Windows::UI::Notifications::ToastTemplateType_ToastText02
: ABI::Windows::UI::Notifications::
ToastTemplateType_ToastImageAndText02;
? winui::Notifications::ToastTemplateType_ToastText02
: winui::Notifications::ToastTemplateType_ToastImageAndText02;
REPORT_AND_RETURN_IF_FAILED(
toastManager->GetTemplateContent(template_type, toast_xml),
"XML: Fetching XML ToastImageAndText02 template failed");
@@ -567,7 +605,7 @@ HRESULT WindowsToastNotification::XmlDocumentFromString(
}
HRESULT WindowsToastNotification::SetupCallbacks(
ABI::Windows::UI::Notifications::IToastNotification* toast) {
winui::Notifications::IToastNotification* toast) {
event_handler_ = Make<ToastEventHandler>(this);
RETURN_IF_FAILED(
toast->add_Activated(event_handler_.Get(), &activated_token_));
@@ -578,7 +616,7 @@ HRESULT WindowsToastNotification::SetupCallbacks(
}
bool WindowsToastNotification::RemoveCallbacks(
ABI::Windows::UI::Notifications::IToastNotification* toast) {
winui::Notifications::IToastNotification* toast) {
if (FAILED(toast->remove_Activated(activated_token_)))
return false;
@@ -597,32 +635,29 @@ ToastEventHandler::ToastEventHandler(Notification* notification)
ToastEventHandler::~ToastEventHandler() = default;
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
winui::Notifications::IToastNotification* sender,
IInspectable* args) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&Notification::NotificationClicked, notification_));
if (IsDebuggingNotifications())
LOG(INFO) << "Notification clicked";
DebugLog("Notification clicked");
return S_OK;
}
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
ABI::Windows::UI::Notifications::IToastDismissedEventArgs* e) {
winui::Notifications::IToastNotification* sender,
winui::Notifications::IToastDismissedEventArgs* e) {
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE,
base::BindOnce(&Notification::NotificationDismissed, notification_));
if (IsDebuggingNotifications())
LOG(INFO) << "Notification dismissed";
FROM_HERE, base::BindOnce(&Notification::NotificationDismissed,
notification_, false));
DebugLog("Notification dismissed");
return S_OK;
}
IFACEMETHODIMP ToastEventHandler::Invoke(
ABI::Windows::UI::Notifications::IToastNotification* sender,
ABI::Windows::UI::Notifications::IToastFailedEventArgs* e) {
winui::Notifications::IToastNotification* sender,
winui::Notifications::IToastFailedEventArgs* e) {
HRESULT error;
e->get_ErrorCode(&error);
std::string errorMessage =
@@ -630,8 +665,7 @@ IFACEMETHODIMP ToastEventHandler::Invoke(
content::GetUIThreadTaskRunner({})->PostTask(
FROM_HERE, base::BindOnce(&Notification::NotificationFailed,
notification_, errorMessage));
if (IsDebuggingNotifications())
LOG(INFO) << errorMessage;
DebugLog(errorMessage);
return S_OK;
}

View File

@@ -52,6 +52,7 @@ class WindowsToastNotification : public Notification {
// Notification:
void Show(const NotificationOptions& options) override;
void Dismiss() override;
void Remove() override;
private:
friend class ToastEventHandler;

View File

@@ -9,11 +9,11 @@
#include "base/containers/contains.h"
#include "base/values.h"
#include "content/public/common/webplugininfo.h"
#include "extensions/buildflags/buildflags.h"
#include "electron/buildflags/buildflags.h"
#include "url/gurl.h"
#include "url/origin.h"
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
#include "extensions/browser/extension_registry.h"
#include "extensions/browser/extension_util.h"
#include "extensions/common/constants.h"
@@ -36,7 +36,7 @@ base::flat_map<std::string, std::string>
PluginUtils::GetMimeTypeToExtensionIdMap(
content::BrowserContext* browser_context) {
base::flat_map<std::string, std::string> mime_type_to_extension_id_map;
#if BUILDFLAG(ENABLE_EXTENSIONS)
#if BUILDFLAG(ENABLE_ELECTRON_EXTENSIONS)
std::vector<std::string> allowed_extension_ids =
MimeTypesHandler::GetMIMETypeAllowlist();
// Go through the white-listed extensions and try to use them to intercept

View File

@@ -262,6 +262,7 @@ using FullScreenTransitionState =
[super windowDidMiniaturize:notification];
is_minimized_ = true;
shell_->set_wants_to_be_visible(false);
shell_->NotifyWindowMinimize();
}
@@ -269,6 +270,7 @@ using FullScreenTransitionState =
[super windowDidDeminiaturize:notification];
is_minimized_ = false;
shell_->set_wants_to_be_visible(true);
shell_->AttachChildren();
shell_->SetWindowLevel(level_);
shell_->NotifyWindowRestore();

View File

@@ -66,14 +66,18 @@
// Manages the PopUpButtonHandler.
@interface ElectronAccessoryView : NSView
@property(nonatomic, strong) PopUpButtonHandler* popUpButtonHandler;
@end
@implementation ElectronAccessoryView
@synthesize popUpButtonHandler;
- (void)dealloc {
auto* popupButton =
static_cast<NSPopUpButton*>([[self subviews] objectAtIndex:1]);
popupButton.target = nil;
popUpButtonHandler = nil;
}
@end
@@ -149,6 +153,7 @@ void SetAllowedFileTypes(NSSavePanel* dialog, const Filters& filters) {
[accessoryView addSubview:label];
[accessoryView addSubview:popupButton];
[accessoryView setPopUpButtonHandler:popUpButtonHandler];
[dialog setAccessoryView:accessoryView];
}

View File

@@ -142,8 +142,11 @@ void InspectableWebContentsViewViews::CloseDevTools() {
devtools_visible_ = false;
if (devtools_window_) {
inspectable_web_contents()->SaveDevToolsBounds(
devtools_window_->GetWindowBoundsInScreen());
auto save_bounds = devtools_window_->IsMinimized()
? devtools_window_->GetRestoredBounds()
: devtools_window_->GetWindowBoundsInScreen();
inspectable_web_contents()->SaveDevToolsBounds(save_bounds);
devtools_window_.reset();
devtools_window_web_view_ = nullptr;
devtools_window_delegate_ = nullptr;
@@ -216,6 +219,8 @@ const std::u16string InspectableWebContentsViewViews::GetTitle() {
void InspectableWebContentsViewViews::Layout() {
if (!devtools_web_view_->GetVisible()) {
contents_web_view_->SetBoundsRect(GetContentsBounds());
// Propagate layout call to all children, for example browser views.
View::Layout();
return;
}
@@ -233,6 +238,9 @@ void InspectableWebContentsViewViews::Layout() {
devtools_web_view_->SetBoundsRect(new_devtools_bounds);
contents_web_view_->SetBoundsRect(new_contents_bounds);
// Propagate layout call to all children, for example browser views.
View::Layout();
if (GetDelegate())
GetDelegate()->DevToolsResized();
}

Some files were not shown because too many files have changed in this diff Show More