Compare commits

...

132 Commits

Author SHA1 Message Date
Electron Bot
98b05b8428 Bump v6.0.0-nightly.20190212 2019-02-12 10:09:30 -08:00
Shelley Vohr
bf276ecc69 feat: add new components to Display structure (#16870)
* feat: add new components to Display structure

* add internal property

* expose colorDepth

* add specs
2019-02-12 05:34:42 -10:00
Jeremy Apthorp
5a44cc50cf docs: migration guide for register{StandardSchemes => SchemesAsPrivileged} (#16762)
* docs: migration guide for register{StandardSchemes => SchemesAsPrivileged}

cc @nitsakh

* Update docs/api/protocol.md

Co-Authored-By: nornagon <nornagon@nornagon.net>

* Update docs/api/protocol.md

Co-Authored-By: nornagon <nornagon@nornagon.net>

* Update protocol.md

* Update docs/api/protocol.md

Co-Authored-By: nornagon <nornagon@nornagon.net>
2019-02-12 04:31:53 -10:00
Samuel Attard
01c442de64 refactor: convert more files to typescript (#16820) 2019-02-12 04:22:33 -10:00
Charles Kerr
cfbdc40814 fix: release-notes plays more nicely with clerk (#16887)
Explicitly look not just for Clerk's "notes persisted"
message but also its "no release notes" message.
2019-02-12 04:21:20 -10:00
Robo
83894dc5db ci: fix binaries for chromedriver build on macOS (#16893) 2019-02-12 16:14:52 +05:30
Roller Bot
deb36d5008 chore: bump chromium in DEPS to 72.0.3626.107 (#16869) 2019-02-11 17:56:03 -08:00
Electron Bot
8141a26ba9 Bump v6.0.0-nightly.20190211 2019-02-11 17:40:41 -08:00
Samuel Attard
9deaacb454 Revert "Bump v6.0.0-nightly.20190211"
This reverts commit c92233cbc8.
2019-02-11 14:23:46 -08:00
John Kleinschmidt
6a47089c78 ci: Refactor mksnapshot test so that it doesn't stall. (#16875) 2019-02-11 12:21:00 -10:00
Samuel Attard
7baa218ca9 docs: remove removed autosize attribute (#16884)
Closes #16199

Notes: no-notes
2019-02-11 14:15:15 -08:00
Electron Bot
c92233cbc8 Bump v6.0.0-nightly.20190211 2019-02-11 14:08:24 -08:00
Samuel Attard
20d9f4b2b5 Revert "Bump v6.0.0-nightly.20190211"
This reverts commit dc0be294dd.
2019-02-11 14:05:22 -08:00
Electron Bot
dc0be294dd Bump v6.0.0-nightly.20190211 2019-02-11 13:32:01 -08:00
Shelley Vohr
9dd3338ede chore: revert "Bump v6.0.0-nightly.20190208"
This reverts commit 70042d2597.
2019-02-11 13:22:44 -08:00
Milan Burda
d8ba1278d1 chore: disable the remote module in devtools / chrome extension background scripts (#16866)
* cache isRemoteModuleEnabled

* chore: disable the remote module in devtools / chrome extension background scripts
2019-02-11 10:42:37 -10:00
robertgrzonka
a3cdf46fb6 docs: change of previously wrong added Polish emoji into proper one (#16700)
* Change Polish flag

* Change of previously setuped flag of Monaco to Polish flag

* fix: change flags

* add Indonesian flag at former place
* append Polish flag at the end
2019-02-11 10:41:06 -10:00
Samuel Attard
5301808926 docs: reference the webviewTag option in the webview docs (#16879)
Closes #16773

Notes: Add a reference to the "webviewTag" option in the webview docs
2019-02-11 10:38:36 -10:00
Heilig Benedek
ccc60a1f33 fix: enable autofill popups on mac (#16308)
* feat: enable autofill popups on mac

* fix: make popup positioning better

* fix: don't try to show popup when widget is closing or not visible

* fix: unify conditions

* refactor: use PopupViewCommon from chrome directly

* lint: mark constructor explicit

* fix: use a patch instead of dummy functions to make things compile on Windows

* chore: address review suggestions

* Update atom/browser/ui/cocoa/views_delegate_mac.mm

Co-Authored-By: brenca <benecene@gmail.com>
2019-02-11 09:38:58 -10:00
Milan Burda
36ce3e9546 feat: promisify webContents.printToPDF() (#16795) 2019-02-11 09:20:04 -10:00
Shelley Vohr
3effa6f20c feat: add support for scroll lock accelerator (#16873) 2019-02-11 09:13:13 -10:00
Charles Kerr
d57b9cb47f chore: bump spec dependencies (#16872)
* bump dbus-native dependency

* semver/patch and semver/minor bumps

patch bumps for basic-auth, bluebird, graceful-fs.
minor bumps for chai, mocha-junit-reporter, multiparty, temp, walkdir.

* major bumps: ws, yargs

* sync spec/package-lock.json
2019-02-11 09:12:13 -10:00
Samuel Attard
90ebd8eb12 docs: document how setAsDefaultProtocolClient works in Windows Store (#16874)
Closes #16852
2019-02-11 10:51:46 -08:00
Milan Burda
c77e187742 chore: fix "creates offscreen window with correct size" spec on Mac with Retina display (#16867) 2019-02-11 10:35:46 -08:00
Milan Burda
7a3d220347 refactor: implement Chrome Extension APIs without the remote module (#16686)
* refactor: implement Chrome Extension APIs without the remote module

* remove unused potentiallyRemoteRequire
2019-02-10 10:38:14 -08:00
Shelley Vohr
1898f91620 fix: enable property having no effect on submenus (#16835) 2019-02-08 18:07:08 -08:00
Cheng Zhao
d16b581140 fix: remove memory leak when using webFrame and spell checker (#16770)
* fix: do not create native api::WebFrame in webFrame

When reloading a page without restarting renderer process (for example
sandbox mode), the blink::WebFrame is not destroyed, but api::WebFrame
is always recreated for the new page context. This leaves a leak of
api::WebFrame.

* fix: remove spell checker when page context is released
2019-02-08 13:38:31 -08:00
Milan Burda
3f52e18a38 chore: add menu-will-close comment explaining setTimeout (#16794) 2019-02-08 13:38:03 -08:00
Electron Bot
70042d2597 Bump v6.0.0-nightly.20190208 2019-02-08 13:28:42 -08:00
Jeremy Apthorp
72f3a22ecc docs: reorder crashReporter notes to make more sense (#16825)
the note about reports from child processes on Windows should be next to the code snippet.

Side note: is that code even still necessary?
2019-02-08 13:26:59 -08:00
Shelley Vohr
c80c3c18dc Revert "Bump v6.0.0-nightly.20190207"
This reverts commit c8282efb75.
2019-02-08 13:26:18 -08:00
Samuel Attard
10607f7e86 chore: make crash-reporter specs not use URL module (#16840) 2019-02-08 13:22:07 -08:00
Shelley Vohr
ccf46a57bc fix: display empty menu item for non-visible submenus (#16832)
* fix: display empty menu item for nonvisible submenus

* use Chromium UI string ID
2019-02-08 13:19:01 -08:00
Shelley Vohr
062778c031 fix: don't construct submenu if it's invisible (#16834) 2019-02-08 12:54:39 -08:00
Samuel Attard
833daaa2b2 chore: add helper to wait for a window to load in a remote-safe way (#16837) 2019-02-08 12:26:03 -08:00
Milan Burda
1632c4b837 refactor: implement chrome.i18n.getMessage() without the remote module (#16739)
* refactor: implement chrome.i18n.getMessage() without the remote module

* replace navigator.language with app.getLocale()
2019-02-08 12:07:09 -08:00
Roller Bot
b97f6bd7d4 chore: bump chromium in DEPS to 72.0.3626.102 (#16830) 2019-02-08 10:36:37 -08:00
Samuel Attard
23b84917e0 ci: set MAS_BUILD=true on mas builds (#16824) 2019-02-08 10:12:18 -08:00
Shelley Vohr
e790dbd737 chore: add standalone function deprecation helper (#16782) 2019-02-08 09:50:11 -08:00
Electron Bot
c8282efb75 Bump v6.0.0-nightly.20190207 2019-02-07 14:13:50 -08:00
Julien Isorce
27bd47a333 feat: implement BrowserWindow.moveTop on X11 (#16629)
It was implemented on Mac and Win but not on X11.
Tested on Ubuntu 16.04 and 18.04.

Also added a unit test in spec/api-browser-window-spec.js.
This test BrowserWindow.moveTop verifies that calling moveTop
on a window does not give the focus to this window.

notes: BrowserWindow.moveTop is now available on Linux/x11

https://github.com/electron/electron/issues/12516
2019-02-07 12:48:19 -08:00
Samuel Attard
db11b9b13b fix: restore accidentally removed chrome-extension require (#16819) 2019-02-07 12:38:57 -08:00
Jeremy Apthorp
4989ecc5e0 chore: re-export chromium patches (#16818)
this is the changeset from running import-patches && export-patches. should be idempotent now.
2019-02-07 12:03:25 -08:00
Shelley Vohr
9ebba76c03 chore: improve existing error preservation in promisify (#16815)
This PR better preserves existing behavior in `deprecate.promisify()` in the cases where the promise fails. Previously, if a callback was only called with `data` instead of `err, data` and the promise was rejected, `data` would be populated with `err`, which could be confusing to users. This makes it such that `err` is called back on promise rejection if a callback is called with `err, data` a la Node.js.
2019-02-07 10:25:20 -08:00
Samuel Attard
4f8ebafa97 chore: dont log 100000000 chars of URL (#16800) 2019-02-07 08:50:47 -08:00
Shelley Vohr
29501dbd01 Revert "Bump v6.0.0-nightly.20190206"
This reverts commit e8608c2dbd.
2019-02-06 18:23:14 -08:00
Electron Bot
acabf6f5ab Bump v6.0.0-nightly.20190206 2019-02-06 16:52:57 -08:00
Shelley Vohr
c6fc5a23fc Revert "build: hack around GitHub upload API failure / flake (#16663)" (#16802)
This reverts commit ab503c7e43.
2019-02-06 16:51:45 -08:00
Shelley Vohr
c8a1231ad7 Revert "Bump v6.0.0-nightly.20190206"
This reverts commit 2d1438456b.
2019-02-06 16:23:08 -08:00
Jeremy Apthorp
6d68026c6c chore: fix ts config to not complain about extraneous files (#16790) 2019-02-06 15:46:10 -08:00
Electron Bot
2d1438456b Bump v6.0.0-nightly.20190206 2019-02-06 15:11:34 -08:00
Roller Bot
dd5264b4d1 chore: bump chromium in DEPS to 72.0.3626.99 (#16779) 2019-02-06 14:50:58 -08:00
Electron Bot
e8608c2dbd Bump v6.0.0-nightly.20190206 2019-02-06 14:43:32 -08:00
Shelley Vohr
a569dad8c5 build: remove non-arm vstsJobs (#16793) 2019-02-06 13:36:17 -08:00
Samuel Attard
17c240a639 ci: make macOS CI faster (#16766)
* ci: cache brew update result

* ci: checkout and sync the macOS build on a linux machine for speed
2019-02-06 13:16:11 -08:00
Samuel Attard
fc06458038 ci: run lint on CircleCI (#16791) 2019-02-06 12:53:25 -08:00
Shelley Vohr
84eef16755 chore: depend on mojo audio and video in BUILD.gn (#16785) 2019-02-06 11:03:39 -08:00
pol
c76459738e docs: fix security doc url check (#16775) 2019-02-06 10:43:58 -08:00
Gilbert Emerson
76d919fff5 docs: added webContents.getType() method (#16767)
* docs: added webContents.getType() method

* docs: add enumeration of return value for webContents.getType()

* docs: getType() in WebContents should be class method not module method
2019-02-06 10:42:34 -08:00
Samuel Attard
26df9992cf build: use typescript for internal Electron JS code (#16441) 2019-02-06 10:27:20 -08:00
Shelley Vohr
858781ba83 feat: allow Menu.buildFromTemplate() to accept MenuItems (#16697)
* feat: allow Menu.buildFromTemplate to accept MenuItems

* add another spec

* fix linter error

* add submenu spec
2019-02-06 10:04:40 -08:00
Milan Burda
4211a9c69f refactor: use ipcRendererUtils.invokeSync / ipcMainUtils.handleSync (#16759) 2019-02-06 09:53:28 -08:00
Jeremy Apthorp
b7d8234a86 docs: add some troubleshooting info related to win_delay_load_hook (#16764)
* docs: add some troubleshooting info related to win_delay_load_hook

* appease lint
2019-02-06 08:29:58 -08:00
Cheng Zhao
d53b51607c fix: do not increase ref-counting in wrong thread (#16738) 2019-02-06 18:22:02 +09:00
Heilig Benedek
ff461d9d26 fix: make getUserMedia APIs work again on C72+ (#16763)
* fix: resolve macos check for video and audio capture devices

* fix: resolve a minor compilation error
2019-02-05 21:25:42 -08:00
Jeremy Apthorp
b7afec0743 docs: improve app.commandLine documentation (#16757) 2019-02-05 16:22:25 -08:00
Shelley Vohr
8946cfd4f1 chore: fix dependency vulnerabilities (#16756) 2019-02-05 15:19:55 -08:00
Shelley Vohr
793d6c3691 chore: remove release notes semantic PR map (#16758) 2019-02-05 15:19:26 -08:00
Samuel Attard
b29e8d18a8 chore: auto-format GN and python files in our precommit (#16722)
* chore: auto-format GN files in our precommit

* chore: update python linting errors and auto-lint python files

* chore: add trick for CHROMIUM_BUILDTOOLS_PATH

* chore: apply suggestions from code review

Co-Authored-By: MarshallOfSound <samuel.r.attard@gmail.com>
2019-02-05 13:54:45 -08:00
Milan Burda
6d674eebb1 refactor: crashReporterInit (#16729) 2019-02-05 12:56:44 -08:00
Roller Bot
c486ab207a chore: bump chromium in DEPS to 72.0.3626.94 (#16745) 2019-02-05 12:17:12 -08:00
Samuel Attard
b202ad1e24 refactor: remove js2asar.py and port logic to JS in more readable / GN-style way (#16718)
* refactor: remove js2asar.py and port logic to JS in more readable / GN-style way

* refactor: further clean up ASAR impl, add new node_action GN template
2019-02-05 12:10:15 -08:00
Samuel Attard
8582325e85 build: ensure index.json is actually valid JSON before uploading (#16518)
* build: ensure index.json is actually valid JSON before uploading

* chore: fix py linting for validation of index.json
2019-02-05 11:36:31 -08:00
Jeremy Apthorp
9b7eb0eecb chore: update issue template, comment out instructions (#16721) 2019-02-05 10:10:24 -08:00
Shelley Vohr
e098d08728 docs: we shouldn't promisify net apis (#16736) 2019-02-04 22:25:59 -08:00
Shelley Vohr
f303caa87c refactor: remove ServiceWorker APIs from WebContents (#16717) 2019-02-04 22:22:46 -08:00
Roller Bot
3aa8ec0818 chore: bump chromium in DEPS to 72.0.3626.90 (#16710) 2019-02-04 16:25:53 -08:00
Cheng Zhao
758d709c7a fix: crash when calling setProgressBar on macOS (#16374)
* fix: correctly check whether dock has progress bar

* fix: do not leak memory when setting dockTile
2019-02-04 15:59:06 -08:00
Shelley Vohr
698d348168 feat: support capslock and numlock as accelerators (#16719)
* feat: support capslock as accelerator

* also add numlock
2019-02-04 15:54:59 -08:00
Shelley Vohr
f142aae9eb chore: remove unused variable in removeWindow (#16715) 2019-02-04 15:00:39 -08:00
Shelley Vohr
a9991f5451 chore: fix falsy comments edge case in release notes (#16720) 2019-02-04 14:57:38 -08:00
Samuel Attard
af64140100 refactor: enforce naming of ipcMainInternal (#16689) 2019-02-04 14:49:53 -08:00
JohanG2012
cacb56b103 Add missing let (#15746) 2019-02-04 11:02:01 -08:00
Birunthan Mohanathas
24f1eac84f docs: Recommend use of callback with dialog.showSaveDialog (#16649)
See #14606.

Notes: no-notes
2019-02-03 23:56:51 -08:00
John Kleinschmidt
0a047194b6 ci: move mac release tests to nightly cron job (#16685) 2019-02-01 15:07:23 -05:00
Milan Burda
7dc565fc2e refactor: implement inspector APIs without the remote module (#16607) 2019-02-01 19:56:46 +01:00
michtsu
392458b252 Add devtools API to inspect shared worker. (#16615) 2019-02-01 10:44:24 -08:00
Charles Kerr
efe52f66e4 fix: show proper clerk notes in release notes script (#16659)
* fix: Note detection in PR

* fix: 'BREAKING CHANGE' detection in PR body

* fix: when to include PRs that landed in other branches too

* fix: when available, use clerk's notes
2019-02-01 10:31:03 -06:00
Xinayu
52952f7d51 Update menu.md (#16670) 2019-02-01 08:28:28 -08:00
Shelley Vohr
bae09643c1 docs: fix referrer typedef in OnCompletedDetails (#16661) 2019-02-01 07:54:31 -08:00
Cheng Zhao
31c7ed9b8c fix: shutdown after message loop is ready (#16671) 2019-02-01 10:21:49 -05:00
Samuel Attard
ab503c7e43 build: hack around GitHub upload API failure / flake (#16663) 2019-01-31 15:21:41 -08:00
Shelley Vohr
c8c1be7ae5 feat: add window removeMenu() method (#16570)
* feat: add window removeMenu() method

* chore: remove original method from docs and code

* retain backwards compatibility
2019-01-31 10:58:23 -08:00
John Kleinschmidt
2f35c98e76 ci: build mac on CircleCI (#16552) 2019-01-31 12:59:32 -05:00
John Kleinschmidt
d71f1fb30c ci: Run Windows Electron tests first to show those failures first (#16610)
* Run electron tests first to show those failures first

Enable logging on CI

* disable failing tests on Windows 32 bit

* Temporarily disable testing mksnapshot as that seems to hang
2019-01-31 12:39:05 -05:00
Birunthan Mohanathas
6c77c220f7 chore: Fix typo in AtomDownloadManagerDelegate::OnDownloadSaveDialogDone (#16646)
I believe the existing code was fine, but better be safe than sorry.
This typo was introduced in #16612.
2019-01-31 20:18:20 +09:00
Charles Kerr
76dcbcd6ea chore: fix 'browserView' typo (#16621) 2019-01-30 21:07:08 -08:00
Shelley Vohr
ba57e1d991 feat: promisify contentTracing recording APIs (#16584)
* feat: promisify contentTracing.startRecording()

* feat: promisify contentTracing.stopRecording()

* test: convert specs for new promisified apis

* chore: deprecate and ensure legacy tests work
2019-01-30 18:53:55 -08:00
Heilig Benedek
cbb5164cc8 fix: improve the way frameless windows are handled on Windows (#16596)
* fix: improve the way frameless windows are handled on Windows

* tidy up code

* fix: return nullAcceleratedWidget instead of nullptr

* fix: format, use reinterpret cast
2019-01-31 11:19:47 +09:00
Vladimir
49ec7e1582 feat: flexible autoresize for BrowserViews (#16184)
* feat: flexible autoresize for BrowserViews

* fix: change to static_cast

* Slight format code
2019-01-31 11:07:19 +09:00
Birunthan Mohanathas
927aac306f fix: use async save dialog for anchor download attribute (#16612) 2019-01-31 11:06:55 +09:00
Nitish Sakhawalkar
bd4e14dcee fix: update docs for protocol API (#16601)
* fix: update docs for protocol API

* upddate source for new attribute name

* update electron-typescript-definitions package
2019-01-30 12:54:18 -08:00
Shelley Vohr
641b47f384 feat: promisify contentTracing.getCategories() (#16583)
* feat: promisify contentTracing.getCategories()

* deprecate contentTracing/getCategories
2019-01-30 12:39:55 -08:00
Jeremy Apthorp
9ed89ace97 fix: expose aes-cfb ciphers from boringssl (#16573)
Ref #16195
2019-01-30 10:34:14 -08:00
Shelley Vohr
c7677b23e6 fix: enable and update osr (#16517)
* fix: enable OSR

* fix some macos errors

* fix client reset not in guard

* fix things not rendering on mac
2019-01-30 09:33:32 -08:00
Shelley Vohr
6e131f2121 docs: remove nonexistent contentTracing methods (#16597) 2019-01-30 08:33:56 -08:00
Milan Burda
dfcee48f81 fix: don't forward IPC filtering events to app for dev-tools and extensions (#16565) 2019-01-30 08:20:03 -08:00
Milan Burda
56c6a51cd2 chore: add miniak to troppers (#16590) 2019-01-29 22:21:38 -08:00
SamvelRaja
8af532ba98 feat: added process.electron to get the electron version in forked process (#16450) 2019-01-29 22:13:18 -08:00
Michael Hamilton
8da91523d0 Fixed a little typo (#16550) 2019-01-29 15:58:01 -08:00
Cheng Zhao
323b688ab8 fix: check the root window in MenuBar::SetPanelFocus (#16581) 2019-01-29 13:21:32 -08:00
Nitish Sakhawalkar
940c4c0787 feat: move webFrame scheme privilege methods to main process (#16416)
* chore: deprecate webFrame.registerURLSchemeAsPrivileged

* Add register schemes protocol api

* update branch to enable browser process API

* Revert deprecation changes

* Fetch API support

* Updated api to take an array, still working on tests

* Update tests

* Remove web frame API

* Minor changes

* update scheme registrations on browser and renderer process

* fix: enable ses.getBlobData spec

* Update breaking changes doc
2019-01-29 16:11:01 +09:00
Jeremy Apthorp
257de6a963 feat: add ELECTRON_DISABLE_SANDBOX env var (#16576) 2019-01-29 15:30:17 +09:00
Milan Burda
fa5442f211 fix: execute session preload scripts in sandboxed renderers (#16538) 2019-01-29 10:16:46 +09:00
Shelley Vohr
a25f82c91f fix: reject with error when url not loaded (#16571)
* fix: reject with error when url not loaded

* improve descriptive spec naming
2019-01-28 14:42:36 -08:00
Jeremy Apthorp
138ba53511 fix: expose ripemd160 hash from boringssl (#16454)
Ref #16195
2019-01-28 13:36:51 -08:00
Shelley Vohr
d105dcc0d3 feat: promisify webContents.hasServiceWorker() (#16535)
* feat: promisify contents.hasServiceWorker()

* spec: add initial test for hasServiceWorker()
2019-01-26 10:23:16 -08:00
Shelley Vohr
5a35c3a279 chore: fix promisify helper (#16544)
* chore: fix promise deprecation helper

* fix deprecations

* update deprecation tests
2019-01-25 14:23:24 -08:00
Jeremy Apthorp
63bf370cc0 fix: registerStreamProtocol callback with large chunks (#16532) 2019-01-25 10:57:26 -08:00
Charles Kerr
8396a2d504 feat: promisify cookies api (#16464)
* feat: promisify the Cookie API

* chore: update specs to test promisified cookies

* chore: add deprecate wrapper for cookie callback API

* docs: update docs to cookie promise changes

* chore: remove redundant namespace use

* docs: improve cookie example

* docs: restore docs for cookie callback API

* chore: restore cookie callback tests

* fix: syntax of cookie promise return types
2019-01-25 12:11:35 -06:00
Milan Burda
e2516dc808 docs: cancel is optional in OnHeadersReceivedResponse (#16506) 2019-01-25 09:41:21 -05:00
Shahzad Lone
74c29fb610 perf: and refactor: Code Scope + Minor Performance Improvement. (#16467)
* We know result's size will be same as app_metrics_'s size so optimize the vector.

Reserving a vector to save on reallocation cost.

* Narrow scopes of variables to avoid error and optimize them.

Made two vectors scope narrower and reserved them because we know the size in advance. This helps save on allocation costs.

* fix spacing
2019-01-25 09:39:32 -05:00
Sofia Nguy
b66b5561ee Electron timelines (#16496) 2019-01-24 16:40:44 -06:00
Milan Burda
713df08e3e chore: remove deprecated modules internally using remote.require in sandboxed renderer context (#15957) 2019-01-24 10:53:52 -08:00
Milan Burda
fef262f829 fix: check process.isMainFrame in sandboxed_renderer/init.js (#16500) 2019-01-24 10:53:16 -08:00
Nitish Sakhawalkar
e6952e2a16 fix: correctly destroy spellcheck client (#16448)
* fix: Destroy spellcheck client

* Address review comments
2019-01-24 08:18:54 -08:00
Tomas Rycl
1db4dd68a7 Troubleshooting for Windows Driver Kit (#16405) 2019-01-23 12:34:18 -08:00
Electron Bot
90151879cc Bump v6.0.0-nightly.20190123 2019-01-23 11:49:22 -08:00
Shelley Vohr
f431ce4971 build: fix individual asset downloading in release script (#16493)
* Revert "build: fix release asset download for now (#16486)"

This reverts commit 7df531bc4e.

* build: clean up asset downloading
2019-01-23 11:47:36 -08:00
Jeremy Apthorp
ad3ea6ec53 ci: re-enable logging on CI (#16257) 2019-01-23 11:28:34 -08:00
Milan Burda
cc90919384 refactor: pass internal flag via IPC message struct for consistency (#16490) 2019-01-23 08:24:57 -08:00
Alexey Kuzmin
0a5adfe365 build: fail a build if some hooks don't succeed (#16369) 2019-01-23 11:31:14 +01:00
224 changed files with 5644 additions and 3712 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,21 @@
{
"extends": "standard",
"parser": "typescript-eslint-parser",
"plugins": ["typescript"],
"env": {
"browser": true
},
"rules": {
"no-var": "error",
"no-unused-vars": 0,
"no-global-assign": 0,
"typescript/no-unused-vars": "error",
"prefer-const": ["error", {
"destructuring": "all"
}]
},
"parserOptions": {
"ecmaVersion": 6,
"sourceType": "module"
}
}

View File

@@ -4,29 +4,39 @@ about: Create a report to help us improve Electron
---
* Output of `node_modules/.bin/electron --version`:
* Operating System (Platform and Version):
* Output of `node_modules/.bin/electron --version` on last known working Electron version (if applicable):
* **Electron Version** (output of `node_modules/.bin/electron --version`):
* <!-- e.g. 4.0.3 -->
* **Operating System** (Platform and Version):
* <!-- e.g. macOS 10.13.6 / Windows 10 (1803) / Ubuntu 18.04 x64 -->
* **Last known working Electron version** (if applicable):
* <!-- e.g. 3.1.0 -->
**Expected Behavior**
A clear and concise description of what you expected to happen.
### Expected Behavior
<!-- A clear and concise description of what you expected to happen. -->
**Actual behavior**
A clear and concise description of what actually happened.
### Actual behavior
<!-- A clear and concise description of what actually happened. -->
**To Reproduce**
### To Reproduce
<!--
Your best chance of getting this bug looked at quickly is to provide a REPOSITORY that can be cloned and run.
-->
<!--
You can fork [electron-quick-start](https://github.com/electron/electron-quick-start) and include a link to the branch with your changes.
-->
<!--
If you provide a URL, please list the commands required to clone/setup/run your repo e.g.
```sh
$ git clone $YOUR_URL -b $BRANCH
$ npm install
$ npm start || electron .
```
**Screenshots**
If applicable, add screenshots to help explain your problem.
-->
**Additional Information**
Add any other context about the problem here.
### Screenshots
<!-- If applicable, add screenshots to help explain your problem. -->
### Additional Information
<!-- Add any other context about the problem here. -->

1
.github/config.yml vendored
View File

@@ -50,6 +50,7 @@ authorizedUsers:
- deepak1556
- jkleinsc
- MarshallOfSound
- miniak
- nitsakh
- nornagon
- zcbenz

3
.gitignore vendored
View File

@@ -59,3 +59,6 @@ spec/.hash
# Generated native addon files
/spec/fixtures/native-addon/echo/build/
# If someone runs tsc this is where stuff will end up
ts-gen

View File

@@ -1,31 +0,0 @@
pool:
vmImage: 'Ubuntu 16.04'
steps:
- bash: |
# "depot_tools" has to be checkout into "//third_party/depot_tools" so pylint.py can a "pylintrc" file.
git clone https://chromium.googlesource.com/chromium/tools/depot_tools.git "${AGENT_BUILDDIRECTORY}/third_party/depot_tools"
echo "##vso[task.setvariable variable=PATH]$PATH:${AGENT_BUILDDIRECTORY}/third_party/depot_tools"
displayName: Setup Depot Tools
- bash: |
chromium_revision="$(grep -A1 chromium_version DEPS | tr -d '\n' | cut -d\' -f4)"
buildtools_revision="$(curl -sL "https://chromium.googlesource.com/chromium/src/+/${chromium_revision}/DEPS?format=TEXT" | base64 -d | grep buildtools_revision -A1 | tr -d '\n' | cut -d\' -f4)"
git clone https://chromium.googlesource.com/chromium/buildtools "${AGENT_TEMPDIRECTORY}/buildtools"
(cd "${AGENT_TEMPDIRECTORY}/buildtools" && git checkout "$buildtools_revision")
echo "##vso[task.setvariable variable=CHROMIUM_BUILDTOOLS_PATH]$AGENT_TEMPDIRECTORY/buildtools"
download_from_google_storage --bucket chromium-gn -s "${AGENT_TEMPDIRECTORY}/buildtools/linux64/gn.sha1"
displayName: Download gn binary
- bash: |
# gn.py tries to find a gclient root folder starting from the current dir.
# When it fails and returns "None" path, the whole script fails. Let's "fix" it.
touch .gclient
# Another option would be to checkout "buildtools" inside the Electron checkout,
# but then we would lint its contents (at least gn format), and it doesn't pass it.
npm install
npm run lint
displayName: Run Lint

120
BUILD.gn
View File

@@ -11,8 +11,10 @@ import("//tools/v8_context_snapshot/v8_context_snapshot.gni")
import("//v8/snapshot_toolchain.gni")
import("build/asar.gni")
import("build/npm.gni")
import("build/tsc.gni")
import("buildflags/buildflags.gni")
import("electron_paks.gni")
import("filenames.auto.gni")
import("filenames.gni")
if (is_mac) {
@@ -53,8 +55,26 @@ config("branding") {
]
}
# We geneate the definitions twice here, once in //electron/electron.d.ts
# and once in $target_gen_dir
# The one in $target_gen_dir is used for the actual TSC build later one
# and the one in //electron/electron.d.ts is used by your IDE (vscode)
# for typescript prompting
npm_action("build_electron_definitions") {
script = "gn-typescript-definitions"
args = [ rebase_path("$target_gen_dir/tsc/typings/electron.d.ts") ]
inputs = auto_filenames.api_docs + [ "package-lock.json" ]
outputs = [
"$target_gen_dir/tsc/typings/electron.d.ts",
]
}
npm_action("atom_browserify_sandbox") {
script = "browserify"
deps = [
":build_electron_definitions",
]
inputs = [
# FIXME(zcbenz): The dependencies of these files are not listed here, so
@@ -62,6 +82,8 @@ npm_action("atom_browserify_sandbox") {
# Use a script to generate all dependencies and put them here.
"lib/sandboxed_renderer/init.js",
"lib/sandboxed_renderer/api/exports/electron.js",
"tsconfig.electron.json",
"tsconfig.json",
]
outputs = [
@@ -74,6 +96,12 @@ npm_action("atom_browserify_sandbox") {
"./lib/sandboxed_renderer/api/exports/electron.js:electron",
"-t",
"aliasify",
"-p",
"[",
"tsify",
"-p",
"tsconfig.electron.json",
"]",
"-o",
rebase_path(outputs[0]),
]
@@ -81,9 +109,14 @@ npm_action("atom_browserify_sandbox") {
npm_action("atom_browserify_isolated") {
script = "browserify"
deps = [
":build_electron_definitions",
]
inputs = [
"lib/isolated_renderer/init.js",
"tsconfig.electron.json",
"tsconfig.json",
]
outputs = [
@@ -94,6 +127,12 @@ npm_action("atom_browserify_isolated") {
"lib/isolated_renderer/init.js",
"-t",
"aliasify",
"-p",
"[",
"tsify",
"-p",
"tsconfig.electron.json",
"]",
"-o",
rebase_path(outputs[0]),
]
@@ -137,7 +176,15 @@ action("atom_js2c") {
rebase_path(sources, root_build_dir)
}
asar("js2asar") {
target_gen_electron_js = "$target_gen_dir/js/electron"
target_gen_default_app_js = "$target_gen_dir/js/default_app"
typescript_build("lib_js") {
deps = [
":build_electron_definitions",
]
type_root = rebase_path("$target_gen_dir/tsc/electron/typings")
sources = filenames.js_sources
if (enable_desktop_capturer) {
sources += [
@@ -156,18 +203,65 @@ asar("js2asar") {
"lib/browser/api/views/text-field.js",
]
}
output_gen_dir = target_gen_electron_js
output_dir_name = "lib"
tsconfig = "tsconfig.electron.json"
}
asar("electron_asar") {
deps = [
":lib_js",
]
root = "$target_gen_electron_js/electron/lib"
sources = get_target_outputs(":lib_js")
outputs = [
"$root_out_dir/resources/electron.asar",
]
root = "lib"
}
asar("app2asar") {
sources = filenames.default_app_sources
typescript_build("default_app_js") {
deps = [
":build_electron_definitions",
]
type_root = rebase_path("$target_gen_dir/tsc/electron/typings")
sources = filenames.default_app_ts_sources
output_gen_dir = target_gen_default_app_js
output_dir_name = "default_app"
tsconfig = "tsconfig.default_app.json"
}
copy("default_app_static") {
sources = filenames.default_app_static_sources
outputs = [
"$target_gen_default_app_js/{{source}}",
]
}
copy("default_app_octicon_deps") {
sources = filenames.default_app_octicon_sources
outputs = [
"$target_gen_default_app_js/electron/default_app/octicon/{{source_file_part}}",
]
}
asar("default_app_asar") {
deps = [
":default_app_js",
":default_app_octicon_deps",
":default_app_static",
]
root = "$target_gen_default_app_js/electron/default_app"
sources = get_target_outputs(":default_app_js") +
get_target_outputs(":default_app_static") +
get_target_outputs(":default_app_octicon_deps")
outputs = [
"$root_out_dir/resources/default_app.asar",
]
root = "default_app"
}
grit("resources") {
@@ -261,8 +355,10 @@ static_library("electron_lib") {
"//ppapi/host",
"//ppapi/proxy",
"//ppapi/shared_impl",
"//services/audio/public/mojom:constants",
"//services/device/public/mojom",
"//services/proxy_resolver:lib",
"//services/video_capture/public/mojom:constants",
"//services/viz/privileged/interfaces/compositing",
"//skia",
"//third_party/blink/public:blink",
@@ -323,8 +419,6 @@ static_library("electron_lib") {
"*_views.cc",
"*_views.h",
"*\bviews/*",
"*/autofill_popup.cc",
"*/autofill_popup.h",
]
}
@@ -349,6 +443,10 @@ static_library("electron_lib") {
"//third_party/crashpad/crashpad/client",
"//ui/accelerated_widget_mac",
]
sources += [
"atom/browser/ui/views/autofill_popup_view.cc",
"atom/browser/ui/views/autofill_popup_view.h",
]
include_dirs += [
# NOTE(nornagon): other chromium files use the full path to include
# crashpad; this is just here for compatibility between GN and GYP, so that
@@ -712,9 +810,9 @@ if (is_mac) {
bundle_data("electron_app_resources") {
public_deps = [
":app2asar",
":default_app_asar",
":electron_app_strings_bundle_data",
":js2asar",
":electron_asar",
]
sources = [
"$root_out_dir/resources/default_app.asar",
@@ -760,10 +858,10 @@ if (is_mac) {
sources = filenames.app_sources
include_dirs = [ "." ]
deps = [
":app2asar",
":default_app_asar",
":electron_app_manifest",
":electron_asar",
":electron_lib",
":js2asar",
":packed_resources",
"//content:sandbox_helper_win",
"//ui/strings",

10
DEPS
View File

@@ -10,7 +10,7 @@ gclient_gn_args = [
vars = {
'chromium_version':
'72.0.3626.52',
'72.0.3626.107',
'node_version':
'ad2c89ec3be0f5db3ea02b0f591d36a5d84c51ad',
@@ -107,7 +107,7 @@ hooks = [
'action': [
'python',
'-c',
'import os; os.chdir("src"); os.chdir("electron"); os.system("npm install")',
'import os, subprocess; os.chdir(os.path.join("src", "electron")); subprocess.check_call(["python", "script/lib/npm.py", "install"]);',
],
},
{
@@ -117,7 +117,7 @@ hooks = [
'action': [
'python',
'-c',
'import os; os.chdir("src"); os.chdir("electron"); os.chdir("vendor"); os.chdir("boto"); os.system("python setup.py build");',
'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "boto")); subprocess.check_call(["python", "setup.py", "build"]);',
],
},
{
@@ -127,9 +127,9 @@ hooks = [
'action': [
'python',
'-c',
'import os; os.chdir("src"); os.chdir("electron"); os.chdir("vendor"); os.chdir("requests"); os.system("python setup.py build");',
'import os, subprocess; os.chdir(os.path.join("src", "electron", "vendor", "requests")); subprocess.check_call(["python", "setup.py", "build"]);',
],
}
},
]
recursedeps = [

View File

@@ -1 +1 @@
5.0.0-nightly.20190122
6.0.0-nightly.20190212

View File

@@ -7,7 +7,7 @@
[![devDependency Status](https://david-dm.org/electron/electron/dev-status.svg)](https://david-dm.org/electron/electron?type=dev)
[![Join the Electron Community on Slack](https://atom-slack.herokuapp.com/badge.svg)](https://atom-slack.herokuapp.com/)
:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹.
:memo: Available Translations: 🇨🇳 🇹🇼 🇧🇷 🇪🇸 🇰🇷 🇯🇵 🇷🇺 🇫🇷 🇹🇭 🇳🇱 🇹🇷 🇮🇩 🇺🇦 🇨🇿 🇮🇹 🇵🇱.
View these docs in other languages at [electron/i18n](https://github.com/electron/i18n/tree/master/content/).
The Electron framework lets you write cross-platform desktop applications

View File

@@ -81,8 +81,6 @@ test_script:
if ((-Not (Test-Path Env:\ELECTRON_RELEASE)) -And ($env:GN_CONFIG -in "testing", "release")) {
$env:RUN_TESTS="true"
}
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
- ps: >-
if ($env:RUN_TESTS -eq 'true') {
New-Item .\out\Default\gen\node_headers\Release -Type directory
@@ -91,8 +89,12 @@ test_script:
echo "Skipping tests for $env:GN_CONFIG build"
}
- cd electron
- if "%RUN_TESTS%"=="true" ( echo Running test suite & npm run test -- --ci )
- if "%RUN_TESTS%"=="true" ( echo Running test suite & npm run test -- --ci --enable-logging)
- cd ..
- if "%RUN_TESTS%"=="true" ( echo Verifying non proprietary ffmpeg & python electron\script\verify-ffmpeg.py --build-dir out\Default --source-root %cd% --ffmpeg-path out\ffmpeg )
- echo "About to verify mksnapshot"
- if "%RUN_TESTS%"=="true" ( echo Verifying mksnapshot & python electron\script\verify-mksnapshot.py --build-dir out\Default --source-root %cd% )
- echo "Done verifying mksnapshot"
deploy_script:
- cd electron
- ps: >-

View File

@@ -213,18 +213,30 @@ base::RefCountedMemory* AtomContentClient::GetDataResourceBytes(
}
void AtomContentClient::AddAdditionalSchemes(Schemes* schemes) {
schemes->standard_schemes.push_back("chrome-extension");
std::vector<std::string> splited;
ConvertStringWithSeparatorToVector(&splited, ",",
switches::kRegisterServiceWorkerSchemes);
switches::kServiceWorkerSchemes);
for (const std::string& scheme : splited)
schemes->service_worker_schemes.push_back(scheme);
schemes->service_worker_schemes.push_back(url::kFileScheme);
ConvertStringWithSeparatorToVector(&splited, ",", switches::kStandardSchemes);
for (const std::string& scheme : splited)
schemes->standard_schemes.push_back(scheme);
schemes->standard_schemes.push_back("chrome-extension");
ConvertStringWithSeparatorToVector(&splited, ",", switches::kSecureSchemes);
for (const std::string& scheme : splited)
schemes->secure_schemes.push_back(scheme);
ConvertStringWithSeparatorToVector(&splited, ",",
switches::kBypassCSPSchemes);
for (const std::string& scheme : splited)
schemes->csp_bypassing_schemes.push_back(scheme);
ConvertStringWithSeparatorToVector(&splited, ",", switches::kCORSSchemes);
for (const std::string& scheme : splited)
schemes->cors_enabled_schemes.push_back(scheme);
}
void AtomContentClient::AddPepperPlugins(

View File

@@ -164,6 +164,9 @@ bool AtomMainDelegate::BasicStartupComplete(int* exit_code) {
if (env->HasVar("ELECTRON_ENABLE_STACK_DUMPING"))
base::debug::EnableInProcessStackDumping();
if (env->HasVar("ELECTRON_DISABLE_SANDBOX"))
command_line->AppendSwitch(service_manager::switches::kNoSandbox);
chrome::RegisterPathProvider();
#if defined(OS_MACOSX)

View File

@@ -11,6 +11,7 @@
#include "atom/browser/javascript_environment.h"
#include "atom/browser/node_debugger.h"
#include "atom/common/api/atom_bindings.h"
#include "atom/common/atom_version.h"
#include "atom/common/crash_reporter/crash_reporter.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/node_bindings.h"
@@ -79,6 +80,11 @@ int NodeMain(int argc, char* argv[]) {
reporter.SetMethod("start", &crash_reporter::CrashReporter::StartInstance);
process.Set("crashReporter", reporter);
mate::Dictionary versions;
if (process.Get("versions", &versions)) {
versions.SetReadOnly(ATOM_PROJECT_NAME, ATOM_VERSION_STRING);
}
node::LoadEnvironment(env);
bool more;

View File

@@ -1154,6 +1154,7 @@ v8::Local<v8::Promise> App::GetFileIcon(const base::FilePath& path,
std::vector<mate::Dictionary> App::GetAppMetrics(v8::Isolate* isolate) {
std::vector<mate::Dictionary> result;
result.reserve(app_metrics_.size());
int processor_count = base::SysInfo::NumberOfProcessors();
for (const auto& process_metric : app_metrics_) {

View File

@@ -37,6 +37,14 @@ struct Converter<atom::AutoResizeFlags> {
if (params.Get("height", &height) && height) {
flags |= atom::kAutoResizeHeight;
}
bool horizontal = false;
if (params.Get("horizontal", &horizontal) && horizontal) {
flags |= atom::kAutoResizeHorizontal;
}
bool vertical = false;
if (params.Get("vertical", &vertical) && vertical) {
flags |= atom::kAutoResizeVertical;
}
*auto_resize_flags = static_cast<atom::AutoResizeFlags>(flags);
return true;

View File

@@ -8,6 +8,7 @@
#include "atom/common/native_mate_converters/callback.h"
#include "atom/common/native_mate_converters/file_path_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/promise_util.h"
#include "base/bind.h"
#include "base/files/file_util.h"
#include "content/public/browser/tracing_controller.h"
@@ -65,23 +66,53 @@ scoped_refptr<TracingController::TraceDataEndpoint> GetTraceDataEndpoint(
result_file_path, base::Bind(callback, result_file_path));
}
void StopRecording(const base::FilePath& path,
const CompletionCallback& callback) {
void OnRecordingStopped(scoped_refptr<atom::util::Promise> promise,
const base::FilePath& path) {
promise->Resolve(path);
}
v8::Local<v8::Promise> StopRecording(v8::Isolate* isolate,
const base::FilePath& path) {
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
TracingController::GetInstance()->StopTracing(
GetTraceDataEndpoint(path, callback));
GetTraceDataEndpoint(path, base::Bind(&OnRecordingStopped, promise)));
return promise->GetHandle();
}
bool GetCategories(
const base::RepeatingCallback<void(const std::set<std::string>&)>&
callback) {
return TracingController::GetInstance()->GetCategories(
base::BindOnce(callback));
void OnCategoriesAvailable(scoped_refptr<atom::util::Promise> promise,
const std::set<std::string>& categories) {
promise->Resolve(categories);
}
bool StartTracing(const base::trace_event::TraceConfig& trace_config,
const base::RepeatingCallback<void()>& callback) {
return TracingController::GetInstance()->StartTracing(
trace_config, base::BindOnce(callback));
v8::Local<v8::Promise> GetCategories(v8::Isolate* isolate) {
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
bool success = TracingController::GetInstance()->GetCategories(
base::BindOnce(&OnCategoriesAvailable, promise));
if (!success)
promise->RejectWithErrorMessage("Could not get categories.");
return promise->GetHandle();
}
void OnTracingStarted(scoped_refptr<atom::util::Promise> promise) {
promise->Resolve();
}
v8::Local<v8::Promise> StartTracing(
v8::Isolate* isolate,
const base::trace_event::TraceConfig& trace_config) {
scoped_refptr<atom::util::Promise> promise = new atom::util::Promise(isolate);
bool success = TracingController::GetInstance()->StartTracing(
trace_config, base::BindOnce(&OnTracingStarted, promise));
if (!success)
promise->RejectWithErrorMessage("Could not start tracing");
return promise->GetHandle();
}
bool GetTraceBufferUsage(

View File

@@ -136,6 +136,21 @@ inline net::CookieStore* GetCookieStore(
return getter->GetURLRequestContext()->cookie_store();
}
void ResolvePromiseWithCookies(scoped_refptr<util::Promise> promise,
net::CookieList cookieList) {
promise->Resolve(cookieList);
}
void ResolvePromise(scoped_refptr<util::Promise> promise) {
promise->Resolve();
}
// Resolve |promise| in UI thread.
void ResolvePromiseInUI(scoped_refptr<util::Promise> promise) {
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI},
base::BindOnce(ResolvePromise, std::move(promise)));
}
// Run |callback| on UI thread.
void RunCallbackInUI(const base::Closure& callback) {
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::UI}, callback);
@@ -143,25 +158,28 @@ void RunCallbackInUI(const base::Closure& callback) {
// Remove cookies from |list| not matching |filter|, and pass it to |callback|.
void FilterCookies(std::unique_ptr<base::DictionaryValue> filter,
const Cookies::GetCallback& callback,
scoped_refptr<util::Promise> promise,
const net::CookieList& list) {
net::CookieList result;
for (const auto& cookie : list) {
if (MatchesCookie(filter.get(), cookie))
result.push_back(cookie);
}
RunCallbackInUI(base::Bind(callback, Cookies::SUCCESS, result));
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::UI},
base::BindOnce(ResolvePromiseWithCookies, std::move(promise), result));
}
// Receives cookies matching |filter| in IO thread.
void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::unique_ptr<base::DictionaryValue> filter,
const Cookies::GetCallback& callback) {
scoped_refptr<util::Promise> promise) {
std::string url;
filter->GetString("url", &url);
auto filtered_callback =
base::Bind(FilterCookies, base::Passed(&filter), callback);
base::Bind(FilterCookies, base::Passed(&filter), std::move(promise));
// Empty url will match all url cookies.
if (url.empty())
@@ -172,31 +190,42 @@ void GetCookiesOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
}
// Removes cookie with |url| and |name| in IO thread.
void RemoveCookieOnIOThread(scoped_refptr<net::URLRequestContextGetter> getter,
const GURL& url,
const std::string& name,
const base::Closure& callback) {
void RemoveCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
const GURL& url,
const std::string& name,
scoped_refptr<util::Promise> promise) {
GetCookieStore(getter)->DeleteCookieAsync(
url, name, base::BindOnce(RunCallbackInUI, callback));
url, name, base::BindOnce(ResolvePromiseInUI, std::move(promise)));
}
// Resolves/rejects the |promise| in UI thread.
void SettlePromiseInUI(scoped_refptr<util::Promise> promise,
const std::string& errmsg) {
if (errmsg.empty()) {
promise->Resolve();
} else {
promise->RejectWithErrorMessage(errmsg);
}
}
// Callback of SetCookie.
void OnSetCookie(const Cookies::SetCallback& callback, bool success) {
RunCallbackInUI(
base::Bind(callback, success ? Cookies::SUCCESS : Cookies::FAILED));
void OnSetCookie(scoped_refptr<util::Promise> promise, bool success) {
const std::string errmsg = success ? "" : "Setting cookie failed";
RunCallbackInUI(base::Bind(SettlePromiseInUI, std::move(promise), errmsg));
}
// Flushes cookie store in IO thread.
void FlushCookieStoreOnIOThread(
scoped_refptr<net::URLRequestContextGetter> getter,
const base::Closure& callback) {
GetCookieStore(getter)->FlushStore(base::BindOnce(RunCallbackInUI, callback));
scoped_refptr<util::Promise> promise) {
GetCookieStore(getter)->FlushStore(
base::BindOnce(ResolvePromiseInUI, std::move(promise)));
}
// Sets cookie with |details| in IO thread.
void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
std::unique_ptr<base::DictionaryValue> details,
const Cookies::SetCallback& callback) {
scoped_refptr<util::Promise> promise) {
std::string url, name, value, domain, path;
bool secure = false;
bool http_only = false;
@@ -237,7 +266,7 @@ void SetCookieOnIO(scoped_refptr<net::URLRequestContextGetter> getter,
GURL(url), name, value, domain, path, creation_time, expiration_time,
last_access_time, secure, http_only,
net::CookieSameSite::DEFAULT_MODE, net::COOKIE_PRIORITY_DEFAULT));
auto completion_callback = base::BindOnce(OnSetCookie, callback);
auto completion_callback = base::BindOnce(OnSetCookie, std::move(promise));
if (!canonical_cookie || !canonical_cookie->IsCanonical()) {
std::move(completion_callback).Run(false);
return;
@@ -267,43 +296,56 @@ Cookies::Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context)
Cookies::~Cookies() {}
void Cookies::Get(const base::DictionaryValue& filter,
const GetCallback& callback) {
v8::Local<v8::Promise> Cookies::Get(const base::DictionaryValue& filter) {
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
auto copy = base::DictionaryValue::From(
base::Value::ToUniquePtrValue(filter.Clone()));
auto* getter = browser_context_->GetRequestContext();
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(GetCookiesOnIO, base::RetainedRef(getter), std::move(copy),
callback));
promise));
return promise->GetHandle();
}
void Cookies::Remove(const GURL& url,
const std::string& name,
const base::Closure& callback) {
v8::Local<v8::Promise> Cookies::Remove(const GURL& url,
const std::string& name) {
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
auto* getter = browser_context_->GetRequestContext();
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(RemoveCookieOnIOThread, base::RetainedRef(getter), url,
name, callback));
base::BindOnce(RemoveCookieOnIO, base::RetainedRef(getter), url, name,
promise));
return promise->GetHandle();
}
void Cookies::Set(const base::DictionaryValue& details,
const SetCallback& callback) {
v8::Local<v8::Promise> Cookies::Set(const base::DictionaryValue& details) {
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
auto copy = base::DictionaryValue::From(
base::Value::ToUniquePtrValue(details.Clone()));
auto* getter = browser_context_->GetRequestContext();
base::PostTaskWithTraits(
FROM_HERE, {BrowserThread::IO},
base::BindOnce(SetCookieOnIO, base::RetainedRef(getter), std::move(copy),
callback));
promise));
return promise->GetHandle();
}
void Cookies::FlushStore(const base::Closure& callback) {
v8::Local<v8::Promise> Cookies::FlushStore() {
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
auto* getter = browser_context_->GetRequestContext();
base::PostTaskWithTraits(FROM_HERE, {BrowserThread::IO},
base::BindOnce(FlushCookieStoreOnIOThread,
base::RetainedRef(getter), callback));
base::RetainedRef(getter), promise));
return promise->GetHandle();
}
void Cookies::OnCookieChanged(const CookieDetails* details) {

View File

@@ -10,6 +10,7 @@
#include "atom/browser/api/trackable_object.h"
#include "atom/browser/net/cookie_details.h"
#include "atom/common/promise_util.h"
#include "base/callback_list.h"
#include "native_mate/handle.h"
#include "net/cookies/canonical_cookie.h"
@@ -35,9 +36,6 @@ class Cookies : public mate::TrackableObject<Cookies> {
FAILED,
};
using GetCallback = base::Callback<void(Error, const net::CookieList&)>;
using SetCallback = base::Callback<void(Error)>;
static mate::Handle<Cookies> Create(v8::Isolate* isolate,
AtomBrowserContext* browser_context);
@@ -49,12 +47,10 @@ class Cookies : public mate::TrackableObject<Cookies> {
Cookies(v8::Isolate* isolate, AtomBrowserContext* browser_context);
~Cookies() override;
void Get(const base::DictionaryValue& filter, const GetCallback& callback);
void Remove(const GURL& url,
const std::string& name,
const base::Closure& callback);
void Set(const base::DictionaryValue& details, const SetCallback& callback);
void FlushStore(const base::Closure& callback);
v8::Local<v8::Promise> Get(const base::DictionaryValue& filter);
v8::Local<v8::Promise> Set(const base::DictionaryValue& details);
v8::Local<v8::Promise> Remove(const GURL& url, const std::string& name);
v8::Local<v8::Promise> FlushStore();
// CookieChangeNotifier subscription:
void OnCookieChanged(const CookieDetails*);

View File

@@ -137,11 +137,12 @@ bool DesktopCapturer::ShouldScheduleNextRefresh(DesktopMediaList* list) {
}
void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
std::vector<DesktopCapturer::Source> window_sources;
if (capture_window_ &&
list->GetMediaListType() == content::DesktopMediaID::TYPE_WINDOW) {
capture_window_ = false;
const auto& media_list_sources = list->GetSources();
std::vector<DesktopCapturer::Source> window_sources;
window_sources.reserve(media_list_sources.size());
for (const auto& media_list_source : media_list_sources) {
window_sources.emplace_back(DesktopCapturer::Source{
media_list_source, std::string(), fetch_window_icons_});
@@ -150,11 +151,12 @@ void DesktopCapturer::UpdateSourcesList(DesktopMediaList* list) {
std::back_inserter(captured_sources_));
}
std::vector<DesktopCapturer::Source> screen_sources;
if (capture_screen_ &&
list->GetMediaListType() == content::DesktopMediaID::TYPE_SCREEN) {
capture_screen_ = false;
const auto& media_list_sources = list->GetSources();
std::vector<DesktopCapturer::Source> screen_sources;
screen_sources.reserve(media_list_sources.size());
for (const auto& media_list_source : media_list_sources) {
screen_sources.emplace_back(
DesktopCapturer::Source{media_list_source, std::string()});

View File

@@ -24,47 +24,119 @@
using content::BrowserThread;
namespace atom {
namespace api {
namespace {
// List of registered custom standard schemes.
std::vector<std::string> g_standard_schemes;
struct SchemeOptions {
bool standard = false;
bool secure = false;
bool bypassCSP = false;
bool allowServiceWorkers = false;
bool supportFetchAPI = false;
bool corsEnabled = false;
};
struct CustomScheme {
std::string scheme;
SchemeOptions options;
};
} // namespace
namespace mate {
template <>
struct Converter<CustomScheme> {
static bool FromV8(v8::Isolate* isolate,
v8::Local<v8::Value> val,
CustomScheme* out) {
mate::Dictionary dict;
if (!ConvertFromV8(isolate, val, &dict))
return false;
if (!dict.Get("scheme", &(out->scheme)))
return false;
mate::Dictionary opt;
// options are optional. Default values specified in SchemeOptions are used
if (dict.Get("privileges", &opt)) {
opt.Get("standard", &(out->options.standard));
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
opt.Get("secure", &(out->options.secure));
opt.Get("bypassCSP", &(out->options.bypassCSP));
opt.Get("allowServiceWorkers", &(out->options.allowServiceWorkers));
opt.Get("supportFetchAPI", &(out->options.supportFetchAPI));
opt.Get("corsEnabled", &(out->options.corsEnabled));
}
return true;
}
};
} // namespace mate
namespace atom {
namespace api {
std::vector<std::string> GetStandardSchemes() {
return g_standard_schemes;
}
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args) {
g_standard_schemes = schemes;
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args) {
std::vector<CustomScheme> custom_schemes;
if (!mate::ConvertFromV8(args->isolate(), val, &custom_schemes)) {
args->ThrowError("Argument must be an array of custom schemes.");
return;
}
mate::Dictionary opts;
bool secure = false;
args->GetNext(&opts) && opts.Get("secure", &secure);
// Dynamically register the schemes.
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
for (const std::string& scheme : schemes) {
url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITH_HOST);
if (secure) {
url::AddSecureScheme(scheme.c_str());
std::vector<std::string> secure_schemes, cspbypassing_schemes, fetch_schemes,
service_worker_schemes, cors_schemes;
for (const auto& custom_scheme : custom_schemes) {
// Register scheme to privileged list (https, wss, data, chrome-extension)
if (custom_scheme.options.standard) {
auto* policy = content::ChildProcessSecurityPolicy::GetInstance();
url::AddStandardScheme(custom_scheme.scheme.c_str(),
url::SCHEME_WITH_HOST);
g_standard_schemes.push_back(custom_scheme.scheme);
policy->RegisterWebSafeScheme(custom_scheme.scheme);
}
if (custom_scheme.options.secure) {
secure_schemes.push_back(custom_scheme.scheme);
url::AddSecureScheme(custom_scheme.scheme.c_str());
}
if (custom_scheme.options.bypassCSP) {
cspbypassing_schemes.push_back(custom_scheme.scheme);
url::AddCSPBypassingScheme(custom_scheme.scheme.c_str());
}
if (custom_scheme.options.corsEnabled) {
cors_schemes.push_back(custom_scheme.scheme);
url::AddCorsEnabledScheme(custom_scheme.scheme.c_str());
}
if (custom_scheme.options.supportFetchAPI) {
fetch_schemes.push_back(custom_scheme.scheme);
}
if (custom_scheme.options.allowServiceWorkers) {
service_worker_schemes.push_back(custom_scheme.scheme);
}
policy->RegisterWebSafeScheme(scheme);
}
// Add the schemes to command line switches, so child processes can also
// register them.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
atom::switches::kStandardSchemes, base::JoinString(schemes, ","));
if (secure) {
const auto AppendSchemesToCmdLine = [](const char* switch_name,
std::vector<std::string> schemes) {
// Add the schemes to command line switches, so child processes can also
// register them.
base::CommandLine::ForCurrentProcess()->AppendSwitchASCII(
atom::switches::kSecureSchemes, base::JoinString(schemes, ","));
}
switch_name, base::JoinString(schemes, ","));
};
AppendSchemesToCmdLine(atom::switches::kSecureSchemes, secure_schemes);
AppendSchemesToCmdLine(atom::switches::kBypassCSPSchemes,
cspbypassing_schemes);
AppendSchemesToCmdLine(atom::switches::kCORSSchemes, cors_schemes);
AppendSchemesToCmdLine(atom::switches::kFetchSchemes, fetch_schemes);
AppendSchemesToCmdLine(atom::switches::kServiceWorkerSchemes,
service_worker_schemes);
AppendSchemesToCmdLine(atom::switches::kStandardSchemes, g_standard_schemes);
}
Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
@@ -73,12 +145,6 @@ Protocol::Protocol(v8::Isolate* isolate, AtomBrowserContext* browser_context)
}
Protocol::~Protocol() {}
void Protocol::RegisterServiceWorkerSchemes(
const std::vector<std::string>& schemes) {
atom::AtomBrowserClient::SetCustomServiceWorkerSchemes(schemes);
}
void Protocol::UnregisterProtocol(const std::string& scheme,
mate::Arguments* args) {
CompletionCallback callback;
@@ -195,8 +261,6 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "Protocol"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("registerServiceWorkerSchemes",
&Protocol::RegisterServiceWorkerSchemes)
.SetMethod("registerStringProtocol",
&Protocol::RegisterProtocol<URLRequestStringJob>)
.SetMethod("registerBufferProtocol",
@@ -228,16 +292,16 @@ void Protocol::BuildPrototype(v8::Isolate* isolate,
namespace {
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args) {
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args) {
if (atom::Browser::Get()->is_ready()) {
args->ThrowError(
"protocol.registerStandardSchemes should be called before "
"protocol.registerSchemesAsPrivileged should be called before "
"app is ready");
return;
}
atom::api::RegisterStandardSchemes(schemes, args);
atom::api::RegisterSchemesAsPrivileged(val, args);
}
void Initialize(v8::Local<v8::Object> exports,
@@ -246,7 +310,7 @@ void Initialize(v8::Local<v8::Object> exports,
void* priv) {
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.SetMethod("registerStandardSchemes", &RegisterStandardSchemes);
dict.SetMethod("registerSchemesAsPrivileged", &RegisterSchemesAsPrivileged);
dict.SetMethod("getStandardSchemes", &atom::api::GetStandardSchemes);
}

View File

@@ -34,8 +34,9 @@ namespace atom {
namespace api {
std::vector<std::string> GetStandardSchemes();
void RegisterStandardSchemes(const std::vector<std::string>& schemes,
mate::Arguments* args);
void RegisterSchemesAsPrivileged(v8::Local<v8::Value> val,
mate::Arguments* args);
class Protocol : public mate::TrackableObject<Protocol> {
public:
@@ -94,9 +95,6 @@ class Protocol : public mate::TrackableObject<Protocol> {
DISALLOW_COPY_AND_ASSIGN(CustomProtocolHandler);
};
// Register schemes that can handle service worker.
void RegisterServiceWorkerSchemes(const std::vector<std::string>& schemes);
// Register the protocol with certain request job.
template <typename RequestJob>
void RegisterProtocol(const std::string& scheme,

View File

@@ -548,11 +548,9 @@ std::vector<int> TopLevelWindow::GetPosition() {
return result;
}
#if defined(OS_WIN) || defined(OS_MACOSX)
void TopLevelWindow::MoveTop() {
window_->MoveTop();
}
#endif
void TopLevelWindow::SetTitle(const std::string& title) {
window_->SetTitle(title);
@@ -659,6 +657,11 @@ void TopLevelWindow::SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> value) {
}
}
void TopLevelWindow::RemoveMenu() {
menu_.Reset();
window_->SetMenu(nullptr);
}
void TopLevelWindow::SetParentWindow(v8::Local<v8::Value> value,
mate::Arguments* args) {
if (IsModal()) {
@@ -1062,9 +1065,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setResizable", &TopLevelWindow::SetResizable)
.SetMethod("isResizable", &TopLevelWindow::IsResizable)
.SetMethod("setMovable", &TopLevelWindow::SetMovable)
#if defined(OS_WIN) || defined(OS_MACOSX)
.SetMethod("moveTop", &TopLevelWindow::MoveTop)
#endif
.SetMethod("isMovable", &TopLevelWindow::IsMovable)
.SetMethod("setMinimizable", &TopLevelWindow::SetMinimizable)
.SetMethod("isMinimizable", &TopLevelWindow::IsMinimizable)
@@ -1103,6 +1104,7 @@ void TopLevelWindow::BuildPrototype(v8::Isolate* isolate,
.SetMethod("setContentProtection", &TopLevelWindow::SetContentProtection)
.SetMethod("setFocusable", &TopLevelWindow::SetFocusable)
.SetMethod("setMenu", &TopLevelWindow::SetMenu)
.SetMethod("removeMenu", &TopLevelWindow::RemoveMenu)
.SetMethod("setParentWindow", &TopLevelWindow::SetParentWindow)
.SetMethod("setBrowserView", &TopLevelWindow::SetBrowserView)
.SetMethod("addBrowserView", &TopLevelWindow::AddBrowserView)

View File

@@ -126,9 +126,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
void SetResizable(bool resizable);
bool IsResizable();
void SetMovable(bool movable);
#if defined(OS_WIN) || defined(OS_MACOSX)
void MoveTop();
#endif
bool IsMovable();
void SetMinimizable(bool minimizable);
bool IsMinimizable();
@@ -165,6 +163,7 @@ class TopLevelWindow : public mate::TrackableObject<TopLevelWindow>,
void SetContentProtection(bool enable);
void SetFocusable(bool focusable);
void SetMenu(v8::Isolate* isolate, v8::Local<v8::Value> menu);
void RemoveMenu();
void SetParentWindow(v8::Local<v8::Value> value, mate::Arguments* args);
virtual void SetBrowserView(v8::Local<v8::Value> value);
virtual void AddBrowserView(v8::Local<v8::Value> value);

View File

@@ -240,21 +240,6 @@ namespace api {
namespace {
content::ServiceWorkerContext* GetServiceWorkerContext(
content::WebContents* web_contents) {
auto* context = web_contents->GetBrowserContext();
auto* site_instance = web_contents->GetSiteInstance();
if (!context || !site_instance)
return nullptr;
auto* storage_partition =
content::BrowserContext::GetStoragePartition(context, site_instance);
if (!storage_partition)
return nullptr;
return storage_partition->GetServiceWorkerContext();
}
// Called when CapturePage is done.
void OnCapturePageDone(scoped_refptr<util::Promise> promise,
const SkBitmap& bitmap) {
@@ -280,10 +265,12 @@ struct WebContents::FrameDispatchHelper {
api_web_contents->OnGetZoomLevel(rfh, reply_msg);
}
void OnRendererMessageSync(const std::string& channel,
void OnRendererMessageSync(bool internal,
const std::string& channel,
const base::ListValue& args,
IPC::Message* message) {
api_web_contents->OnRendererMessageSync(rfh, channel, args, message);
api_web_contents->OnRendererMessageSync(rfh, internal, channel, args,
message);
}
};
@@ -599,7 +586,7 @@ void WebContents::SetContentsBounds(content::WebContents* source,
void WebContents::CloseContents(content::WebContents* source) {
Emit("close");
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
HideAutofillPopup();
#endif
if (managed_web_contents())
@@ -1028,7 +1015,7 @@ void WebContents::DevToolsClosed() {
Emit("devtools-closed");
}
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
void WebContents::ShowAutofillPopup(content::RenderFrameHost* frame_host,
const gfx::RectF& bounds,
const std::vector<base::string16>& values,
@@ -1070,12 +1057,13 @@ bool WebContents::OnMessageReceived(const IPC::Message& message,
IPC_MESSAGE_FORWARD_DELAY_REPLY(AtomFrameHostMsg_Message_Sync, &helper,
FrameDispatchHelper::OnRendererMessageSync)
IPC_MESSAGE_HANDLER(AtomFrameHostMsg_Message_To, OnRendererMessageTo)
IPC_MESSAGE_HANDLER(AtomFrameHostMsg_Message_Host, OnRendererMessageHost)
IPC_MESSAGE_FORWARD_DELAY_REPLY(
AtomFrameHostMsg_SetTemporaryZoomLevel, &helper,
FrameDispatchHelper::OnSetTemporaryZoomLevel)
IPC_MESSAGE_FORWARD_DELAY_REPLY(AtomFrameHostMsg_GetZoomLevel, &helper,
FrameDispatchHelper::OnGetZoomLevel)
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
IPC_MESSAGE_HANDLER(AtomAutofillFrameHostMsg_ShowPopup, ShowAutofillPopup)
IPC_MESSAGE_HANDLER(AtomAutofillFrameHostMsg_HidePopup, HideAutofillPopup)
#endif
@@ -1413,6 +1401,23 @@ void WebContents::InspectElement(int x, int y) {
managed_web_contents()->InspectElement(x, y);
}
void WebContents::InspectSharedWorker() {
if (type_ == REMOTE)
return;
if (!enable_devtools_)
return;
for (const auto& agent_host : content::DevToolsAgentHost::GetOrCreateAll()) {
if (agent_host->GetType() ==
content::DevToolsAgentHost::kTypeSharedWorker) {
OpenDevTools(nullptr);
managed_web_contents()->AttachTo(agent_host);
break;
}
}
}
void WebContents::InspectServiceWorker() {
if (type_ == REMOTE)
return;
@@ -1430,40 +1435,6 @@ void WebContents::InspectServiceWorker() {
}
}
void WebContents::HasServiceWorker(const base::Callback<void(bool)>& callback) {
auto* context = GetServiceWorkerContext(web_contents());
if (!context)
return;
struct WrappedCallback {
base::Callback<void(bool)> callback_;
explicit WrappedCallback(const base::Callback<void(bool)>& callback)
: callback_(callback) {}
void Run(content::ServiceWorkerCapability capability) {
callback_.Run(capability !=
content::ServiceWorkerCapability::NO_SERVICE_WORKER);
delete this;
}
};
auto* wrapped_callback = new WrappedCallback(callback);
context->CheckHasServiceWorker(
web_contents()->GetLastCommittedURL(), GURL::EmptyGURL(),
base::BindOnce(&WrappedCallback::Run,
base::Unretained(wrapped_callback)));
}
void WebContents::UnregisterServiceWorker(
const base::Callback<void(bool)>& callback) {
auto* context = GetServiceWorkerContext(web_contents());
if (!context)
return;
context->UnregisterServiceWorker(web_contents()->GetLastCommittedURL(),
callback);
}
void WebContents::SetIgnoreMenuShortcuts(bool ignore) {
auto* web_preferences = WebContentsPreferences::From(web_contents());
DCHECK(web_preferences);
@@ -1528,11 +1499,12 @@ std::vector<printing::PrinterBasicInfo> WebContents::GetPrinterList() {
return printers;
}
void WebContents::PrintToPDF(
const base::DictionaryValue& settings,
const PrintPreviewMessageHandler::PrintToPDFCallback& callback) {
v8::Local<v8::Promise> WebContents::PrintToPDF(
const base::DictionaryValue& settings) {
scoped_refptr<util::Promise> promise = new util::Promise(isolate());
PrintPreviewMessageHandler::FromWebContents(web_contents())
->PrintToPDF(settings, callback);
->PrintToPDF(settings, promise);
return promise->GetHandle();
}
#endif
@@ -1988,6 +1960,9 @@ v8::Local<v8::Value> WebContents::GetLastWebPreferences(
}
bool WebContents::IsRemoteModuleEnabled() const {
if (web_contents()->GetVisibleURL().SchemeIs("chrome-devtools")) {
return false;
}
if (auto* web_preferences = WebContentsPreferences::From(web_contents())) {
return web_preferences->IsRemoteModuleEnabled();
}
@@ -2170,10 +2145,8 @@ void WebContents::BuildPrototype(v8::Isolate* isolate,
.SetMethod("getLastWebPreferences", &WebContents::GetLastWebPreferences)
.SetMethod("_isRemoteModuleEnabled", &WebContents::IsRemoteModuleEnabled)
.SetMethod("getOwnerBrowserWindow", &WebContents::GetOwnerBrowserWindow)
.SetMethod("hasServiceWorker", &WebContents::HasServiceWorker)
.SetMethod("unregisterServiceWorker",
&WebContents::UnregisterServiceWorker)
.SetMethod("inspectServiceWorker", &WebContents::InspectServiceWorker)
.SetMethod("inspectSharedWorker", &WebContents::InspectSharedWorker)
#if BUILDFLAG(ENABLE_PRINTING)
.SetMethod("_print", &WebContents::Print)
.SetMethod("_getPrinters", &WebContents::GetPrinterList)
@@ -2206,18 +2179,22 @@ AtomBrowserContext* WebContents::GetBrowserContext() const {
}
void WebContents::OnRendererMessage(content::RenderFrameHost* frame_host,
bool internal,
const std::string& channel,
const base::ListValue& args) {
// webContents.emit(channel, new Event(), args...);
EmitWithSender(channel, frame_host, nullptr, args);
// webContents.emit('-ipc-message', new Event(), internal, channel, args);
EmitWithSender("-ipc-message", frame_host, nullptr, internal, channel, args);
}
void WebContents::OnRendererMessageSync(content::RenderFrameHost* frame_host,
bool internal,
const std::string& channel,
const base::ListValue& args,
IPC::Message* message) {
// webContents.emit(channel, new Event(sender, message), args...);
EmitWithSender(channel, frame_host, message, args);
// webContents.emit('-ipc-message-sync', new Event(sender, message), internal,
// channel, args);
EmitWithSender("-ipc-message-sync", frame_host, message, internal, channel,
args);
}
void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
@@ -2235,6 +2212,13 @@ void WebContents::OnRendererMessageTo(content::RenderFrameHost* frame_host,
}
}
void WebContents::OnRendererMessageHost(content::RenderFrameHost* frame_host,
const std::string& channel,
const base::ListValue& args) {
// webContents.emit('ipc-message-host', new Event(), channel, args);
EmitWithSender("ipc-message-host", frame_host, nullptr, channel, args);
}
// static
mate::Handle<WebContents> WebContents::Create(v8::Isolate* isolate,
const mate::Dictionary& options) {

View File

@@ -160,9 +160,8 @@ class WebContents : public mate::TrackableObject<WebContents>,
void EnableDeviceEmulation(const blink::WebDeviceEmulationParams& params);
void DisableDeviceEmulation();
void InspectElement(int x, int y);
void InspectSharedWorker();
void InspectServiceWorker();
void HasServiceWorker(const base::Callback<void(bool)>&);
void UnregisterServiceWorker(const base::Callback<void(bool)>&);
void SetIgnoreMenuShortcuts(bool ignore);
void SetAudioMuted(bool muted);
bool IsAudioMuted();
@@ -175,9 +174,7 @@ class WebContents : public mate::TrackableObject<WebContents>,
void Print(mate::Arguments* args);
std::vector<printing::PrinterBasicInfo> GetPrinterList();
// Print current page as PDF.
void PrintToPDF(
const base::DictionaryValue& settings,
const PrintPreviewMessageHandler::PrintToPDFCallback& callback);
v8::Local<v8::Promise> PrintToPDF(const base::DictionaryValue& settings);
#endif
// DevTools workspace api.
@@ -480,11 +477,13 @@ class WebContents : public mate::TrackableObject<WebContents>,
// Called when received a message from renderer.
void OnRendererMessage(content::RenderFrameHost* frame_host,
bool internal,
const std::string& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer.
void OnRendererMessageSync(content::RenderFrameHost* frame_host,
bool internal,
const std::string& channel,
const base::ListValue& args,
IPC::Message* message);
@@ -497,6 +496,11 @@ class WebContents : public mate::TrackableObject<WebContents>,
const std::string& channel,
const base::ListValue& args);
// Called when received a message from renderer to host.
void OnRendererMessageHost(content::RenderFrameHost* frame_host,
const std::string& channel,
const base::ListValue& args);
// Called when received a synchronous message from renderer to
// set temporary zoom level.
void OnSetTemporaryZoomLevel(content::RenderFrameHost* frame_host,

View File

@@ -82,6 +82,8 @@
#include "net/ssl/client_cert_store_win.h"
#elif defined(OS_MACOSX)
#include "net/ssl/client_cert_store_mac.h"
#include "services/audio/public/mojom/constants.mojom.h"
#include "services/video_capture/public/mojom/constants.mojom.h"
#elif defined(USE_OPENSSL)
#include "net/ssl/client_cert_store.h"
#endif
@@ -114,9 +116,6 @@ namespace {
// Next navigation should not restart renderer process.
bool g_suppress_renderer_process_restart = false;
// Custom schemes to be registered to handle service worker.
base::NoDestructor<std::string> g_custom_service_worker_schemes;
bool IsSameWebSite(content::BrowserContext* browser_context,
const GURL& src_url,
const GURL& dest_url) {
@@ -148,11 +147,6 @@ void AtomBrowserClient::SuppressRendererProcessRestartForOnce() {
g_suppress_renderer_process_restart = true;
}
void AtomBrowserClient::SetCustomServiceWorkerSchemes(
const std::vector<std::string>& schemes) {
*g_custom_service_worker_schemes = base::JoinString(schemes, ",");
}
AtomBrowserClient* AtomBrowserClient::Get() {
return g_browser_client;
}
@@ -477,18 +471,15 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
return;
// Copy following switches to child process.
static const char* const kCommonSwitchNames[] = {switches::kStandardSchemes,
switches::kEnableSandbox,
switches::kSecureSchemes};
static const char* const kCommonSwitchNames[] = {
switches::kStandardSchemes, switches::kEnableSandbox,
switches::kSecureSchemes, switches::kBypassCSPSchemes,
switches::kCORSSchemes, switches::kFetchSchemes,
switches::kServiceWorkerSchemes};
command_line->CopySwitchesFrom(*base::CommandLine::ForCurrentProcess(),
kCommonSwitchNames,
arraysize(kCommonSwitchNames));
// The registered service worker schemes.
if (!g_custom_service_worker_schemes->empty())
command_line->AppendSwitchASCII(switches::kRegisterServiceWorkerSchemes,
*g_custom_service_worker_schemes);
#if defined(OS_WIN)
// Append --app-user-model-id.
PWSTR current_app_id;
@@ -514,6 +505,7 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
if (web_contents->GetVisibleURL().SchemeIs("chrome-devtools")) {
command_line->AppendSwitch(service_manager::switches::kNoSandbox);
command_line->AppendSwitch(::switches::kNoZygote);
command_line->AppendSwitch(switches::kDisableRemoteModule);
}
auto* web_preferences = WebContentsPreferences::From(web_contents);
if (web_preferences)
@@ -523,6 +515,16 @@ void AtomBrowserClient::AppendExtraCommandLineSwitches(
}
}
void AtomBrowserClient::AdjustUtilityServiceProcessCommandLine(
const service_manager::Identity& identity,
base::CommandLine* command_line) {
#if defined(OS_MACOSX)
if (identity.name() == video_capture::mojom::kServiceName ||
identity.name() == audio::mojom::kServiceName)
command_line->AppendSwitch(::switches::kMessageLoopTypeUi);
#endif
}
void AtomBrowserClient::DidCreatePpapiPlugin(content::BrowserPpapiHost* host) {
#if BUILDFLAG(ENABLE_PEPPER_FLASH)
host->GetPpapiHost()->AddHostFactoryFilter(

View File

@@ -49,10 +49,6 @@ class AtomBrowserClient : public content::ContentBrowserClient,
// Don't force renderer process to restart for once.
static void SuppressRendererProcessRestartForOnce();
// Custom schemes to be registered to handle service worker.
static void SetCustomServiceWorkerSchemes(
const std::vector<std::string>& schemes);
NotificationPresenter* GetNotificationPresenter();
void WebNotificationAllowed(int render_process_id,
@@ -89,6 +85,9 @@ class AtomBrowserClient : public content::ContentBrowserClient,
content::SiteInstance* pending_site_instance) override;
void AppendExtraCommandLineSwitches(base::CommandLine* command_line,
int child_process_id) override;
void AdjustUtilityServiceProcessCommandLine(
const service_manager::Identity& identity,
base::CommandLine* command_line) override;
void DidCreatePpapiPlugin(content::BrowserPpapiHost* browser_host) override;
std::string GetGeolocationApiKey() override;
content::QuotaPermissionContext* CreateQuotaPermissionContext() override;

View File

@@ -455,7 +455,7 @@ bool AtomBrowserMainParts::MainMessageLoopRun(int* result_code) {
void AtomBrowserMainParts::PreDefaultMainMessageLoopRun(
base::OnceClosure quit_closure) {
Browser::SetMainMessageLoopQuitClosure(std::move(quit_closure));
Browser::Get()->SetMainMessageLoopQuitClosure(std::move(quit_closure));
}
void AtomBrowserMainParts::PostMainMessageLoopStart() {

View File

@@ -100,23 +100,58 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
if (relay)
window = relay->GetNativeWindow();
auto* web_preferences = WebContentsPreferences::From(web_contents);
bool offscreen =
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
// Show save dialog if save path was not set already on item
base::FilePath path;
GetItemSavePath(item, &path);
// Show save dialog if save path was not set already on item
file_dialog::DialogSettings settings;
GetItemSaveDialogOptions(item, &settings);
if (!settings.parent_window)
settings.parent_window = window;
settings.force_detached = offscreen;
if (settings.title.size() == 0)
settings.title = item->GetURL().spec();
if (!settings.default_path.empty())
settings.default_path = default_path;
if (path.empty() && file_dialog::ShowSaveDialog(settings, &path)) {
if (path.empty()) {
file_dialog::DialogSettings settings;
GetItemSaveDialogOptions(item, &settings);
if (!settings.parent_window)
settings.parent_window = window;
if (settings.title.size() == 0)
settings.title = item->GetURL().spec();
if (!settings.default_path.empty())
settings.default_path = default_path;
auto* web_preferences = WebContentsPreferences::From(web_contents);
const bool offscreen =
!web_preferences || web_preferences->IsEnabled(options::kOffscreen);
settings.force_detached = offscreen;
auto dialog_callback =
base::Bind(&AtomDownloadManagerDelegate::OnDownloadSaveDialogDone,
base::Unretained(this), download_id, callback);
file_dialog::ShowSaveDialog(settings, dialog_callback);
} else {
callback.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
download::DOWNLOAD_INTERRUPT_REASON_NONE);
}
}
#if defined(MAS_BUILD)
void AtomDownloadManagerDelegate::OnDownloadSaveDialogDone(
uint32_t download_id,
const content::DownloadTargetCallback& download_callback,
bool result,
const base::FilePath& path,
const std::string& bookmark)
#else
void AtomDownloadManagerDelegate::OnDownloadSaveDialogDone(
uint32_t download_id,
const content::DownloadTargetCallback& download_callback,
bool result,
const base::FilePath& path)
#endif
{
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
auto* item = download_manager_->GetDownload(download_id);
if (!item)
return;
if (result) {
// Remember the last selected download directory.
AtomBrowserContext* browser_context = static_cast<AtomBrowserContext*>(
download_manager_->GetBrowserContext());
@@ -133,12 +168,16 @@ void AtomDownloadManagerDelegate::OnDownloadPathGenerated(
}
// Running the DownloadTargetCallback with an empty FilePath signals that the
// download should be cancelled.
// If user cancels the file save dialog, run the callback with empty FilePath.
callback.Run(path, download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path,
path.empty() ? download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
: download::DOWNLOAD_INTERRUPT_REASON_NONE);
// download should be cancelled. If user cancels the file save dialog, run
// the callback with empty FilePath.
const base::FilePath download_path = result ? path : base::FilePath();
const auto interrupt_reason =
download_path.empty() ? download::DOWNLOAD_INTERRUPT_REASON_USER_CANCELED
: download::DOWNLOAD_INTERRUPT_REASON_NONE;
download_callback.Run(download_path,
download::DownloadItem::TARGET_DISPOSITION_PROMPT,
download::DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
download_path, interrupt_reason);
}
void AtomDownloadManagerDelegate::Shutdown() {

View File

@@ -25,10 +25,6 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
explicit AtomDownloadManagerDelegate(content::DownloadManager* manager);
~AtomDownloadManagerDelegate() override;
void OnDownloadPathGenerated(uint32_t download_id,
const content::DownloadTargetCallback& callback,
const base::FilePath& default_path);
// content::DownloadManagerDelegate:
void Shutdown() override;
bool DetermineDownloadTarget(
@@ -45,6 +41,25 @@ class AtomDownloadManagerDelegate : public content::DownloadManagerDelegate {
void GetItemSaveDialogOptions(download::DownloadItem* item,
file_dialog::DialogSettings* settings);
void OnDownloadPathGenerated(uint32_t download_id,
const content::DownloadTargetCallback& callback,
const base::FilePath& default_path);
#if defined(MAS_BUILD)
void OnDownloadSaveDialogDone(
uint32_t download_id,
const content::DownloadTargetCallback& download_callback,
bool result,
const base::FilePath& path,
const std::string& bookmark);
#else
void OnDownloadSaveDialogDone(
uint32_t download_id,
const content::DownloadTargetCallback& download_callback,
bool result,
const base::FilePath& path);
#endif
content::DownloadManager* download_manager_;
base::WeakPtrFactory<AtomDownloadManagerDelegate> weak_ptr_factory_;

View File

@@ -25,9 +25,6 @@
namespace atom {
// Null until/unless the default main message loop is running.
base::NoDestructor<base::OnceClosure> g_quit_main_message_loop;
Browser::LoginItemSettings::LoginItemSettings() = default;
Browser::LoginItemSettings::~LoginItemSettings() = default;
Browser::LoginItemSettings::LoginItemSettings(const LoginItemSettings& other) =
@@ -95,11 +92,12 @@ void Browser::Shutdown() {
for (BrowserObserver& observer : observers_)
observer.OnQuit();
if (*g_quit_main_message_loop) {
std::move(*g_quit_main_message_loop).Run();
if (quit_main_message_loop_) {
std::move(quit_main_message_loop_).Run();
} else {
// There is no message loop available so we are in early stage.
exit(0);
// There is no message loop available so we are in early stage, wait until
// the quit_main_message_loop_ is available.
// Exiting now would leave defunct processes behind.
}
}
@@ -196,7 +194,10 @@ void Browser::PreMainMessageLoopRun() {
}
void Browser::SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure) {
*g_quit_main_message_loop = std::move(quit_closure);
if (is_shutdown_)
std::move(quit_closure).Run();
else
quit_main_message_loop_ = std::move(quit_closure);
}
void Browser::NotifyAndShutdown() {

View File

@@ -244,7 +244,7 @@ class Browser : public WindowListObserver {
// Stores the supplied |quit_closure|, to be run when the last Browser
// instance is destroyed.
static void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
void SetMainMessageLoopQuitClosure(base::OnceClosure quit_closure);
void AddObserver(BrowserObserver* obs) { observers_.AddObserver(obs); }
@@ -287,6 +287,9 @@ class Browser : public WindowListObserver {
// The browser is being shutdown.
bool is_shutdown_ = false;
// Null until/unless the default main message loop is running.
base::OnceClosure quit_main_message_loop_;
int badge_count_ = 0;
util::Promise* ready_promise_ = nullptr;

View File

@@ -206,7 +206,7 @@ void CommonWebContentsDelegate::SetOwnerWindow(
NativeWindow* owner_window) {
if (owner_window) {
owner_window_ = owner_window->GetWeakPtr();
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
autofill_popup_.reset(new AutofillPopup());
#endif
NativeWindowRelay::CreateForWebContents(web_contents,
@@ -619,4 +619,24 @@ void CommonWebContentsDelegate::SetHtmlApiFullscreen(bool enter_fullscreen) {
native_fullscreen_ = false;
}
void CommonWebContentsDelegate::ShowAutofillPopup(
content::RenderFrameHost* frame_host,
content::RenderFrameHost* embedder_frame_host,
bool offscreen,
const gfx::RectF& bounds,
const std::vector<base::string16>& values,
const std::vector<base::string16>& labels) {
if (!owner_window())
return;
autofill_popup_->CreateView(frame_host, embedder_frame_host, offscreen,
owner_window()->content_view(), bounds);
autofill_popup_->SetItems(values, labels);
}
void CommonWebContentsDelegate::HideAutofillPopup() {
if (autofill_popup_)
autofill_popup_->Hide();
}
} // namespace atom

View File

@@ -18,7 +18,7 @@
#include "content/public/browser/web_contents_delegate.h"
#include "electron/buildflags/buildflags.h"
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
#include "atom/browser/ui/autofill_popup.h"
#endif
@@ -105,7 +105,7 @@ class CommonWebContentsDelegate : public content::WebContentsDelegate,
const content::NativeWebKeyboardEvent& event) override;
// Autofill related events.
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
void ShowAutofillPopup(content::RenderFrameHost* frame_host,
content::RenderFrameHost* embedder_frame_host,
bool offscreen,
@@ -175,7 +175,7 @@ class CommonWebContentsDelegate : public content::WebContentsDelegate,
bool native_fullscreen_ = false;
// UI related helper classes.
#if defined(TOOLKIT_VIEWS) && !defined(OS_MACOSX)
#if defined(TOOLKIT_VIEWS)
std::unique_ptr<AutofillPopup> autofill_popup_;
#endif
std::unique_ptr<WebDialogHelper> web_dialog_helper_;

View File

@@ -41,27 +41,6 @@ bool CommonWebContentsDelegate::HandleKeyboardEvent(
return false;
}
void CommonWebContentsDelegate::ShowAutofillPopup(
content::RenderFrameHost* frame_host,
content::RenderFrameHost* embedder_frame_host,
bool offscreen,
const gfx::RectF& bounds,
const std::vector<base::string16>& values,
const std::vector<base::string16>& labels) {
if (!owner_window())
return;
auto* window = static_cast<NativeWindowViews*>(owner_window());
autofill_popup_->CreateView(frame_host, embedder_frame_host, offscreen,
window->content_view(), bounds);
autofill_popup_->SetItems(values, labels);
}
void CommonWebContentsDelegate::HideAutofillPopup() {
if (autofill_popup_)
autofill_popup_->Hide();
}
gfx::ImageSkia CommonWebContentsDelegate::GetDevToolsWindowIcon() {
if (!owner_window())
return gfx::ImageSkia();

View File

@@ -21,6 +21,8 @@ namespace atom {
enum AutoResizeFlags {
kAutoResizeWidth = 0x1,
kAutoResizeHeight = 0x2,
kAutoResizeHorizontal = 0x4,
kAutoResizeVertical = 0x8,
};
class InspectableWebContents;

View File

@@ -175,6 +175,14 @@ void NativeBrowserViewMac::SetAutoResizeFlags(uint8_t flags) {
if (flags & kAutoResizeHeight) {
autoresizing_mask |= NSViewHeightSizable;
}
if (flags & kAutoResizeHorizontal) {
autoresizing_mask |=
NSViewMaxXMargin | NSViewMinXMargin | NSViewWidthSizable;
}
if (flags & kAutoResizeVertical) {
autoresizing_mask |=
NSViewMaxYMargin | NSViewMinYMargin | NSViewHeightSizable;
}
auto* view =
GetInspectableWebContentsView()->GetNativeView().GetNativeNSView();

View File

@@ -19,11 +19,82 @@ NativeBrowserViewViews::~NativeBrowserViewViews() {}
void NativeBrowserViewViews::SetAutoResizeFlags(uint8_t flags) {
auto_resize_flags_ = flags;
ResetAutoResizeProportions();
}
void NativeBrowserViewViews::SetAutoResizeProportions(
const gfx::Size& window_size) {
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) &&
!auto_horizontal_proportion_set_) {
auto* view = GetInspectableWebContentsView()->GetView();
auto view_bounds = view->bounds();
auto_horizontal_proportion_width_ =
static_cast<float>(window_size.width()) /
static_cast<float>(view_bounds.width());
auto_horizontal_proportion_left_ = static_cast<float>(window_size.width()) /
static_cast<float>(view_bounds.x());
auto_horizontal_proportion_set_ = true;
}
if ((auto_resize_flags_ & AutoResizeFlags::kAutoResizeVertical) &&
!auto_vertical_proportion_set_) {
auto* view = GetInspectableWebContentsView()->GetView();
auto view_bounds = view->bounds();
auto_vertical_proportion_height_ =
static_cast<float>(window_size.height()) /
static_cast<float>(view_bounds.height());
auto_vertical_proportion_top_ = static_cast<float>(window_size.height()) /
static_cast<float>(view_bounds.y());
auto_vertical_proportion_set_ = true;
}
}
void NativeBrowserViewViews::AutoResize(const gfx::Rect& new_window,
int width_delta,
int height_delta) {
auto* view = GetInspectableWebContentsView()->GetView();
const auto flags = GetAutoResizeFlags();
if (!(flags & kAutoResizeWidth)) {
width_delta = 0;
}
if (!(flags & kAutoResizeHeight)) {
height_delta = 0;
}
if (height_delta || width_delta) {
auto new_view_size = view->size();
new_view_size.set_width(new_view_size.width() + width_delta);
new_view_size.set_height(new_view_size.height() + height_delta);
view->SetSize(new_view_size);
}
auto new_view_bounds = view->bounds();
if (flags & kAutoResizeHorizontal) {
new_view_bounds.set_width(new_window.width() /
auto_horizontal_proportion_width_);
new_view_bounds.set_x(new_window.width() /
auto_horizontal_proportion_left_);
}
if (flags & kAutoResizeVertical) {
new_view_bounds.set_height(new_window.height() /
auto_vertical_proportion_height_);
new_view_bounds.set_y(new_window.height() / auto_vertical_proportion_top_);
}
if ((flags & kAutoResizeHorizontal) || (flags & kAutoResizeVertical)) {
view->SetBoundsRect(new_view_bounds);
}
}
void NativeBrowserViewViews::ResetAutoResizeProportions() {
if (auto_resize_flags_ & AutoResizeFlags::kAutoResizeHorizontal) {
auto_horizontal_proportion_set_ = false;
}
if (auto_resize_flags_ & AutoResizeFlags::kAutoResizeVertical) {
auto_vertical_proportion_set_ = false;
}
}
void NativeBrowserViewViews::SetBounds(const gfx::Rect& bounds) {
auto* view = GetInspectableWebContentsView()->GetView();
view->SetBoundsRect(bounds);
ResetAutoResizeProportions();
}
void NativeBrowserViewViews::SetBackgroundColor(SkColor color) {

View File

@@ -15,13 +15,29 @@ class NativeBrowserViewViews : public NativeBrowserView {
InspectableWebContents* inspectable_web_contents);
~NativeBrowserViewViews() override;
void SetAutoResizeProportions(const gfx::Size& window_size);
void AutoResize(const gfx::Rect& new_window,
int width_delta,
int height_delta);
uint8_t GetAutoResizeFlags() { return auto_resize_flags_; }
// NativeBrowserView:
void SetAutoResizeFlags(uint8_t flags) override;
void SetBounds(const gfx::Rect& bounds) override;
void SetBackgroundColor(SkColor color) override;
private:
uint8_t auto_resize_flags_;
void ResetAutoResizeProportions();
uint8_t auto_resize_flags_ = 0;
bool auto_horizontal_proportion_set_ = false;
float auto_horizontal_proportion_width_ = 0.;
float auto_horizontal_proportion_left_ = 0.;
bool auto_vertical_proportion_set_ = false;
float auto_vertical_proportion_height_ = 0.;
float auto_vertical_proportion_top_ = 0.;
DISALLOW_COPY_AND_ASSIGN(NativeBrowserViewViews);
};

View File

@@ -82,8 +82,13 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
} else if (options.Get(options::kCenter, &center) && center) {
Center();
}
bool use_content_size = false;
options.Get(options::kUseContentSize, &use_content_size);
// On Linux and Window we may already have maximum size defined.
extensions::SizeConstraints size_constraints(GetContentSizeConstraints());
extensions::SizeConstraints size_constraints(
use_content_size ? GetContentSizeConstraints() : GetSizeConstraints());
int min_height = 0, min_width = 0;
if (options.Get(options::kMinHeight, &min_height) |
options.Get(options::kMinWidth, &min_width)) {
@@ -94,8 +99,6 @@ void NativeWindow::InitFromOptions(const mate::Dictionary& options) {
options.Get(options::kMaxWidth, &max_width)) {
size_constraints.set_maximum_size(gfx::Size(max_width, max_height));
}
bool use_content_size = false;
options.Get(options::kUseContentSize, &use_content_size);
if (use_content_size) {
SetContentSizeConstraints(size_constraints);
} else {

View File

@@ -113,9 +113,7 @@ class NativeWindow : public base::SupportsUserData,
virtual double GetSheetOffsetX();
virtual double GetSheetOffsetY();
virtual void SetResizable(bool resizable) = 0;
#if defined(OS_WIN) || defined(OS_MACOSX)
virtual void MoveTop() = 0;
#endif
virtual bool IsResizable() = 0;
virtual void SetMovable(bool movable) = 0;
virtual bool IsMovable() = 0;

View File

@@ -1131,17 +1131,23 @@ void NativeWindowMac::SetProgressBar(double progress,
const NativeWindow::ProgressState state) {
NSDockTile* dock_tile = [NSApp dockTile];
// Sometimes macOS would install a default contentView for dock, we must
// verify whether NSProgressIndicator has been installed.
bool first_time = !dock_tile.contentView ||
[[dock_tile.contentView subviews] count] == 0 ||
![[[dock_tile.contentView subviews] lastObject]
isKindOfClass:[NSProgressIndicator class]];
// For the first time API invoked, we need to create a ContentView in
// DockTile.
if (dock_tile.contentView == nullptr) {
NSImageView* image_view = [[NSImageView alloc] init];
if (first_time) {
NSImageView* image_view = [[[NSImageView alloc] init] autorelease];
[image_view setImage:[NSApp applicationIconImage]];
[dock_tile setContentView:image_view];
}
if ([[dock_tile.contentView subviews] count] == 0) {
NSProgressIndicator* progress_indicator = [[AtomProgressBar alloc]
initWithFrame:NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0)];
NSRect frame = NSMakeRect(0.0f, 0.0f, dock_tile.size.width, 15.0);
NSProgressIndicator* progress_indicator =
[[[AtomProgressBar alloc] initWithFrame:frame] autorelease];
[progress_indicator setStyle:NSProgressIndicatorBarStyle];
[progress_indicator setIndeterminate:NO];
[progress_indicator setBezeled:YES];
@@ -1152,7 +1158,7 @@ void NativeWindowMac::SetProgressBar(double progress,
}
NSProgressIndicator* progress_indicator = static_cast<NSProgressIndicator*>(
[[[dock_tile contentView] subviews] objectAtIndex:0]);
[[[dock_tile contentView] subviews] lastObject]);
if (progress < 0) {
[progress_indicator setHidden:YES];
} else if (progress > 1) {

View File

@@ -32,6 +32,7 @@
#include "ui/aura/window_tree_host.h"
#include "ui/base/hit_test.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/native_widget_types.h"
#include "ui/views/background.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
#include "ui/views/controls/webview/webview.h"
@@ -80,6 +81,27 @@ void FlipWindowStyle(HWND handle, bool on, DWORD flag) {
style &= ~flag;
::SetWindowLong(handle, GWL_STYLE, style);
}
// Similar to the ones in display::win::ScreenWin, but with rounded values
// These help to avoid problems that arise from unresizable windows where the
// original ceil()-ed values can cause calculation errors, since converting
// both ways goes through a ceil() call. Related issue: #15816
gfx::Rect ScreenToDIPRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
gfx::Rect dip_rect = ScaleToRoundedRect(pixel_bounds, 1.0f / scale_factor);
dip_rect.set_origin(
display::win::ScreenWin::ScreenToDIPRect(hwnd, pixel_bounds).origin());
return dip_rect;
}
gfx::Rect DIPToScreenRect(HWND hwnd, const gfx::Rect& pixel_bounds) {
float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(hwnd);
gfx::Rect screen_rect = ScaleToRoundedRect(pixel_bounds, scale_factor);
screen_rect.set_origin(
display::win::ScreenWin::DIPToScreenRect(hwnd, pixel_bounds).origin());
return screen_rect;
}
#endif
class NativeWindowClientView : public views::ClientView {
@@ -238,7 +260,7 @@ NativeWindowViews::NativeWindowViews(const mate::Dictionary& options,
if (!has_frame()) {
// Set Window style so that we get a minimize and maximize animation when
// frameless.
DWORD frame_style = WS_CAPTION;
DWORD frame_style = WS_CAPTION | WS_OVERLAPPED;
if (resizable_)
frame_style |= WS_THICKFRAME;
if (minimizable_)
@@ -635,15 +657,19 @@ void NativeWindowViews::SetResizable(bool resizable) {
resizable_ = resizable;
}
#if defined(OS_WIN)
void NativeWindowViews::MoveTop() {
// TODO(julien.isorce): fix chromium in order to use existing
// widget()->StackAtTop().
#if defined(OS_WIN)
gfx::Point pos = GetPosition();
gfx::Size size = GetSize();
::SetWindowPos(GetAcceleratedWidget(), HWND_TOP, pos.x(), pos.y(),
size.width(), size.height(),
SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
}
#elif defined(USE_X11)
atom::MoveWindowToForeground(GetAcceleratedWidget());
#endif
}
bool NativeWindowViews::IsResizable() {
#if defined(OS_WIN)
@@ -1076,7 +1102,10 @@ bool NativeWindowViews::IsVisibleOnAllWorkspaces() {
}
gfx::AcceleratedWidget NativeWindowViews::GetAcceleratedWidget() const {
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
if (GetNativeWindow() && GetNativeWindow()->GetHost())
return GetNativeWindow()->GetHost()->GetAcceleratedWidget();
else
return gfx::kNullAcceleratedWidget;
}
NativeWindowHandle NativeWindowViews::GetNativeWindowHandle() const {
@@ -1091,8 +1120,8 @@ gfx::Rect NativeWindowViews::ContentBoundsToWindowBounds(
gfx::Rect window_bounds(bounds);
#if defined(OS_WIN)
HWND hwnd = GetAcceleratedWidget();
gfx::Rect dpi_bounds = display::win::ScreenWin::DIPToScreenRect(hwnd, bounds);
window_bounds = display::win::ScreenWin::ScreenToDIPRect(
gfx::Rect dpi_bounds = DIPToScreenRect(hwnd, bounds);
window_bounds = ScreenToDIPRect(
hwnd,
widget()->non_client_view()->GetWindowBoundsForClientBounds(dpi_bounds));
#endif
@@ -1113,8 +1142,7 @@ gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
gfx::Rect content_bounds(bounds);
#if defined(OS_WIN)
HWND hwnd = GetAcceleratedWidget();
content_bounds.set_size(
display::win::ScreenWin::DIPToScreenSize(hwnd, content_bounds.size()));
content_bounds.set_size(DIPToScreenRect(hwnd, content_bounds).size());
RECT rect;
SetRectEmpty(&rect);
DWORD style = ::GetWindowLong(hwnd, GWL_STYLE);
@@ -1122,8 +1150,7 @@ gfx::Rect NativeWindowViews::WindowBoundsToContentBounds(
AdjustWindowRectEx(&rect, style, FALSE, ex_style);
content_bounds.set_width(content_bounds.width() - (rect.right - rect.left));
content_bounds.set_height(content_bounds.height() - (rect.bottom - rect.top));
content_bounds.set_size(
display::win::ScreenWin::ScreenToDIPSize(hwnd, content_bounds.size()));
content_bounds.set_size(ScreenToDIPRect(hwnd, content_bounds).size());
#endif
if (root_view_->HasMenu() && root_view_->IsMenuBarVisible()) {
@@ -1176,26 +1203,6 @@ void NativeWindowViews::OnWidgetActivationChanged(views::Widget* changed_widget,
root_view_->ResetAltState();
}
void NativeWindowViews::AutoresizeBrowserView(int width_delta,
int height_delta,
NativeBrowserView* browser_view) {
const auto flags =
static_cast<NativeBrowserViewViews*>(browser_view)->GetAutoResizeFlags();
if (!(flags & kAutoResizeWidth)) {
width_delta = 0;
}
if (!(flags & kAutoResizeHeight)) {
height_delta = 0;
}
if (height_delta || width_delta) {
auto* view = browser_view->GetInspectableWebContentsView()->GetView();
auto new_view_size = view->size();
new_view_size.set_width(new_view_size.width() + width_delta);
new_view_size.set_height(new_view_size.height() + height_delta);
view->SetSize(new_view_size);
}
}
void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
const gfx::Rect& bounds) {
if (changed_widget != widget())
@@ -1208,7 +1215,10 @@ void NativeWindowViews::OnWidgetBoundsChanged(views::Widget* changed_widget,
int width_delta = new_bounds.width() - widget_size_.width();
int height_delta = new_bounds.height() - widget_size_.height();
for (NativeBrowserView* item : browser_views()) {
AutoresizeBrowserView(width_delta, height_delta, item);
NativeBrowserViewViews* native_view =
static_cast<NativeBrowserViewViews*>(item);
native_view->SetAutoResizeProportions(widget_size_);
native_view->AutoResize(new_bounds, width_delta, height_delta);
}
NotifyWindowResize();

View File

@@ -74,9 +74,7 @@ class NativeWindowViews : public NativeWindow,
void SetContentSizeConstraints(
const extensions::SizeConstraints& size_constraints) override;
void SetResizable(bool resizable) override;
#if defined(OS_WIN)
void MoveTop() override;
#endif
bool IsResizable() override;
void SetMovable(bool movable) override;
bool IsMovable() override;
@@ -158,10 +156,8 @@ class NativeWindowViews : public NativeWindow,
void OnWidgetActivationChanged(views::Widget* widget, bool active) override;
void OnWidgetBoundsChanged(views::Widget* widget,
const gfx::Rect& bounds) override;
void AutoresizeBrowserView(int width_delta,
int height_delta,
NativeBrowserView* browser_view);
void OnWidgetDestroying(views::Widget* widget) override;
// views::WidgetDelegate:
void DeleteDelegate() override;
views::View* GetInitiallyFocusedView() override;
@@ -244,6 +240,8 @@ class NativeWindowViews : public NativeWindow,
ui::WindowShowState last_window_state_;
gfx::Rect last_normal_placement_bounds_;
// There's an issue with restore on Windows, that sometimes causes the Window
// to receive the wrong size (#2498). To circumvent that, we keep tabs on the
// size of the window while in the normal state (not maximized, minimized or

View File

@@ -4,9 +4,12 @@
#include "atom/browser/browser.h"
#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/views/root_view.h"
#include "atom/common/atom_constants.h"
#include "content/public/browser/browser_accessibility_state.h"
#include "ui/base/win/accessibility_misc_utils.h"
#include "ui/display/win/screen_win.h"
#include "ui/gfx/geometry/insets.h"
// Must be included after other Windows headers.
#include <UIAutomationCoreApi.h>
@@ -183,6 +186,48 @@ bool NativeWindowViews::PreHandleMSG(UINT message,
return false;
}
case WM_GETMINMAXINFO: {
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
// We do this to work around a Windows bug, where the minimized Window
// would report that the closest display to it is not the one that it was
// previously on (but the leftmost one instead). We restore the position
// of the window during the restore operation, this way chromium can
// use the proper display to calculate the scale factor to use.
if (!last_normal_placement_bounds_.IsEmpty() &&
GetWindowPlacement(GetAcceleratedWidget(), &wp)) {
last_normal_placement_bounds_.set_size(gfx::Size(0, 0));
wp.rcNormalPosition = last_normal_placement_bounds_.ToRECT();
SetWindowPlacement(GetAcceleratedWidget(), &wp);
last_normal_placement_bounds_ = gfx::Rect();
}
return false;
}
case WM_NCCALCSIZE: {
if (!has_frame() && w_param == TRUE) {
NCCALCSIZE_PARAMS* params =
reinterpret_cast<NCCALCSIZE_PARAMS*>(l_param);
RECT PROPOSED = params->rgrc[0];
RECT BEFORE = params->rgrc[1];
// We need to call the default to have cascade and tile windows
// working
// (https://github.com/rossy/borderless-window/blob/master/borderless-window.c#L239),
// but we need to provide the proposed original value as suggested in
// https://blogs.msdn.microsoft.com/wpfsdk/2008/09/08/custom-window-chrome-in-wpf/
DefWindowProcW(GetAcceleratedWidget(), WM_NCCALCSIZE, w_param, l_param);
params->rgrc[0] = PROPOSED;
params->rgrc[1] = BEFORE;
return true;
} else {
return false;
}
}
case WM_COMMAND:
// Handle thumbar button click message.
if (HIWORD(w_param) == THBN_CLICKED)
@@ -258,15 +303,40 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
// Here we handle the WM_SIZE event in order to figure out what is the current
// window state and notify the user accordingly.
switch (w_param) {
case SIZE_MAXIMIZED:
case SIZE_MAXIMIZED: {
// Frameless maximized windows are size compensated by Windows for a
// border that's not actually there, so we must conter-compensate.
// https://blogs.msdn.microsoft.com/wpfsdk/2008/09/08/custom-window-chrome-in-wpf/
if (!has_frame()) {
float scale_factor = display::win::ScreenWin::GetScaleFactorForHWND(
GetAcceleratedWidget());
int border =
GetSystemMetrics(SM_CXFRAME) + GetSystemMetrics(SM_CXPADDEDBORDER);
if (!thick_frame_) {
border -= GetSystemMetrics(SM_CXBORDER);
}
root_view_->SetInsets(gfx::Insets(border).Scale(1.0f / scale_factor));
}
last_window_state_ = ui::SHOW_STATE_MAXIMIZED;
if (consecutive_moves_) {
last_normal_bounds_ = last_normal_bounds_before_move_;
}
NotifyWindowMaximize();
break;
}
case SIZE_MINIMIZED:
last_window_state_ = ui::SHOW_STATE_MINIMIZED;
WINDOWPLACEMENT wp;
wp.length = sizeof(WINDOWPLACEMENT);
if (GetWindowPlacement(GetAcceleratedWidget(), &wp)) {
last_normal_placement_bounds_ = gfx::Rect(wp.rcNormalPosition);
}
NotifyWindowMinimize();
break;
case SIZE_RESTORED:
@@ -278,10 +348,7 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
switch (last_window_state_) {
case ui::SHOW_STATE_MAXIMIZED:
last_window_state_ = ui::SHOW_STATE_NORMAL;
// Don't force out last known bounds onto the window as Windows
// actually gets these correct
root_view_->SetInsets(gfx::Insets(0));
NotifyWindowUnmaximize();
break;
case ui::SHOW_STATE_MINIMIZED:
@@ -293,7 +360,9 @@ void NativeWindowViews::HandleSizeEvent(WPARAM w_param, LPARAM l_param) {
// When the window is restored we resize it to the previous known
// normal size.
SetBounds(last_normal_bounds_, false);
if (has_frame()) {
SetBounds(last_normal_bounds_, false);
}
NotifyWindowRestore();
}

View File

@@ -141,6 +141,7 @@ void URLRequestStreamJob::StartAsync(
}
void URLRequestStreamJob::OnData(std::vector<char>&& buffer) { // NOLINT
DCHECK_CURRENTLY_ON(content::BrowserThread::IO);
if (write_buffer_.empty()) {
// Quick branch without copying.
write_buffer_ = std::move(buffer);
@@ -175,7 +176,7 @@ void URLRequestStreamJob::OnError(int error) {
int URLRequestStreamJob::ReadRawData(net::IOBuffer* dest, int dest_size) {
response_start_time_ = base::TimeTicks::Now();
if (ended_)
if (ended_ && write_buffer_.empty())
return 0;
// When write_buffer_ is empty, there is no data valable yet, we have to save

View File

@@ -252,6 +252,50 @@ class AtomBeginFrameTimer : public viz::DelayBasedTimeSourceClient {
DISALLOW_COPY_AND_ASSIGN(AtomBeginFrameTimer);
};
#if !defined(OS_MACOSX)
class AtomDelegatedFrameHostClient : public content::DelegatedFrameHostClient {
public:
explicit AtomDelegatedFrameHostClient(OffScreenRenderWidgetHostView* view)
: view_(view) {}
ui::Layer* DelegatedFrameHostGetLayer() const override {
return view_->GetRootLayer();
}
bool DelegatedFrameHostIsVisible() const override {
return view_->IsShowing();
}
SkColor DelegatedFrameHostGetGutterColor() const override {
if (view_->render_widget_host()->delegate() &&
view_->render_widget_host()->delegate()->IsFullscreenForCurrentTab()) {
return SK_ColorWHITE;
}
return *view_->GetBackgroundColor();
}
void OnFrameTokenChanged(uint32_t frame_token) override {
view_->render_widget_host()->DidProcessFrame(frame_token);
}
float GetDeviceScaleFactor() const override {
return view_->GetDeviceScaleFactor();
}
std::vector<viz::SurfaceId> CollectSurfaceIdsForEviction() override {
return view_->render_widget_host()->CollectSurfaceIdsForEviction();
}
void OnBeginFrame(base::TimeTicks frame_time) override {}
void InvalidateLocalSurfaceIdOnEviction() override {}
private:
OffScreenRenderWidgetHostView* const view_;
DISALLOW_COPY_AND_ASSIGN(AtomDelegatedFrameHostClient);
};
#endif // !defined(OS_MACOSX)
OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
bool transparent,
bool painting,
@@ -274,18 +318,22 @@ OffScreenRenderWidgetHostView::OffScreenRenderWidgetHostView(
weak_ptr_factory_(this) {
DCHECK(render_widget_host_);
bool is_guest_view_hack = parent_host_view_ != nullptr;
current_device_scale_factor_ = kDefaultScaleFactor;
#if !defined(OS_MACOSX)
local_surface_id_allocator_.GenerateId();
local_surface_id_allocation_ =
local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
delegated_frame_host_client_.reset(new AtomDelegatedFrameHostClient(this));
delegated_frame_host_ = std::make_unique<content::DelegatedFrameHost>(
AllocateFrameSinkId(is_guest_view_hack), this,
AllocateFrameSinkId(is_guest_view_hack),
delegated_frame_host_client_.get(),
true /* should_register_frame_sink_id */);
root_layer_.reset(new ui::Layer(ui::LAYER_SOLID_COLOR));
#endif
current_device_scale_factor_ = kDefaultScaleFactor;
local_surface_id_ = local_surface_id_allocator_.GenerateId();
#if defined(OS_MACOSX)
last_frame_root_background_color_ = SK_ColorTRANSPARENT;
CreatePlatformWidget(is_guest_view_hack);
@@ -374,7 +422,7 @@ void OffScreenRenderWidgetHostView::SendBeginFrame(
begin_frame_number_++;
if (renderer_compositor_frame_sink_)
renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args);
renderer_compositor_frame_sink_->OnBeginFrame(begin_frame_args, {});
}
void OffScreenRenderWidgetHostView::InitAsChild(gfx::NativeView) {
@@ -433,8 +481,9 @@ void OffScreenRenderWidgetHostView::Show() {
browser_compositor_->SetRenderWidgetHostIsHidden(false);
#else
delegated_frame_host_->AttachToCompositor(compositor_.get());
delegated_frame_host_->WasShown(GetLocalSurfaceId(),
GetRootLayer()->bounds().size(), false);
delegated_frame_host_->WasShown(
GetLocalSurfaceIdAllocation().local_surface_id(),
GetRootLayer()->bounds().size(), false);
#endif
if (render_widget_host_)
@@ -525,19 +574,22 @@ void OffScreenRenderWidgetHostView::TakeFallbackContentFrom(
void OffScreenRenderWidgetHostView::DidCreateNewRendererCompositorFrameSink(
viz::mojom::CompositorFrameSinkClient* renderer_compositor_frame_sink) {
renderer_compositor_frame_sink_ = renderer_compositor_frame_sink;
#if defined(OS_MACOSX)
browser_compositor_->DidCreateNewRendererCompositorFrameSink(
renderer_compositor_frame_sink_);
#else
if (GetDelegatedFrameHost()) {
GetDelegatedFrameHost()->DidCreateNewRendererCompositorFrameSink(
renderer_compositor_frame_sink_);
}
#endif
}
void OffScreenRenderWidgetHostView::SubmitCompositorFrame(
const viz::LocalSurfaceId& local_surface_id,
viz::CompositorFrame frame,
base::Optional<viz::HitTestRegionList> hit_test_region_list) {
TRACE_EVENT0("electron",
"OffScreenRenderWidgetHostView::SubmitCompositorFrame");
#if defined(OS_MACOSX)
last_frame_root_background_color_ = frame.metadata.root_background_color;
#endif
@@ -587,7 +639,7 @@ void OffScreenRenderWidgetHostView::SubmitCompositorFrame(
}
void OffScreenRenderWidgetHostView::ClearCompositorFrame() {
GetDelegatedFrameHost()->ClearDelegatedFrame();
NOTREACHED();
}
void OffScreenRenderWidgetHostView::ResetFallbackToFirstNavigationSurface() {
@@ -667,9 +719,6 @@ void OffScreenRenderWidgetHostView::Destroy() {
void OffScreenRenderWidgetHostView::SetTooltipText(const base::string16&) {}
void OffScreenRenderWidgetHostView::SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params&) {}
uint32_t OffScreenRenderWidgetHostView::GetCaptureSequenceNumber() const {
return latest_capture_sequence_number_;
}
@@ -698,7 +747,6 @@ void OffScreenRenderWidgetHostView::InitAsGuest(
content::RenderWidgetHostView* parent_host_view,
content::RenderWidgetHostViewGuest* guest_view) {
parent_host_view_->AddGuestHostView(this);
parent_host_view_->RegisterGuestViewFrameSwappedCallback(guest_view);
}
void OffScreenRenderWidgetHostView::TransformPointToRootSurface(
@@ -745,40 +793,6 @@ OffScreenRenderWidgetHostView::CreateViewForWidget(
render_widget_host, embedder_host_view, size());
}
#if !defined(OS_MACOSX)
ui::Layer* OffScreenRenderWidgetHostView::DelegatedFrameHostGetLayer() const {
return const_cast<ui::Layer*>(root_layer_.get());
}
bool OffScreenRenderWidgetHostView::DelegatedFrameHostIsVisible() const {
return is_showing_;
}
SkColor OffScreenRenderWidgetHostView::DelegatedFrameHostGetGutterColor()
const {
if (render_widget_host_->delegate() &&
render_widget_host_->delegate()->IsFullscreenForCurrentTab()) {
return SK_ColorWHITE;
}
return background_color_;
}
void OffScreenRenderWidgetHostView::OnFirstSurfaceActivation(
const viz::SurfaceInfo& surface_info) {}
void OffScreenRenderWidgetHostView::OnBeginFrame(base::TimeTicks frame_time) {}
void OffScreenRenderWidgetHostView::OnFrameTokenChanged(uint32_t frame_token) {
render_widget_host_->DidProcessFrame(frame_token);
}
const viz::LocalSurfaceId& OffScreenRenderWidgetHostView::GetLocalSurfaceId()
const {
return local_surface_id_;
}
#endif // !defined(OS_MACOSX)
const viz::FrameSinkId& OffScreenRenderWidgetHostView::GetFrameSinkId() const {
return GetDelegatedFrameHost()->frame_sink_id();
}
@@ -875,21 +889,6 @@ void OffScreenRenderWidgetHostView::ProxyViewDestroyed(
Invalidate();
}
void OffScreenRenderWidgetHostView::RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view) {
guest_host_view->RegisterFrameSwappedCallback(base::BindOnce(
&OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped,
weak_ptr_factory_.GetWeakPtr(), base::Unretained(guest_host_view)));
}
void OffScreenRenderWidgetHostView::OnGuestViewFrameSwapped(
content::RenderWidgetHostViewGuest* guest_host_view) {
InvalidateBounds(gfx::ConvertRectToPixel(current_device_scale_factor_,
guest_host_view->GetViewBounds()));
RegisterGuestViewFrameSwappedCallback(guest_host_view);
}
std::unique_ptr<viz::SoftwareOutputDevice>
OffScreenRenderWidgetHostView::CreateSoftwareOutputDevice(
ui::Compositor* compositor) {
@@ -925,7 +924,7 @@ void OffScreenRenderWidgetHostView::SetNeedsBeginFrames(
begin_frame_timer_->SetActive(needs_begin_frames);
if (software_output_device_) {
software_output_device_->SetActive(needs_begin_frames && painting_, false);
software_output_device_->SetActive(painting_, false);
}
}
@@ -937,8 +936,6 @@ void OffScreenRenderWidgetHostView::SetWantsAnimateOnlyBeginFrames() {
void OffScreenRenderWidgetHostView::OnPaint(const gfx::Rect& damage_rect,
const SkBitmap& bitmap) {
TRACE_EVENT0("electron", "OffScreenRenderWidgetHostView::OnPaint");
HoldResize();
if (parent_callback_) {
@@ -1023,10 +1020,6 @@ void OffScreenRenderWidgetHostView::SynchronizeVisualProperties() {
}
ResizeRootLayer(false);
if (render_widget_host_)
render_widget_host_->SynchronizeVisualProperties();
GetDelegatedFrameHost()->EmbedSurface(
local_surface_id_, size_, cc::DeadlinePolicy::UseDefaultDeadline());
}
void OffScreenRenderWidgetHostView::SendMouseEvent(
@@ -1192,6 +1185,13 @@ ui::Layer* OffScreenRenderWidgetHostView::GetRootLayer() const {
return root_layer_.get();
}
#if !defined(OS_MACOSX)
const viz::LocalSurfaceIdAllocation&
OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const {
return local_surface_id_allocation_;
}
#endif // defined(OS_MACOSX)
content::DelegatedFrameHost*
OffScreenRenderWidgetHostView::GetDelegatedFrameHost() const {
return delegated_frame_host_.get();
@@ -1204,11 +1204,6 @@ void OffScreenRenderWidgetHostView::SetupFrameRate(bool force) {
frame_rate_threshold_us_ = 1000000 / frame_rate_;
if (GetCompositor()) {
GetCompositor()->SetAuthoritativeVSyncInterval(
base::TimeDelta::FromMicroseconds(frame_rate_threshold_us_));
}
if (copy_frame_generator_.get()) {
copy_frame_generator_->set_frame_rate_threshold_us(
frame_rate_threshold_us_);
@@ -1257,28 +1252,32 @@ void OffScreenRenderWidgetHostView::ResizeRootLayer(bool force) {
size == GetRootLayer()->bounds().size())
return;
const gfx::Size& size_in_pixels =
gfx::ConvertSizeToPixel(current_device_scale_factor_, size);
local_surface_id_ = local_surface_id_allocator_.GenerateId();
GetRootLayer()->SetBounds(gfx::Rect(size));
GetCompositor()->SetScaleAndSize(current_device_scale_factor_, size_in_pixels,
local_surface_id_);
#if defined(OS_MACOSX)
bool resized = UpdateNSViewAndDisplay();
#else
const gfx::Size& size_in_pixels =
gfx::ConvertSizeToPixel(current_device_scale_factor_, size);
local_surface_id_allocator_.GenerateId();
local_surface_id_allocation_ =
local_surface_id_allocator_.GetCurrentLocalSurfaceIdAllocation();
GetCompositor()->SetScaleAndSize(current_device_scale_factor_, size_in_pixels,
local_surface_id_allocation_);
bool resized = true;
GetDelegatedFrameHost()->EmbedSurface(
local_surface_id_, size, cc::DeadlinePolicy::UseDefaultDeadline());
local_surface_id_allocation_.local_surface_id(), size,
cc::DeadlinePolicy::UseDefaultDeadline());
#endif
// Note that |render_widget_host_| will retrieve resize parameters from the
// DelegatedFrameHost, so it must have SynchronizeVisualProperties called
// after.
if (resized && render_widget_host_)
if (resized && render_widget_host_) {
render_widget_host_->SynchronizeVisualProperties();
}
}
viz::FrameSinkId OffScreenRenderWidgetHostView::AllocateFrameSinkId(

View File

@@ -66,13 +66,12 @@ class AtomBeginFrameTimer;
#if defined(OS_MACOSX)
class MacHelper;
#else
class AtomDelegatedFrameHostClient;
#endif
class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
public ui::CompositorDelegate,
#if !defined(OS_MACOSX)
public content::DelegatedFrameHostClient,
#endif
public OffscreenViewProxyObserver {
public:
OffScreenRenderWidgetHostView(bool transparent,
@@ -118,7 +117,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
void SetActive(bool active) override;
void ShowDefinitionForSelection() override;
void SpeakSelection() override;
bool ShouldContinueToPauseForFrame() override;
bool UpdateNSViewAndDisplay();
#endif // defined(OS_MACOSX)
@@ -144,8 +142,6 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
void Destroy(void) override;
void SetTooltipText(const base::string16&) override;
content::CursorManager* GetCursorManager() override;
void SelectionBoundsChanged(
const ViewHostMsg_SelectionBounds_Params&) override;
void CopyFromSurface(
const gfx::Rect& src_rect,
const gfx::Size& output_size,
@@ -170,18 +166,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
content::RenderWidgetHost*,
content::WebContentsView*) override;
#if !defined(OS_MACOSX)
// content::DelegatedFrameHostClient:
int DelegatedFrameHostGetGpuMemoryBufferClientId(void) const;
ui::Layer* DelegatedFrameHostGetLayer(void) const override;
bool DelegatedFrameHostIsVisible(void) const override;
SkColor DelegatedFrameHostGetGutterColor() const override;
void OnFirstSurfaceActivation(const viz::SurfaceInfo& surface_info) override;
void OnBeginFrame(base::TimeTicks frame_time) override;
void OnFrameTokenChanged(uint32_t frame_token) override;
#endif // !defined(OS_MACOSX)
const viz::LocalSurfaceId& GetLocalSurfaceId() const override;
const viz::LocalSurfaceIdAllocation& GetLocalSurfaceIdAllocation()
const override;
const viz::FrameSinkId& GetFrameSinkId() const override;
void DidNavigate() override;
@@ -220,16 +206,13 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
void RemoveViewProxy(OffscreenViewProxy* proxy);
void ProxyViewDestroyed(OffscreenViewProxy* proxy) override;
void RegisterGuestViewFrameSwappedCallback(
content::RenderWidgetHostViewGuest* guest_host_view);
void OnGuestViewFrameSwapped(
content::RenderWidgetHostViewGuest* guest_host_view);
void OnPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
void OnPopupPaint(const gfx::Rect& damage_rect, const SkBitmap& bitmap);
void OnProxyViewPaint(const gfx::Rect& damage_rect) override;
bool IsPopupWidget() const { return popup_type_ != blink::kWebPopupTypeNone; }
bool IsPopupWidget() const {
return widget_type_ == content::WidgetType::kPopup;
}
void HoldResize();
void ReleaseResize();
@@ -322,7 +305,7 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
bool paint_callback_running_ = false;
viz::LocalSurfaceId local_surface_id_;
viz::LocalSurfaceIdAllocation local_surface_id_allocation_;
viz::ParentLocalSurfaceIdAllocator local_surface_id_allocator_;
std::unique_ptr<ui::Layer> root_layer_;
@@ -349,6 +332,8 @@ class OffScreenRenderWidgetHostView : public content::RenderWidgetHostViewBase,
// Selected text on the renderer.
std::string selected_text_;
#else
std::unique_ptr<AtomDelegatedFrameHostClient> delegated_frame_host_client_;
#endif
content::MouseWheelPhaseHandler mouse_wheel_phase_handler_;

View File

@@ -11,13 +11,15 @@
#include "ui/accelerated_widget_mac/accelerated_widget_mac.h"
#include "ui/display/screen.h"
#include "components/viz/common/features.h"
namespace atom {
class MacHelper : public content::BrowserCompositorMacClient,
public ui::AcceleratedWidgetMacNSView {
public:
explicit MacHelper(OffScreenRenderWidgetHostView* view) : view_(view) {
[view_->GetNativeView() setWantsLayer:YES];
[view_->GetNativeView().GetNativeNSView() setWantsLayer:YES];
}
virtual ~MacHelper() {}
@@ -44,25 +46,14 @@ class MacHelper : public content::BrowserCompositorMacClient,
void DestroyCompositorForShutdown() override {}
bool SynchronizeVisualProperties(
const base::Optional<viz::LocalSurfaceId>&
child_allocated_local_surface_id) override {
auto* browser_compositor = view_->browser_compositor();
if (child_allocated_local_surface_id) {
browser_compositor->UpdateRendererLocalSurfaceIdFromChild(
*child_allocated_local_surface_id);
} else {
browser_compositor->AllocateNewRendererLocalSurfaceId();
}
if (auto* host = browser_compositor->GetDelegatedFrameHost()) {
host->EmbedSurface(browser_compositor->GetRendererLocalSurfaceId(),
browser_compositor->GetRendererSize(),
cc::DeadlinePolicy::UseDefaultDeadline());
}
bool OnBrowserCompositorSurfaceIdChanged() override {
return view_->render_widget_host()->SynchronizeVisualProperties();
}
std::vector<viz::SurfaceId> CollectSurfaceIdsForEviction() override {
return view_->render_widget_host()->CollectSurfaceIdsForEviction();
}
private:
OffScreenRenderWidgetHostView* view_;
@@ -76,20 +67,20 @@ void OffScreenRenderWidgetHostView::ShowDefinitionForSelection() {}
void OffScreenRenderWidgetHostView::SpeakSelection() {}
bool OffScreenRenderWidgetHostView::UpdateNSViewAndDisplay() {
return browser_compositor_->UpdateNSViewAndDisplay(
return browser_compositor_->UpdateSurfaceFromNSView(
GetRootLayer()->bounds().size(), GetDisplay());
}
bool OffScreenRenderWidgetHostView::ShouldContinueToPauseForFrame() {
return browser_compositor_->ShouldContinueToPauseForFrame();
}
void OffScreenRenderWidgetHostView::CreatePlatformWidget(
bool is_guest_view_hack) {
mac_helper_ = new MacHelper(this);
browser_compositor_.reset(new content::BrowserCompositorMac(
mac_helper_, mac_helper_, render_widget_host_->is_hidden(), GetDisplay(),
AllocateFrameSinkId(is_guest_view_hack)));
if (!base::FeatureList::IsEnabled(features::kVizDisplayCompositor)) {
SetNeedsBeginFrames(true);
}
}
void OffScreenRenderWidgetHostView::DestroyPlatformWidget() {
@@ -132,14 +123,15 @@ display::Display OffScreenRenderWidgetHostView::GetDisplay() {
void OffScreenRenderWidgetHostView::OnDidUpdateVisualPropertiesComplete(
const cc::RenderFrameMetadata& metadata) {
DCHECK_EQ(current_device_scale_factor_, metadata.device_scale_factor);
browser_compositor_->SynchronizeVisualProperties(
browser_compositor_->UpdateSurfaceFromChild(
metadata.device_scale_factor, metadata.viewport_size_in_pixels,
metadata.local_surface_id.value_or(viz::LocalSurfaceId()));
metadata.local_surface_id_allocation.value_or(
viz::LocalSurfaceIdAllocation()));
}
const viz::LocalSurfaceId& OffScreenRenderWidgetHostView::GetLocalSurfaceId()
const {
return browser_compositor_->GetRendererLocalSurfaceId();
const viz::LocalSurfaceIdAllocation&
OffScreenRenderWidgetHostView::GetLocalSurfaceIdAllocation() const {
return browser_compositor_->GetRendererLocalSurfaceIdAllocation();
}
ui::Compositor* OffScreenRenderWidgetHostView::GetCompositor() const {

View File

@@ -128,7 +128,7 @@ OffScreenWebContentsView::CreateViewForWidget(
}
content::RenderWidgetHostViewBase*
OffScreenWebContentsView::CreateViewForPopupWidget(
OffScreenWebContentsView::CreateViewForChildWidget(
content::RenderWidgetHost* render_widget_host) {
content::WebContentsImpl* web_contents_impl =
static_cast<content::WebContentsImpl*>(web_contents_);

View File

@@ -57,7 +57,7 @@ class OffScreenWebContentsView : public content::WebContentsView,
content::RenderWidgetHostViewBase* CreateViewForWidget(
content::RenderWidgetHost* render_widget_host,
bool is_guest_view_hack) override;
content::RenderWidgetHostViewBase* CreateViewForPopupWidget(
content::RenderWidgetHostViewBase* CreateViewForChildWidget(
content::RenderWidgetHost* render_widget_host) override;
void SetPageTitle(const base::string16& title) override;
void RenderViewCreated(content::RenderViewHost* host) override;

View File

@@ -89,7 +89,7 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
const PrintHostMsg_DidPrintContent_Params& content = params.content;
if (!content.metafile_data_region.IsValid() ||
params.expected_pages_count <= 0) {
RunPrintToPDFCallback(ids.request_id, nullptr);
RejectPromise(ids.request_id);
return;
}
@@ -102,10 +102,9 @@ void PrintPreviewMessageHandler::OnMetafileReadyForPrinting(
base::BindOnce(&PrintPreviewMessageHandler::OnCompositePdfDocumentDone,
weak_ptr_factory_.GetWeakPtr(), ids));
} else {
RunPrintToPDFCallback(
ids.request_id,
base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(
content.metafile_data_region));
ResolvePromise(ids.request_id,
base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(
content.metafile_data_region));
}
}
@@ -117,11 +116,11 @@ void PrintPreviewMessageHandler::OnCompositePdfDocumentDone(
if (status != printing::mojom::PdfCompositor::Status::SUCCESS) {
DLOG(ERROR) << "Compositing pdf failed with error " << status;
RunPrintToPDFCallback(ids.request_id, nullptr);
RejectPromise(ids.request_id);
return;
}
RunPrintToPDFCallback(
ResolvePromise(
ids.request_id,
base::RefCountedSharedMemoryMapping::CreateFromWholeRegion(region));
}
@@ -131,7 +130,7 @@ void PrintPreviewMessageHandler::OnPrintPreviewFailed(
const PrintHostMsg_PreviewIds& ids) {
StopWorker(document_cookie);
RunPrintToPDFCallback(ids.request_id, nullptr);
RejectPromise(ids.request_id);
}
void PrintPreviewMessageHandler::OnPrintPreviewCancelled(
@@ -139,15 +138,15 @@ void PrintPreviewMessageHandler::OnPrintPreviewCancelled(
const PrintHostMsg_PreviewIds& ids) {
StopWorker(document_cookie);
RunPrintToPDFCallback(ids.request_id, nullptr);
RejectPromise(ids.request_id);
}
void PrintPreviewMessageHandler::PrintToPDF(
const base::DictionaryValue& options,
const PrintToPDFCallback& callback) {
scoped_refptr<atom::util::Promise> promise) {
int request_id;
options.GetInteger(printing::kPreviewRequestID, &request_id);
print_to_pdf_callback_map_[request_id] = callback;
promise_map_[request_id] = std::move(promise);
auto* focused_frame = web_contents()->GetFocusedFrame();
auto* rfh = focused_frame && focused_frame->HasSelection()
@@ -156,28 +155,44 @@ void PrintPreviewMessageHandler::PrintToPDF(
rfh->Send(new PrintMsg_PrintPreview(rfh->GetRoutingID(), options));
}
void PrintPreviewMessageHandler::RunPrintToPDFCallback(
scoped_refptr<atom::util::Promise> PrintPreviewMessageHandler::GetPromise(
int request_id) {
auto it = promise_map_.find(request_id);
DCHECK(it != promise_map_.end());
auto promise = it->second;
promise_map_.erase(it);
return promise;
}
void PrintPreviewMessageHandler::ResolvePromise(
int request_id,
scoped_refptr<base::RefCountedMemory> data_bytes) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::Locker locker(isolate);
auto promise = GetPromise(request_id);
v8::Isolate* isolate = promise->isolate();
mate::Locker locker(isolate);
v8::HandleScope handle_scope(isolate);
if (data_bytes && data_bytes->size()) {
v8::Local<v8::Value> buffer =
node::Buffer::Copy(isolate,
reinterpret_cast<const char*>(data_bytes->front()),
data_bytes->size())
.ToLocalChecked();
print_to_pdf_callback_map_[request_id].Run(v8::Null(isolate), buffer);
} else {
v8::Local<v8::String> error_message =
v8::String::NewFromUtf8(isolate, "Failed to generate PDF");
print_to_pdf_callback_map_[request_id].Run(
v8::Exception::Error(error_message), v8::Null(isolate));
}
print_to_pdf_callback_map_.erase(request_id);
v8::Context::Scope context_scope(
v8::Local<v8::Context>::New(isolate, promise->GetContext()));
v8::Local<v8::Value> buffer =
node::Buffer::Copy(isolate,
reinterpret_cast<const char*>(data_bytes->front()),
data_bytes->size())
.ToLocalChecked();
promise->Resolve(buffer);
}
void PrintPreviewMessageHandler::RejectPromise(int request_id) {
DCHECK_CURRENTLY_ON(BrowserThread::UI);
auto promise = GetPromise(request_id);
promise->RejectWithErrorMessage("Failed to generate PDF");
}
} // namespace atom

View File

@@ -7,6 +7,7 @@
#include <map>
#include "atom/common/promise_util.h"
#include "base/memory/ref_counted_memory.h"
#include "base/memory/weak_ptr.h"
#include "components/services/pdf_compositor/public/interfaces/pdf_compositor.mojom.h"
@@ -28,13 +29,10 @@ class PrintPreviewMessageHandler
: public content::WebContentsObserver,
public content::WebContentsUserData<PrintPreviewMessageHandler> {
public:
using PrintToPDFCallback =
base::Callback<void(v8::Local<v8::Value>, v8::Local<v8::Value>)>;
~PrintPreviewMessageHandler() override;
void PrintToPDF(const base::DictionaryValue& options,
const PrintToPDFCallback& callback);
scoped_refptr<atom::util::Promise> promise);
protected:
// content::WebContentsObserver implementation.
@@ -57,11 +55,15 @@ class PrintPreviewMessageHandler
const PrintHostMsg_PreviewIds& ids);
void OnPrintPreviewCancelled(int document_cookie,
const PrintHostMsg_PreviewIds& ids);
void RunPrintToPDFCallback(int request_id,
scoped_refptr<base::RefCountedMemory> data_bytes);
using PrintToPDFCallbackMap = std::map<int, PrintToPDFCallback>;
PrintToPDFCallbackMap print_to_pdf_callback_map_;
scoped_refptr<atom::util::Promise> GetPromise(int request_id);
void ResolvePromise(int request_id,
scoped_refptr<base::RefCountedMemory> data_bytes);
void RejectPromise(int request_id);
using PromiseMap = std::map<int, scoped_refptr<atom::util::Promise>>;
PromiseMap promise_map_;
base::WeakPtrFactory<PrintPreviewMessageHandler> weak_ptr_factory_;

View File

@@ -17,9 +17,9 @@
<key>CFBundleIconFile</key>
<string>electron.icns</string>
<key>CFBundleVersion</key>
<string>5.0.0-nightly.20190122</string>
<string>6.0.0-nightly.20190212</string>
<key>CFBundleShortVersionString</key>
<string>5.0.0-nightly.20190122</string>
<string>6.0.0-nightly.20190212</string>
<key>LSApplicationCategoryType</key>
<string>public.app-category.developer-tools</string>
<key>LSMinimumSystemVersion</key>

View File

@@ -50,8 +50,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 5,0,0,20190122
PRODUCTVERSION 5,0,0,20190122
FILEVERSION 6,0,0,20190212
PRODUCTVERSION 6,0,0,20190212
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
@@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "GitHub, Inc."
VALUE "FileDescription", "Electron"
VALUE "FileVersion", "5.0.0"
VALUE "FileVersion", "6.0.0"
VALUE "InternalName", "electron.exe"
VALUE "LegalCopyright", "Copyright (C) 2015 GitHub, Inc. All rights reserved."
VALUE "OriginalFilename", "electron.exe"
VALUE "ProductName", "Electron"
VALUE "ProductVersion", "5.0.0"
VALUE "ProductVersion", "6.0.0"
VALUE "SquirrelAwareVersion", "1"
END
END

View File

@@ -9,6 +9,8 @@
#include "atom/browser/native_window_views.h"
#include "atom/browser/ui/autofill_popup.h"
#include "atom/common/api/api_messages.h"
#include "base/i18n/rtl.h"
#include "chrome/browser/ui/autofill/popup_view_common.h"
#include "electron/buildflags/buildflags.h"
#include "ui/display/display.h"
#include "ui/display/screen.h"
@@ -25,85 +27,18 @@
namespace atom {
namespace {
class PopupViewCommon : public autofill::PopupViewCommon {
public:
explicit PopupViewCommon(const gfx::Rect& window_bounds)
: window_bounds_(window_bounds) {}
std::pair<int, int> CalculatePopupXAndWidth(
const display::Display& left_display,
const display::Display& right_display,
int popup_required_width,
const gfx::Rect& element_bounds,
bool is_rtl) {
int leftmost_display_x = left_display.bounds().x();
int rightmost_display_x =
right_display.GetSizeInPixel().width() + right_display.bounds().x();
// Calculate the start coordinates for the popup if it is growing right or
// the end position if it is growing to the left, capped to screen space.
int right_growth_start = std::max(
leftmost_display_x, std::min(rightmost_display_x, element_bounds.x()));
int left_growth_end =
std::max(leftmost_display_x,
std::min(rightmost_display_x, element_bounds.right()));
int right_available = rightmost_display_x - right_growth_start;
int left_available = left_growth_end - leftmost_display_x;
int popup_width =
std::min(popup_required_width, std::max(right_available, left_available));
std::pair<int, int> grow_right(right_growth_start, popup_width);
std::pair<int, int> grow_left(left_growth_end - popup_width, popup_width);
// Prefer to grow towards the end (right for LTR, left for RTL). But if there
// is not enough space available in the desired direction and more space in
// the other direction, reverse it.
if (is_rtl) {
return left_available >= popup_width || left_available >= right_available
? grow_left
: grow_right;
gfx::Rect GetWindowBounds(gfx::NativeView container_view) override {
return window_bounds_;
}
return right_available >= popup_width || right_available >= left_available
? grow_right
: grow_left;
}
std::pair<int, int> CalculatePopupYAndHeight(
const display::Display& top_display,
const display::Display& bottom_display,
int popup_required_height,
const gfx::Rect& element_bounds) {
int topmost_display_y = top_display.bounds().y();
int bottommost_display_y =
bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y();
// Calculate the start coordinates for the popup if it is growing down or
// the end position if it is growing up, capped to screen space.
int top_growth_end = std::max(
topmost_display_y, std::min(bottommost_display_y, element_bounds.y()));
int bottom_growth_start =
std::max(topmost_display_y,
std::min(bottommost_display_y, element_bounds.bottom()));
int top_available = bottom_growth_start - topmost_display_y;
int bottom_available = bottommost_display_y - top_growth_end;
// TODO(csharp): Restrict the popup height to what is available.
if (bottom_available >= popup_required_height ||
bottom_available >= top_available) {
// The popup can appear below the field.
return std::make_pair(bottom_growth_start, popup_required_height);
} else {
// The popup must appear above the field.
return std::make_pair(top_growth_end - popup_required_height,
popup_required_height);
}
}
display::Display GetDisplayNearestPoint(const gfx::Point& point) {
return display::Screen::GetScreen()->GetDisplayNearestPoint(point);
}
} // namespace
private:
gfx::Rect window_bounds_;
};
AutofillPopup::AutofillPopup() {
bold_font_list_ = gfx::FontList().DeriveWithWeight(gfx::Font::Weight::BOLD);
@@ -181,34 +116,14 @@ void AutofillPopup::UpdatePopupBounds() {
DCHECK(parent_);
gfx::Point origin(element_bounds_.origin());
views::View::ConvertPointToScreen(parent_, &origin);
gfx::Rect bounds(origin, element_bounds_.size());
gfx::Rect window_bounds = parent_->GetBoundsInScreen();
int desired_width = GetDesiredPopupWidth();
int desired_height = GetDesiredPopupHeight();
bool is_rtl = false;
gfx::Point top_left_corner_of_popup =
origin + gfx::Vector2d(bounds.width() - desired_width, -desired_height);
// This is the bottom right point of the popup if the popup is below the
// element and grows to the right (since the is the lowest and furthest right
// the popup could go).
gfx::Point bottom_right_corner_of_popup =
origin + gfx::Vector2d(desired_width, bounds.height() + desired_height);
display::Display top_left_display =
GetDisplayNearestPoint(top_left_corner_of_popup);
display::Display bottom_right_display =
GetDisplayNearestPoint(bottom_right_corner_of_popup);
std::pair<int, int> popup_x_and_width = CalculatePopupXAndWidth(
top_left_display, bottom_right_display, desired_width, bounds, is_rtl);
std::pair<int, int> popup_y_and_height = CalculatePopupYAndHeight(
top_left_display, bottom_right_display, desired_height, bounds);
popup_bounds_ =
gfx::Rect(popup_x_and_width.first, popup_y_and_height.first,
popup_x_and_width.second, popup_y_and_height.second);
PopupViewCommon popup_view_common(window_bounds);
popup_bounds_ = popup_view_common.CalculatePopupBounds(
GetDesiredPopupWidth(), GetDesiredPopupHeight(), bounds,
gfx::NativeView(), base::i18n::IsRTL());
}
gfx::Rect AutofillPopup::popup_bounds_in_view() {

View File

@@ -17,6 +17,7 @@
#include "ui/base/l10n/l10n_util_mac.h"
#include "ui/events/cocoa/cocoa_event_utils.h"
#include "ui/gfx/image/image.h"
#include "ui/strings/grit/ui_strings.h"
using content::BrowserThread;
@@ -58,6 +59,29 @@ Role kRolesMap[] = {
{@selector(clearRecentDocuments:), "clearrecentdocuments"},
};
// Called when adding a submenu to the menu and checks if the submenu, via its
// |model|, has visible child items.
bool MenuHasVisibleItems(const atom::AtomMenuModel* model) {
int count = model->GetItemCount();
for (int index = 0; index < count; index++) {
if (model->IsVisibleAt(index))
return true;
}
return false;
}
// Called when an empty submenu is created. This inserts a menu item labeled
// "(empty)" into the submenu. Matches Windows behavior.
NSMenu* MakeEmptySubmenu() {
base::scoped_nsobject<NSMenu> submenu([[NSMenu alloc] initWithTitle:@""]);
NSString* empty_menu_title =
l10n_util::GetNSString(IDS_APP_MENU_EMPTY_SUBMENU);
[submenu addItemWithTitle:empty_menu_title action:NULL keyEquivalent:@""];
[[submenu itemAtIndex:0] setEnabled:NO];
return submenu.autorelease();
}
} // namespace
// Menu item is located for ease of removing it from the parent owner
@@ -220,13 +244,21 @@ static base::scoped_nsobject<NSMenu> recentDocumentsMenuSwap_;
NSMenu* submenu = [[NSMenu alloc] initWithTitle:label];
[item setSubmenu:submenu];
[NSApp setServicesMenu:submenu];
} else if (type == atom::AtomMenuModel::TYPE_SUBMENU) {
} else if (type == atom::AtomMenuModel::TYPE_SUBMENU &&
model->IsVisibleAt(index)) {
// We need to specifically check that the submenu top-level item has been
// enabled as it's not validated by validateUserInterfaceItem
if (!model->IsEnabledAt(index))
[item setEnabled:NO];
// Recursively build a submenu from the sub-model at this index.
[item setTarget:nil];
[item setAction:nil];
atom::AtomMenuModel* submenuModel =
static_cast<atom::AtomMenuModel*>(model->GetSubmenuModelAt(index));
NSMenu* submenu = [self menuFromModel:submenuModel];
NSMenu* submenu = MenuHasVisibleItems(submenuModel)
? [self menuFromModel:submenuModel]
: MakeEmptySubmenu();
[submenu setTitle:[item title]];
[item setSubmenu:submenu];

View File

@@ -16,7 +16,19 @@ ViewsDelegateMac::~ViewsDelegateMac() {}
void ViewsDelegateMac::OnBeforeWidgetInit(
views::Widget::InitParams* params,
views::internal::NativeWidgetDelegate* delegate) {
DCHECK(params->native_widget);
// If we already have a native_widget, we don't have to try to come
// up with one.
if (params->native_widget)
return;
if (!native_widget_factory().is_null()) {
params->native_widget = native_widget_factory().Run(*params, delegate);
if (params->native_widget)
return;
}
// Setting null here causes Widget to create the default NativeWidget implementation.
params->native_widget = nullptr;
}
ui::ContextFactory* ViewsDelegateMac::GetContextFactory() {

View File

@@ -56,19 +56,12 @@ AutofillPopupView::~AutofillPopupView() {
}
void AutofillPopupView::Show() {
if (!popup_)
if (!popup_ || !parent_widget_->IsVisible() || parent_widget_->IsClosed())
return;
const bool initialize_widget = !GetWidget();
if (initialize_widget) {
parent_widget_->AddObserver(this);
views::FocusManager* focus_manager = parent_widget_->GetFocusManager();
focus_manager->RegisterAccelerator(
ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE),
ui::AcceleratorManager::kNormalPriority, this);
focus_manager->RegisterAccelerator(
ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE),
ui::AcceleratorManager::kNormalPriority, this);
// The widget is destroyed by the corresponding NativeWidget, so we use
// a weak pointer to hold the reference and don't have to worry about
@@ -487,7 +480,6 @@ void AutofillPopupView::ClearSelection() {
}
void AutofillPopupView::RemoveObserver() {
parent_widget_->GetFocusManager()->UnregisterAccelerators(this);
parent_widget_->RemoveObserver(this);
views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this);
}

View File

@@ -10,6 +10,7 @@
#include "atom/browser/ui/views/submenu_button.h"
#include "atom/common/keyboard_util.h"
#include "ui/aura/window.h"
#include "ui/base/models/menu_model.h"
#include "ui/views/background.h"
#include "ui/views/layout/box_layout.h"
@@ -174,6 +175,27 @@ bool MenuBar::AcceleratorPressed(const ui::Accelerator& accelerator) {
}
bool MenuBar::SetPaneFocus(views::View* initial_focus) {
// TODO(zcbenz): Submit patch to upstream Chromium to fix the crash.
//
// Without this check, Electron would crash when running tests.
//
// Check failed: rules_->CanFocusWindow(window, nullptr).
// logging::LogMessage::~LogMessage
// wm::FocusController::SetFocusedWindow
// wm::FocusController::ResetFocusWithinActiveWindow
// views::View::OnFocus
// views::Button::OnFocus
// views::LabelButton::OnFocus
// views::View::Focus
// views::FocusManager::SetFocusedViewWithReason
// views::AccessiblePaneView::SetPaneFocus
// atom::MenuBar::SetPaneFocus
if (initial_focus && initial_focus->GetWidget()) {
aura::Window* window = initial_focus->GetWidget()->GetNativeWindow();
if (!window || !window->GetRootWindow())
return false;
}
bool result = views::AccessiblePaneView::SetPaneFocus(initial_focus);
if (result) {

View File

@@ -173,14 +173,18 @@ void RootView::Layout() {
return;
const auto menu_bar_bounds =
menu_bar_visible_ ? gfx::Rect(0, 0, size().width(), kMenuBarHeight)
: gfx::Rect();
menu_bar_visible_
? gfx::Rect(insets_.left(), insets_.top(),
size().width() - insets_.width(), kMenuBarHeight)
: gfx::Rect();
if (menu_bar_)
menu_bar_->SetBoundsRect(menu_bar_bounds);
window_->content_view()->SetBoundsRect(
gfx::Rect(0, menu_bar_bounds.height(), size().width(),
size().height() - menu_bar_bounds.height()));
gfx::Rect(insets_.left(),
menu_bar_visible_ ? menu_bar_bounds.bottom() : insets_.top(),
size().width() - insets_.width(),
size().height() - menu_bar_bounds.height() - insets_.height()));
}
gfx::Size RootView::GetMinimumSize() const {
@@ -217,4 +221,11 @@ void RootView::UnregisterAcceleratorsWithFocusManager() {
focus_manager->UnregisterAccelerators(this);
}
void RootView::SetInsets(const gfx::Insets& insets) {
if (insets != insets_) {
insets_ = insets;
Layout();
}
}
} // namespace atom

View File

@@ -8,6 +8,7 @@
#include <memory>
#include "atom/browser/ui/accelerator_util.h"
#include "ui/gfx/geometry/insets.h"
#include "ui/views/view.h"
#include "ui/views/view_tracker.h"
@@ -39,6 +40,8 @@ class RootView : public views::View {
// Register/Unregister accelerators supported by the menu model.
void RegisterAcceleratorsWithFocusManager(AtomMenuModel* menu_model);
void UnregisterAcceleratorsWithFocusManager();
void SetInsets(const gfx::Insets& insets);
gfx::Insets insets() const { return insets_; }
// views::View:
void Layout() override;
@@ -56,6 +59,8 @@ class RootView : public views::View {
bool menu_bar_visible_ = false;
bool menu_bar_alt_pressed_ = false;
gfx::Insets insets_;
// Map from accelerator to menu item's command id.
accelerator_util::AcceleratorTable accelerator_table_;

View File

@@ -88,4 +88,25 @@ bool ShouldUseGlobalMenuBar() {
return false;
}
void MoveWindowToForeground(::Window xwindow) {
XDisplay* xdisplay = gfx::GetXDisplay();
XEvent xclient;
memset(&xclient, 0, sizeof(xclient));
xclient.type = ClientMessage;
xclient.xclient.display = xdisplay;
xclient.xclient.window = xwindow;
xclient.xclient.message_type = GetAtom("_NET_RESTACK_WINDOW");
xclient.xclient.format = 32;
xclient.xclient.data.l[0] = 2;
xclient.xclient.data.l[1] = 0;
xclient.xclient.data.l[2] = Above;
xclient.xclient.data.l[3] = 0;
xclient.xclient.data.l[4] = 0;
XSendEvent(xdisplay, DefaultRootWindow(xdisplay), x11::False,
SubstructureRedirectMask | SubstructureNotifyMask, &xclient);
XFlush(xdisplay);
}
} // namespace atom

View File

@@ -23,6 +23,9 @@ void SetWindowType(::Window xwindow, const std::string& type);
// Returns true if the bus name "com.canonical.AppMenu.Registrar" is available.
bool ShouldUseGlobalMenuBar();
// Bring the given window to the front and give it the focus.
void MoveWindowToForeground(::Window xwindow);
} // namespace atom
#endif // ATOM_BROWSER_UI_X_X_WINDOW_UTILS_H_

View File

@@ -128,6 +128,7 @@ WebContentsPreferences::WebContentsPreferences(
SetDefaultBoolIfUndefined(options::kWebviewTag, false);
SetDefaultBoolIfUndefined(options::kSandbox, false);
SetDefaultBoolIfUndefined(options::kNativeWindowOpen, false);
SetDefaultBoolIfUndefined(options::kEnableRemoteModule, true);
SetDefaultBoolIfUndefined(options::kContextIsolation, false);
SetDefaultBoolIfUndefined("javascript", true);
SetDefaultBoolIfUndefined("images", true);

View File

@@ -25,11 +25,13 @@ IPC_STRUCT_TRAITS_BEGIN(atom::DraggableRegion)
IPC_STRUCT_TRAITS_MEMBER(bounds)
IPC_STRUCT_TRAITS_END()
IPC_MESSAGE_ROUTED2(AtomFrameHostMsg_Message,
IPC_MESSAGE_ROUTED3(AtomFrameHostMsg_Message,
bool /* internal */,
std::string /* channel */,
base::ListValue /* arguments */)
IPC_SYNC_MESSAGE_ROUTED2_1(AtomFrameHostMsg_Message_Sync,
IPC_SYNC_MESSAGE_ROUTED3_1(AtomFrameHostMsg_Message_Sync,
bool /* internal */,
std::string /* channel */,
base::ListValue /* arguments */,
base::ListValue /* result */)
@@ -41,6 +43,10 @@ IPC_MESSAGE_ROUTED5(AtomFrameHostMsg_Message_To,
std::string /* channel */,
base::ListValue /* arguments */)
IPC_MESSAGE_ROUTED2(AtomFrameHostMsg_Message_Host,
std::string /* channel */,
base::ListValue /* arguments */)
IPC_MESSAGE_ROUTED5(AtomFrameMsg_Message,
bool /* internal */,
bool /* send_to_all */,

View File

@@ -56,13 +56,12 @@ void RemoteObjectFreer::RunDestructor() {
if (!render_frame)
return;
auto* channel = "ipc-internal-message";
auto* channel = "ELECTRON_BROWSER_DEREFERENCE";
base::ListValue args;
args.AppendString("ELECTRON_BROWSER_DEREFERENCE");
args.AppendString(context_id_);
args.AppendInteger(object_id_);
render_frame->Send(new AtomFrameHostMsg_Message(render_frame->GetRoutingID(),
channel, args));
true, channel, args));
}
} // namespace atom

View File

@@ -5,11 +5,11 @@
#ifndef ATOM_COMMON_ATOM_VERSION_H_
#define ATOM_COMMON_ATOM_VERSION_H_
#define ATOM_MAJOR_VERSION 5
#define ATOM_MAJOR_VERSION 6
#define ATOM_MINOR_VERSION 0
#define ATOM_PATCH_VERSION 0
// clang-format off
#define ATOM_PRE_RELEASE_VERSION -nightly.20190122
#define ATOM_PRE_RELEASE_VERSION -nightly.20190212
// clang-format on
#ifndef ATOM_STRINGIFY

View File

@@ -38,6 +38,12 @@ ui::KeyboardCode KeyboardCodeFromKeyIdentifier(const std::string& s,
} else if (str == "plus") {
*shifted = true;
return ui::VKEY_OEM_PLUS;
} else if (str == "capslock") {
return ui::VKEY_CAPITAL;
} else if (str == "numlock") {
return ui::VKEY_NUMLOCK;
} else if (str == "scrolllock") {
return ui::VKEY_SCROLL;
} else if (str == "tab") {
return ui::VKEY_TAB;
} else if (str == "num0") {

View File

@@ -105,6 +105,22 @@ bool Converter<gfx::Rect>::FromV8(v8::Isolate* isolate,
return true;
}
template <>
struct Converter<display::Display::AccelerometerSupport> {
static v8::Local<v8::Value> ToV8(
v8::Isolate* isolate,
const display::Display::AccelerometerSupport& val) {
switch (val) {
case display::Display::AccelerometerSupport::AVAILABLE:
return StringToV8(isolate, "available");
case display::Display::AccelerometerSupport::UNAVAILABLE:
return StringToV8(isolate, "unavailable");
default:
return StringToV8(isolate, "unknown");
}
}
};
template <>
struct Converter<display::Display::TouchSupport> {
static v8::Local<v8::Value> ToV8(v8::Isolate* isolate,
@@ -128,10 +144,15 @@ v8::Local<v8::Value> Converter<display::Display>::ToV8(
dict.Set("id", val.id());
dict.Set("bounds", val.bounds());
dict.Set("workArea", val.work_area());
dict.Set("accelerometerSupport", val.accelerometer_support());
dict.Set("monochrome", val.is_monochrome());
dict.Set("colorDepth", val.color_depth());
dict.Set("depthPerComponent", val.depth_per_component());
dict.Set("size", val.size());
dict.Set("workAreaSize", val.work_area_size());
dict.Set("scaleFactor", val.device_scale_factor());
dict.Set("rotation", val.RotationAsDegree());
dict.Set("internal", val.IsInternal());
dict.Set("touchSupport", val.touch_support());
return dict.GetHandle();
}

View File

@@ -179,11 +179,20 @@ const char kDisableHttpCache[] = "disable-http-cache";
const char kStandardSchemes[] = "standard-schemes";
// Register schemes to handle service worker.
const char kRegisterServiceWorkerSchemes[] = "register-service-worker-schemes";
const char kServiceWorkerSchemes[] = "service-worker-schemes";
// Register schemes as secure.
const char kSecureSchemes[] = "secure-schemes";
// Register schemes as bypassing CSP.
const char kBypassCSPSchemes[] = "bypasscsp-schemes";
// Register schemes as support fetch API.
const char kFetchSchemes[] = "fetch-schemes";
// Register schemes as CORS enabled.
const char kCORSSchemes[] = "cors-schemes";
// The browser process app model ID
const char kAppUserModelId[] = "app-user-model-id";

View File

@@ -89,8 +89,11 @@ extern const char kPpapiFlashPath[];
extern const char kPpapiFlashVersion[];
extern const char kDisableHttpCache[];
extern const char kStandardSchemes[];
extern const char kRegisterServiceWorkerSchemes[];
extern const char kServiceWorkerSchemes[];
extern const char kSecureSchemes[];
extern const char kBypassCSPSchemes[];
extern const char kFetchSchemes[];
extern const char kCORSSchemes[];
extern const char kAppUserModelId[];
extern const char kAppPath[];

View File

@@ -5,7 +5,6 @@
#include <string>
#include "atom/common/api/api_messages.h"
#include "atom/common/native_mate_converters/string16_converter.h"
#include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/node_bindings.h"
#include "atom/common/node_includes.h"
@@ -29,6 +28,7 @@ RenderFrame* GetCurrentRenderFrame() {
}
void Send(mate::Arguments* args,
bool internal,
const std::string& channel,
const base::ListValue& arguments) {
RenderFrame* render_frame = GetCurrentRenderFrame();
@@ -36,13 +36,14 @@ void Send(mate::Arguments* args,
return;
bool success = render_frame->Send(new AtomFrameHostMsg_Message(
render_frame->GetRoutingID(), channel, arguments));
render_frame->GetRoutingID(), internal, channel, arguments));
if (!success)
args->ThrowError("Unable to send AtomFrameHostMsg_Message");
}
base::ListValue SendSync(mate::Arguments* args,
bool internal,
const std::string& channel,
const base::ListValue& arguments) {
base::ListValue result;
@@ -52,7 +53,7 @@ base::ListValue SendSync(mate::Arguments* args,
return result;
IPC::SyncMessage* message = new AtomFrameHostMsg_Message_Sync(
render_frame->GetRoutingID(), channel, arguments, &result);
render_frame->GetRoutingID(), internal, channel, arguments, &result);
bool success = render_frame->Send(message);
if (!success)
@@ -79,6 +80,20 @@ void SendTo(mate::Arguments* args,
args->ThrowError("Unable to send AtomFrameHostMsg_Message_To");
}
void SendToHost(mate::Arguments* args,
const std::string& channel,
const base::ListValue& arguments) {
RenderFrame* render_frame = GetCurrentRenderFrame();
if (render_frame == nullptr)
return;
bool success = render_frame->Send(new AtomFrameHostMsg_Message_Host(
render_frame->GetRoutingID(), channel, arguments));
if (!success)
args->ThrowError("Unable to send AtomFrameHostMsg_Message_Host");
}
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
@@ -87,6 +102,7 @@ void Initialize(v8::Local<v8::Object> exports,
dict.SetMethod("send", &Send);
dict.SetMethod("sendSync", &SendSync);
dict.SetMethod("sendTo", &SendTo);
dict.SetMethod("sendToHost", &SendToHost);
}
} // namespace

View File

@@ -2,7 +2,10 @@
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#include "atom/renderer/api/atom_api_web_frame.h"
#include <memory>
#include <string>
#include <utility>
#include <vector>
#include "atom/common/api/api_messages.h"
#include "atom/common/api/event_emitter_caller.h"
@@ -29,7 +32,6 @@
#include "third_party/blink/public/web/web_script_execution_callback.h"
#include "third_party/blink/public/web/web_script_source.h"
#include "third_party/blink/public/web/web_view.h"
#include "third_party/blink/renderer/platform/weborigin/scheme_registry.h"
#include "url/url_util.h"
#include "atom/common/node_includes.h"
@@ -111,15 +113,15 @@ class ScriptExecutionCallback : public blink::WebScriptExecutionCallback {
DISALLOW_COPY_AND_ASSIGN(ScriptExecutionCallback);
};
class FrameSpellChecker : public content::RenderFrameVisitor {
class FrameSetSpellChecker : public content::RenderFrameVisitor {
public:
explicit FrameSpellChecker(SpellCheckClient* spell_check_client,
content::RenderFrame* main_frame)
: spell_check_client_(spell_check_client), main_frame_(main_frame) {}
~FrameSpellChecker() override {
spell_check_client_ = nullptr;
main_frame_ = nullptr;
FrameSetSpellChecker(SpellCheckClient* spell_check_client,
content::RenderFrame* main_frame)
: spell_check_client_(spell_check_client), main_frame_(main_frame) {
content::RenderFrame::ForEach(this);
main_frame->GetWebFrame()->SetSpellCheckPanelHostClient(spell_check_client);
}
bool Visit(content::RenderFrame* render_frame) override {
auto* view = render_frame->GetRenderView();
if (view->GetMainRenderFrame() == main_frame_ ||
@@ -132,75 +134,129 @@ class FrameSpellChecker : public content::RenderFrameVisitor {
private:
SpellCheckClient* spell_check_client_;
content::RenderFrame* main_frame_;
DISALLOW_COPY_AND_ASSIGN(FrameSpellChecker);
DISALLOW_COPY_AND_ASSIGN(FrameSetSpellChecker);
};
class SpellCheckerHolder : public content::RenderFrameObserver {
public:
// Find existing holder for the |render_frame|.
static SpellCheckerHolder* FromRenderFrame(
content::RenderFrame* render_frame) {
for (auto* holder : instances_) {
if (holder->render_frame() == render_frame)
return holder;
}
return nullptr;
}
SpellCheckerHolder(content::RenderFrame* render_frame,
std::unique_ptr<SpellCheckClient> spell_check_client)
: content::RenderFrameObserver(render_frame),
spell_check_client_(std::move(spell_check_client)) {
DCHECK(!FromRenderFrame(render_frame));
instances_.insert(this);
}
~SpellCheckerHolder() final { instances_.erase(this); }
void UnsetAndDestroy() {
FrameSetSpellChecker set_spell_checker(nullptr, render_frame());
delete this;
}
// RenderFrameObserver implementation.
void OnDestruct() final {
// Since we delete this in WillReleaseScriptContext, this method is unlikely
// to be called, but override anyway since I'm not sure if there are some
// corner cases.
//
// Note that while there are two "delete this", it is totally fine as the
// observer unsubscribes automatically in destructor and the other one won't
// be called.
//
// Also note that we should not call UnsetAndDestroy here, as the render
// frame is going to be destroyed.
delete this;
}
void WillReleaseScriptContext(v8::Local<v8::Context> context,
int world_id) final {
// Unset spell checker when the script context is going to be released, as
// the spell check implementation lives there.
UnsetAndDestroy();
}
private:
static std::set<SpellCheckerHolder*> instances_;
std::unique_ptr<SpellCheckClient> spell_check_client_;
};
} // namespace
WebFrame::WebFrame(v8::Isolate* isolate)
: web_frame_(blink::WebLocalFrame::FrameForCurrentContext()) {
Init(isolate);
// static
std::set<SpellCheckerHolder*> SpellCheckerHolder::instances_;
void SetName(v8::Local<v8::Value> window, const std::string& name) {
GetRenderFrame(window)->GetWebFrame()->SetName(
blink::WebString::FromUTF8(name));
}
WebFrame::WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame)
: web_frame_(blink_frame) {
Init(isolate);
}
WebFrame::~WebFrame() {}
void WebFrame::SetName(const std::string& name) {
web_frame_->SetName(blink::WebString::FromUTF8(name));
}
double WebFrame::SetZoomLevel(double level) {
double SetZoomLevel(v8::Local<v8::Value> window, double level) {
double result = 0.0;
content::RenderFrame* render_frame =
content::RenderFrame::FromWebFrame(web_frame_);
content::RenderFrame* render_frame = GetRenderFrame(window);
render_frame->Send(new AtomFrameHostMsg_SetTemporaryZoomLevel(
render_frame->GetRoutingID(), level, &result));
return result;
}
double WebFrame::GetZoomLevel() const {
double GetZoomLevel(v8::Local<v8::Value> window) {
double result = 0.0;
content::RenderFrame* render_frame =
content::RenderFrame::FromWebFrame(web_frame_);
content::RenderFrame* render_frame = GetRenderFrame(window);
render_frame->Send(
new AtomFrameHostMsg_GetZoomLevel(render_frame->GetRoutingID(), &result));
return result;
}
double WebFrame::SetZoomFactor(double factor) {
double SetZoomFactor(v8::Local<v8::Value> window, double factor) {
return blink::WebView::ZoomLevelToZoomFactor(
SetZoomLevel(blink::WebView::ZoomFactorToZoomLevel(factor)));
SetZoomLevel(window, blink::WebView::ZoomFactorToZoomLevel(factor)));
}
double WebFrame::GetZoomFactor() const {
return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel());
double GetZoomFactor(v8::Local<v8::Value> window) {
return blink::WebView::ZoomLevelToZoomFactor(GetZoomLevel(window));
}
void WebFrame::SetVisualZoomLevelLimits(double min_level, double max_level) {
web_frame_->View()->SetDefaultPageScaleLimits(min_level, max_level);
web_frame_->View()->SetIgnoreViewportTagScaleLimits(true);
void SetVisualZoomLevelLimits(v8::Local<v8::Value> window,
double min_level,
double max_level) {
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
web_frame->View()->SetDefaultPageScaleLimits(min_level, max_level);
web_frame->View()->SetIgnoreViewportTagScaleLimits(true);
}
void WebFrame::SetLayoutZoomLevelLimits(double min_level, double max_level) {
web_frame_->View()->ZoomLimitsChanged(min_level, max_level);
void SetLayoutZoomLevelLimits(v8::Local<v8::Value> window,
double min_level,
double max_level) {
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
web_frame->View()->ZoomLimitsChanged(min_level, max_level);
}
void WebFrame::AllowGuestViewElementDefinition(
v8::Local<v8::Object> context,
v8::Local<v8::Function> register_cb) {
v8::HandleScope handle_scope(isolate());
void AllowGuestViewElementDefinition(v8::Isolate* isolate,
v8::Local<v8::Value> window,
v8::Local<v8::Object> context,
v8::Local<v8::Function> register_cb) {
v8::HandleScope handle_scope(isolate);
v8::Context::Scope context_scope(context->CreationContext());
blink::WebCustomElement::EmbedderNamesAllowedScope embedder_names_scope;
web_frame_->RequestExecuteV8Function(context->CreationContext(), register_cb,
v8::Null(isolate()), 0, nullptr,
nullptr);
GetRenderFrame(context)->GetWebFrame()->RequestExecuteV8Function(
context->CreationContext(), register_cb, v8::Null(isolate), 0, nullptr,
nullptr);
}
int WebFrame::GetWebFrameId(v8::Local<v8::Value> content_window) {
int GetWebFrameId(v8::Local<v8::Value> window,
v8::Local<v8::Value> content_window) {
// Get the WebLocalFrame before (possibly) executing any user-space JS while
// getting the |params|. We track the status of the RenderFrame via an
// observer in case it is deleted during user code execution.
@@ -219,9 +275,10 @@ int WebFrame::GetWebFrameId(v8::Local<v8::Value> content_window) {
return render_frame->GetRoutingID();
}
void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
const std::string& language,
v8::Local<v8::Object> provider) {
void SetSpellCheckProvider(mate::Arguments* args,
v8::Local<v8::Value> window,
const std::string& language,
v8::Local<v8::Object> provider) {
auto context = args->isolate()->GetCurrentContext();
if (!provider->Has(context, mate::StringToV8(args->isolate(), "spellCheck"))
.ToChecked()) {
@@ -229,92 +286,61 @@ void WebFrame::SetSpellCheckProvider(mate::Arguments* args,
return;
}
auto client =
std::make_unique<SpellCheckClient>(language, args->isolate(), provider);
// Remove the old client.
content::RenderFrame* render_frame = GetRenderFrame(window);
auto* existing = SpellCheckerHolder::FromRenderFrame(render_frame);
if (existing)
existing->UnsetAndDestroy();
// Set spellchecker for all live frames in the same process or
// in the sandbox mode for all live sub frames to this WebFrame.
FrameSpellChecker spell_checker(
client.get(), content::RenderFrame::FromWebFrame(web_frame_));
content::RenderFrame::ForEach(&spell_checker);
spell_check_client_.swap(client);
web_frame_->SetSpellCheckPanelHostClient(spell_check_client_.get());
auto spell_check_client =
std::make_unique<SpellCheckClient>(language, args->isolate(), provider);
FrameSetSpellChecker spell_checker(spell_check_client.get(), render_frame);
// Attach the spell checker to RenderFrame.
new SpellCheckerHolder(render_frame, std::move(spell_check_client));
}
void WebFrame::RegisterURLSchemeAsBypassingCSP(const std::string& scheme) {
// Register scheme to bypass pages's Content Security Policy.
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
WTF::String::FromUTF8(scheme.data(), scheme.length()));
}
void WebFrame::RegisterURLSchemeAsPrivileged(const std::string& scheme,
mate::Arguments* args) {
// TODO(deepak1556): blink::SchemeRegistry methods should be called
// before any renderer threads are created. Fixing this would break
// current api. Change it with 2.0.
// Read optional flags
bool secure = true;
bool bypassCSP = true;
bool allowServiceWorkers = true;
bool supportFetchAPI = true;
bool corsEnabled = true;
if (args->Length() == 2) {
mate::Dictionary options;
if (args->GetNext(&options)) {
options.Get("secure", &secure);
options.Get("bypassCSP", &bypassCSP);
options.Get("allowServiceWorkers", &allowServiceWorkers);
options.Get("supportFetchAPI", &supportFetchAPI);
options.Get("corsEnabled", &corsEnabled);
}
}
// Register scheme to privileged list (https, wss, data, chrome-extension)
WTF::String privileged_scheme(
WTF::String::FromUTF8(scheme.data(), scheme.length()));
if (bypassCSP) {
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
privileged_scheme);
}
if (allowServiceWorkers) {
blink::SchemeRegistry::RegisterURLSchemeAsAllowingServiceWorkers(
privileged_scheme);
}
if (supportFetchAPI) {
blink::SchemeRegistry::RegisterURLSchemeAsSupportingFetchAPI(
privileged_scheme);
}
if (corsEnabled) {
url::AddCorsEnabledScheme(scheme.c_str());
void InsertText(v8::Local<v8::Value> window, const std::string& text) {
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
if (web_frame->IsWebLocalFrame()) {
web_frame->ToWebLocalFrame()
->FrameWidget()
->GetActiveWebInputMethodController()
->CommitText(blink::WebString::FromUTF8(text),
blink::WebVector<blink::WebImeTextSpan>(),
blink::WebRange(), 0);
}
}
void WebFrame::InsertText(const std::string& text) {
web_frame_->FrameWidget()->GetActiveWebInputMethodController()->CommitText(
blink::WebString::FromUTF8(text),
blink::WebVector<blink::WebImeTextSpan>(), blink::WebRange(), 0);
void InsertCSS(v8::Local<v8::Value> window, const std::string& css) {
blink::WebFrame* web_frame = GetRenderFrame(window)->GetWebFrame();
if (web_frame->IsWebLocalFrame()) {
web_frame->ToWebLocalFrame()->GetDocument().InsertStyleSheet(
blink::WebString::FromUTF8(css));
}
}
void WebFrame::InsertCSS(const std::string& css) {
web_frame_->GetDocument().InsertStyleSheet(blink::WebString::FromUTF8(css));
}
void WebFrame::ExecuteJavaScript(const base::string16& code,
mate::Arguments* args) {
void ExecuteJavaScript(mate::Arguments* args,
v8::Local<v8::Value> window,
const base::string16& code) {
bool has_user_gesture = false;
args->GetNext(&has_user_gesture);
ScriptExecutionCallback::CompletionCallback completion_callback;
args->GetNext(&completion_callback);
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
new ScriptExecutionCallback(completion_callback));
web_frame_->RequestExecuteScriptAndReturnValue(
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptAndReturnValue(
blink::WebScriptSource(blink::WebString::FromUTF16(code)),
has_user_gesture, callback.release());
}
void WebFrame::ExecuteJavaScriptInIsolatedWorld(
void ExecuteJavaScriptInIsolatedWorld(
mate::Arguments* args,
v8::Local<v8::Value> window,
int world_id,
const std::vector<mate::Dictionary>& scripts,
mate::Arguments* args) {
const std::vector<mate::Dictionary>& scripts) {
std::vector<blink::WebScriptSource> sources;
for (const auto& script : scripts) {
@@ -346,186 +372,132 @@ void WebFrame::ExecuteJavaScriptInIsolatedWorld(
std::unique_ptr<blink::WebScriptExecutionCallback> callback(
new ScriptExecutionCallback(completion_callback));
web_frame_->RequestExecuteScriptInIsolatedWorld(
GetRenderFrame(window)->GetWebFrame()->RequestExecuteScriptInIsolatedWorld(
world_id, &sources.front(), sources.size(), has_user_gesture,
scriptExecutionType, callback.release());
}
void WebFrame::SetIsolatedWorldSecurityOrigin(int world_id,
const std::string& origin_url) {
web_frame_->SetIsolatedWorldSecurityOrigin(
void SetIsolatedWorldSecurityOrigin(v8::Local<v8::Value> window,
int world_id,
const std::string& origin_url) {
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldSecurityOrigin(
world_id, blink::WebSecurityOrigin::CreateFromString(
blink::WebString::FromUTF8(origin_url)));
}
void WebFrame::SetIsolatedWorldContentSecurityPolicy(
int world_id,
const std::string& security_policy) {
web_frame_->SetIsolatedWorldContentSecurityPolicy(
void SetIsolatedWorldContentSecurityPolicy(v8::Local<v8::Value> window,
int world_id,
const std::string& security_policy) {
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldContentSecurityPolicy(
world_id, blink::WebString::FromUTF8(security_policy));
}
void WebFrame::SetIsolatedWorldHumanReadableName(int world_id,
const std::string& name) {
web_frame_->SetIsolatedWorldHumanReadableName(
void SetIsolatedWorldHumanReadableName(v8::Local<v8::Value> window,
int world_id,
const std::string& name) {
GetRenderFrame(window)->GetWebFrame()->SetIsolatedWorldHumanReadableName(
world_id, blink::WebString::FromUTF8(name));
}
// static
mate::Handle<WebFrame> WebFrame::Create(v8::Isolate* isolate) {
return mate::CreateHandle(isolate, new WebFrame(isolate));
}
blink::WebCache::ResourceTypeStats WebFrame::GetResourceUsage(
v8::Isolate* isolate) {
blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate) {
blink::WebCache::ResourceTypeStats stats;
blink::WebCache::GetResourceTypeStats(&stats);
return stats;
}
void WebFrame::ClearCache(v8::Isolate* isolate) {
void ClearCache(v8::Isolate* isolate) {
isolate->IdleNotificationDeadline(0.5);
blink::WebCache::Clear();
base::MemoryPressureListener::NotifyMemoryPressure(
base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL);
}
v8::Local<v8::Value> WebFrame::Opener() const {
blink::WebFrame* frame = web_frame_->Opener();
if (frame && frame->IsWebLocalFrame())
return mate::CreateHandle(isolate(),
new WebFrame(isolate(), frame->ToWebLocalFrame()))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::Parent() const {
blink::WebFrame* frame = web_frame_->Parent();
if (frame && frame->IsWebLocalFrame())
return mate::CreateHandle(isolate(),
new WebFrame(isolate(), frame->ToWebLocalFrame()))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::Top() const {
blink::WebFrame* frame = web_frame_->Top();
if (frame && frame->IsWebLocalFrame())
return mate::CreateHandle(isolate(),
new WebFrame(isolate(), frame->ToWebLocalFrame()))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::FirstChild() const {
blink::WebFrame* frame = web_frame_->FirstChild();
if (frame && frame->IsWebLocalFrame())
return mate::CreateHandle(isolate(),
new WebFrame(isolate(), frame->ToWebLocalFrame()))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::NextSibling() const {
blink::WebFrame* frame = web_frame_->NextSibling();
if (frame && frame->IsWebLocalFrame())
return mate::CreateHandle(isolate(),
new WebFrame(isolate(), frame->ToWebLocalFrame()))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::GetFrameForSelector(
const std::string& selector) const {
blink::WebElement element = web_frame_->GetDocument().QuerySelector(
blink::WebString::FromUTF8(selector));
blink::WebLocalFrame* element_frame =
blink::WebLocalFrame::FromFrameOwnerElement(element);
if (element_frame)
return mate::CreateHandle(isolate(), new WebFrame(isolate(), element_frame))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::FindFrameByName(const std::string& name) const {
blink::WebLocalFrame* local_frame =
web_frame_->FindFrameByName(blink::WebString::FromUTF8(name))
->ToWebLocalFrame();
if (local_frame)
return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
.ToV8();
else
return v8::Null(isolate());
}
v8::Local<v8::Value> WebFrame::FindFrameByRoutingId(int routing_id) const {
v8::Local<v8::Value> FindFrameByRoutingId(v8::Isolate* isolate,
v8::Local<v8::Value> window,
int routing_id) {
content::RenderFrame* render_frame =
content::RenderFrame::FromRoutingID(routing_id);
blink::WebLocalFrame* local_frame = nullptr;
if (render_frame)
local_frame = render_frame->GetWebFrame();
if (local_frame)
return mate::CreateHandle(isolate(), new WebFrame(isolate(), local_frame))
.ToV8();
return render_frame->GetWebFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate());
return v8::Null(isolate);
}
v8::Local<v8::Value> WebFrame::RoutingId() const {
int routing_id = content::RenderFrame::GetRoutingIdForWebFrame(web_frame_);
return v8::Number::New(isolate(), routing_id);
v8::Local<v8::Value> GetOpener(v8::Isolate* isolate,
v8::Local<v8::Value> window) {
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Opener();
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
// static
void WebFrame::BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype) {
prototype->SetClassName(mate::StringToV8(isolate, "WebFrame"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
.SetMethod("setName", &WebFrame::SetName)
.SetMethod("setZoomLevel", &WebFrame::SetZoomLevel)
.SetMethod("getZoomLevel", &WebFrame::GetZoomLevel)
.SetMethod("setZoomFactor", &WebFrame::SetZoomFactor)
.SetMethod("getZoomFactor", &WebFrame::GetZoomFactor)
.SetMethod("setVisualZoomLevelLimits",
&WebFrame::SetVisualZoomLevelLimits)
.SetMethod("setLayoutZoomLevelLimits",
&WebFrame::SetLayoutZoomLevelLimits)
.SetMethod("allowGuestViewElementDefinition",
&WebFrame::AllowGuestViewElementDefinition)
.SetMethod("getWebFrameId", &WebFrame::GetWebFrameId)
.SetMethod("setSpellCheckProvider", &WebFrame::SetSpellCheckProvider)
.SetMethod("registerURLSchemeAsBypassingCSP",
&WebFrame::RegisterURLSchemeAsBypassingCSP)
.SetMethod("registerURLSchemeAsPrivileged",
&WebFrame::RegisterURLSchemeAsPrivileged)
.SetMethod("insertText", &WebFrame::InsertText)
.SetMethod("insertCSS", &WebFrame::InsertCSS)
.SetMethod("executeJavaScript", &WebFrame::ExecuteJavaScript)
.SetMethod("executeJavaScriptInIsolatedWorld",
&WebFrame::ExecuteJavaScriptInIsolatedWorld)
.SetMethod("setIsolatedWorldSecurityOrigin",
&WebFrame::SetIsolatedWorldSecurityOrigin)
.SetMethod("setIsolatedWorldContentSecurityPolicy",
&WebFrame::SetIsolatedWorldContentSecurityPolicy)
.SetMethod("setIsolatedWorldHumanReadableName",
&WebFrame::SetIsolatedWorldHumanReadableName)
.SetMethod("getResourceUsage", &WebFrame::GetResourceUsage)
.SetMethod("clearCache", &WebFrame::ClearCache)
.SetMethod("getFrameForSelector", &WebFrame::GetFrameForSelector)
.SetMethod("findFrameByName", &WebFrame::FindFrameByName)
.SetProperty("opener", &WebFrame::Opener)
.SetProperty("parent", &WebFrame::Parent)
.SetProperty("top", &WebFrame::Top)
.SetProperty("firstChild", &WebFrame::FirstChild)
.SetProperty("nextSibling", &WebFrame::NextSibling)
.SetProperty("routingId", &WebFrame::RoutingId)
.SetMethod("findFrameByRoutingId", &WebFrame::FindFrameByRoutingId);
// Don't name it as GetParent, Windows has API with same name.
v8::Local<v8::Value> GetFrameParent(v8::Isolate* isolate,
v8::Local<v8::Value> window) {
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Parent();
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
v8::Local<v8::Value> GetTop(v8::Isolate* isolate, v8::Local<v8::Value> window) {
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->Top();
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
v8::Local<v8::Value> GetFirstChild(v8::Isolate* isolate,
v8::Local<v8::Value> window) {
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->FirstChild();
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
v8::Local<v8::Value> GetNextSibling(v8::Isolate* isolate,
v8::Local<v8::Value> window) {
blink::WebFrame* frame = GetRenderFrame(window)->GetWebFrame()->NextSibling();
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
v8::Local<v8::Value> GetFrameForSelector(v8::Isolate* isolate,
v8::Local<v8::Value> window,
const std::string& selector) {
blink::WebElement element =
GetRenderFrame(window)->GetWebFrame()->GetDocument().QuerySelector(
blink::WebString::FromUTF8(selector));
if (element.IsNull()) // not found
return v8::Null(isolate);
blink::WebFrame* frame = blink::WebFrame::FromFrameOwnerElement(element);
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
v8::Local<v8::Value> FindFrameByName(v8::Isolate* isolate,
v8::Local<v8::Value> window,
const std::string& name) {
blink::WebFrame* frame =
GetRenderFrame(window)->GetWebFrame()->FindFrameByName(
blink::WebString::FromUTF8(name));
if (frame && frame->IsWebLocalFrame())
return frame->ToWebLocalFrame()->MainWorldScriptContext()->Global();
else
return v8::Null(isolate);
}
int GetRoutingId(v8::Local<v8::Value> window) {
return GetRenderFrame(window)->GetRoutingID();
}
} // namespace api
@@ -534,18 +506,47 @@ void WebFrame::BuildPrototype(v8::Isolate* isolate,
namespace {
using atom::api::WebFrame;
void Initialize(v8::Local<v8::Object> exports,
v8::Local<v8::Value> unused,
v8::Local<v8::Context> context,
void* priv) {
using namespace atom::api; // NOLINT(build/namespaces)
v8::Isolate* isolate = context->GetIsolate();
mate::Dictionary dict(isolate, exports);
dict.Set("webFrame", WebFrame::Create(isolate));
dict.Set(
"WebFrame",
WebFrame::GetConstructor(isolate)->GetFunction(context).ToLocalChecked());
dict.SetMethod("setName", &SetName);
dict.SetMethod("setZoomLevel", &SetZoomLevel);
dict.SetMethod("getZoomLevel", &GetZoomLevel);
dict.SetMethod("setZoomFactor", &SetZoomFactor);
dict.SetMethod("getZoomFactor", &GetZoomFactor);
dict.SetMethod("setVisualZoomLevelLimits", &SetVisualZoomLevelLimits);
dict.SetMethod("setLayoutZoomLevelLimits", &SetLayoutZoomLevelLimits);
dict.SetMethod("allowGuestViewElementDefinition",
&AllowGuestViewElementDefinition);
dict.SetMethod("getWebFrameId", &GetWebFrameId);
dict.SetMethod("setSpellCheckProvider", &SetSpellCheckProvider);
dict.SetMethod("insertText", &InsertText);
dict.SetMethod("insertCSS", &InsertCSS);
dict.SetMethod("executeJavaScript", &ExecuteJavaScript);
dict.SetMethod("executeJavaScriptInIsolatedWorld",
&ExecuteJavaScriptInIsolatedWorld);
dict.SetMethod("setIsolatedWorldSecurityOrigin",
&SetIsolatedWorldSecurityOrigin);
dict.SetMethod("setIsolatedWorldContentSecurityPolicy",
&SetIsolatedWorldContentSecurityPolicy);
dict.SetMethod("setIsolatedWorldHumanReadableName",
&SetIsolatedWorldHumanReadableName);
dict.SetMethod("getResourceUsage", &GetResourceUsage);
dict.SetMethod("clearCache", &ClearCache);
dict.SetMethod("_findFrameByRoutingId", &FindFrameByRoutingId);
dict.SetMethod("_getFrameForSelector", &GetFrameForSelector);
dict.SetMethod("_findFrameByName", &FindFrameByName);
dict.SetMethod("_getOpener", &GetOpener);
dict.SetMethod("_getParent", &GetFrameParent);
dict.SetMethod("_getTop", &GetTop);
dict.SetMethod("_getFirstChild", &GetFirstChild);
dict.SetMethod("_getNextSibling", &GetNextSibling);
dict.SetMethod("_getRoutingId", &GetRoutingId);
}
} // namespace

View File

@@ -1,111 +0,0 @@
// Copyright (c) 2014 GitHub, Inc.
// Use of this source code is governed by the MIT license that can be
// found in the LICENSE file.
#ifndef ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_
#define ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_
#include <memory>
#include <string>
#include <vector>
#include "native_mate/handle.h"
#include "native_mate/wrappable.h"
#include "third_party/blink/public/platform/web_cache.h"
namespace blink {
class WebLocalFrame;
}
namespace mate {
class Dictionary;
class Arguments;
} // namespace mate
namespace atom {
namespace api {
class SpellCheckClient;
class WebFrame : public mate::Wrappable<WebFrame> {
public:
static mate::Handle<WebFrame> Create(v8::Isolate* isolate);
static void BuildPrototype(v8::Isolate* isolate,
v8::Local<v8::FunctionTemplate> prototype);
private:
explicit WebFrame(v8::Isolate* isolate);
explicit WebFrame(v8::Isolate* isolate, blink::WebLocalFrame* blink_frame);
~WebFrame() override;
void SetName(const std::string& name);
double SetZoomLevel(double level);
double GetZoomLevel() const;
double SetZoomFactor(double factor);
double GetZoomFactor() const;
void SetVisualZoomLevelLimits(double min_level, double max_level);
void SetLayoutZoomLevelLimits(double min_level, double max_level);
void AllowGuestViewElementDefinition(v8::Local<v8::Object> context,
v8::Local<v8::Function> register_cb);
int GetWebFrameId(v8::Local<v8::Value> content_window);
// Set the provider that will be used by SpellCheckClient for spell check.
void SetSpellCheckProvider(mate::Arguments* args,
const std::string& language,
v8::Local<v8::Object> provider);
void RegisterURLSchemeAsBypassingCSP(const std::string& scheme);
void RegisterURLSchemeAsPrivileged(const std::string& scheme,
mate::Arguments* args);
// Editing.
void InsertText(const std::string& text);
void InsertCSS(const std::string& css);
// Executing scripts.
void ExecuteJavaScript(const base::string16& code, mate::Arguments* args);
void ExecuteJavaScriptInIsolatedWorld(
int world_id,
const std::vector<mate::Dictionary>& scripts,
mate::Arguments* args);
// Isolated world related methods
void SetIsolatedWorldSecurityOrigin(int world_id,
const std::string& origin_url);
void SetIsolatedWorldContentSecurityPolicy(
int world_id,
const std::string& security_policy);
void SetIsolatedWorldHumanReadableName(int world_id, const std::string& name);
// Resource related methods
blink::WebCache::ResourceTypeStats GetResourceUsage(v8::Isolate* isolate);
void ClearCache(v8::Isolate* isolate);
// Frame navigation
v8::Local<v8::Value> Opener() const;
v8::Local<v8::Value> Parent() const;
v8::Local<v8::Value> Top() const;
v8::Local<v8::Value> FirstChild() const;
v8::Local<v8::Value> NextSibling() const;
v8::Local<v8::Value> GetFrameForSelector(const std::string& selector) const;
v8::Local<v8::Value> FindFrameByName(const std::string& name) const;
v8::Local<v8::Value> FindFrameByRoutingId(int routing_id) const;
v8::Local<v8::Value> RoutingId() const;
std::unique_ptr<SpellCheckClient> spell_check_client_;
blink::WebLocalFrame* web_frame_;
DISALLOW_COPY_AND_ASSIGN(WebFrame);
};
} // namespace api
} // namespace atom
#endif // ATOM_RENDERER_API_ATOM_API_WEB_FRAME_H_

View File

@@ -212,11 +212,10 @@ void AtomRenderFrameObserver::OnTakeHeapSnapshot(
bool success = TakeHeapSnapshot(blink::MainThreadIsolate(), &file);
base::ListValue args;
args.AppendString(channel);
args.AppendBoolean(success);
render_frame_->Send(new AtomFrameHostMsg_Message(
render_frame_->GetRoutingID(), "ipc-internal-message", args));
render_frame_->GetRoutingID(), true, channel, args));
}
void AtomRenderFrameObserver::EmitIPCEvent(blink::WebLocalFrame* frame,

View File

@@ -114,11 +114,12 @@ class AtomSandboxedRenderFrameObserver : public AtomRenderFrameObserver {
auto context = renderer_client_->GetContext(frame, isolate);
v8::Context::Scope context_scope(context);
v8::Local<v8::Value> argv[] = {mate::ConvertToV8(isolate, channel),
v8::Local<v8::Value> argv[] = {mate::ConvertToV8(isolate, internal),
mate::ConvertToV8(isolate, channel),
mate::ConvertToV8(isolate, args),
mate::ConvertToV8(isolate, sender_id)};
renderer_client_->InvokeIpcCallback(
context, internal ? "onInternalMessage" : "onMessage",
context, "onMessage",
std::vector<v8::Local<v8::Value>>(argv, argv + node::arraysize(argv)));
}

View File

@@ -163,6 +163,25 @@ void RendererClientBase::RenderThreadStarted() {
blink::SchemeRegistry::RegisterURLSchemeAsSecure(
WTF::String::FromUTF8(scheme.data(), scheme.length()));
std::vector<std::string> fetch_enabled_schemes =
ParseSchemesCLISwitch(command_line, switches::kFetchSchemes);
for (const std::string& scheme : fetch_enabled_schemes) {
blink::WebSecurityPolicy::RegisterURLSchemeAsSupportingFetchAPI(
blink::WebString::FromASCII(scheme));
}
std::vector<std::string> service_worker_schemes =
ParseSchemesCLISwitch(command_line, switches::kServiceWorkerSchemes);
for (const std::string& scheme : service_worker_schemes)
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers(
blink::WebString::FromASCII(scheme));
std::vector<std::string> csp_bypassing_schemes =
ParseSchemesCLISwitch(command_line, switches::kBypassCSPSchemes);
for (const std::string& scheme : csp_bypassing_schemes)
blink::SchemeRegistry::RegisterURLSchemeAsBypassingContentSecurityPolicy(
WTF::String::FromUTF8(scheme.data(), scheme.length()));
// Allow file scheme to handle service worker by default.
// FIXME(zcbenz): Can this be moved elsewhere?
blink::WebSecurityPolicy::RegisterURLSchemeAsAllowingServiceWorkers("file");

View File

@@ -1,5 +1,6 @@
import("npm.gni")
import("node.gni")
# TODO(MarshallOfSound): Move to electron/node, this is the only place it is used now
# Run an action with a given working directory. Behaves identically to the
# action() target type, with the exception that it changes directory before
# running the script.
@@ -32,19 +33,28 @@ template("chdir_action") {
template("asar") {
assert(defined(invoker.sources),
"Need sources in $target_name listing the JS files.")
"Need sources in $target_name listing the source files")
assert(defined(invoker.outputs),
"Need asar name (as 1-element array, e.g. \$root_out_dir/foo.asar)")
assert(defined(invoker.root), "Need asar root directory")
asar_root = invoker.root
assert(defined(invoker.root), "Need the base dir for generating the ASAR")
# js2asar.py expects relative paths to its inputs, so we must run it in a
# working directory in which those relative paths make sense.
chdir_action(target_name) {
sources = invoker.sources
outputs = invoker.outputs
script = "//electron/tools/js2asar.py"
cwd = rebase_path(get_path_info(".", "abspath"))
args = rebase_path(outputs, cwd) + [ asar_root ] + rebase_path(sources, ".")
node_action(target_name) {
forward_variables_from(invoker,
"*",
[
"script",
"args",
])
script = "//electron/script/gn-asar.js"
args = [
"--base",
rebase_path(root),
"--files",
] + rebase_path(sources) +
[
"--out",
rebase_path(outputs[0]),
]
}
}

21
build/node.gni Normal file
View File

@@ -0,0 +1,21 @@
template("node_action") {
assert(defined(invoker.script), "Need script path to run")
assert(defined(invoker.args), "Need script argumets")
action(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"sources",
"inputs",
"outputs",
])
if (!defined(inputs)) {
inputs = []
}
inputs += [ invoker.script ]
script = "//electron/build/run-node.py"
args = [ rebase_path(invoker.script) ] + invoker.args
}
}

14
build/run-node.py Normal file
View File

@@ -0,0 +1,14 @@
import os
import subprocess
import sys
SOURCE_ROOT = os.path.dirname(os.path.dirname(__file__))
def main():
# Proxy all args to node script
script = os.path.join(SOURCE_ROOT, sys.argv[1])
subprocess.check_call(['node', script] + [str(x) for x in sys.argv[2:]])
if __name__ == '__main__':
sys.exit(main())

50
build/tsc.gni Normal file
View File

@@ -0,0 +1,50 @@
import("npm.gni")
template("typescript_build") {
assert(defined(invoker.tsconfig), "Need tsconfig name to run")
assert(defined(invoker.sources), "Need tsc sources to run")
assert(defined(invoker.output_dir_name),
"Need output_dir_name to run, should be 'lib' or other top level dir")
assert(defined(invoker.output_gen_dir),
"Need output_gen_dir to run, should be relative to the root gen dir")
npm_action(target_name) {
forward_variables_from(invoker,
[
"deps",
"public_deps",
"outputs",
])
script = "tsc"
sources = invoker.sources
inputs = [
invoker.tsconfig,
"//electron/tsconfig.json",
"//electron/package-lock.json",
]
type_roots = "node_modules/@types,typings"
if (defined(invoker.type_root)) {
type_roots += "," + invoker.type_root
}
base_out_path = invoker.output_gen_dir + "/electron/"
args = [
"-p",
rebase_path(invoker.tsconfig),
"--outDir",
rebase_path("$base_out_path" + invoker.output_dir_name),
"--typeRoots",
type_roots,
]
outputs = []
foreach(invoker_source, invoker.sources) {
# The output of TSC is all inputs but with JS instead of TS as the extension
outputs += [ "$base_out_path" + get_path_info(invoker_source, "dir") +
"/" + get_path_info(invoker_source, "name") + ".js" ]
}
}
}

View File

@@ -8,7 +8,7 @@ declare_args() {
# Allow running Electron as a node binary.
enable_run_as_node = true
enable_osr = false
enable_osr = true
enable_view_api = false

View File

@@ -41,6 +41,8 @@ static_library("chrome") {
"//chrome/browser/net/proxy_service_factory.h",
"//chrome/browser/ssl/security_state_tab_helper.cc",
"//chrome/browser/ssl/security_state_tab_helper.h",
"//chrome/browser/ui/autofill/popup_view_common.cc",
"//chrome/browser/ui/autofill/popup_view_common.h",
"//chrome/browser/win/chrome_process_finder.cc",
"//chrome/browser/win/chrome_process_finder.h",
"//extensions/browser/app_window/size_constraints.cc",
@@ -51,6 +53,7 @@ static_library("chrome") {
]
deps = [
"//chrome/common",
"//components/feature_engagement:buildflags",
"//components/keyed_service/content",
"//components/proxy_config",
"//components/security_state/content",

View File

@@ -1,19 +1,17 @@
'use strict'
import { app, BrowserWindow, BrowserWindowConstructorOptions } from 'electron'
import * as path from 'path'
const { app, BrowserWindow } = require('electron')
const path = require('path')
let mainWindow = null
let mainWindow: BrowserWindow | null = null
// Quit when all windows are closed.
app.on('window-all-closed', () => {
app.quit()
})
exports.load = async (appUrl) => {
export const load = async (appUrl: string) => {
await app.whenReady()
const options = {
const options: BrowserWindowConstructorOptions = {
width: 900,
height: 600,
autoHideMenuBar: true,
@@ -33,7 +31,7 @@ exports.load = async (appUrl) => {
mainWindow = new BrowserWindow(options)
mainWindow.on('ready-to-show', () => mainWindow.show())
mainWindow.on('ready-to-show', () => mainWindow!.show())
mainWindow.loadURL(appUrl)
mainWindow.focus()

View File

@@ -4,7 +4,7 @@
<title>Electron</title>
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self'; style-src 'self'; img-src 'self'" />
<link href="./styles.css" type="text/css" rel="stylesheet" />
<link href="./node_modules/octicons/build/build.css" type="text/css" rel="stylesheet" />
<link href="./octicon/build.css" type="text/css" rel="stylesheet" />
</head>
<body>

View File

@@ -1,20 +1,31 @@
'use strict'
import { app, dialog } from 'electron'
const { app, dialog } = require('electron')
import * as fs from 'fs'
import * as path from 'path'
import * as url from 'url'
type DefaultAppOptions = {
file: null | string;
noHelp: boolean;
version: boolean;
webdriver: boolean;
interactive: boolean;
abi: boolean;
modules: string[];
}
const fs = require('fs')
const Module = require('module')
const path = require('path')
const url = require('url')
// Parse command line options.
const argv = process.argv.slice(1)
const option = {
const option: DefaultAppOptions = {
file: null,
noHelp: Boolean(process.env.ELECTRON_NO_HELP),
version: null,
webdriver: null,
version: false,
webdriver: false,
interactive: false,
abi: false,
modules: []
}
@@ -62,7 +73,7 @@ if (option.modules.length > 0) {
Module._preloadModules(option.modules)
}
function loadApplicationPackage (packagePath) {
function loadApplicationPackage (packagePath: string) {
// Add a flag indicating app is started from default app.
Object.defineProperty(process, 'defaultApp', {
configurable: false,
@@ -112,14 +123,15 @@ function loadApplicationPackage (packagePath) {
}
}
function showErrorMessage (message) {
function showErrorMessage (message: string) {
app.focus()
dialog.showErrorBox('Error launching app', message)
process.exit(1)
}
function loadApplicationByUrl (appUrl) {
require('./default_app').load(appUrl)
async function loadApplicationByUrl (appUrl: string) {
const { load } = await import('./default_app')
load(appUrl)
}
function startRepl () {

View File

@@ -1,67 +0,0 @@
'use strict'
const { remote, shell } = require('electron')
const fs = require('fs')
const path = require('path')
const URL = require('url')
function initialize () {
// Find the shortest path to the electron binary
const absoluteElectronPath = remote.process.execPath
const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath)
const electronPath = absoluteElectronPath.length < relativeElectronPath.length
? absoluteElectronPath
: relativeElectronPath
for (const link of document.querySelectorAll('a[href]')) {
// safely add `?utm_source=default_app
const parsedUrl = URL.parse(link.getAttribute('href'), true)
parsedUrl.query = { ...parsedUrl.query, utm_source: 'default_app' }
const url = URL.format(parsedUrl)
const openLinkExternally = (e) => {
e.preventDefault()
shell.openExternalSync(url)
}
link.addEventListener('click', openLinkExternally)
link.addEventListener('auxclick', openLinkExternally)
}
document.querySelector('.electron-version').innerText = `Electron v${process.versions.electron}`
document.querySelector('.chrome-version').innerText = `Chromium v${process.versions.chrome}`
document.querySelector('.node-version').innerText = `Node v${process.versions.node}`
document.querySelector('.v8-version').innerText = `v8 v${process.versions.v8}`
document.querySelector('.command-example').innerText = `${electronPath} path-to-app`
function getOcticonSvg (name) {
const octiconPath = path.resolve(__dirname, 'node_modules', 'octicons', 'build', 'svg', `${name}.svg`)
if (fs.existsSync(octiconPath)) {
const content = fs.readFileSync(octiconPath, 'utf8')
const div = document.createElement('div')
div.innerHTML = content
return div
}
return null
}
function loadSVG (element) {
for (const cssClass of element.classList) {
if (cssClass.startsWith('octicon-')) {
const icon = getOcticonSvg(cssClass.substr(8))
if (icon) {
icon.classList = element.classList
element.parentNode.insertBefore(icon, element)
element.remove()
break
}
}
}
}
for (const element of document.querySelectorAll('.octicon')) {
loadSVG(element)
}
}
window.addEventListener('load', initialize)

67
default_app/renderer.ts Normal file
View File

@@ -0,0 +1,67 @@
import { remote, shell } from 'electron'
import * as fs from 'fs'
import * as path from 'path'
import * as URL from 'url'
function initialize () {
// Find the shortest path to the electron binary
const absoluteElectronPath = remote.process.execPath
const relativeElectronPath = path.relative(process.cwd(), absoluteElectronPath)
const electronPath = absoluteElectronPath.length < relativeElectronPath.length
? absoluteElectronPath
: relativeElectronPath
for (const link of document.querySelectorAll<HTMLLinkElement>('a[href]')) {
// safely add `?utm_source=default_app
const parsedUrl = URL.parse(link.getAttribute('href')!, true)
parsedUrl.query = { ...parsedUrl.query, utm_source: 'default_app' }
const url = URL.format(parsedUrl)
const openLinkExternally = (e: Event) => {
e.preventDefault()
shell.openExternalSync(url)
}
link.addEventListener('click', openLinkExternally)
link.addEventListener('auxclick', openLinkExternally)
}
document.querySelector<HTMLAnchorElement>('.electron-version')!.innerText = `Electron v${process.versions.electron}`
document.querySelector<HTMLAnchorElement>('.chrome-version')!.innerText = `Chromium v${process.versions.chrome}`
document.querySelector<HTMLAnchorElement>('.node-version')!.innerText = `Node v${process.versions.node}`
document.querySelector<HTMLAnchorElement>('.v8-version')!.innerText = `v8 v${process.versions.v8}`
document.querySelector<HTMLAnchorElement>('.command-example')!.innerText = `${electronPath} path-to-app`
function getOcticonSvg (name: string) {
const octiconPath = path.resolve(__dirname, 'octicon', `${name}.svg`)
if (fs.existsSync(octiconPath)) {
const content = fs.readFileSync(octiconPath, 'utf8')
const div = document.createElement('div')
div.innerHTML = content
return div
}
return null
}
function loadSVG (element: HTMLSpanElement) {
for (const cssClass of element.classList) {
if (cssClass.startsWith('octicon-')) {
const icon = getOcticonSvg(cssClass.substr(8))
if (icon) {
for (const elemClass of element.classList) {
icon.classList.add(elemClass)
}
element.before(icon)
element.remove()
break
}
}
}
}
for (const element of document.querySelectorAll<HTMLSpanElement>('.octicon')) {
loadSVG(element)
}
}
window.addEventListener('load', initialize)

View File

@@ -58,6 +58,9 @@ The `Super` key is mapped to the `Windows` key on Windows and Linux and
* `Plus`
* `Space`
* `Tab`
* `Capslock`
* `Numlock`
* `Scrolllock`
* `Backspace`
* `Delete`
* `Insert`

View File

@@ -606,7 +606,7 @@ You can request the following paths by the name:
Fetches a path's associated icon.
On _Windows_, there a 2 kinds of icons:
On _Windows_, there are 2 kinds of icons:
- Icons associated with certain file extensions, like `.mp3`, `.png`, etc.
- Icons inside the file itself, like `.exe`, `.dll`, `.ico`.
@@ -725,6 +725,11 @@ your app's `info.plist`, which can not be modified at runtime. You can however
change the file with a simple text editor or script during build time.
Please refer to [Apple's documentation][CFBundleURLTypes] for details.
**Note:** In a Windows Store environment (when packaged as an `appx`) this API
will return `true` for all calls but the registry key it sets won't be accessible
by other applications. In order to register your Windows Store application
as a default protocol handler you must [declare the protocol in your manifest](https://docs.microsoft.com/en-us/uwp/schemas/appxpackage/uapmanifestschema/element-uap-protocol).
The API uses the Windows Registry and LSSetDefaultHandlerForURLScheme internally.
### `app.removeAsDefaultProtocolClient(protocol[, path, args])` _macOS_ _Windows_
@@ -1188,22 +1193,25 @@ Start accessing a security scoped resource. With this method Electron applicatio
### `app.commandLine.appendSwitch(switch[, value])`
* `switch` String - A command-line switch
* `switch` String - A command-line switch, without the leading `--`
* `value` String (optional) - A value for the given switch
Append a switch (with optional `value`) to Chromium's command line.
**Note:** This will not affect `process.argv`, and is mainly used by developers
to control some low-level Chromium behaviors.
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.
### `app.commandLine.appendArgument(value)`
* `value` String - The argument to append to the command line
Append an argument to Chromium's command line. The argument will be quoted
correctly.
correctly. Switches will precede arguments regardless of appending order.
**Note:** This will not affect `process.argv`.
If you're appending an argument like `--switch=value`, consider using `appendSwitch('switch', 'value')` instead.
**Note:** This will not affect `process.argv`. The intended usage of this function is to
control Chromium's behavior.
### `app.commandLine.hasSwitch(switch)`
@@ -1217,7 +1225,7 @@ Returns `Boolean` - Whether the command-line switch is present.
Returns `String` - The command-line switch value.
**Note:** When the switch is not present, it returns empty string.
**Note:** When the switch is not present or has no value, it returns empty string.
### `app.enableSandbox()` _Experimental_ _macOS_ _Windows_

View File

@@ -8,6 +8,15 @@ The `FIXME` string is used in code comments to denote things that should be fixe
# Planned Breaking API Changes (6.0)
## `win.setMenu(null)`
```js
// Deprecated
win.setMenu(null)
// Replace with
win.removeMenu()
```
## `electron.screen` in renderer process
```js
@@ -57,9 +66,14 @@ The following `webPreferences` option default values are deprecated in favor of
Child windows opened with the `nativeWindowOpen` option will always have Node.js integration disabled.
## Privileged Schemes Registration
Renderer process APIs `webFrame.setRegisterURLSchemeAsPrivileged` and `webFrame.registerURLSchemeAsBypassingCSP` as well as browser process API `protocol.registerStandardSchemes` have been removed.
A new API, `protocol.registerSchemesAsPrivileged` has been added and should be used for registering custom schemes with the required privileges. Custom schemes are required to be registered before app ready.
# Planned Breaking API Changes (4.0)
The following list includes the breaking API changes planned for Electron 4.0.
The following list includes the breaking API changes made in Electron 4.0.
## `app.makeSingleInstance`

View File

@@ -83,6 +83,10 @@ Returns `Boolean` - Whether the view is destroyed.
with the window. `false` by default.
* `height` Boolean - If `true`, the view's height will grow and shrink
together with the window. `false` by default.
* `horizontal` Boolean - If `true`, the view's x position and width will grow
and shrink proportionly with the window. `false` by default.
* `vertical` Boolean - If `true`, the view's y position and height will grow
and shrink proportinaly with the window. `false` by default.
#### `view.setBounds(bounds)` _Experimental_

View File

@@ -1089,7 +1089,7 @@ can not be focused on.
Returns `Boolean` - Whether the window is always on top of other windows.
#### `win.moveTop()` _macOS_ _Windows_
#### `win.moveTop()`
Moves window to top(z-order) regardless of focus
@@ -1308,8 +1308,11 @@ Same as `webContents.reload`.
* `menu` Menu | null
Sets the `menu` as the window's menu bar, setting it to `null` will remove the
menu bar.
Sets the `menu` as the window's menu bar.
#### `win.removeMenu()` _Linux_ _Windows_
Remove the window's menu bar.
#### `win.setProgressBar(progress[, options])`

View File

@@ -12,7 +12,6 @@ result.
**Note:** You should not use this module until the `ready` event of the app
module is emitted.
```javascript
const { app, contentTracing } = require('electron')
@@ -43,11 +42,18 @@ The `contentTracing` module has the following methods:
* `callback` Function
* `categories` String[]
Get a set of category groups. The category groups can change as new code paths
are reached.
Get a set of category groups. The category groups can change as new code paths are reached.
Once all child processes have acknowledged the `getCategories` request the `callback` is invoked with an array of category groups.
**[Deprecated Soon](promisification.md)**
### `contentTracing.getCategories()`
Returns `Promise<String[]>` - resolves with an array of category groups once all child processes have acknowledged the `getCategories` request
Get a set of category groups. The category groups can change as new code paths are reached.
Once all child processes have acknowledged the `getCategories` request the
`callback` is invoked with an array of category groups.
### `contentTracing.startRecording(options, callback)`
@@ -60,6 +66,19 @@ Recording begins immediately locally and asynchronously on child processes
as soon as they receive the EnableRecording request. The `callback` will be
called once all child processes have acknowledged the `startRecording` request.
**[Deprecated Soon](promisification.md)**
### `contentTracing.startRecording(options)`
* `options` ([TraceCategoriesAndOptions](structures/trace-categories-and-options.md) | [TraceConfig](structures/trace-config.md))
Returns `Promise<void>` - resolved once all child processes have acknowledged the `startRecording` request.
Start recording on all processes.
Recording begins immediately locally and asynchronously on child processes
as soon as they receive the EnableRecording request.
### `contentTracing.stopRecording(resultFilePath, callback)`
* `resultFilePath` String
@@ -81,47 +100,24 @@ Trace data will be written into `resultFilePath` if it is not empty or into a
temporary file. The actual file path will be passed to `callback` if it's not
`null`.
### `contentTracing.startMonitoring(options, callback)`
**[Deprecated Soon](promisification.md)**
* `options` Object
* `categoryFilter` String
* `traceOptions` String
* `callback` Function
Start monitoring on all processes.
Monitoring begins immediately locally and asynchronously on child processes as
soon as they receive the `startMonitoring` request.
Once all child processes have acknowledged the `startMonitoring` request the
`callback` will be called.
### `contentTracing.stopMonitoring(callback)`
* `callback` Function
Stop monitoring on all processes.
Once all child processes have acknowledged the `stopMonitoring` request the
`callback` is called.
### `contentTracing.captureMonitoringSnapshot(resultFilePath, callback)`
### `contentTracing.stopRecording(resultFilePath)`
* `resultFilePath` String
* `callback` Function
* `resultFilePath` String
Get the current monitoring traced data.
Returns `Promise<String>` - resolves with a file that contains the traced data once all child processes have acknowledged the `stopRecording` request
Stop recording on all processes.
Child processes typically cache trace data and only rarely flush and send
trace data back to the main process. This is because it may be an expensive
operation to send the trace data over IPC and we would like to avoid unneeded
runtime overhead from tracing. So, to end tracing, we must asynchronously ask
all child processes to flush any pending trace data.
Once all child processes have acknowledged the `captureMonitoringSnapshot`
request the `callback` will be called with a file that contains the traced data.
trace data back to the main process. This helps to minimize the runtime overhead
of tracing since sending trace data over IPC can be an expensive operation. So,
to end tracing, we must asynchronously ask all child processes to flush any
pending trace data.
Trace data will be written into `resultFilePath` if it is not empty or into a
temporary file.
### `contentTracing.getTraceBufferUsage(callback)`

View File

@@ -13,21 +13,30 @@ For example:
const { session } = require('electron')
// Query all cookies.
session.defaultSession.cookies.get({}, (error, cookies) => {
console.log(error, cookies)
})
session.defaultSession.cookies.get({})
.then((cookies) => {
console.log(cookies)
}).catch((error) => {
console.log(error)
})
// Query all cookies associated with a specific url.
session.defaultSession.cookies.get({ url: 'http://www.github.com' }, (error, cookies) => {
console.log(error, cookies)
})
session.defaultSession.cookies.get({ url: 'http://www.github.com' })
.then((cookies) => {
console.log(cookies)
}).catch((error) => {
console.log(error)
})
// Set a cookie with the given cookie data;
// may overwrite equivalent cookies if they exist.
const cookie = { url: 'http://www.github.com', name: 'dummy_name', value: 'dummy' }
session.defaultSession.cookies.set(cookie, (error) => {
if (error) console.error(error)
})
session.defaultSession.cookies.set(cookie)
.then(() => {
// success
}, (error) => {
console.error(error)
})
```
### Instance Events
@@ -55,6 +64,23 @@ expired.
The following methods are available on instances of `Cookies`:
#### `cookies.get(filter)`
* `filter` Object
* `url` String (optional) - Retrieves cookies which are associated with
`url`. Empty implies retrieving cookies of all urls.
* `name` String (optional) - Filters cookies by name.
* `domain` String (optional) - Retrieves cookies whose domains match or are
subdomains of `domains`.
* `path` String (optional) - Retrieves cookies whose path matches `path`.
* `secure` Boolean (optional) - Filters cookies by their Secure property.
* `session` Boolean (optional) - Filters out session or persistent cookies.
Returns `Promise<Cookie[]>` - A promise which resolves an array of cookie objects.
Sends a request to get all cookies matching `filter`, and resolves a promise with
the response.
#### `cookies.get(filter, callback)`
* `filter` Object
@@ -73,6 +99,28 @@ The following methods are available on instances of `Cookies`:
Sends a request to get all cookies matching `filter`, `callback` will be called
with `callback(error, cookies)` on complete.
**[Deprecated Soon](promisification.md)**
#### `cookies.set(details)`
* `details` Object
* `url` String - The url to associate the cookie with.
* `name` String (optional) - The name of the cookie. Empty by default if omitted.
* `value` String (optional) - The value of the cookie. Empty by default if omitted.
* `domain` String (optional) - The domain of the cookie. Empty by default if omitted.
* `path` String (optional) - The path of the cookie. Empty by default if omitted.
* `secure` Boolean (optional) - Whether the cookie should be marked as Secure. Defaults to
false.
* `httpOnly` Boolean (optional) - Whether the cookie should be marked as HTTP only.
Defaults to false.
* `expirationDate` Double (optional) - The expiration date of the cookie as the number of
seconds since the UNIX epoch. If omitted then the cookie becomes a session
cookie and will not be retained between sessions.
Returns `Promise<void>` - A promise which resolves when the cookie has been set
Sets a cookie with `details`.
#### `cookies.set(details, callback)`
* `details` Object
@@ -94,6 +142,17 @@ with `callback(error, cookies)` on complete.
Sets a cookie with `details`, `callback` will be called with `callback(error)`
on complete.
**[Deprecated Soon](promisification.md)**
#### `cookies.remove(url, name)`
* `url` String - The URL associated with the cookie.
* `name` String - The name of cookie to remove.
Returns `Promise<void>` - A promise which resolves when the cookie has been removed
Removes the cookies matching `url` and `name`
#### `cookies.remove(url, name, callback)`
* `url` String - The URL associated with the cookie.
@@ -103,8 +162,18 @@ on complete.
Removes the cookies matching `url` and `name`, `callback` will called with
`callback()` on complete.
**[Deprecated Soon](promisification.md)**
#### `cookies.flushStore()`
Returns `Promise<void>` - A promise which resolves when the cookie store has been flushed
Writes any unwritten cookies data to disk.
#### `cookies.flushStore(callback)`
* `callback` Function
Writes any unwritten cookies data to disk.
**[Deprecated Soon](promisification.md)**

View File

@@ -62,14 +62,14 @@ Therefore, to collect crash reports from them, use `process.crashReporter.start`
along with an additional one called `crashesDirectory` that should point to a directory to store the crash
reports temporarily. You can test this out by calling `process.crash()` to crash the child process.
**Note:** To collect crash reports from child process in Windows, you need to add this extra code as well.
This will start the process that will monitor and send the crash reports. Replace `submitURL`, `productName`
and `crashesDirectory` with appropriate values.
**Note:** If you need send additional/updated `extra` parameters after your
first call `start` you can call `addExtraParameter` on macOS or call `start`
again with the new/updated `extra` parameters on Linux and Windows.
**Note:** To collect crash reports from child process in Windows, you need to add this extra code as well.
This will start the process that will monitor and send the crash reports. Replace `submitURL`, `productName`
and `crashesDirectory` with appropriate values.
```js
const args = [
`--reporter-url=${submitURL}`,

View File

@@ -117,6 +117,9 @@ The `filters` specifies an array of file types that can be displayed, see
If a `callback` is passed, the API call will be asynchronous and the result
will be passed via `callback(filename)`.
**Note:** On macOS, using the `callback` is recommended to avoid issues when
expanding and collapsing the dialog.
### `dialog.showMessageBox([browserWindow, ]options[, callback])`
* `browserWindow` [BrowserWindow](browser-window.md) (optional)

View File

@@ -14,7 +14,7 @@ See [`Menu`](menu.md) for examples.
* `menuItem` MenuItem
* `browserWindow` [BrowserWindow](browser-window.md)
* `event` Event
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteandmatchstyle`, `delete`, `selectall`, `reload`, `forcereload`, `toggledevtools`, `resetzoom`, `zoomin`, `zoomout`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideothers`, `unhide`, `quit`, `startspeaking`, `stopspeaking`, `close`, `minimize`, `zoom` or `front` - Define the action of the menu item, when specified the
* `role` String (optional) - Can be `undo`, `redo`, `cut`, `copy`, `paste`, `pasteandmatchstyle`, `delete`, `selectall`, `reload`, `forcereload`, `toggledevtools`, `resetzoom`, `zoomin`, `zoomout`, `togglefullscreen`, `window`, `minimize`, `close`, `help`, `about`, `services`, `hide`, `hideothers`, `unhide`, `quit`, `startspeaking`, `stopspeaking`, `close`, `minimize`, `zoom`, `front`, `appMenu`, `fileMenu`, `editMenu`, `viewMenu` or `windowMenu` - Define the action of the menu item, when specified the
`click` property will be ignored. See [roles](#roles).
* `type` String (optional) - Can be `normal`, `separator`, `submenu`, `checkbox` or
`radio`.

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