mirror of
https://github.com/electron/electron.git
synced 2026-02-19 03:14:51 -05:00
Compare commits
175 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f37c1ff644 | ||
|
|
5c8e7e8b7f | ||
|
|
36b1f8fcf8 | ||
|
|
e83bd9bbf0 | ||
|
|
c2136b6065 | ||
|
|
a57428553e | ||
|
|
559c008e0d | ||
|
|
2d41c02714 | ||
|
|
662810f881 | ||
|
|
0065e3d12b | ||
|
|
2b69fbc4bd | ||
|
|
72511cc9d2 | ||
|
|
84ce462803 | ||
|
|
533b9716af | ||
|
|
24a1234e28 | ||
|
|
b2e345857a | ||
|
|
63873140d9 | ||
|
|
738740fd7d | ||
|
|
415c1f9e9b | ||
|
|
07c4e24ebb | ||
|
|
b7b714a020 | ||
|
|
14d03d7b78 | ||
|
|
7bd4570ff4 | ||
|
|
a5c65aae37 | ||
|
|
d28a7b15a2 | ||
|
|
ef674025b5 | ||
|
|
7446006c24 | ||
|
|
24fbb73838 | ||
|
|
16b8c06bbf | ||
|
|
f729d7456f | ||
|
|
badae800c1 | ||
|
|
d89aa3a36e | ||
|
|
5b53cfa56f | ||
|
|
56e906d073 | ||
|
|
d94a5ddc09 | ||
|
|
7feffc7c35 | ||
|
|
2800ddf930 | ||
|
|
fabe766816 | ||
|
|
87e2950e2d | ||
|
|
979e59e871 | ||
|
|
1384b76570 | ||
|
|
1ba30ace9b | ||
|
|
8326cea7e7 | ||
|
|
e6b24a21e4 | ||
|
|
a9b1f2fd0e | ||
|
|
0563bcad49 | ||
|
|
a64a3e8aa9 | ||
|
|
f1ffcb56d9 | ||
|
|
f3af287d4a | ||
|
|
305d623570 | ||
|
|
c8d7be4a09 | ||
|
|
e3d1a3163f | ||
|
|
8261e580ae | ||
|
|
d007efa5e8 | ||
|
|
a1e9b973b1 | ||
|
|
eca3138e10 | ||
|
|
8443cf143b | ||
|
|
b7584fa0e8 | ||
|
|
0b5f24002b | ||
|
|
dcb5b8244e | ||
|
|
6785021927 | ||
|
|
d073ab64fb | ||
|
|
205f9432ee | ||
|
|
b2fb8cd60e | ||
|
|
ab504006e2 | ||
|
|
e2ab29fb29 | ||
|
|
8837679de6 | ||
|
|
ba167e6c86 | ||
|
|
1bc5b7f350 | ||
|
|
9d72cda6c4 | ||
|
|
6763cca16f | ||
|
|
599da9c728 | ||
|
|
16db2d7856 | ||
|
|
04548770fb | ||
|
|
ca8cda068d | ||
|
|
b4f7463215 | ||
|
|
1efe79b874 | ||
|
|
e58853af3d | ||
|
|
437701d0ef | ||
|
|
13f319eddf | ||
|
|
88baf5507f | ||
|
|
2472f81647 | ||
|
|
40f0c01e15 | ||
|
|
5e6c03c5c5 | ||
|
|
9d3aa08c75 | ||
|
|
a5a34868d5 | ||
|
|
c481324725 | ||
|
|
ea7d9182a1 | ||
|
|
143c6b3d39 | ||
|
|
86372e642c | ||
|
|
09677ab592 | ||
|
|
2cd8848b97 | ||
|
|
82151b4f0d | ||
|
|
37ece8b71a | ||
|
|
e4c2be03b2 | ||
|
|
d1735ee2f3 | ||
|
|
4c8eb34bab | ||
|
|
14ded68b75 | ||
|
|
220b356233 | ||
|
|
858d74bc36 | ||
|
|
c32cb09a68 | ||
|
|
194edd0270 | ||
|
|
6c3c9b5a51 | ||
|
|
a43d4cacde | ||
|
|
a7372e8f53 | ||
|
|
3aa207c2dc | ||
|
|
f96153a4d1 | ||
|
|
1aeba811cc | ||
|
|
f6dced63b5 | ||
|
|
489aafc1f9 | ||
|
|
a6ed6480d8 | ||
|
|
81c1a6ed29 | ||
|
|
fe3378db92 | ||
|
|
fe85a94035 | ||
|
|
48779feb91 | ||
|
|
5e289cee04 | ||
|
|
5f4ccec09a | ||
|
|
20f58fddf1 | ||
|
|
75f193a089 | ||
|
|
7de2539399 | ||
|
|
a90397f348 | ||
|
|
6e734570ac | ||
|
|
79c1c8d21f | ||
|
|
35b348a7d7 | ||
|
|
213f2fc838 | ||
|
|
fb03807cd2 | ||
|
|
89523b2504 | ||
|
|
243dbda31c | ||
|
|
587157e933 | ||
|
|
15f9300a64 | ||
|
|
88898acfef | ||
|
|
8a69889048 | ||
|
|
b032c415c1 | ||
|
|
e8643c1144 | ||
|
|
f8af08c279 | ||
|
|
713ff4c471 | ||
|
|
99abcba062 | ||
|
|
086086b4e5 | ||
|
|
6e7425164f | ||
|
|
4a03aa5bd2 | ||
|
|
99b4fd1ce0 | ||
|
|
a60211333c | ||
|
|
732ce44e61 | ||
|
|
0f70d096fc | ||
|
|
56cde790e1 | ||
|
|
7dc7b3627f | ||
|
|
123f4087ca | ||
|
|
b5720bb2b8 | ||
|
|
84f05ee0a4 | ||
|
|
694e8d8e66 | ||
|
|
1529bf7ce5 | ||
|
|
d688b77187 | ||
|
|
7651036bce | ||
|
|
294825837c | ||
|
|
945defd47e | ||
|
|
cbd91b1fba | ||
|
|
1aebbe9538 | ||
|
|
508d2cb1f5 | ||
|
|
f769da64ad | ||
|
|
e16decd6a1 | ||
|
|
03c7a54dc5 | ||
|
|
eefcbda641 | ||
|
|
ea118c3984 | ||
|
|
b204da6603 | ||
|
|
cf321a9b55 | ||
|
|
358d6e1116 | ||
|
|
12934c911f | ||
|
|
e2c4e341cc | ||
|
|
79f6ba4b18 | ||
|
|
3e835c1247 | ||
|
|
91849fccbe | ||
|
|
8dc38cb973 | ||
|
|
f799b6eb37 | ||
|
|
7063ba73df | ||
|
|
f01bb5f43b |
@@ -61,7 +61,7 @@ parameters:
|
||||
# Build machines configs.
|
||||
docker-image: &docker-image
|
||||
docker:
|
||||
- image: electronjs/build:d09fd95029bd8c1c73069888231b29688ef385ed
|
||||
- image: electron.azurecr.io/build:4cec2c5ab66765caa724e37bae2bffb9b29722a5
|
||||
|
||||
machine-linux-medium: &machine-linux-medium
|
||||
<<: *docker-image
|
||||
@@ -90,6 +90,7 @@ env-release-build: &env-release-build
|
||||
STRIP_BINARIES: true
|
||||
GENERATE_SYMBOLS: true
|
||||
CHECK_DIST_MANIFEST: '1'
|
||||
IS_RELEASE: true
|
||||
|
||||
env-headless-testing: &env-headless-testing
|
||||
DISPLAY: ':99.0'
|
||||
@@ -228,23 +229,34 @@ step-gclient-sync: &step-gclient-sync
|
||||
"$CIRCLE_REPOSITORY_URL"
|
||||
|
||||
ELECTRON_USE_THREE_WAY_MERGE_FOR_PATCHES=1 gclient sync --with_branch_heads --with_tags
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
cd src/electron
|
||||
git update-index --refresh || true
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
# There are changes to the patches. Make a git commit with the updated patches
|
||||
git add patches
|
||||
GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="anonymous@electronjs.org" git commit -m "update patches" --author="Electron Bot <anonymous@electronjs.org>"
|
||||
# Export it
|
||||
mkdir -p ../../patches
|
||||
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "There were changes to the patches when applying."
|
||||
echo "Check the CI artifacts for a patch you can apply to fix it."
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
if [ "$IS_RELEASE" != "true" ]; then
|
||||
# Re-export all the patches to check if there were changes.
|
||||
python src/electron/script/export_all_patches.py src/electron/patches/config.json
|
||||
cd src/electron
|
||||
git update-index --refresh || true
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
# There are changes to the patches. Make a git commit with the updated patches
|
||||
git add patches
|
||||
GIT_COMMITTER_NAME="Electron Bot" GIT_COMMITTER_EMAIL="electron@github.com" git commit -m "update patches" --author="Electron Bot <electron@github.com>"
|
||||
# Export it
|
||||
mkdir -p ../../patches
|
||||
git format-patch -1 --stdout --keep-subject --no-stat --full-index > ../../patches/update-patches.patch
|
||||
if (node ./script/push-patch.js 2> /dev/null > /dev/null); then
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "Changes to the patches when applying, we have auto-pushed the diff to the current branch"
|
||||
echo "A new CI job will kick off shortly"
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
else
|
||||
echo
|
||||
echo "======================================================================"
|
||||
echo "There were changes to the patches when applying."
|
||||
echo "Check the CI artifacts for a patch you can apply to fix it."
|
||||
echo "======================================================================"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -271,10 +283,10 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
name: Setup Goma
|
||||
command: |
|
||||
echo 'export USE_GOMA=true' >> $BASH_ENV
|
||||
if [ "`uname`" == "Linux" ]; then
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
||||
else
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=25' >> $BASH_ENV
|
||||
echo 'export NUMBER_OF_NINJA_PROCESSES=300' >> $BASH_ENV
|
||||
if [ "`uname`" == "Darwin" ]; then
|
||||
echo 'ulimit -n 10000' >> $BASH_ENV
|
||||
echo 'sudo launchctl limit maxfiles 65536 200000' >> $BASH_ENV
|
||||
fi
|
||||
if [ ! -z "$RAW_GOMA_AUTH" ]; then
|
||||
echo $RAW_GOMA_AUTH > ~/.goma_oauth2_config
|
||||
@@ -283,7 +295,7 @@ step-setup-goma-for-build: &step-setup-goma-for-build
|
||||
cd build-tools
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare()"
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
node -e "require('./src/utils/goma.js').ensure()"
|
||||
echo 'export GN_GOMA_FILE='`node -e "console.log(require('./src/utils/goma.js').gnFilePath)"` >> $BASH_ENV
|
||||
echo 'export LOCAL_GOMA_DIR='`node -e "console.log(require('./src/utils/goma.js').dir)"` >> $BASH_ENV
|
||||
@@ -538,10 +550,10 @@ step-electron-publish: &step-electron-publish
|
||||
cd src/electron
|
||||
if [ "$UPLOAD_TO_S3" == "1" ]; then
|
||||
echo 'Uploading Electron release distribution to S3'
|
||||
script/release/uploaders/upload.py --upload_to_s3
|
||||
script/release/uploaders/upload.py --verbose --upload_to_s3
|
||||
else
|
||||
echo 'Uploading Electron release distribution to Github releases'
|
||||
script/release/uploaders/upload.py
|
||||
script/release/uploaders/upload.py --verbose
|
||||
fi
|
||||
|
||||
step-persist-data-for-tests: &step-persist-data-for-tests
|
||||
|
||||
10
.gitattributes
vendored
10
.gitattributes
vendored
@@ -2,3 +2,13 @@
|
||||
# files to be checked out with LF endings even if core.autocrlf is true.
|
||||
*.patch text eol=lf
|
||||
patches/**/.patches merge=union
|
||||
|
||||
# Source code and markdown files should always use LF as line ending.
|
||||
*.cc text eol=lf
|
||||
*.mm text eol=lf
|
||||
*.h text eol=lf
|
||||
*.js text eol=lf
|
||||
*.ts text eol=lf
|
||||
*.py text eol=lf
|
||||
*.ps1 text eol=lf
|
||||
*.md text eol=lf
|
||||
|
||||
13
BUILD.gn
13
BUILD.gn
@@ -1115,20 +1115,17 @@ if (is_mac) {
|
||||
"//components/crash/core/app:run_as_crashpad_handler",
|
||||
]
|
||||
|
||||
ldflags = []
|
||||
|
||||
libs = [
|
||||
"comctl32.lib",
|
||||
"uiautomationcore.lib",
|
||||
"wtsapi32.lib",
|
||||
]
|
||||
|
||||
configs += [ "//build/config/win:windowed" ]
|
||||
|
||||
ldflags = [
|
||||
# Windows 7 doesn't have these DLLs.
|
||||
# TODO: are there other DLLs we need to list here to be win7
|
||||
# compatible?
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-l1-1-0.dll",
|
||||
"/DELAYLOAD:api-ms-win-core-winrt-string-l1-1-0.dll",
|
||||
configs += [
|
||||
"//build/config/win:windowed",
|
||||
"//build/config/win:delayloads",
|
||||
]
|
||||
|
||||
# This is to support renaming of electron.exe. node-gyp has hard-coded
|
||||
|
||||
@@ -1 +1 @@
|
||||
9.2.0
|
||||
9.4.0
|
||||
10
appveyor.yml
10
appveyor.yml
@@ -53,7 +53,9 @@ build_script:
|
||||
} else {
|
||||
node script/yarn.js install --frozen-lockfile
|
||||
|
||||
if ($(node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH;$LASTEXITCODE -eq 0)) {
|
||||
$result = node script/doc-only-change.js --prNumber=$env:APPVEYOR_PULL_REQUEST_NUMBER --prBranch=$env:APPVEYOR_REPO_BRANCH
|
||||
Write-Output $result
|
||||
if ($result.ExitCode -eq 0) {
|
||||
Write-warning "Skipping build for doc only change"; Exit-AppveyorBuild
|
||||
}
|
||||
}
|
||||
@@ -127,7 +129,7 @@ build_script:
|
||||
cd build-tools
|
||||
npm install
|
||||
mkdir third_party
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare()"
|
||||
node -e "require('./src/utils/goma.js').downloadAndPrepare({ gomaOneForAll: true })"
|
||||
$env:GN_GOMA_FILE = node -e "console.log(require('./src/utils/goma.js').gnFilePath)"
|
||||
$env:LOCAL_GOMA_DIR = node -e "console.log(require('./src/utils/goma.js').dir)"
|
||||
cd ..
|
||||
@@ -212,10 +214,10 @@ deploy_script:
|
||||
if (Test-Path Env:\ELECTRON_RELEASE) {
|
||||
if (Test-Path Env:\UPLOAD_TO_S3) {
|
||||
Write-Output "Uploading Electron release distribution to s3"
|
||||
& python script\release\uploaders\upload.py --upload_to_s3
|
||||
& python script\release\uploaders\upload.py --verbose --upload_to_s3
|
||||
} else {
|
||||
Write-Output "Uploading Electron release distribution to github releases"
|
||||
& python script\release\uploaders\upload.py
|
||||
& python script\release\uploaders\upload.py --verbose
|
||||
}
|
||||
} elseif (Test-Path Env:\TEST_WOA) {
|
||||
node script/release/ci-release-build.js --job=electron-woa-testing --ci=VSTS --armTest --appveyorJobId=$env:APPVEYOR_JOB_ID $env:APPVEYOR_REPO_BRANCH
|
||||
|
||||
@@ -10,10 +10,9 @@ config.output = {
|
||||
filename: path.basename(outPath)
|
||||
}
|
||||
|
||||
const { wrapInitWithProfilingTimeout } = config;
|
||||
delete config.wrapInitWithProfilingTimeout;
|
||||
const { wrapInitWithProfilingTimeout, wrapInitWithTryCatch, ...webpackConfig } = config;
|
||||
|
||||
webpack(config, (err, stats) => {
|
||||
webpack(webpackConfig, (err, stats) => {
|
||||
if (err) {
|
||||
console.error(err)
|
||||
process.exit(1)
|
||||
@@ -21,9 +20,17 @@ webpack(config, (err, stats) => {
|
||||
console.error(stats.toString('normal'))
|
||||
process.exit(1)
|
||||
} else {
|
||||
let contents = fs.readFileSync(outPath, 'utf8');
|
||||
if (wrapInitWithTryCatch) {
|
||||
contents = `try {
|
||||
${contents}
|
||||
} catch (err) {
|
||||
console.error('Electron ${webpackConfig.output.filename} script failed to run');
|
||||
console.error(err);
|
||||
}`;
|
||||
}
|
||||
if (wrapInitWithProfilingTimeout) {
|
||||
const contents = fs.readFileSync(outPath, 'utf8');
|
||||
const newContents = `function ___electron_webpack_init__() {
|
||||
contents = `function ___electron_webpack_init__() {
|
||||
${contents}
|
||||
};
|
||||
if ((globalThis.process || binding.process).argv.includes("--profile-electron-init")) {
|
||||
@@ -31,8 +38,8 @@ if ((globalThis.process || binding.process).argv.includes("--profile-electron-in
|
||||
} else {
|
||||
___electron_webpack_init__();
|
||||
}`;
|
||||
fs.writeFileSync(outPath, newContents);
|
||||
}
|
||||
fs.writeFileSync(outPath, contents)
|
||||
process.exit(0)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -86,7 +86,8 @@ module.exports = ({
|
||||
loadElectronFromAlternateTarget,
|
||||
targetDeletesNodeGlobals,
|
||||
target,
|
||||
wrapInitWithProfilingTimeout
|
||||
wrapInitWithProfilingTimeout,
|
||||
wrapInitWithTryCatch
|
||||
}) => {
|
||||
let entry = path.resolve(electronRoot, 'lib', target, 'init.ts')
|
||||
if (!fs.existsSync(entry)) {
|
||||
@@ -102,6 +103,7 @@ module.exports = ({
|
||||
filename: `${target}.bundle.js`
|
||||
},
|
||||
wrapInitWithProfilingTimeout,
|
||||
wrapInitWithTryCatch,
|
||||
resolve: {
|
||||
alias: {
|
||||
'@electron/internal': path.resolve(electronRoot, 'lib'),
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
module.exports = require('./webpack.config.base')({
|
||||
target: 'isolated_renderer',
|
||||
alwaysHasNode: false
|
||||
alwaysHasNode: false,
|
||||
wrapInitWithTryCatch: true
|
||||
})
|
||||
|
||||
@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
|
||||
target: 'renderer',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true,
|
||||
wrapInitWithProfilingTimeout: true
|
||||
wrapInitWithProfilingTimeout: true,
|
||||
wrapInitWithTryCatch: true
|
||||
})
|
||||
|
||||
@@ -2,4 +2,5 @@ module.exports = require('./webpack.config.base')({
|
||||
target: 'sandboxed_renderer',
|
||||
alwaysHasNode: false,
|
||||
wrapInitWithProfilingTimeout: true,
|
||||
wrapInitWithTryCatch: true
|
||||
})
|
||||
|
||||
@@ -2,5 +2,6 @@ module.exports = require('./webpack.config.base')({
|
||||
target: 'worker',
|
||||
loadElectronFromAlternateTarget: 'renderer',
|
||||
alwaysHasNode: true,
|
||||
targetDeletesNodeGlobals: true
|
||||
targetDeletesNodeGlobals: true,
|
||||
wrapInitWithTryCatch: true
|
||||
})
|
||||
|
||||
@@ -36,6 +36,7 @@ net::NSSCertDatabase* GetNSSCertDatabaseForResourceContext(
|
||||
// Linux has only a single persistent slot compared to ChromeOS's separate
|
||||
// public and private slot.
|
||||
// Redirect any slot usage to this persistent slot on Linux.
|
||||
crypto::EnsureNSSInit();
|
||||
g_nss_cert_database = new net::NSSCertDatabase(
|
||||
crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* public slot */,
|
||||
crypto::ScopedPK11Slot(PK11_GetInternalKeySlot()) /* private slot */);
|
||||
|
||||
@@ -827,10 +827,9 @@ ProcessSingleton::NotifyResult ProcessSingleton::NotifyOtherProcessWithTimeout(
|
||||
to_send.append(current_dir.value());
|
||||
|
||||
const std::vector<std::string>& argv = electron::ElectronCommandLine::argv();
|
||||
for (std::vector<std::string>::const_iterator it = argv.begin();
|
||||
it != argv.end(); ++it) {
|
||||
for (const auto& arg : argv) {
|
||||
to_send.push_back(kTokenDelimiter);
|
||||
to_send.append(*it);
|
||||
to_send.append(arg);
|
||||
}
|
||||
|
||||
// Send the message
|
||||
|
||||
@@ -122,8 +122,7 @@ void GlobalMenuBarRegistrarX11::OnNameOwnerChanged(GObject* /* ignored */,
|
||||
GParamSpec* /* ignored */) {
|
||||
// If the name owner changed, we need to reregister all the live xids with
|
||||
// the system.
|
||||
for (std::set<unsigned long>::const_iterator it = live_xids_.begin();
|
||||
it != live_xids_.end(); ++it) {
|
||||
RegisterXID(*it);
|
||||
for (auto xid : live_xids_) {
|
||||
RegisterXID(xid);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,8 @@ In most cases, you should do everything in the `ready` event handler.
|
||||
|
||||
Returns:
|
||||
|
||||
* `launchInfo` unknown _macOS_
|
||||
* `event` Event
|
||||
* `launchInfo` Record<string, any> _macOS_
|
||||
|
||||
Emitted once, when Electron has finished initializing. On macOS, `launchInfo`
|
||||
holds the `userInfo` of the `NSUserNotification` that was used to open the
|
||||
@@ -382,7 +383,7 @@ Returns:
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failure` - Process never successfully launched
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
|
||||
Emitted when the renderer process unexpectedly dissapears. This is normally
|
||||
@@ -1259,7 +1260,7 @@ systems Application folder. Use in combination with `app.moveToApplicationsFolde
|
||||
### `app.moveToApplicationsFolder([options])` _macOS_
|
||||
|
||||
* `options` Object (optional)
|
||||
* `conflictHandler` Function<Boolean> (optional) - A handler for potential conflict in move failure.
|
||||
* `conflictHandler` Function\<Boolean> (optional) - A handler for potential conflict in move failure.
|
||||
* `conflictType` String - The type of move conflict encountered by the handler; can be `exists` or `existsAndRunning`, where `exists` means that an app of the same name is present in the Applications directory and `existsAndRunning` means both that it exists and that it's presently running.
|
||||
|
||||
Returns `Boolean` - Whether the move was successful. Please note that if
|
||||
|
||||
@@ -1669,9 +1669,12 @@ Sets whether the menu bar should be visible. If the menu bar is auto-hide, users
|
||||
|
||||
Returns `Boolean` - Whether the menu bar is visible.
|
||||
|
||||
#### `win.setVisibleOnAllWorkspaces(visible)`
|
||||
#### `win.setVisibleOnAllWorkspaces(visible[, options])`
|
||||
|
||||
* `visible` Boolean
|
||||
* `options` Object (optional)
|
||||
* `visibleOnFullScreen` Boolean (optional) _macOS_ - Sets whether
|
||||
the window should be visible above fullscreen windows
|
||||
|
||||
Sets whether the window should be visible on all workspaces.
|
||||
|
||||
|
||||
@@ -157,10 +157,16 @@ parameters in a renderer process will not result in those parameters being sent
|
||||
with crashes that occur in other renderer processes or in the main process.
|
||||
|
||||
**Note:** Parameters have limits on the length of the keys and values. Key
|
||||
names must be no longer than 39 bytes, and values must be no longer than 127
|
||||
names must be no longer than 39 bytes, and values must be no longer than 20320
|
||||
bytes. Keys with names longer than the maximum will be silently ignored. Key
|
||||
values longer than the maximum length will be truncated.
|
||||
|
||||
**Note:** On linux values that are longer than 127 bytes will be chunked into
|
||||
multiple keys, each 127 bytes in length. E.g. `addExtraParameter('foo', 'a'.repeat(130))`
|
||||
will result in two chunked keys `foo__1` and `foo__2`, the first will contain
|
||||
the first 127 bytes and the second will contain the remaining 3 bytes. On
|
||||
your crash reporting backend you should stitch together keys in this format.
|
||||
|
||||
### `crashReporter.removeExtraParameter(key)`
|
||||
|
||||
* `key` String - Parameter key, must be no longer than 39 bytes.
|
||||
|
||||
@@ -28,6 +28,9 @@ session.loadExtension('path/to/unpacked/extension').then(({ id }) => {
|
||||
Loaded extensions will not be automatically remembered across exits; if you do
|
||||
not call `loadExtension` when the app runs, the extension will not be loaded.
|
||||
|
||||
Note that loading extensions is only supported in persistent sessions.
|
||||
Attempting to load an extension into an in-memory session will throw an error.
|
||||
|
||||
See the [`session`](session.md) documentation for more information about
|
||||
loading, unloading, and querying active extensions.
|
||||
|
||||
@@ -99,3 +102,15 @@ The following methods of `chrome.tabs` are supported:
|
||||
> **Note:** In Chrome, passing `-1` as a tab ID signifies the "currently active
|
||||
> tab". Since Electron has no such concept, passing `-1` as a tab ID is not
|
||||
> supported and will raise an error.
|
||||
|
||||
### `chrome.management`
|
||||
|
||||
The following methods of `chrome.management` are supported:
|
||||
|
||||
- `chrome.management.getAll`
|
||||
- `chrome.management.get`
|
||||
- `chrome.management.getSelf`
|
||||
- `chrome.management.getPermissionWarningsById`
|
||||
- `chrome.management.getPermissionWarningsByManifest`
|
||||
- `chrome.management.onEnabled`
|
||||
- `chrome.management.onDisabled`
|
||||
|
||||
@@ -91,7 +91,7 @@ Removes listeners of the specified `channel`.
|
||||
### `ipcMain.handle(channel, listener)`
|
||||
|
||||
* `channel` String
|
||||
* `listener` Function<Promise<void> | any>
|
||||
* `listener` Function<Promise\<void> | any>
|
||||
* `event` IpcMainInvokeEvent
|
||||
* `...args` any[]
|
||||
|
||||
@@ -123,7 +123,7 @@ WebContents is the source of the invoke request.
|
||||
### `ipcMain.handleOnce(channel, listener)`
|
||||
|
||||
* `channel` String
|
||||
* `listener` Function<Promise<void> | any>
|
||||
* `listener` Function<Promise\<void> | any>
|
||||
* `event` IpcMainInvokeEvent
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -24,19 +24,19 @@ app.whenReady().then(() => {
|
||||
|
||||
The `powerMonitor` module emits the following events:
|
||||
|
||||
### Event: 'suspend' _Linux_ _Windows_
|
||||
### Event: 'suspend' _macOS_ _Windows_
|
||||
|
||||
Emitted when the system is suspending.
|
||||
|
||||
### Event: 'resume' _Linux_ _Windows_
|
||||
### Event: 'resume' _macOS_ _Windows_
|
||||
|
||||
Emitted when system is resuming.
|
||||
|
||||
### Event: 'on-ac' _Windows_
|
||||
### Event: 'on-ac' _macOS_ _Windows_
|
||||
|
||||
Emitted when the system changes to AC power.
|
||||
|
||||
### Event: 'on-battery' _Windows_
|
||||
### Event: 'on-battery' _macOS_ _Windows_
|
||||
|
||||
Emitted when system changes to battery power.
|
||||
|
||||
|
||||
@@ -376,7 +376,7 @@ session.fromPartition('some-partition').setPermissionRequestHandler((webContents
|
||||
|
||||
#### `ses.setPermissionCheckHandler(handler)`
|
||||
|
||||
* `handler` Function<Boolean> | null
|
||||
* `handler` Function\<Boolean> | null
|
||||
* `webContents` [WebContents](web-contents.md) - WebContents checking the permission. Please note that if the request comes from a subframe you should use `requestingUrl` to check the request origin.
|
||||
* `permission` String - Enum of 'media'.
|
||||
* `requestingOrigin` String - The origin URL of the permission check
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
# IpcMainEvent Object extends `Event`
|
||||
|
||||
* `processId` Integer - The internal ID of the renderer process that sent this message
|
||||
* `frameId` Integer - The ID of the renderer frame that sent this message
|
||||
* `returnValue` any - Set this to the value to be returned in a synchronous message
|
||||
* `sender` WebContents - Returns the `webContents` that sent the message
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
# IpcMainInvokeEvent Object extends `Event`
|
||||
|
||||
* `processId` Integer - The internal ID of the renderer process that sent this message
|
||||
* `frameId` Integer - The ID of the renderer frame that sent this message
|
||||
* `sender` WebContents - Returns the `webContents` that sent the message
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
* `contentLengths` Number[] - The total size of the content, in bytes.
|
||||
* `price` Number - The cost of the product in the local currency.
|
||||
* `formattedPrice` String - The locale formatted price of the product.
|
||||
* `currencyCode` String - 3 character code presenting a product's currency based on the ISO 4217 standard.
|
||||
* `isDownloadable` Boolean - A Boolean value that indicates whether the App Store has downloadable content for this product. `true` if at least one file has been associated with the product.
|
||||
|
||||
@@ -351,7 +351,7 @@ Returns:
|
||||
* `killed` - Process was sent a SIGTERM or otherwise killed externally
|
||||
* `crashed` - Process crashed
|
||||
* `oom` - Process ran out of memory
|
||||
* `launch-failure` - Process never successfully launched
|
||||
* `launch-failed` - Process never successfully launched
|
||||
* `integrity-failure` - Windows code integrity checks failed
|
||||
|
||||
Emitted when the renderer process unexpectedly dissapears. This is normally
|
||||
@@ -1570,7 +1570,7 @@ app.whenReady().then(() => {
|
||||
|
||||
#### `contents.sendToFrame(frameId, channel, ...args)`
|
||||
|
||||
* `frameId` Integer
|
||||
* `frameId` Integer | [number, number]
|
||||
* `channel` String
|
||||
* `...args` any[]
|
||||
|
||||
|
||||
@@ -1,61 +0,0 @@
|
||||
# Breaking changes (NetworkService) (Draft)
|
||||
|
||||
This document describes changes to Electron APIs after migrating network code
|
||||
to NetworkService API.
|
||||
|
||||
We don't currently have an estimate of when we will enable `NetworkService` by
|
||||
default in Electron, but as Chromium is already removing non-`NetworkService`
|
||||
code, we might switch before Electron 10.
|
||||
|
||||
The content of this document should be moved to `breaking-changes.md` once we have
|
||||
determined when to enable `NetworkService` in Electron.
|
||||
|
||||
## Planned Breaking API Changes
|
||||
|
||||
### `protocol.unregisterProtocol`
|
||||
### `protocol.uninterceptProtocol`
|
||||
|
||||
The APIs are now synchronous and the optional callback is no longer needed.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.unregisterProtocol(scheme, () => { /* ... */ })
|
||||
// Replace with
|
||||
protocol.unregisterProtocol(scheme)
|
||||
```
|
||||
|
||||
### `protocol.registerFileProtocol`
|
||||
### `protocol.registerBufferProtocol`
|
||||
### `protocol.registerStringProtocol`
|
||||
### `protocol.registerHttpProtocol`
|
||||
### `protocol.registerStreamProtocol`
|
||||
### `protocol.interceptFileProtocol`
|
||||
### `protocol.interceptStringProtocol`
|
||||
### `protocol.interceptBufferProtocol`
|
||||
### `protocol.interceptHttpProtocol`
|
||||
### `protocol.interceptStreamProtocol`
|
||||
|
||||
The APIs are now synchronous and the optional callback is no longer needed.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.registerFileProtocol(scheme, handler, () => { /* ... */ })
|
||||
// Replace with
|
||||
protocol.registerFileProtocol(scheme, handler)
|
||||
```
|
||||
|
||||
The registered or intercepted protocol does not have effect on current page
|
||||
until navigation happens.
|
||||
|
||||
### `protocol.isProtocolHandled`
|
||||
|
||||
This API is deprecated and users should use `protocol.isProtocolRegistered`
|
||||
and `protocol.isProtocolIntercepted` instead.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.isProtocolHandled(scheme).then(() => { /* ... */ })
|
||||
// Replace with
|
||||
const isRegistered = protocol.isProtocolRegistered(scheme)
|
||||
const isIntercepted = protocol.isProtocolIntercepted(scheme)
|
||||
```
|
||||
@@ -105,6 +105,54 @@ const w = new BrowserWindow({
|
||||
We [recommend moving away from the remote
|
||||
module](https://medium.com/@nornagon/electrons-remote-module-considered-harmful-70d69500f31).
|
||||
|
||||
### `protocol.unregisterProtocol`
|
||||
### `protocol.uninterceptProtocol`
|
||||
|
||||
The APIs are now synchronous and the optional callback is no longer needed.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.unregisterProtocol(scheme, () => { /* ... */ })
|
||||
// Replace with
|
||||
protocol.unregisterProtocol(scheme)
|
||||
```
|
||||
|
||||
### `protocol.registerFileProtocol`
|
||||
### `protocol.registerBufferProtocol`
|
||||
### `protocol.registerStringProtocol`
|
||||
### `protocol.registerHttpProtocol`
|
||||
### `protocol.registerStreamProtocol`
|
||||
### `protocol.interceptFileProtocol`
|
||||
### `protocol.interceptStringProtocol`
|
||||
### `protocol.interceptBufferProtocol`
|
||||
### `protocol.interceptHttpProtocol`
|
||||
### `protocol.interceptStreamProtocol`
|
||||
|
||||
The APIs are now synchronous and the optional callback is no longer needed.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.registerFileProtocol(scheme, handler, () => { /* ... */ })
|
||||
// Replace with
|
||||
protocol.registerFileProtocol(scheme, handler)
|
||||
```
|
||||
|
||||
The registered or intercepted protocol does not have effect on current page
|
||||
until navigation happens.
|
||||
|
||||
### `protocol.isProtocolHandled`
|
||||
|
||||
This API is deprecated and users should use `protocol.isProtocolRegistered`
|
||||
and `protocol.isProtocolIntercepted` instead.
|
||||
|
||||
```javascript
|
||||
// Deprecated
|
||||
protocol.isProtocolHandled(scheme).then(() => { /* ... */ })
|
||||
// Replace with
|
||||
const isRegistered = protocol.isProtocolRegistered(scheme)
|
||||
const isIntercepted = protocol.isProtocolIntercepted(scheme)
|
||||
```
|
||||
|
||||
## Planned Breaking API Changes (9.0)
|
||||
|
||||
### Default Changed: Loading non-context-aware native modules in the renderer process is disabled by default
|
||||
@@ -119,6 +167,45 @@ you should plan to update your native modules to be context aware.
|
||||
|
||||
For more detailed information see [#18397](https://github.com/electron/electron/issues/18397).
|
||||
|
||||
### Deprecated: `BrowserWindow` extension APIs
|
||||
|
||||
The following extension APIs have been deprecated:
|
||||
* `BrowserWindow.addExtension(path)`
|
||||
* `BrowserWindow.addDevToolsExtension(path)`
|
||||
* `BrowserWindow.removeExtension(name)`
|
||||
* `BrowserWindow.removeDevToolsExtension(name)`
|
||||
* `BrowserWindow.getExtensions()`
|
||||
* `BrowserWindow.getDevToolsExtensions()`
|
||||
|
||||
Use the session APIs instead:
|
||||
* `ses.loadExtension(path)`
|
||||
* `ses.removeExtension(extension_id)`
|
||||
* `ses.getAllExtensions()`
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.addExtension(path)
|
||||
BrowserWindow.addDevToolsExtension(path)
|
||||
// Replace with
|
||||
session.defaultSession.loadExtension(path)
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.removeExtension(name)
|
||||
BrowserWindow.removeDevToolsExtension(name)
|
||||
// Replace with
|
||||
session.defaultSession.removeExtension(extension_id)
|
||||
```
|
||||
|
||||
```js
|
||||
// Deprecated in Electron 9
|
||||
BrowserWindow.getExtensions()
|
||||
BrowserWindow.getDevToolsExtensions()
|
||||
// Replace with
|
||||
session.defaultSession.getAllExtensions()
|
||||
```
|
||||
|
||||
### Removed: `<webview>.getWebContents()`
|
||||
|
||||
This API, which was deprecated in Electron 8.0, is now removed.
|
||||
|
||||
@@ -186,12 +186,12 @@ $ gn gen out/Testing-x86 --args='... target_cpu = "x86"'
|
||||
|
||||
Not all combinations of source and target CPU/OS are supported by Chromium.
|
||||
|
||||
<table>
|
||||
<tr><th>Host</th><th>Target</th><th>Status</th></tr>
|
||||
<tr><td>Windows x64</td><td>Windows arm64</td><td>Experimental</td>
|
||||
<tr><td>Windows x64</td><td>Windows x86</td><td>Automatically tested</td></tr>
|
||||
<tr><td>Linux x64</td><td>Linux x86</td><td>Automatically tested</td></tr>
|
||||
</table>
|
||||
| Host | Target | Status |
|
||||
|-------------|---------------|----------------------|
|
||||
| Windows x64 | Windows arm64 | Experimental |
|
||||
| Windows x64 | Windows x86 | Automatically tested |
|
||||
| Linux x64 | Linux x86 | Automatically tested |
|
||||
|
||||
|
||||
If you test other combinations and find them to work, please update this document :)
|
||||
|
||||
|
||||
@@ -43,8 +43,8 @@ SRV*c:\code\symbols\*https://msdl.microsoft.com/download/symbols;SRV*c:\code\sym
|
||||
|
||||
## Using the symbol server in Visual Studio
|
||||
|
||||
<img src='https://mdn.mozillademos.org/files/733/symbol-server-vc8express-menu.jpg'>
|
||||
<img src='https://mdn.mozillademos.org/files/2497/2005_options.gif'>
|
||||

|
||||

|
||||
|
||||
## Troubleshooting: Symbols will not load
|
||||
|
||||
|
||||
@@ -1,95 +1,95 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('open-error-dialog', event => {
|
||||
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
|
||||
})
|
||||
|
||||
ipcMain.on('open-information-dialog', event => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, index => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('open-file-dialog', event => {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
properties: ['openFile', 'openDirectory']
|
||||
},
|
||||
files => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
ipcMain.on('save-dialog', event => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
|
||||
}
|
||||
dialog.showSaveDialog(options, filename => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('open-error-dialog', event => {
|
||||
dialog.showErrorBox('An Error Message', 'Demonstrating an error message.')
|
||||
})
|
||||
|
||||
ipcMain.on('open-information-dialog', event => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, index => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
|
||||
ipcMain.on('open-file-dialog', event => {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
properties: ['openFile', 'openDirectory']
|
||||
},
|
||||
files => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
ipcMain.on('save-dialog', event => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
|
||||
}
|
||||
dialog.showSaveDialog(options, filename => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
const errorBtn = document.getElementById('error-dialog')
|
||||
|
||||
errorBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-error-dialog')
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
const errorBtn = document.getElementById('error-dialog')
|
||||
|
||||
errorBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-error-dialog')
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,70 +1,70 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on('open-information-dialog', event => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, index => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on('open-information-dialog', event => {
|
||||
const options = {
|
||||
type: 'info',
|
||||
title: 'Information',
|
||||
message: "This is an information dialog. Isn't it nice?",
|
||||
buttons: ['Yes', 'No']
|
||||
}
|
||||
dialog.showMessageBox(options, index => {
|
||||
event.sender.send('information-dialog-selection', index)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const informationBtn = document.getElementById('information-dialog')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
informationBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-information-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('information-dialog-selection', (event, index) => {
|
||||
let message = 'You selected '
|
||||
if (index === 0) message += 'yes.'
|
||||
else message += 'no.'
|
||||
document.getElementById('info-selection').innerHTML = message
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const informationBtn = document.getElementById('information-dialog')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
informationBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-information-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('information-dialog-selection', (event, index) => {
|
||||
let message = 'You selected '
|
||||
if (index === 0) message += 'yes.'
|
||||
else message += 'no.'
|
||||
document.getElementById('info-selection').innerHTML = message
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,70 +1,70 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on('open-file-dialog', event => {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
properties: ['openFile', 'openDirectory']
|
||||
},
|
||||
files => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
ipcMain.on('open-file-dialog', event => {
|
||||
dialog.showOpenDialog(
|
||||
{
|
||||
properties: ['openFile', 'openDirectory']
|
||||
},
|
||||
files => {
|
||||
if (files) {
|
||||
event.sender.send('selected-directory', files)
|
||||
}
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const selectDirBtn = document.getElementById('select-directory')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
selectDirBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-file-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('selected-directory', (event, path) => {
|
||||
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const selectDirBtn = document.getElementById('select-directory')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
selectDirBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('open-file-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('selected-directory', (event, path) => {
|
||||
document.getElementById('selected-file').innerHTML = `You selected: ${path}`
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,66 +1,66 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('save-dialog', event => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
|
||||
}
|
||||
dialog.showSaveDialog(options, filename => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow, ipcMain, dialog } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
ipcMain.on('save-dialog', event => {
|
||||
const options = {
|
||||
title: 'Save an Image',
|
||||
filters: [{ name: 'Images', extensions: ['jpg', 'png', 'gif'] }]
|
||||
}
|
||||
dialog.showSaveDialog(options, filename => {
|
||||
event.sender.send('saved-file', filename)
|
||||
})
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const saveBtn = document.getElementById('save-dialog')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
saveBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('save-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('saved-file', (event, path) => {
|
||||
if (!path) path = 'No path'
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const saveBtn = document.getElementById('save-dialog')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
saveBtn.addEventListener('click', event => {
|
||||
ipcRenderer.send('save-dialog')
|
||||
})
|
||||
|
||||
ipcRenderer.on('saved-file', (event, path) => {
|
||||
if (!path) path = 'No path'
|
||||
document.getElementById('file-saved').innerHTML = `Path selected: ${path}`
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,56 +1,56 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
const { shell } = require('electron')
|
||||
const os = require('os')
|
||||
|
||||
const exLinksBtn = document.getElementById('open-ex-links')
|
||||
const fileManagerBtn = document.getElementById('open-file-manager')
|
||||
|
||||
fileManagerBtn.addEventListener('click', (event) => {
|
||||
shell.showItemInFolder(os.homedir())
|
||||
})
|
||||
|
||||
exLinksBtn.addEventListener('click', (event) => {
|
||||
shell.openExternal('http://electron.atom.io')
|
||||
const { shell } = require('electron')
|
||||
const os = require('os')
|
||||
|
||||
const exLinksBtn = document.getElementById('open-ex-links')
|
||||
const fileManagerBtn = document.getElementById('open-file-manager')
|
||||
|
||||
fileManagerBtn.addEventListener('click', (event) => {
|
||||
shell.showItemInFolder(os.homedir())
|
||||
})
|
||||
|
||||
exLinksBtn.addEventListener('click', (event) => {
|
||||
shell.openExternal('http://electron.atom.io')
|
||||
})
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,29 +1,29 @@
|
||||
const basicNotification = {
|
||||
title: 'Basic Notification',
|
||||
body: 'Short message part'
|
||||
}
|
||||
|
||||
const notification = {
|
||||
title: 'Notification with image',
|
||||
body: 'Short message plus a custom image',
|
||||
icon: 'https://via.placeholder.com/150'
|
||||
}
|
||||
|
||||
const basicNotificationButton = document.getElementById('basic-noti')
|
||||
const notificationButton = document.getElementById('advanced-noti')
|
||||
|
||||
notificationButton.addEventListener('click', () => {
|
||||
const myNotification = new window.Notification(notification.title, notification)
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
})
|
||||
|
||||
basicNotificationButton.addEventListener('click', () => {
|
||||
const myNotification = new window.Notification(basicNotification.title, basicNotification)
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
})
|
||||
const basicNotification = {
|
||||
title: 'Basic Notification',
|
||||
body: 'Short message part'
|
||||
}
|
||||
|
||||
const notification = {
|
||||
title: 'Notification with image',
|
||||
body: 'Short message plus a custom image',
|
||||
icon: 'https://via.placeholder.com/150'
|
||||
}
|
||||
|
||||
const basicNotificationButton = document.getElementById('basic-noti')
|
||||
const notificationButton = document.getElementById('advanced-noti')
|
||||
|
||||
notificationButton.addEventListener('click', () => {
|
||||
const myNotification = new window.Notification(notification.title, notification)
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
})
|
||||
|
||||
basicNotificationButton.addEventListener('click', () => {
|
||||
const myNotification = new window.Notification(basicNotification.title, basicNotification)
|
||||
|
||||
myNotification.onclick = () => {
|
||||
console.log('Notification clicked')
|
||||
}
|
||||
})
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,35 +1,35 @@
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const trayBtn = document.getElementById('put-in-tray')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let trayOn = false
|
||||
|
||||
trayBtn.addEventListener('click', function (event) {
|
||||
if (trayOn) {
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
ipcRenderer.send('remove-tray')
|
||||
} else {
|
||||
trayOn = true
|
||||
const message = 'Click demo again to remove.'
|
||||
document.getElementById('tray-countdown').innerHTML = message
|
||||
ipcRenderer.send('put-in-tray')
|
||||
}
|
||||
})
|
||||
// Tray removed from context menu on icon
|
||||
ipcRenderer.on('tray-removed', function () {
|
||||
ipcRenderer.send('remove-tray')
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
const { ipcRenderer, shell } = require('electron')
|
||||
|
||||
const trayBtn = document.getElementById('put-in-tray')
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let trayOn = false
|
||||
|
||||
trayBtn.addEventListener('click', function (event) {
|
||||
if (trayOn) {
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
ipcRenderer.send('remove-tray')
|
||||
} else {
|
||||
trayOn = true
|
||||
const message = 'Click demo again to remove.'
|
||||
document.getElementById('tray-countdown').innerHTML = message
|
||||
ipcRenderer.send('put-in-tray')
|
||||
}
|
||||
})
|
||||
// Tray removed from context menu on icon
|
||||
ipcRenderer.on('tray-removed', function () {
|
||||
ipcRenderer.send('remove-tray')
|
||||
trayOn = false
|
||||
document.getElementById('tray-countdown').innerHTML = ''
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -1,56 +1,56 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,25 +1,25 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const framelessWindowBtn = document.getElementById('frameless-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
framelessWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
let win = new BrowserWindow({ frame: false })
|
||||
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const framelessWindowBtn = document.getElementById('frameless-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
framelessWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
let win = new BrowserWindow({ frame: false })
|
||||
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,35 +1,35 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const manageWindowBtn = document.getElementById('manage-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let win
|
||||
|
||||
manageWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 400, height: 275 })
|
||||
|
||||
win.on('resize', updateReply)
|
||||
win.on('move', updateReply)
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
function updateReply () {
|
||||
const manageWindowReply = document.getElementById('manage-window-reply')
|
||||
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
|
||||
manageWindowReply.innerText = message
|
||||
}
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const manageWindowBtn = document.getElementById('manage-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let win
|
||||
|
||||
manageWindowBtn.addEventListener('click', (event) => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 400, height: 275 })
|
||||
|
||||
win.on('resize', updateReply)
|
||||
win.on('move', updateReply)
|
||||
win.on('close', () => { win = null })
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
function updateReply () {
|
||||
const manageWindowReply = document.getElementById('manage-window-reply')
|
||||
const message = `Size: ${win.getSize()} Position: ${win.getPosition()}`
|
||||
manageWindowReply.innerText = message
|
||||
}
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -1,56 +1,56 @@
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// Modules to control application life and create native browser window
|
||||
const { app, BrowserWindow } = require('electron')
|
||||
|
||||
// Keep a global reference of the window object, if you don't, the window will
|
||||
// be closed automatically when the JavaScript object is garbage collected.
|
||||
let mainWindow
|
||||
|
||||
function createWindow () {
|
||||
// Create the browser window.
|
||||
mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
}
|
||||
})
|
||||
|
||||
// and load the index.html of the app.
|
||||
mainWindow.loadFile('index.html')
|
||||
|
||||
// Open the DevTools.
|
||||
// mainWindow.webContents.openDevTools()
|
||||
|
||||
// Emitted when the window is closed.
|
||||
mainWindow.on('closed', function () {
|
||||
// Dereference the window object, usually you would store windows
|
||||
// in an array if your app supports multi windows, this is the time
|
||||
// when you should delete the corresponding element.
|
||||
mainWindow = null
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
// Some APIs can only be used after this event occurs.
|
||||
app.whenReady().then(createWindow)
|
||||
|
||||
// Quit when all windows are closed.
|
||||
app.on('window-all-closed', function () {
|
||||
// On macOS it is common for applications and their menu bar
|
||||
// to stay active until the user quits explicitly with Cmd + Q
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit()
|
||||
}
|
||||
})
|
||||
|
||||
app.on('activate', function () {
|
||||
// On macOS it is common to re-create a window in the app when the
|
||||
// dock icon is clicked and there are no other windows open.
|
||||
if (mainWindow === null) {
|
||||
createWindow()
|
||||
}
|
||||
})
|
||||
|
||||
// In this file you can include the rest of your app's specific main process
|
||||
// code. You can also put them in separate files and require them here.
|
||||
|
||||
@@ -1,48 +1,48 @@
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const listenToWindowBtn = document.getElementById('listen-to-window')
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let win
|
||||
|
||||
listenToWindowBtn.addEventListener('click', () => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 600, height: 400 })
|
||||
|
||||
const hideFocusBtn = () => {
|
||||
focusModalBtn.classList.add('disappear')
|
||||
focusModalBtn.classList.remove('smooth-appear')
|
||||
focusModalBtn.removeEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
const showFocusBtn = (btn) => {
|
||||
if (!win) return
|
||||
focusModalBtn.classList.add('smooth-appear')
|
||||
focusModalBtn.classList.remove('disappear')
|
||||
focusModalBtn.addEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
win.on('focus', hideFocusBtn)
|
||||
win.on('blur', showFocusBtn)
|
||||
win.on('close', () => {
|
||||
hideFocusBtn()
|
||||
win = null
|
||||
})
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
const clickHandler = () => { win.focus() }
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
const { BrowserWindow } = require('electron').remote
|
||||
const shell = require('electron').shell
|
||||
|
||||
const listenToWindowBtn = document.getElementById('listen-to-window')
|
||||
const focusModalBtn = document.getElementById('focus-on-modal-window')
|
||||
|
||||
const links = document.querySelectorAll('a[href]')
|
||||
|
||||
let win
|
||||
|
||||
listenToWindowBtn.addEventListener('click', () => {
|
||||
const modalPath = 'https://electronjs.org'
|
||||
win = new BrowserWindow({ width: 600, height: 400 })
|
||||
|
||||
const hideFocusBtn = () => {
|
||||
focusModalBtn.classList.add('disappear')
|
||||
focusModalBtn.classList.remove('smooth-appear')
|
||||
focusModalBtn.removeEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
const showFocusBtn = (btn) => {
|
||||
if (!win) return
|
||||
focusModalBtn.classList.add('smooth-appear')
|
||||
focusModalBtn.classList.remove('disappear')
|
||||
focusModalBtn.addEventListener('click', clickHandler)
|
||||
}
|
||||
|
||||
win.on('focus', hideFocusBtn)
|
||||
win.on('blur', showFocusBtn)
|
||||
win.on('close', () => {
|
||||
hideFocusBtn()
|
||||
win = null
|
||||
})
|
||||
win.loadURL(modalPath)
|
||||
win.show()
|
||||
|
||||
const clickHandler = () => { win.focus() }
|
||||
})
|
||||
|
||||
Array.prototype.forEach.call(links, (link) => {
|
||||
const url = link.getAttribute('href')
|
||||
if (url.indexOf('http') === 0) {
|
||||
link.addEventListener('click', (e) => {
|
||||
e.preventDefault()
|
||||
shell.openExternal(url)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -178,6 +178,7 @@ filenames = {
|
||||
"shell/browser/electron_speech_recognition_manager_delegate.h",
|
||||
"shell/browser/electron_web_ui_controller_factory.cc",
|
||||
"shell/browser/electron_web_ui_controller_factory.h",
|
||||
"shell/browser/extended_web_contents_observer.h",
|
||||
"shell/browser/feature_list.cc",
|
||||
"shell/browser/feature_list.h",
|
||||
"shell/browser/font_defaults.cc",
|
||||
@@ -338,6 +339,7 @@ filenames = {
|
||||
"shell/browser/ui/devtools_manager_delegate.h",
|
||||
"shell/browser/ui/devtools_ui.cc",
|
||||
"shell/browser/ui/devtools_ui.h",
|
||||
"shell/browser/ui/drag_util.cc",
|
||||
"shell/browser/ui/drag_util.h",
|
||||
"shell/browser/ui/drag_util_mac.mm",
|
||||
"shell/browser/ui/drag_util_views.cc",
|
||||
@@ -614,6 +616,8 @@ filenames = {
|
||||
"shell/browser/extensions/api/resources_private/resources_private_api.h",
|
||||
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.cc",
|
||||
"shell/browser/extensions/api/runtime/electron_runtime_api_delegate.h",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.cc",
|
||||
"shell/browser/extensions/api/management/electron_management_api_delegate.h",
|
||||
"shell/browser/extensions/api/tabs/tabs_api.cc",
|
||||
"shell/browser/extensions/api/tabs/tabs_api.h",
|
||||
"shell/browser/extensions/api/streams_private/streams_private_api.cc",
|
||||
|
||||
@@ -16,7 +16,7 @@ if ('getAppLevelAppearance' in systemPreferences) {
|
||||
}
|
||||
|
||||
if ('getEffectiveAppearance' in systemPreferences) {
|
||||
const nativeEAGetter = systemPreferences.getAppLevelAppearance;
|
||||
const nativeEAGetter = systemPreferences.getEffectiveAppearance;
|
||||
Object.defineProperty(SystemPreferences.prototype, 'effectiveAppearance', {
|
||||
get: () => nativeEAGetter.call(systemPreferences)
|
||||
});
|
||||
|
||||
@@ -166,29 +166,29 @@ WebContents.prototype._sendInternalToAll = function (channel, ...args) {
|
||||
|
||||
return this._send(internal, sendToAll, channel, args);
|
||||
};
|
||||
WebContents.prototype.sendToFrame = function (frameId, channel, ...args) {
|
||||
WebContents.prototype.sendToFrame = function (frame, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument');
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument');
|
||||
} else if (!(typeof frame === 'number' || Array.isArray(frame))) {
|
||||
throw new Error('Missing required frame argument (must be number or array)');
|
||||
}
|
||||
|
||||
const internal = false;
|
||||
const sendToAll = false;
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||
return this._sendToFrame(internal, sendToAll, frame, channel, args);
|
||||
};
|
||||
WebContents.prototype._sendToFrameInternal = function (frameId, channel, ...args) {
|
||||
WebContents.prototype._sendToFrameInternal = function (frame, channel, ...args) {
|
||||
if (typeof channel !== 'string') {
|
||||
throw new Error('Missing required channel argument');
|
||||
} else if (typeof frameId !== 'number') {
|
||||
throw new Error('Missing required frameId argument');
|
||||
} else if (!(typeof frame === 'number' || Array.isArray(frame))) {
|
||||
throw new Error('Missing required frame argument (must be number or array)');
|
||||
}
|
||||
|
||||
const internal = true;
|
||||
const sendToAll = false;
|
||||
|
||||
return this._sendToFrame(internal, sendToAll, frameId, channel, args);
|
||||
return this._sendToFrame(internal, sendToAll, frame, channel, args);
|
||||
};
|
||||
|
||||
// Following methods are mapped to webFrame.
|
||||
@@ -437,8 +437,9 @@ WebContents.prototype.loadFile = function (filePath, options = {}) {
|
||||
};
|
||||
|
||||
const addReplyToEvent = (event) => {
|
||||
const { processId, frameId } = event;
|
||||
event.reply = (...args) => {
|
||||
event.sender.sendToFrame(event.frameId, ...args);
|
||||
event.sender.sendToFrame([processId, frameId], ...args);
|
||||
};
|
||||
};
|
||||
|
||||
@@ -459,6 +460,10 @@ const addReturnValueToEvent = (event) => {
|
||||
});
|
||||
};
|
||||
|
||||
const loggingEnabled = () => {
|
||||
return process.env.ELECTRON_ENABLE_LOGGING || app.commandLine.hasSwitch('enable-logging');
|
||||
};
|
||||
|
||||
// Add JavaScript wrappers for WebContents class.
|
||||
WebContents.prototype._init = function () {
|
||||
// The navigation controller.
|
||||
@@ -527,8 +532,13 @@ WebContents.prototype._init = function () {
|
||||
app.emit('renderer-process-crashed', event, this, ...args);
|
||||
});
|
||||
|
||||
this.on('render-process-gone', (event, ...args) => {
|
||||
app.emit('render-process-gone', event, this, ...args);
|
||||
this.on('render-process-gone', (event, details) => {
|
||||
app.emit('render-process-gone', event, this, details);
|
||||
|
||||
// Log out a hint to help users better debug renderer crashes.
|
||||
if (loggingEnabled()) {
|
||||
console.info(`Renderer process ${details.reason} - see https://www.electronjs.org/docs/tutorial/application-debugging for potential debugging information.`);
|
||||
}
|
||||
});
|
||||
|
||||
// The devtools requests the webContents to reload.
|
||||
|
||||
@@ -275,7 +275,7 @@ const fakeConstructor = (constructor: Function, name: string) =>
|
||||
});
|
||||
|
||||
// Convert array of meta data from renderer into array of real values.
|
||||
const unwrapArgs = function (sender: electron.WebContents, frameId: number, contextId: string, args: any[]) {
|
||||
const unwrapArgs = function (sender: electron.WebContents, frameId: [number, number], contextId: string, args: any[]) {
|
||||
const metaToValue = function (meta: MetaTypeFromRenderer): any {
|
||||
switch (meta.type) {
|
||||
case 'nativeimage':
|
||||
@@ -329,7 +329,7 @@ const unwrapArgs = function (sender: electron.WebContents, frameId: number, cont
|
||||
v8Util.setHiddenValue(callIntoRenderer, 'location', meta.location);
|
||||
Object.defineProperty(callIntoRenderer, 'length', { value: meta.length });
|
||||
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, frameId, contextId, meta.id, sender);
|
||||
v8Util.setRemoteCallbackFreer(callIntoRenderer, frameId[0], frameId[1], contextId, meta.id, sender);
|
||||
rendererFunctions.set(objectId, callIntoRenderer);
|
||||
return callIntoRenderer;
|
||||
}
|
||||
@@ -478,7 +478,7 @@ handleRemoteCommand('ELECTRON_BROWSER_CURRENT_WEB_CONTENTS', function (event, co
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const constructor = objectsRegistry.get(id);
|
||||
|
||||
if (constructor == null) {
|
||||
@@ -489,7 +489,7 @@ handleRemoteCommand('ELECTRON_BROWSER_CONSTRUCTOR', function (event, contextId,
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId, id, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const func = objectsRegistry.get(id);
|
||||
|
||||
if (func == null) {
|
||||
@@ -506,7 +506,7 @@ handleRemoteCommand('ELECTRON_BROWSER_FUNCTION_CALL', function (event, contextId
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const object = objectsRegistry.get(id);
|
||||
|
||||
if (object == null) {
|
||||
@@ -517,7 +517,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CONSTRUCTOR', function (event, cont
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId, id, method, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const object = objectsRegistry.get(id);
|
||||
|
||||
if (object == null) {
|
||||
@@ -534,7 +534,7 @@ handleRemoteCommand('ELECTRON_BROWSER_MEMBER_CALL', function (event, contextId,
|
||||
});
|
||||
|
||||
handleRemoteCommand('ELECTRON_BROWSER_MEMBER_SET', function (event, contextId, id, name, args) {
|
||||
args = unwrapArgs(event.sender, event.frameId, contextId, args);
|
||||
args = unwrapArgs(event.sender, [event.processId, event.frameId], contextId, args);
|
||||
const obj = objectsRegistry.get(id);
|
||||
|
||||
if (obj == null) {
|
||||
|
||||
@@ -33,10 +33,10 @@ Object.defineProperty(electronModule, 'exports', {
|
||||
Module._cache['electron'] = electronModule;
|
||||
|
||||
const originalResolveFilename = Module._resolveFilename;
|
||||
Module._resolveFilename = function (request: string, parent: NodeModule, isMain: boolean) {
|
||||
Module._resolveFilename = function (request: string, parent: NodeModule, isMain: boolean, options?: { paths: Array<string>}) {
|
||||
if (request === 'electron') {
|
||||
return 'electron';
|
||||
} else {
|
||||
return originalResolveFilename(request, parent, isMain);
|
||||
return originalResolveFilename(request, parent, isMain, options);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -279,7 +279,7 @@ function metaToError (meta) {
|
||||
}
|
||||
|
||||
function handleMessage (channel, handler) {
|
||||
ipcRendererInternal.on(channel, (event, passedContextId, id, ...args) => {
|
||||
ipcRendererInternal.onMessageFromMain(channel, (event, passedContextId, id, ...args) => {
|
||||
if (passedContextId === contextId) {
|
||||
handler(id, ...args);
|
||||
} else {
|
||||
|
||||
@@ -73,7 +73,7 @@ export function injectTo (extensionId: string, context: any) {
|
||||
|
||||
const chrome = context.chrome = context.chrome || {};
|
||||
|
||||
ipcRendererInternal.on(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, (
|
||||
ipcRendererInternal.onMessageFromMain(`CHROME_RUNTIME_ONCONNECT_${extensionId}`, (
|
||||
_event: Electron.Event, tabId: number, portId: number, connectInfo: { name: string }
|
||||
) => {
|
||||
chrome.runtime.onConnect.emit(new Port(tabId, portId, extensionId, connectInfo.name));
|
||||
@@ -87,11 +87,11 @@ export function injectTo (extensionId: string, context: any) {
|
||||
});
|
||||
});
|
||||
|
||||
ipcRendererInternal.on('CHROME_TABS_ONCREATED', (_event: Electron.Event, tabId: number) => {
|
||||
ipcRendererInternal.onMessageFromMain('CHROME_TABS_ONCREATED', (_event: Electron.Event, tabId: number) => {
|
||||
chrome.tabs.onCreated.emit(new Tab(tabId));
|
||||
});
|
||||
|
||||
ipcRendererInternal.on('CHROME_TABS_ONREMOVED', (_event: Electron.Event, tabId: number) => {
|
||||
ipcRendererInternal.onMessageFromMain('CHROME_TABS_ONREMOVED', (_event: Electron.Event, tabId: number) => {
|
||||
chrome.tabs.onRemoved.emit(tabId);
|
||||
});
|
||||
|
||||
|
||||
@@ -6,11 +6,11 @@ class WebNavigation {
|
||||
private onCompleted = new Event()
|
||||
|
||||
constructor () {
|
||||
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', (event: Electron.IpcRendererEvent, details: any) => {
|
||||
ipcRendererInternal.onMessageFromMain('CHROME_WEBNAVIGATION_ONBEFORENAVIGATE', (event: Electron.IpcRendererEvent, details: any) => {
|
||||
this.onBeforeNavigate.emit(details);
|
||||
});
|
||||
|
||||
ipcRendererInternal.on('CHROME_WEBNAVIGATION_ONCOMPLETED', (event: Electron.IpcRendererEvent, details: any) => {
|
||||
ipcRendererInternal.onMessageFromMain('CHROME_WEBNAVIGATION_ONCOMPLETED', (event: Electron.IpcRendererEvent, details: any) => {
|
||||
this.onCompleted.emit(details);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ import { ipcRendererInternal } from '@electron/internal/renderer/ipc-renderer-in
|
||||
type IPCHandler = (event: Electron.IpcRendererEvent, ...args: any[]) => any
|
||||
|
||||
export const handle = function <T extends IPCHandler> (channel: string, handler: T) {
|
||||
ipcRendererInternal.on(channel, async (event, requestId, ...args) => {
|
||||
ipcRendererInternal.onMessageFromMain(channel, async (event, requestId, ...args) => {
|
||||
const replyChannel = `${channel}_RESPONSE_${requestId}`;
|
||||
try {
|
||||
event.sender.send(replyChannel, null, await handler(event, ...args));
|
||||
|
||||
@@ -29,4 +29,27 @@ if (!ipcRendererInternal.send) {
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
ipcRendererInternal.onMessageFromMain = function (channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void) {
|
||||
return ipcRendererInternal.on(channel, (event, ...args) => {
|
||||
if (event.senderId !== 0) {
|
||||
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
|
||||
return;
|
||||
}
|
||||
|
||||
listener(event, ...args);
|
||||
});
|
||||
};
|
||||
|
||||
ipcRendererInternal.onceMessageFromMain = function (channel: string, listener: (event: Electron.IpcRendererEvent, ...args: any[]) => void) {
|
||||
return ipcRendererInternal.on(channel, function wrapper (event, ...args) {
|
||||
if (event.senderId !== 0) {
|
||||
console.error(`Message ${channel} sent by unexpected WebContents (${event.senderId})`);
|
||||
return;
|
||||
}
|
||||
|
||||
ipcRendererInternal.removeListener(channel, wrapper);
|
||||
listener(event, ...args);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ const WEB_VIEW_EVENTS: Record<string, Array<string>> = {
|
||||
'focus-change': ['focus', 'guestInstanceId'],
|
||||
'close': [],
|
||||
'crashed': [],
|
||||
'render-process-gone': ['details'],
|
||||
'plugin-crashed': ['name', 'version'],
|
||||
'destroyed': [],
|
||||
'page-title-updated': ['title', 'explicitSet'],
|
||||
@@ -66,18 +67,18 @@ const dispatchEvent = function (
|
||||
};
|
||||
|
||||
export function registerEvents (webView: WebViewImpl, viewInstanceId: number) {
|
||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () {
|
||||
ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DESTROY_GUEST-${viewInstanceId}`, function () {
|
||||
webView.guestInstanceId = undefined;
|
||||
webView.reset();
|
||||
const domEvent = new Event('destroyed');
|
||||
webView.dispatchEvent(domEvent);
|
||||
});
|
||||
|
||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) {
|
||||
ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_DISPATCH_EVENT-${viewInstanceId}`, function (event, eventName, ...args) {
|
||||
dispatchEvent(webView, eventName, eventName, ...args);
|
||||
});
|
||||
|
||||
ipcRendererInternal.on(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) {
|
||||
ipcRendererInternal.onMessageFromMain(`ELECTRON_GUEST_VIEW_INTERNAL_IPC_MESSAGE-${viewInstanceId}`, function (event, channel, ...args) {
|
||||
const domEvent = new Event('ipc-message') as IpcMessageEvent;
|
||||
domEvent.channel = channel;
|
||||
domEvent.args = args;
|
||||
|
||||
@@ -180,7 +180,7 @@ class BrowserWindowProxy {
|
||||
this.guestId = guestId;
|
||||
this._location = new LocationProxy(guestId);
|
||||
|
||||
ipcRendererInternal.once(`ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_${guestId}`, () => {
|
||||
ipcRendererInternal.onceMessageFromMain(`ELECTRON_GUEST_WINDOW_MANAGER_WINDOW_CLOSED_${guestId}`, () => {
|
||||
removeProxy(guestId);
|
||||
this.closed = true;
|
||||
});
|
||||
@@ -280,7 +280,7 @@ export const windowSetup = (
|
||||
if (contextIsolationEnabled) internalContextBridge.overrideGlobalValueFromIsolatedWorld(['prompt'], window.prompt);
|
||||
|
||||
if (!usesNativeWindowOpen || openerId != null) {
|
||||
ipcRendererInternal.on('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (
|
||||
ipcRendererInternal.onMessageFromMain('ELECTRON_GUEST_WINDOW_POSTMESSAGE', function (
|
||||
_event, sourceId: number, message: any, sourceOrigin: string
|
||||
) {
|
||||
// Manually dispatch event instead of using postMessage because we also need to
|
||||
@@ -335,7 +335,7 @@ export const windowSetup = (
|
||||
let cachedVisibilityState = isHiddenPage ? 'hidden' : 'visible';
|
||||
|
||||
// Subscribe to visibilityState changes.
|
||||
ipcRendererInternal.on('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', function (_event, visibilityState: VisibilityState) {
|
||||
ipcRendererInternal.onMessageFromMain('ELECTRON_GUEST_INSTANCE_VISIBILITY_CHANGE', function (_event, visibilityState: VisibilityState) {
|
||||
if (cachedVisibilityState !== visibilityState) {
|
||||
cachedVisibilityState = visibilityState;
|
||||
document.dispatchEvent(new Event('visibilitychange'));
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
{
|
||||
"name": "electron",
|
||||
"version": "9.2.0",
|
||||
"version": "9.4.0",
|
||||
"repository": "https://github.com/electron/electron",
|
||||
"description": "Build cross platform desktop apps with JavaScript, HTML, and CSS",
|
||||
"devDependencies": {
|
||||
"@electron/docs-parser": "^0.4.2",
|
||||
"@electron/typescript-definitions": "^8.6.4",
|
||||
"@octokit/auth-app": "^2.10.0",
|
||||
"@octokit/rest": "^16.3.2",
|
||||
"@primer/octicons": "^9.1.1",
|
||||
"@types/basic-auth": "^1.1.2",
|
||||
|
||||
3
patches/angle/.patches
Normal file
3
patches/angle/.patches
Normal file
@@ -0,0 +1,3 @@
|
||||
fix_stale_validation_cache_on_buffer_deletion.patch
|
||||
d3d11_fix_bug_with_static_vertex_attributes.patch
|
||||
cherry-pick-2882e1afd982.patch
|
||||
35
patches/angle/cherry-pick-2882e1afd982.patch
Normal file
35
patches/angle/cherry-pick-2882e1afd982.patch
Normal file
@@ -0,0 +1,35 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 20 Oct 2020 09:45:23 -0400
|
||||
Subject: Fix missing validation cache update on VAO binding.
|
||||
|
||||
Bug: chromium:1139398
|
||||
Change-Id: I85a0d7a72bc2c97b07ebc5f86effd8e36aefd544
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2485581
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
|
||||
index 3233d12dd233786b0988f299ace57d932e0d0fe6..0bdc3f6e5e8ebfcc6bbb2ff1bef57a1d50736368 100644
|
||||
--- a/src/libANGLE/Context.cpp
|
||||
+++ b/src/libANGLE/Context.cpp
|
||||
@@ -8441,6 +8441,7 @@ void StateCache::onVertexArrayBindingChange(Context *context)
|
||||
updateActiveAttribsMask(context);
|
||||
updateVertexElementLimits(context);
|
||||
updateBasicDrawStatesError();
|
||||
+ updateBasicDrawElementsError();
|
||||
}
|
||||
|
||||
void StateCache::onProgramExecutableChange(Context *context)
|
||||
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
|
||||
index 06eeff3b94c937067e674fc127afdeab34e63f21..1e61266921bc7aafb26388b12d0aa1b914c4b5a9 100644
|
||||
--- a/src/libANGLE/Context.h
|
||||
+++ b/src/libANGLE/Context.h
|
||||
@@ -203,6 +203,7 @@ class StateCache final : angle::NonCopyable
|
||||
// 2. onVertexArrayBufferStateChange.
|
||||
// 3. onBufferBindingChange.
|
||||
// 4. onVertexArrayStateChange.
|
||||
+ // 5. onVertexArrayBindingStateChange.
|
||||
intptr_t getBasicDrawElementsError(const Context *context) const
|
||||
{
|
||||
if (mCachedBasicDrawElementsError != kInvalidPointer)
|
||||
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Wed, 22 Jul 2020 13:58:50 -0400
|
||||
Subject: D3D11: Fix bug with static vertex attributes.
|
||||
|
||||
In some specific cases after binding a zero size buffer we could end
|
||||
up trying to use a buffer storage that was no longer valid. Fix this
|
||||
by ensuring we don't flush dirty bits when we have an early exit due
|
||||
to a zero size buffer.
|
||||
|
||||
Also adds a regression test.
|
||||
|
||||
Bug: chromium:1107433
|
||||
Change-Id: I9db560e8dd3699abed2bb7fe6d91060148ba1817
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2314216
|
||||
Commit-Queue: Jamie Madill <jmadill@chromium.org>
|
||||
Reviewed-by: Geoff Lang <geofflang@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp b/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
|
||||
index 5f834b5c8dbc63d3bcc374eca15a17ee442d77e3..b0e27c9f0c6c316fe347a44776a6926b093a81c4 100644
|
||||
--- a/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
|
||||
+++ b/src/libANGLE/renderer/d3d/d3d11/VertexArray11.cpp
|
||||
@@ -250,8 +250,6 @@ angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
|
||||
|
||||
for (size_t dirtyAttribIndex : activeDirtyAttribs)
|
||||
{
|
||||
- mAttribsToTranslate.reset(dirtyAttribIndex);
|
||||
-
|
||||
auto *translatedAttrib = &mTranslatedAttribs[dirtyAttribIndex];
|
||||
const auto ¤tValue = glState.getVertexAttribCurrentValue(dirtyAttribIndex);
|
||||
|
||||
@@ -279,6 +277,9 @@ angle::Result VertexArray11::updateDirtyAttribs(const gl::Context *context,
|
||||
UNREACHABLE();
|
||||
break;
|
||||
}
|
||||
+
|
||||
+ // Make sure we reset the dirty bit after the switch because STATIC can early exit.
|
||||
+ mAttribsToTranslate.reset(dirtyAttribIndex);
|
||||
}
|
||||
|
||||
return angle::Result::Continue;
|
||||
@@ -0,0 +1,39 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Jamie Madill <jmadill@chromium.org>
|
||||
Date: Tue, 14 Jul 2020 17:20:18 -0400
|
||||
Subject: Fix stale validation cache on buffer deletion.
|
||||
|
||||
When we would delete the currently bound element array buffer we
|
||||
would neglect to invalidate a specific validation cache variable.
|
||||
This incorrectly would let us skip buffer size validation and lead
|
||||
to internal invalid memory accesses.
|
||||
|
||||
Bug: chromium:1105202
|
||||
Change-Id: I23ab28ccd3ac6b5d461cb8745b930f4d42d53b35
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2323644
|
||||
Reviewed-by: Jamie Madill <jmadill@chromium.org>
|
||||
|
||||
diff --git a/src/libANGLE/Context.cpp b/src/libANGLE/Context.cpp
|
||||
index d8bccaf1e920e261c45c777993b77b8c40a011ad..3233d12dd233786b0988f299ace57d932e0d0fe6 100644
|
||||
--- a/src/libANGLE/Context.cpp
|
||||
+++ b/src/libANGLE/Context.cpp
|
||||
@@ -8468,6 +8468,7 @@ void StateCache::onVertexArrayStateChange(Context *context)
|
||||
updateActiveAttribsMask(context);
|
||||
updateVertexElementLimits(context);
|
||||
updateBasicDrawStatesError();
|
||||
+ updateBasicDrawElementsError();
|
||||
}
|
||||
|
||||
void StateCache::onVertexArrayBufferStateChange(Context *context)
|
||||
diff --git a/src/libANGLE/Context.h b/src/libANGLE/Context.h
|
||||
index 201010f9f5555faa79cab480a34caf63bf5ffbf2..06eeff3b94c937067e674fc127afdeab34e63f21 100644
|
||||
--- a/src/libANGLE/Context.h
|
||||
+++ b/src/libANGLE/Context.h
|
||||
@@ -202,6 +202,7 @@ class StateCache final : angle::NonCopyable
|
||||
// 1. onActiveTransformFeedbackChange.
|
||||
// 2. onVertexArrayBufferStateChange.
|
||||
// 3. onBufferBindingChange.
|
||||
+ // 4. onVertexArrayStateChange.
|
||||
intptr_t getBasicDrawElementsError(const Context *context) const
|
||||
{
|
||||
if (mCachedBasicDrawElementsError != kInvalidPointer)
|
||||
@@ -81,7 +81,6 @@ feat_allow_disabling_blink_scheduler_throttling_per_renderview.patch
|
||||
accessible_pane_view.patch
|
||||
fixme_grit_conflicts.patch
|
||||
fix_use_the_new_mediaplaypause_key_listener_for_internal_chrome.patch
|
||||
use_electron_resources_in_pdf_util.patch
|
||||
hack_plugin_response_interceptor_to_point_to_electron.patch
|
||||
delay_lock_the_protocol_scheme_registry.patch
|
||||
fix_route_mouse_event_navigations_through_the_web_contents_delegate.patch
|
||||
@@ -117,3 +116,49 @@ backport_1074340.patch
|
||||
backport_1016278.patch
|
||||
backport_1042986.patch
|
||||
a11y_axplatformnodebase_getindexinparent_returns_base_optional.patch
|
||||
worker_feat_add_hook_to_notify_script_ready.patch
|
||||
reconnect_p2p_socket_dispatcher_if_network_service_dies.patch
|
||||
allow_focus_to_move_into_an_editable_combobox_s_listbox.patch
|
||||
cherry-pick-70579363ce7b.patch
|
||||
cherry-pick-138b748dd0a4.patch
|
||||
cherry-pick-9d100199c92b.patch
|
||||
cherry-pick-bee371eeaf66.patch
|
||||
cherry-pick-9746a4cde14a.patch
|
||||
avoid_loading_dri_via_gbm_when_gpumemorybuffers_are_disabled.patch
|
||||
cherry-pick-72ee7c437c88.patch
|
||||
cherry-pick-9ad8c9610d0a.patch
|
||||
indexeddb_fix_crash_in_webidbgetdbnamescallbacksimpl.patch
|
||||
indexeddb_reset_async_tasks_in_webidbgetdbnamescallbacksimpl.patch
|
||||
reland_fix_uaf_in_selecttype.patch
|
||||
cherry-pick-f6cb89728f04.patch
|
||||
backport_1081874.patch
|
||||
backport_1122684.patch
|
||||
backport_1111737.patch
|
||||
cherry-pick-0e61c69ebd47.patch
|
||||
cherry-pick-814a27f8522b.patch
|
||||
cherry-pick-adc731d678c4.patch
|
||||
cherry-pick-52dceba66599.patch
|
||||
cherry-pick-abc6ab85e704.patch
|
||||
avoid_use-after-free.patch
|
||||
cherry-pick-f06a6cb3a38e.patch
|
||||
reland_add_more_checks_for_chrome_debugger_extensions.patch
|
||||
cherry-pick-8629cd7f8af3.patch
|
||||
fix_use_electron_generated_resources.patch
|
||||
cherry-pick-f440137cd96a.patch
|
||||
cherry-pick-30261f9de11e.patch
|
||||
cherry-pick-88f263f401b4.patch
|
||||
cherry-pick-229fdaf8fc05.patch
|
||||
cherry-pick-1ed869ad4bb3.patch
|
||||
cherry-pick-8f24f935c903.patch
|
||||
crashpad-initialize-logging.patch
|
||||
make_macos_os_version_numbers_consistent.patch
|
||||
ignore_renderframehostimpl_detach_for_speculative_rfhs.patch
|
||||
ui_check_that_unpremultiply_is_passed_a_32bpp_image.patch
|
||||
cherry-pick-eec5025668f8.patch
|
||||
cherry-pick-3abc372c9c00.patch
|
||||
cherry-pick-d8d64b7cd244.patch
|
||||
cherry-pick-5ffbb7ed173a.patch
|
||||
propagate_disable-dev-shm-usage_to_child_processes.patch
|
||||
cherry-pick-bbc6ab5bb49c.patch
|
||||
cherry-pick-ecdec1fb0f42.patch
|
||||
fix_setparentacessibile_crash_win.patch
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Aaron Leventhal <aleventhal@chromium.org>
|
||||
Date: Tue, 21 Jul 2020 19:41:11 +0000
|
||||
Subject: Allow focus to move into an editable combobox's listbox
|
||||
|
||||
In bug 593646 (https://codereview.chromium.org/2024053003/) a rule was
|
||||
added, apparently similar to a rule in WebKit, that prevents
|
||||
aria-activedescendant on an editable combobox field from moving focus
|
||||
into its listbox. However, removing this condition fixes an issue where
|
||||
the first item is not read. It also improves the verbalization,
|
||||
providing the user with the positional info, e.g. "2 of 5".
|
||||
Removing this line also does not seem to break the example attached to
|
||||
bug 593646.
|
||||
|
||||
Bug: 1082865
|
||||
Change-Id: I4250fb152f4b06f3c57b300ebe7ef5549c58d624
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2303789
|
||||
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
|
||||
Commit-Queue: Aaron Leventhal <aleventhal@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#790502}
|
||||
|
||||
diff --git a/content/browser/accessibility/browser_accessibility_manager_mac.mm b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
index 33324bbca5953f6f2f9d829e4c7b5d7daa3f49ea..a27cacfd303706ef3ee637107d2de0c8839bfa20 100644
|
||||
--- a/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
+++ b/content/browser/accessibility/browser_accessibility_manager_mac.mm
|
||||
@@ -143,11 +143,6 @@ BrowserAccessibility* BrowserAccessibilityManagerMac::GetFocus() const {
|
||||
if (!focus)
|
||||
return nullptr;
|
||||
|
||||
- // For editable combo boxes, focus should stay on the combo box so the user
|
||||
- // will not be taken out of the combo box while typing.
|
||||
- if (focus->GetRole() == ax::mojom::Role::kTextFieldWithComboBox)
|
||||
- return focus;
|
||||
-
|
||||
// Otherwise, follow the active descendant.
|
||||
return GetActiveDescendant(focus);
|
||||
}
|
||||
diff --git a/content/test/data/accessibility/aria/aria-combobox-expected-mac.txt b/content/test/data/accessibility/aria/aria-combobox-expected-mac.txt
|
||||
index d28f2235dedeedab23bf23db0475087c3d3ec73e..9dd9803232490edb95c80abcb2f084b8c42ceb7e 100644
|
||||
--- a/content/test/data/accessibility/aria/aria-combobox-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/aria/aria-combobox-expected-mac.txt
|
||||
@@ -1,7 +1,7 @@
|
||||
AXWebArea
|
||||
++AXGroup
|
||||
++++AXStaticText AXValue='State'
|
||||
-++AXComboBox AXTitle='State' AXAutocompleteValue='list' AXFocused='1'
|
||||
+++AXComboBox AXTitle='State' AXAutocompleteValue='list'
|
||||
++AXList
|
||||
++++AXStaticText AXValue='Alabama'
|
||||
-++++AXStaticText AXValue='Alaska'
|
||||
\ No newline at end of file
|
||||
+++++AXStaticText AXFocused='1' AXValue='Alaska'
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-collapse-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-collapse-expected-mac.txt
|
||||
index 97c3c417f30812abecdde273f130088df86bd4ae..93ef79e311977bb4277842fa5332f6097faba837 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-collapse-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-collapse-expected-mac.txt
|
||||
@@ -1,2 +1,3 @@
|
||||
AXExpandedChanged on AXComboBox
|
||||
-AXSelectedChildrenChanged on AXComboBox
|
||||
+AXFocusedUIElementChanged on AXComboBox
|
||||
+AXSelectedChildrenChanged on AXComboBox
|
||||
\ No newline at end of file
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-add-list-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-delay-add-list-expected-mac.txt
|
||||
index 47ff72a2689baa23600ededfe38d79fd6b5bedcf..f7d4c30f49fe3f3f62132cddf59942181b8127b8 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-delay-add-list-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-add-list-expected-mac.txt
|
||||
@@ -1 +1,2 @@
|
||||
-AXSelectedChildrenChanged on AXComboBox
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Apple"
|
||||
+AXSelectedChildrenChanged on AXComboBox
|
||||
\ No newline at end of file
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
|
||||
index 47ff72a2689baa23600ededfe38d79fd6b5bedcf..ab757bb0687ff49affcc67076eddd52e18b0eacc 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-delay-show-list-expected-mac.txt
|
||||
@@ -1 +1,2 @@
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Apple"
|
||||
AXSelectedChildrenChanged on AXComboBox
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt
|
||||
index 97cdb8b8b67d46e0a952d22765c823bd346aef3a..343feae3d79a48981cc1e27015ba2a93423eedc0 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-expand-expected-mac.txt
|
||||
@@ -1,3 +1,4 @@
|
||||
AXExpandedChanged on AXComboBox
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Apple"
|
||||
AXSelectedChildrenChanged on AXComboBox
|
||||
-AXSelectedChildrenChanged on AXList
|
||||
+AXSelectedChildrenChanged on AXList
|
||||
\ No newline at end of file
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
index 2bfc70f5fecea2c2a5e7268cef641d6d0e7d4a47..ad5e2bf2c8029185c51eecc94cac1dbe7608c99e 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-focus-expected-mac.txt
|
||||
@@ -1,3 +1,3 @@
|
||||
-AXFocusedUIElementChanged on AXComboBox
|
||||
-AXSelectedTextChanged on AXComboBox
|
||||
-AXSelectedTextChanged on AXWebArea
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Apple not selected"
|
||||
+AXSelectedTextChanged on AXStaticText AXValue="Apple not selected"
|
||||
+AXSelectedTextChanged on AXWebArea
|
||||
\ No newline at end of file
|
||||
diff --git a/content/test/data/accessibility/event/aria-combo-box-next-expected-mac.txt b/content/test/data/accessibility/event/aria-combo-box-next-expected-mac.txt
|
||||
index d5f21183c3d0a1c24cb6665194a93c3299dbfd56..9e7d0c0aaeb1c52dc1f1b3afed36f287851b89ff 100644
|
||||
--- a/content/test/data/accessibility/event/aria-combo-box-next-expected-mac.txt
|
||||
+++ b/content/test/data/accessibility/event/aria-combo-box-next-expected-mac.txt
|
||||
@@ -1,5 +1,7 @@
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Orange"
|
||||
AXSelectedChildrenChanged on AXComboBox
|
||||
AXSelectedChildrenChanged on AXList
|
||||
=== Start Continuation ===
|
||||
+AXFocusedUIElementChanged on AXStaticText AXValue="Banana"
|
||||
AXSelectedChildrenChanged on AXComboBox
|
||||
-AXSelectedChildrenChanged on AXList
|
||||
+AXSelectedChildrenChanged on AXList
|
||||
\ No newline at end of file
|
||||
@@ -0,0 +1,41 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Tom Anderson <thomasanderson@chromium.org>
|
||||
Date: Thu, 21 May 2020 01:20:33 +0000
|
||||
Subject: Avoid loading DRI via GBM when GpuMemoryBuffers are disabled
|
||||
|
||||
We haven't yet whitelisted the necessary dri files in the GPU sandbox,
|
||||
which is leading to issues like 1077609 and 1077626. Since GMBs are
|
||||
not yet supported, avoid loading GBM unless
|
||||
--enable-native-gpu-memory-buffers is passed.
|
||||
|
||||
Bug: 1077609, 1077626, 1031269
|
||||
Change-Id: Ic052d2e89330c6558da86a91b77637229808102f
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2211120
|
||||
Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#770878}
|
||||
|
||||
diff --git a/content/gpu/gpu_main.cc b/content/gpu/gpu_main.cc
|
||||
index 9b22493abbd81c2f592e75fe32f7ab7efbb281d9..d650cef5e081da9cd00896db7d59f00635f13279 100644
|
||||
--- a/content/gpu/gpu_main.cc
|
||||
+++ b/content/gpu/gpu_main.cc
|
||||
@@ -366,11 +366,13 @@ int GpuMain(const MainFunctionParams& parameters) {
|
||||
#if defined(USE_X11)
|
||||
// ui::GbmDevice() takes >50ms with amdgpu, so kick off
|
||||
// GpuMemoryBufferSupportX11 creation on another thread now.
|
||||
- base::PostTask(
|
||||
- FROM_HERE, base::BindOnce([]() {
|
||||
- SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime");
|
||||
- ui::GpuMemoryBufferSupportX11::GetInstance();
|
||||
- }));
|
||||
+ if (gpu_preferences.enable_native_gpu_memory_buffers) {
|
||||
+ base::PostTask(
|
||||
+ FROM_HERE, base::BindOnce([]() {
|
||||
+ SCOPED_UMA_HISTOGRAM_TIMER("Linux.X11.GbmSupportX11CreationTime");
|
||||
+ ui::GpuMemoryBufferSupportX11::GetInstance();
|
||||
+ }));
|
||||
+ }
|
||||
#endif
|
||||
|
||||
if (client)
|
||||
50
patches/chromium/avoid_use-after-free.patch
Normal file
50
patches/chromium/avoid_use-after-free.patch
Normal file
@@ -0,0 +1,50 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bruce Dawson <brucedawson@chromium.org>
|
||||
Date: Thu, 17 Sep 2020 22:34:58 +0000
|
||||
Subject: Avoid use-after-free
|
||||
|
||||
SetNotWaitingForResponse can trigger a message pump which can then free
|
||||
the object which |this| points to. This use-after-free can be avoided by
|
||||
not dereferencing |this| after the call, by ensuring that calling
|
||||
SetNotWaitingForResponse is the last thing done.
|
||||
|
||||
(cherry picked from commit e1c5c8442210bccfbc2475c9bc75a9cf99bb259e)
|
||||
|
||||
Bug: 1125199
|
||||
Change-Id: Ie1289c93112151978e6daaa1d24326770028c529
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2407065
|
||||
Reviewed-by: Alex Moshchuk <alexmos@chromium.org>
|
||||
Commit-Queue: Bruce Dawson <brucedawson@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#806839}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2416264
|
||||
Reviewed-by: Bruce Dawson <brucedawson@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#816}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/content/browser/web_contents/web_contents_impl.cc b/content/browser/web_contents/web_contents_impl.cc
|
||||
index 5b4f85cfadac54fa81a357ebece6f9b274066a29..d300755ec1402d7bd0fb9488a2829962b98853cb 100644
|
||||
--- a/content/browser/web_contents/web_contents_impl.cc
|
||||
+++ b/content/browser/web_contents/web_contents_impl.cc
|
||||
@@ -3409,10 +3409,11 @@ void WebContentsImpl::SetNotWaitingForResponse() {
|
||||
return;
|
||||
|
||||
waiting_for_response_ = false;
|
||||
- if (delegate_)
|
||||
- delegate_->LoadingStateChanged(this, is_load_to_different_document_);
|
||||
for (auto& observer : observers_)
|
||||
observer.DidReceiveResponse();
|
||||
+
|
||||
+ if (delegate_)
|
||||
+ delegate_->LoadingStateChanged(this, is_load_to_different_document_);
|
||||
}
|
||||
|
||||
void WebContentsImpl::SendScreenRects() {
|
||||
@@ -4526,6 +4527,8 @@ void WebContentsImpl::ReadyToCommitNavigation(
|
||||
: false);
|
||||
}
|
||||
|
||||
+ // LoadingStateChanged must be called last in case it triggers deletion of
|
||||
+ // |this| due to recursive message pumps.
|
||||
SetNotWaitingForResponse();
|
||||
}
|
||||
|
||||
549
patches/chromium/backport_1081874.patch
Normal file
549
patches/chromium/backport_1081874.patch
Normal file
@@ -0,0 +1,549 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
||||
Subject: fix: data race on NodeChannel destruction
|
||||
|
||||
[1081874] [High] [CVE-2020-6575]: Double free on NodeChannel
|
||||
Backport https://chromium.googlesource.com/chromium/src/+/5e61913985df0cc621bf72f7fa75e76759ffde15.
|
||||
|
||||
diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
|
||||
index e6fcb96256f6fdb867a362588547a7829f28efe8..6282eed9158c691a9ca49d1ec9a57cedc4392741 100644
|
||||
--- a/mojo/core/BUILD.gn
|
||||
+++ b/mojo/core/BUILD.gn
|
||||
@@ -18,6 +18,7 @@ component("embedder_internal") {
|
||||
":test_sources",
|
||||
"//mojo:*",
|
||||
"//mojo/core/embedder",
|
||||
+ "//mojo/core/test:test_support",
|
||||
]
|
||||
}
|
||||
|
||||
@@ -57,6 +58,7 @@ template("core_impl_source_set") {
|
||||
"handle_table.h",
|
||||
"invitation_dispatcher.h",
|
||||
"message_pipe_dispatcher.h",
|
||||
+ "node_channel.h",
|
||||
"node_controller.h",
|
||||
"options_validation.h",
|
||||
"platform_handle_dispatcher.h",
|
||||
@@ -86,7 +88,6 @@ template("core_impl_source_set") {
|
||||
"invitation_dispatcher.cc",
|
||||
"message_pipe_dispatcher.cc",
|
||||
"node_channel.cc",
|
||||
- "node_channel.h",
|
||||
"node_controller.cc",
|
||||
"platform_handle_dispatcher.cc",
|
||||
"platform_handle_in_transit.cc",
|
||||
@@ -289,6 +290,7 @@ source_set("test_sources") {
|
||||
"handle_table_unittest.cc",
|
||||
"message_pipe_unittest.cc",
|
||||
"message_unittest.cc",
|
||||
+ "node_channel_unittest.cc",
|
||||
"options_validation_unittest.cc",
|
||||
"platform_handle_dispatcher_unittest.cc",
|
||||
"quota_unittest.cc",
|
||||
@@ -387,6 +389,7 @@ fuzzer_test("mojo_core_node_channel_fuzzer") {
|
||||
deps = [
|
||||
":core_impl_for_fuzzers",
|
||||
"//base",
|
||||
+ "//mojo/core/test:test_support",
|
||||
"//mojo/public/cpp/platform",
|
||||
]
|
||||
}
|
||||
diff --git a/mojo/core/embedder/embedder.cc b/mojo/core/embedder/embedder.cc
|
||||
index ec68e37d09888f672759f79961e3e6e4d18f0c5c..f70c73be4df529cce09cb503dfce28f2a04e7e1a 100644
|
||||
--- a/mojo/core/embedder/embedder.cc
|
||||
+++ b/mojo/core/embedder/embedder.cc
|
||||
@@ -35,7 +35,7 @@ void SetDefaultProcessErrorCallback(ProcessErrorCallback callback) {
|
||||
Core::Get()->SetDefaultProcessErrorCallback(std::move(callback));
|
||||
}
|
||||
|
||||
-scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
|
||||
+scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
|
||||
return Core::Get()->GetNodeController()->io_task_runner();
|
||||
}
|
||||
|
||||
diff --git a/mojo/core/embedder/embedder.h b/mojo/core/embedder/embedder.h
|
||||
index 5d65400987728940a296ba2a84d40158f52d6d34..96dc44c0a78e0e6cb6e5aa511bd2fd4f1252cf16 100644
|
||||
--- a/mojo/core/embedder/embedder.h
|
||||
+++ b/mojo/core/embedder/embedder.h
|
||||
@@ -13,7 +13,7 @@
|
||||
#include "base/component_export.h"
|
||||
#include "base/memory/ref_counted.h"
|
||||
#include "base/process/process_handle.h"
|
||||
-#include "base/task_runner.h"
|
||||
+#include "base/single_thread_task_runner.h"
|
||||
#include "build/build_config.h"
|
||||
#include "mojo/core/embedder/configuration.h"
|
||||
|
||||
@@ -42,9 +42,10 @@ void SetDefaultProcessErrorCallback(ProcessErrorCallback callback);
|
||||
|
||||
// Initialialization/shutdown for interprocess communication (IPC) -------------
|
||||
|
||||
-// Retrieves the TaskRunner used for IPC I/O, as set by ScopedIPCSupport.
|
||||
+// Retrieves the SequencedTaskRunner used for IPC I/O, as set by
|
||||
+// ScopedIPCSupport.
|
||||
COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
|
||||
-scoped_refptr<base::TaskRunner> GetIOTaskRunner();
|
||||
+scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner();
|
||||
|
||||
} // namespace core
|
||||
} // namespace mojo
|
||||
diff --git a/mojo/core/node_channel.cc b/mojo/core/node_channel.cc
|
||||
index e898b044286e019b5e423b941502030ce3094582..061ea1026e95d1b1f80a762ce377aebdd97e1b42 100644
|
||||
--- a/mojo/core/node_channel.cc
|
||||
+++ b/mojo/core/node_channel.cc
|
||||
@@ -228,7 +228,7 @@ void NodeChannel::NotifyBadMessage(const std::string& error) {
|
||||
}
|
||||
|
||||
void NodeChannel::SetRemoteProcessHandle(ScopedProcessHandle process_handle) {
|
||||
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
{
|
||||
base::AutoLock lock(channel_lock_);
|
||||
if (channel_)
|
||||
@@ -253,7 +253,7 @@ ScopedProcessHandle NodeChannel::CloneRemoteProcessHandle() {
|
||||
}
|
||||
|
||||
void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
|
||||
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
remote_node_name_ = name;
|
||||
}
|
||||
|
||||
@@ -468,15 +468,15 @@ NodeChannel::NodeChannel(
|
||||
Channel::HandlePolicy channel_handle_policy,
|
||||
scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
|
||||
const ProcessErrorCallback& process_error_callback)
|
||||
- : delegate_(delegate),
|
||||
- io_task_runner_(io_task_runner),
|
||||
+ : base::RefCountedDeleteOnSequence<NodeChannel>(io_task_runner),
|
||||
+ delegate_(delegate),
|
||||
process_error_callback_(process_error_callback)
|
||||
#if !defined(OS_NACL_SFI)
|
||||
,
|
||||
channel_(Channel::Create(this,
|
||||
std::move(connection_params),
|
||||
channel_handle_policy,
|
||||
- io_task_runner_))
|
||||
+ std::move(io_task_runner)))
|
||||
#endif
|
||||
{
|
||||
}
|
||||
@@ -499,15 +499,10 @@ void NodeChannel::CreateAndBindLocalBrokerHost(
|
||||
void NodeChannel::OnChannelMessage(const void* payload,
|
||||
size_t payload_size,
|
||||
std::vector<PlatformHandle> handles) {
|
||||
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
|
||||
RequestContext request_context(RequestContext::Source::SYSTEM);
|
||||
|
||||
- // Ensure this NodeChannel stays alive through the extent of this method. The
|
||||
- // delegate may have the only other reference to this object and it may choose
|
||||
- // to drop it here in response to, e.g., a malformed message.
|
||||
- scoped_refptr<NodeChannel> keepalive = this;
|
||||
-
|
||||
if (payload_size <= sizeof(Header)) {
|
||||
delegate_->OnChannelError(remote_node_name_, this);
|
||||
return;
|
||||
@@ -739,7 +734,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
|
||||
}
|
||||
|
||||
void NodeChannel::OnChannelError(Channel::Error error) {
|
||||
- DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
|
||||
+ DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
|
||||
|
||||
RequestContext request_context(RequestContext::Source::SYSTEM);
|
||||
|
||||
diff --git a/mojo/core/node_channel.h b/mojo/core/node_channel.h
|
||||
index ea91f927049befa258884b13e7f7966c09518687..04501da0fb6cd36df1b332135282104dd442b41e 100644
|
||||
--- a/mojo/core/node_channel.h
|
||||
+++ b/mojo/core/node_channel.h
|
||||
@@ -11,7 +11,7 @@
|
||||
#include "base/callback.h"
|
||||
#include "base/containers/queue.h"
|
||||
#include "base/macros.h"
|
||||
-#include "base/memory/ref_counted.h"
|
||||
+#include "base/memory/ref_counted_delete_on_sequence.h"
|
||||
#include "base/process/process_handle.h"
|
||||
#include "base/single_thread_task_runner.h"
|
||||
#include "base/synchronization/lock.h"
|
||||
@@ -21,13 +21,15 @@
|
||||
#include "mojo/core/embedder/process_error_callback.h"
|
||||
#include "mojo/core/ports/name.h"
|
||||
#include "mojo/core/scoped_process_handle.h"
|
||||
+#include "mojo/core/system_impl_export.h"
|
||||
|
||||
namespace mojo {
|
||||
namespace core {
|
||||
|
||||
// Wraps a Channel to send and receive Node control messages.
|
||||
-class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
|
||||
- public Channel::Delegate {
|
||||
+class MOJO_SYSTEM_IMPL_EXPORT NodeChannel
|
||||
+ : public base::RefCountedDeleteOnSequence<NodeChannel>,
|
||||
+ public Channel::Delegate {
|
||||
public:
|
||||
class Delegate {
|
||||
public:
|
||||
@@ -92,8 +94,6 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
|
||||
void** data,
|
||||
size_t* num_data_bytes);
|
||||
|
||||
- Channel* channel() const { return channel_.get(); }
|
||||
-
|
||||
// Start receiving messages.
|
||||
void Start();
|
||||
|
||||
@@ -155,7 +155,8 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
|
||||
#endif
|
||||
|
||||
private:
|
||||
- friend class base::RefCountedThreadSafe<NodeChannel>;
|
||||
+ friend class base::RefCountedDeleteOnSequence<NodeChannel>;
|
||||
+ friend class base::DeleteHelper<NodeChannel>;
|
||||
|
||||
using PendingMessageQueue = base::queue<Channel::MessagePtr>;
|
||||
using PendingRelayMessageQueue =
|
||||
@@ -181,13 +182,12 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
|
||||
void WriteChannelMessage(Channel::MessagePtr message);
|
||||
|
||||
Delegate* const delegate_;
|
||||
- const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
|
||||
const ProcessErrorCallback process_error_callback_;
|
||||
|
||||
base::Lock channel_lock_;
|
||||
- scoped_refptr<Channel> channel_;
|
||||
+ scoped_refptr<Channel> channel_ GUARDED_BY(channel_lock_);
|
||||
|
||||
- // Must only be accessed from |io_task_runner_|'s thread.
|
||||
+ // Must only be accessed from the owning task runner's thread.
|
||||
ports::NodeName remote_node_name_;
|
||||
|
||||
base::Lock remote_process_handle_lock_;
|
||||
diff --git a/mojo/core/node_channel_fuzzer.cc b/mojo/core/node_channel_fuzzer.cc
|
||||
index 99047c000dbe6be90f1d28b4b6817e608f9853a6..54fe757e0dec8aa138af96aa1a0afe596563c26c 100644
|
||||
--- a/mojo/core/node_channel_fuzzer.cc
|
||||
+++ b/mojo/core/node_channel_fuzzer.cc
|
||||
@@ -14,6 +14,7 @@
|
||||
#include "mojo/core/connection_params.h"
|
||||
#include "mojo/core/entrypoints.h"
|
||||
#include "mojo/core/node_channel.h" // nogncheck
|
||||
+#include "mojo/core/test/mock_node_channel_delegate.h"
|
||||
#include "mojo/public/cpp/platform/platform_channel.h"
|
||||
|
||||
#if defined(OS_WIN)
|
||||
@@ -24,60 +25,6 @@ using mojo::core::Channel;
|
||||
using mojo::core::ConnectionParams;
|
||||
using mojo::core::ports::NodeName;
|
||||
|
||||
-// Implementation of NodeChannel::Delegate which does nothing. All of the
|
||||
-// interesting NodeChannel control message message parsing is done by
|
||||
-// NodeChannel by the time any of the delegate methods are invoked, so there's
|
||||
-// no need for this to do any work.
|
||||
-class FakeNodeChannelDelegate : public mojo::core::NodeChannel::Delegate {
|
||||
- public:
|
||||
- FakeNodeChannelDelegate() = default;
|
||||
- ~FakeNodeChannelDelegate() override = default;
|
||||
-
|
||||
- void OnAcceptInvitee(const NodeName& from_node,
|
||||
- const NodeName& inviter_name,
|
||||
- const NodeName& token) override {}
|
||||
- void OnAcceptInvitation(const NodeName& from_node,
|
||||
- const NodeName& token,
|
||||
- const NodeName& invitee_name) override {}
|
||||
- void OnAddBrokerClient(const NodeName& from_node,
|
||||
- const NodeName& client_name,
|
||||
- base::ProcessHandle process_handle) override {}
|
||||
- void OnBrokerClientAdded(const NodeName& from_node,
|
||||
- const NodeName& client_name,
|
||||
- mojo::PlatformHandle broker_channel) override {}
|
||||
- void OnAcceptBrokerClient(const NodeName& from_node,
|
||||
- const NodeName& broker_name,
|
||||
- mojo::PlatformHandle broker_channel) override {}
|
||||
- void OnEventMessage(const NodeName& from_node,
|
||||
- Channel::MessagePtr message) override {}
|
||||
- void OnRequestPortMerge(
|
||||
- const NodeName& from_node,
|
||||
- const mojo::core::ports::PortName& connector_port_name,
|
||||
- const std::string& token) override {}
|
||||
- void OnRequestIntroduction(const NodeName& from_node,
|
||||
- const NodeName& name) override {}
|
||||
- void OnIntroduce(const NodeName& from_node,
|
||||
- const NodeName& name,
|
||||
- mojo::PlatformHandle channel_handle) override {}
|
||||
- void OnBroadcast(const NodeName& from_node,
|
||||
- Channel::MessagePtr message) override {}
|
||||
-#if defined(OS_WIN)
|
||||
- void OnRelayEventMessage(const NodeName& from_node,
|
||||
- base::ProcessHandle from_process,
|
||||
- const NodeName& destination,
|
||||
- Channel::MessagePtr message) override {}
|
||||
- void OnEventMessageFromRelay(const NodeName& from_node,
|
||||
- const NodeName& source_node,
|
||||
- Channel::MessagePtr message) override {}
|
||||
-#endif
|
||||
- void OnAcceptPeer(const NodeName& from_node,
|
||||
- const NodeName& token,
|
||||
- const NodeName& peer_name,
|
||||
- const mojo::core::ports::PortName& port_name) override {}
|
||||
- void OnChannelError(const NodeName& node,
|
||||
- mojo::core::NodeChannel* channel) override {}
|
||||
-};
|
||||
-
|
||||
// A fake delegate for the sending Channel endpoint. The sending Channel is not
|
||||
// being fuzzed and won't receive any interesting messages, so this doesn't need
|
||||
// to do anything.
|
||||
@@ -109,7 +56,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
|
||||
// used to carry messages between processes.
|
||||
mojo::PlatformChannel channel;
|
||||
|
||||
- FakeNodeChannelDelegate receiver_delegate;
|
||||
+ mojo::core::MockNodeChannelDelegate receiver_delegate;
|
||||
auto receiver = mojo::core::NodeChannel::Create(
|
||||
&receiver_delegate, ConnectionParams(channel.TakeLocalEndpoint()),
|
||||
Channel::HandlePolicy::kRejectHandles,
|
||||
diff --git a/mojo/core/node_channel_unittest.cc b/mojo/core/node_channel_unittest.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..13c46f13fea6342316534a7a843debbf7586108d
|
||||
--- /dev/null
|
||||
+++ b/mojo/core/node_channel_unittest.cc
|
||||
@@ -0,0 +1,72 @@
|
||||
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "mojo/core/node_channel.h"
|
||||
+
|
||||
+#include "base/bind_helpers.h"
|
||||
+#include "base/memory/scoped_refptr.h"
|
||||
+#include "base/message_loop/message_pump_type.h"
|
||||
+#include "base/test/task_environment.h"
|
||||
+#include "base/threading/thread.h"
|
||||
+#include "mojo/core/embedder/embedder.h"
|
||||
+#include "mojo/core/test/mock_node_channel_delegate.h"
|
||||
+#include "mojo/public/cpp/platform/platform_channel.h"
|
||||
+#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
|
||||
+#include "testing/gtest/include/gtest/gtest.h"
|
||||
+
|
||||
+namespace mojo {
|
||||
+namespace core {
|
||||
+namespace {
|
||||
+
|
||||
+using NodeChannelTest = testing::Test;
|
||||
+using ports::NodeName;
|
||||
+
|
||||
+scoped_refptr<NodeChannel> CreateNodeChannel(NodeChannel::Delegate* delegate,
|
||||
+ PlatformChannelEndpoint endpoint) {
|
||||
+ return NodeChannel::Create(delegate, ConnectionParams(std::move(endpoint)),
|
||||
+ Channel::HandlePolicy::kAcceptHandles,
|
||||
+ GetIOTaskRunner(), base::NullCallback());
|
||||
+}
|
||||
+
|
||||
+TEST_F(NodeChannelTest, DestructionIsSafe) {
|
||||
+ // Regression test for https://crbug.com/1081874.
|
||||
+ base::test::TaskEnvironment task_environment;
|
||||
+
|
||||
+ PlatformChannel channel;
|
||||
+ MockNodeChannelDelegate local_delegate;
|
||||
+ auto local_channel =
|
||||
+ CreateNodeChannel(&local_delegate, channel.TakeLocalEndpoint());
|
||||
+ local_channel->Start();
|
||||
+ MockNodeChannelDelegate remote_delegate;
|
||||
+ auto remote_channel =
|
||||
+ CreateNodeChannel(&remote_delegate, channel.TakeRemoteEndpoint());
|
||||
+ remote_channel->Start();
|
||||
+
|
||||
+ // Verify end-to-end operation
|
||||
+ const NodeName kRemoteNodeName{123, 456};
|
||||
+ const NodeName kToken{987, 654};
|
||||
+ base::RunLoop loop;
|
||||
+ EXPECT_CALL(local_delegate,
|
||||
+ OnAcceptInvitee(ports::kInvalidNodeName, kRemoteNodeName, kToken))
|
||||
+ .WillRepeatedly([&] { loop.Quit(); });
|
||||
+ remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
|
||||
+ loop.Run();
|
||||
+
|
||||
+ // Now send another message to the local endpoint but tear it down
|
||||
+ // immediately. This will race with the message being received on the IO
|
||||
+ // thread, and although the corresponding delegate call may or may not
|
||||
+ // dispatch as a result, the race should still be memory-safe.
|
||||
+ remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
|
||||
+
|
||||
+ base::RunLoop error_loop;
|
||||
+ EXPECT_CALL(remote_delegate, OnChannelError).WillOnce([&] {
|
||||
+ error_loop.Quit();
|
||||
+ });
|
||||
+ local_channel.reset();
|
||||
+ error_loop.Run();
|
||||
+}
|
||||
+
|
||||
+} // namespace
|
||||
+} // namespace core
|
||||
+} // namespace mojo
|
||||
diff --git a/mojo/core/test/BUILD.gn b/mojo/core/test/BUILD.gn
|
||||
index 1abadfc503d5176d2af1dcecfde153f17488546d..9429c61853059e10ca2430ad79ec8d9a39d90906 100644
|
||||
--- a/mojo/core/test/BUILD.gn
|
||||
+++ b/mojo/core/test/BUILD.gn
|
||||
@@ -7,6 +7,8 @@ import("//third_party/protobuf/proto_library.gni")
|
||||
static_library("test_support") {
|
||||
testonly = true
|
||||
sources = [
|
||||
+ "mock_node_channel_delegate.cc",
|
||||
+ "mock_node_channel_delegate.h",
|
||||
"mojo_test_base.cc",
|
||||
"mojo_test_base.h",
|
||||
"test_utils.h",
|
||||
@@ -27,8 +29,10 @@ static_library("test_support") {
|
||||
public_deps = [
|
||||
"//base",
|
||||
"//base/test:test_support",
|
||||
+ "//mojo/core:embedder_internal",
|
||||
"//mojo/core/embedder",
|
||||
"//mojo/public/cpp/system",
|
||||
+ "//testing/gmock",
|
||||
"//testing/gtest",
|
||||
]
|
||||
}
|
||||
diff --git a/mojo/core/test/mock_node_channel_delegate.cc b/mojo/core/test/mock_node_channel_delegate.cc
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..d257c3e1dc03857f91e94807328a0dc176f332f4
|
||||
--- /dev/null
|
||||
+++ b/mojo/core/test/mock_node_channel_delegate.cc
|
||||
@@ -0,0 +1,15 @@
|
||||
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#include "mojo/core/test/mock_node_channel_delegate.h"
|
||||
+
|
||||
+namespace mojo {
|
||||
+namespace core {
|
||||
+
|
||||
+MockNodeChannelDelegate::MockNodeChannelDelegate() = default;
|
||||
+
|
||||
+MockNodeChannelDelegate::~MockNodeChannelDelegate() = default;
|
||||
+
|
||||
+} // namespace core
|
||||
+} // namespace mojo
|
||||
diff --git a/mojo/core/test/mock_node_channel_delegate.h b/mojo/core/test/mock_node_channel_delegate.h
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..06ca96857b9472682d577a802c68a56a7af0aacd
|
||||
--- /dev/null
|
||||
+++ b/mojo/core/test/mock_node_channel_delegate.h
|
||||
@@ -0,0 +1,114 @@
|
||||
+// Copyright 2020 The Chromium Authors. All rights reserved.
|
||||
+// Use of this source code is governed by a BSD-style license that can be
|
||||
+// found in the LICENSE file.
|
||||
+
|
||||
+#ifndef MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_
|
||||
+#define MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_
|
||||
+
|
||||
+#include "build/build_config.h"
|
||||
+#include "mojo/core/node_channel.h"
|
||||
+#include "testing/gmock/include/gmock/gmock.h"
|
||||
+
|
||||
+namespace mojo {
|
||||
+namespace core {
|
||||
+
|
||||
+// A NodeChannel Delegate implementation which can be used by NodeChannel unit
|
||||
+// tests and fuzzers.
|
||||
+class MockNodeChannelDelegate
|
||||
+ : public testing::NiceMock<NodeChannel::Delegate> {
|
||||
+ public:
|
||||
+ using NodeName = ports::NodeName;
|
||||
+ using PortName = ports::PortName;
|
||||
+
|
||||
+ MockNodeChannelDelegate();
|
||||
+ MockNodeChannelDelegate(const MockNodeChannelDelegate&) = delete;
|
||||
+ MockNodeChannelDelegate& operator=(const MockNodeChannelDelegate&) = delete;
|
||||
+ ~MockNodeChannelDelegate() override;
|
||||
+
|
||||
+ // testing::NiceMock<NodeChannel::Delegate> implementation:
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnAcceptInvitee,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& inviter_name,
|
||||
+ const NodeName& token),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnAcceptInvitation,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& token,
|
||||
+ const NodeName& invitee_name),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnAddBrokerClient,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& client_name,
|
||||
+ base::ProcessHandle process_handle),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnBrokerClientAdded,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& client_name,
|
||||
+ PlatformHandle broker_channel),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnAcceptBrokerClient,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& broker_name,
|
||||
+ PlatformHandle broker_channel),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnEventMessage,
|
||||
+ (const NodeName& from_node, Channel::MessagePtr message),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnRequestPortMerge,
|
||||
+ (const NodeName& from_node,
|
||||
+ const PortName& connector_port_name,
|
||||
+ const std::string& token),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnRequestIntroduction,
|
||||
+ (const NodeName& from_node, const NodeName& name),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnIntroduce,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& name,
|
||||
+ PlatformHandle channel_handle),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnBroadcast,
|
||||
+ (const NodeName& from_node, Channel::MessagePtr message),
|
||||
+ (override));
|
||||
+#if defined(OS_WIN)
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnRelayEventMessage,
|
||||
+ (const NodeName& from_node,
|
||||
+ base::ProcessHandle from_process,
|
||||
+ const NodeName& destination,
|
||||
+ Channel::MessagePtr message),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnEventMessageFromRelay,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& source_node,
|
||||
+ Channel::MessagePtr message),
|
||||
+ (override));
|
||||
+#endif
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnAcceptPeer,
|
||||
+ (const NodeName& from_node,
|
||||
+ const NodeName& token,
|
||||
+ const NodeName& peer_name,
|
||||
+ const PortName& port_name),
|
||||
+ (override));
|
||||
+ MOCK_METHOD(void,
|
||||
+ OnChannelError,
|
||||
+ (const NodeName& node, NodeChannel* channel),
|
||||
+ (override));
|
||||
+};
|
||||
+
|
||||
+} // namespace core
|
||||
+} // namespace mojo
|
||||
+
|
||||
+#endif // MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_
|
||||
23
patches/chromium/backport_1111737.patch
Normal file
23
patches/chromium/backport_1111737.patch
Normal file
@@ -0,0 +1,23 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
||||
Subject: fix: remove references to launched device before it is reset
|
||||
|
||||
[1111737] [High] [CVE-2020-6576]: Security: OffscreenCanvas - Use After Free in OffscreenCanvasRenderingContext2D::DrawTextInternal()
|
||||
Backport https://chromium.googlesource.com/chromium/src/+/1283160e334f78c5eed4668d95e04f2ed2e2a4a3.
|
||||
|
||||
diff --git a/content/browser/renderer_host/media/video_capture_controller.cc b/content/browser/renderer_host/media/video_capture_controller.cc
|
||||
index 8a3f1c3be3d804e3879a8a6aa5921bee99b0879e..85ed13b0008c58ba45cc28be36441234d928ed30 100644
|
||||
--- a/content/browser/renderer_host/media/video_capture_controller.cc
|
||||
+++ b/content/browser/renderer_host/media/video_capture_controller.cc
|
||||
@@ -709,6 +709,10 @@ void VideoCaptureController::ReleaseDeviceAsync(base::OnceClosure done_cb) {
|
||||
device_launcher_->AbortLaunch();
|
||||
return;
|
||||
}
|
||||
+ // |buffer_contexts_| contain references to |launched_device_| as observers.
|
||||
+ // Clear those observer references prior to resetting |launced_device_|.
|
||||
+ for (auto& entry : buffer_contexts_)
|
||||
+ entry.set_consumer_feedback_observer(nullptr);
|
||||
launched_device_.reset();
|
||||
}
|
||||
|
||||
149
patches/chromium/backport_1122684.patch
Normal file
149
patches/chromium/backport_1122684.patch
Normal file
@@ -0,0 +1,149 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Cheng Zhao <zcbenz@gmail.com>
|
||||
Date: Thu, 4 Oct 2018 14:57:02 -0700
|
||||
Subject: fix: elide headers in QuicHttp3Logger
|
||||
|
||||
[1122684] [High] [CVE-2020-15959]: Insufficient policy enforcement in networking.
|
||||
Backport https://chromium.googlesource.com/chromium/src/+/c1a7439efcc7626c34d3e38503c974e4c215c489.
|
||||
|
||||
diff --git a/net/quic/quic_http3_logger.cc b/net/quic/quic_http3_logger.cc
|
||||
index 8240046a419ed41fa340c106f45d6e9468ec7bf9..4cebe54bce4df8daaffe1a31f07ffe431a96bff6 100644
|
||||
--- a/net/quic/quic_http3_logger.cc
|
||||
+++ b/net/quic/quic_http3_logger.cc
|
||||
@@ -9,10 +9,13 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/metrics/histogram_macros.h"
|
||||
+#include "base/strings/strcat.h"
|
||||
#include "base/strings/string_number_conversions.h"
|
||||
+#include "net/http/http_log_util.h"
|
||||
#include "net/log/net_log_capture_mode.h"
|
||||
#include "net/log/net_log_event_type.h"
|
||||
#include "net/log/net_log_values.h"
|
||||
+#include "net/spdy/spdy_log_util.h"
|
||||
|
||||
namespace net {
|
||||
|
||||
@@ -64,20 +67,19 @@ base::Value NetLogThreeIntParams(base::StringPiece name1,
|
||||
return dict;
|
||||
}
|
||||
|
||||
-base::Value NetLogHeadersToDict(const quic::QuicHeaderList& headers) {
|
||||
- base::Value dict(base::Value::Type::DICTIONARY);
|
||||
- for (auto header : headers) {
|
||||
- dict.SetStringKey(header.first, header.second);
|
||||
- }
|
||||
- return dict;
|
||||
-}
|
||||
-
|
||||
-base::Value NetLogHeadersToDict(const spdy::SpdyHeaderBlock& headers) {
|
||||
- base::Value dict(base::Value::Type::DICTIONARY);
|
||||
- for (auto header : headers) {
|
||||
- dict.SetStringKey(header.first, header.second);
|
||||
+base::ListValue ElideQuicHeaderListForNetLog(
|
||||
+ const quic::QuicHeaderList& headers,
|
||||
+ NetLogCaptureMode capture_mode) {
|
||||
+ base::ListValue headers_list;
|
||||
+ for (const auto& header : headers) {
|
||||
+ base::StringPiece key = header.first;
|
||||
+ base::StringPiece value = header.second;
|
||||
+ headers_list.Append(NetLogStringValue(
|
||||
+ base::StrCat({key, ": ",
|
||||
+ ElideHeaderValueForNetLog(capture_mode, key.as_string(),
|
||||
+ value.as_string())})));
|
||||
}
|
||||
- return dict;
|
||||
+ return headers_list;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -235,11 +237,13 @@ void QuicHttp3Logger::OnHeadersDecoded(quic::QuicStreamId stream_id,
|
||||
return;
|
||||
}
|
||||
net_log_.AddEvent(
|
||||
- NetLogEventType::HTTP3_HEADERS_DECODED, [stream_id, &headers] {
|
||||
+ NetLogEventType::HTTP3_HEADERS_DECODED,
|
||||
+ [stream_id, &headers](NetLogCaptureMode capture_mode) {
|
||||
base::Value dict(base::Value::Type::DICTIONARY);
|
||||
dict.SetKey("stream_id",
|
||||
NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
- dict.SetKey("headers", NetLogHeadersToDict(headers));
|
||||
+ dict.SetKey("headers",
|
||||
+ ElideQuicHeaderListForNetLog(headers, capture_mode));
|
||||
return dict;
|
||||
});
|
||||
}
|
||||
@@ -266,16 +270,18 @@ void QuicHttp3Logger::OnPushPromiseDecoded(quic::QuicStreamId stream_id,
|
||||
if (!net_log_.IsCapturing()) {
|
||||
return;
|
||||
}
|
||||
- net_log_.AddEvent(NetLogEventType::HTTP3_PUSH_PROMISE_DECODED, [stream_id,
|
||||
- push_id,
|
||||
- &headers] {
|
||||
- base::Value dict(base::Value::Type::DICTIONARY);
|
||||
- dict.SetKey("stream_id",
|
||||
- NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
- dict.SetKey("push_id", NetLogNumberValue(static_cast<uint64_t>(push_id)));
|
||||
- dict.SetKey("headers", NetLogHeadersToDict(headers));
|
||||
- return dict;
|
||||
- });
|
||||
+ net_log_.AddEvent(
|
||||
+ NetLogEventType::HTTP3_PUSH_PROMISE_DECODED,
|
||||
+ [stream_id, push_id, &headers](NetLogCaptureMode capture_mode) {
|
||||
+ base::Value dict(base::Value::Type::DICTIONARY);
|
||||
+ dict.SetKey("stream_id",
|
||||
+ NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
+ dict.SetKey("push_id",
|
||||
+ NetLogNumberValue(static_cast<uint64_t>(push_id)));
|
||||
+ dict.SetKey("headers",
|
||||
+ ElideQuicHeaderListForNetLog(headers, capture_mode));
|
||||
+ return dict;
|
||||
+ });
|
||||
}
|
||||
|
||||
void QuicHttp3Logger::OnUnknownFrameReceived(
|
||||
@@ -344,11 +350,13 @@ void QuicHttp3Logger::OnHeadersFrameSent(
|
||||
return;
|
||||
}
|
||||
net_log_.AddEvent(
|
||||
- NetLogEventType::HTTP3_HEADERS_SENT, [stream_id, &header_block] {
|
||||
+ NetLogEventType::HTTP3_HEADERS_SENT,
|
||||
+ [stream_id, &header_block](NetLogCaptureMode capture_mode) {
|
||||
base::Value dict(base::Value::Type::DICTIONARY);
|
||||
dict.SetKey("stream_id",
|
||||
NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
- dict.SetKey("headers", NetLogHeadersToDict(header_block));
|
||||
+ dict.SetKey("headers",
|
||||
+ ElideSpdyHeaderBlockForNetLog(header_block, capture_mode));
|
||||
return dict;
|
||||
});
|
||||
}
|
||||
@@ -360,16 +368,18 @@ void QuicHttp3Logger::OnPushPromiseFrameSent(
|
||||
if (!net_log_.IsCapturing()) {
|
||||
return;
|
||||
}
|
||||
- net_log_.AddEvent(NetLogEventType::HTTP3_PUSH_PROMISE_SENT, [stream_id,
|
||||
- push_id,
|
||||
- &header_block] {
|
||||
- base::Value dict(base::Value::Type::DICTIONARY);
|
||||
- dict.SetKey("stream_id",
|
||||
- NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
- dict.SetKey("push_id", NetLogNumberValue(static_cast<uint64_t>(push_id)));
|
||||
- dict.SetKey("headers", NetLogHeadersToDict(header_block));
|
||||
- return dict;
|
||||
- });
|
||||
+ net_log_.AddEvent(
|
||||
+ NetLogEventType::HTTP3_PUSH_PROMISE_SENT,
|
||||
+ [stream_id, push_id, &header_block](NetLogCaptureMode capture_mode) {
|
||||
+ base::Value dict(base::Value::Type::DICTIONARY);
|
||||
+ dict.SetKey("stream_id",
|
||||
+ NetLogNumberValue(static_cast<uint64_t>(stream_id)));
|
||||
+ dict.SetKey("push_id",
|
||||
+ NetLogNumberValue(static_cast<uint64_t>(push_id)));
|
||||
+ dict.SetKey("headers",
|
||||
+ ElideSpdyHeaderBlockForNetLog(header_block, capture_mode));
|
||||
+ return dict;
|
||||
+ });
|
||||
}
|
||||
|
||||
} // namespace net
|
||||
750
patches/chromium/cherry-pick-0e61c69ebd47.patch
Normal file
750
patches/chromium/cherry-pick-0e61c69ebd47.patch
Normal file
@@ -0,0 +1,750 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Ramin Halavati <rhalavati@chromium.org>
|
||||
Date: Wed, 9 Sep 2020 05:10:19 +0000
|
||||
Subject: Reland Run ObfuscatedFileUtilMemoryDelegate entirely on TaskRunner.
|
||||
|
||||
MemoryFileStreamWriter called some ObfuscatedFileUtilMemoryDelegate
|
||||
functions through IO thread while other functions in OFUMD are called
|
||||
on a threadpool sequence. This could result in races in updating
|
||||
directory structure.
|
||||
|
||||
To fix the issue, MemoryFileStreamWriter and MemoryFileStreamReader are
|
||||
updated to call all OFUMD on the default task runner of the file system
|
||||
context.
|
||||
|
||||
This CL was landed in crrev.com/c/2308721 and reverted due to flakiness.
|
||||
The flaky crashes are believed to be because the buffer passed to
|
||||
MemoryFileStreamReader::Read and MemoryFileStreamWrite::Write are not
|
||||
thread safe.
|
||||
|
||||
Patchset1 is a copy of the previous CL and the issue is fixed in the
|
||||
next patchsets.
|
||||
|
||||
Bug: 1100136
|
||||
Change-Id: I619b82c2f4d23a020e9ce7e5e6c16980907b501b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2398701
|
||||
Reviewed-by: Marijn Kruisselbrink <mek@chromium.org>
|
||||
Commit-Queue: Ramin Halavati <rhalavati@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#805198}
|
||||
(cherry picked from commit 0e61c69ebd476e5b688f341f8d0bf69fe814c515)
|
||||
|
||||
diff --git a/storage/browser/file_system/file_stream_reader.h b/storage/browser/file_system/file_stream_reader.h
|
||||
index b3cfc7f751be2e8654ba6d5e51849a4f35863d7a..d9ac296c94a4df765417d71b0c80b798ff7c888c 100644
|
||||
--- a/storage/browser/file_system/file_stream_reader.h
|
||||
+++ b/storage/browser/file_system/file_stream_reader.h
|
||||
@@ -60,6 +60,7 @@ class FileStreamReader {
|
||||
// ERR_UPLOAD_FILE_CHANGED error.
|
||||
COMPONENT_EXPORT(STORAGE_BROWSER)
|
||||
static std::unique_ptr<FileStreamReader> CreateForMemoryFile(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset,
|
||||
diff --git a/storage/browser/file_system/file_stream_test_utils.cc b/storage/browser/file_system/file_stream_test_utils.cc
|
||||
index 835a423c9c913ed46e8b68e7a9d3b323b3263695..e66dfc716aae031cc9c6e00d660753d4487cb60a 100644
|
||||
--- a/storage/browser/file_system/file_stream_test_utils.cc
|
||||
+++ b/storage/browser/file_system/file_stream_test_utils.cc
|
||||
@@ -40,6 +40,14 @@ void ReadFromReader(FileStreamReader* reader,
|
||||
}
|
||||
}
|
||||
|
||||
+int64_t GetLengthFromReader(FileStreamReader* reader) {
|
||||
+ EXPECT_NE(nullptr, reader);
|
||||
+ net::TestInt64CompletionCallback callback;
|
||||
+
|
||||
+ int rv = reader->GetLength(callback.callback());
|
||||
+ return callback.GetResult(rv);
|
||||
+}
|
||||
+
|
||||
int WriteStringToWriter(FileStreamWriter* writer, const std::string& data) {
|
||||
scoped_refptr<net::StringIOBuffer> buffer =
|
||||
base::MakeRefCounted<net::StringIOBuffer>(data);
|
||||
diff --git a/storage/browser/file_system/file_stream_test_utils.h b/storage/browser/file_system/file_stream_test_utils.h
|
||||
index 5714f7a1e7a1f6e91628e9f958a1b13324d7ec8e..d6425f15af6309a0891a10ca54cc092b8c1180f1 100644
|
||||
--- a/storage/browser/file_system/file_stream_test_utils.h
|
||||
+++ b/storage/browser/file_system/file_stream_test_utils.h
|
||||
@@ -20,8 +20,12 @@ void ReadFromReader(FileStreamReader* reader,
|
||||
size_t size,
|
||||
int* result);
|
||||
|
||||
-// Writes |data| to |writer|, an intialized FileStreamWriter. Returns net::OK if
|
||||
-// successful, otherwise a net error.
|
||||
+// Returns the length of the file if it could be successfully retrieved,
|
||||
+// otherwise a net error.
|
||||
+int64_t GetLengthFromReader(FileStreamReader* reader);
|
||||
+
|
||||
+// Writes |data| to |writer|, an initialized FileStreamWriter. Returns net::OK
|
||||
+// if successful, otherwise a net error.
|
||||
int WriteStringToWriter(FileStreamWriter* writer, const std::string& data);
|
||||
|
||||
} // namespace storage
|
||||
diff --git a/storage/browser/file_system/file_stream_writer.h b/storage/browser/file_system/file_stream_writer.h
|
||||
index 2ddbecc6587d94d16ad547e3b2249c103621ee7e..11ce21c64d9b0f43d761b45ae7a710be60f03316 100644
|
||||
--- a/storage/browser/file_system/file_stream_writer.h
|
||||
+++ b/storage/browser/file_system/file_stream_writer.h
|
||||
@@ -48,10 +48,9 @@ class FileStreamWriter {
|
||||
|
||||
// Creates a writer for the existing memory file in the path |file_path|
|
||||
// starting from |initial_offset|.
|
||||
- // TODO(mek): Remove or use |open_or_create| field here, as it is not
|
||||
- // currently used. https://crbug.com/1041048
|
||||
COMPONENT_EXPORT(STORAGE_BROWSER)
|
||||
static std::unique_ptr<FileStreamWriter> CreateForMemoryFile(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset);
|
||||
diff --git a/storage/browser/file_system/file_system_file_stream_reader.cc b/storage/browser/file_system/file_system_file_stream_reader.cc
|
||||
index 8a3b85166bf85fb9661953c37b2942eddd5a61e1..9d37b8075199fe5c93c058610bb1f9d99730b526 100644
|
||||
--- a/storage/browser/file_system/file_system_file_stream_reader.cc
|
||||
+++ b/storage/browser/file_system/file_system_file_stream_reader.cc
|
||||
@@ -112,6 +112,7 @@ void FileSystemFileStreamReader::DidCreateSnapshot(
|
||||
file_system_context_->sandbox_delegate()->memory_file_util_delegate();
|
||||
}
|
||||
file_reader_ = FileStreamReader::CreateForMemoryFile(
|
||||
+ file_system_context_->default_file_task_runner(),
|
||||
memory_file_util_delegate, platform_path, initial_offset_,
|
||||
expected_modification_time_);
|
||||
} else {
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_reader.cc b/storage/browser/file_system/memory_file_stream_reader.cc
|
||||
index f5d895c6cc97e883024e854395a24f094c797ed4..0ca229bb8e8e853d96710fc5946e7a5d854c2180 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_reader.cc
|
||||
+++ b/storage/browser/file_system/memory_file_stream_reader.cc
|
||||
@@ -8,68 +8,114 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
+#include "base/task_runner_util.h"
|
||||
+#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
|
||||
namespace storage {
|
||||
|
||||
std::unique_ptr<FileStreamReader> FileStreamReader::CreateForMemoryFile(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset,
|
||||
const base::Time& expected_modification_time) {
|
||||
- return base::WrapUnique(
|
||||
- new MemoryFileStreamReader(std::move(memory_file_util), file_path,
|
||||
- initial_offset, expected_modification_time));
|
||||
+ return base::WrapUnique(new MemoryFileStreamReader(
|
||||
+ std::move(task_runner), std::move(memory_file_util), file_path,
|
||||
+ initial_offset, expected_modification_time));
|
||||
}
|
||||
|
||||
MemoryFileStreamReader::MemoryFileStreamReader(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset,
|
||||
const base::Time& expected_modification_time)
|
||||
: memory_file_util_(std::move(memory_file_util)),
|
||||
+ task_runner_(std::move(task_runner)),
|
||||
file_path_(file_path),
|
||||
expected_modification_time_(expected_modification_time),
|
||||
offset_(initial_offset) {
|
||||
- DCHECK(memory_file_util_);
|
||||
+ DCHECK(memory_file_util_.MaybeValid());
|
||||
}
|
||||
|
||||
MemoryFileStreamReader::~MemoryFileStreamReader() = default;
|
||||
|
||||
int MemoryFileStreamReader::Read(net::IOBuffer* buf,
|
||||
int buf_len,
|
||||
- net::CompletionOnceCallback /*callback*/) {
|
||||
- base::File::Info file_info;
|
||||
- if (memory_file_util_->GetFileInfo(file_path_, &file_info) !=
|
||||
- base::File::FILE_OK) {
|
||||
- return net::ERR_FILE_NOT_FOUND;
|
||||
- }
|
||||
-
|
||||
- if (!FileStreamReader::VerifySnapshotTime(expected_modification_time_,
|
||||
- file_info)) {
|
||||
- return net::ERR_UPLOAD_FILE_CHANGED;
|
||||
- }
|
||||
-
|
||||
- int result = memory_file_util_->ReadFile(file_path_, offset_, buf, buf_len);
|
||||
+ net::CompletionOnceCallback callback) {
|
||||
+ task_runner_->PostTaskAndReplyWithResult(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(
|
||||
+ [](base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> util,
|
||||
+ const base::FilePath& path, base::Time expected_modification_time,
|
||||
+ int64_t offset, scoped_refptr<net::IOBuffer> buf,
|
||||
+ int buf_len) -> int {
|
||||
+ if (!util)
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+ base::File::Info file_info;
|
||||
+ if (util->GetFileInfo(path, &file_info) != base::File::FILE_OK)
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+
|
||||
+ if (!FileStreamReader::VerifySnapshotTime(
|
||||
+ expected_modification_time, file_info)) {
|
||||
+ return net::ERR_UPLOAD_FILE_CHANGED;
|
||||
+ }
|
||||
+
|
||||
+ return util->ReadFile(path, offset, std::move(buf), buf_len);
|
||||
+ },
|
||||
+ memory_file_util_, file_path_, expected_modification_time_, offset_,
|
||||
+ base::WrapRefCounted(buf), buf_len),
|
||||
+ base::BindOnce(&MemoryFileStreamReader::OnReadCompleted,
|
||||
+ weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
+
|
||||
+ return net::ERR_IO_PENDING;
|
||||
+}
|
||||
+
|
||||
+void MemoryFileStreamReader::OnReadCompleted(
|
||||
+ net::CompletionOnceCallback callback,
|
||||
+ int result) {
|
||||
if (result > 0)
|
||||
offset_ += result;
|
||||
- return result;
|
||||
+
|
||||
+ std::move(callback).Run(result);
|
||||
}
|
||||
|
||||
int64_t MemoryFileStreamReader::GetLength(
|
||||
- net::Int64CompletionOnceCallback /*callback*/) {
|
||||
- base::File::Info file_info;
|
||||
- if (memory_file_util_->GetFileInfo(file_path_, &file_info) !=
|
||||
- base::File::FILE_OK) {
|
||||
- return net::ERR_FILE_NOT_FOUND;
|
||||
- }
|
||||
-
|
||||
- if (!FileStreamReader::VerifySnapshotTime(expected_modification_time_,
|
||||
- file_info)) {
|
||||
- return net::ERR_UPLOAD_FILE_CHANGED;
|
||||
- }
|
||||
-
|
||||
- return file_info.size;
|
||||
+ net::Int64CompletionOnceCallback callback) {
|
||||
+ task_runner_->PostTaskAndReplyWithResult(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(
|
||||
+ [](base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> util,
|
||||
+ const base::FilePath& path,
|
||||
+ base::Time expected_modification_time) -> int64_t {
|
||||
+ if (!util)
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+ base::File::Info file_info;
|
||||
+ if (util->GetFileInfo(path, &file_info) != base::File::FILE_OK) {
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+ }
|
||||
+
|
||||
+ if (!FileStreamReader::VerifySnapshotTime(
|
||||
+ expected_modification_time, file_info)) {
|
||||
+ return net::ERR_UPLOAD_FILE_CHANGED;
|
||||
+ }
|
||||
+
|
||||
+ return file_info.size;
|
||||
+ },
|
||||
+ memory_file_util_, file_path_, expected_modification_time_),
|
||||
+ // |callback| is not directly used to make sure that it is not called if
|
||||
+ // stream is deleted while this function is in flight.
|
||||
+ base::BindOnce(&MemoryFileStreamReader::OnGetLengthCompleted,
|
||||
+ weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
+
|
||||
+ return net::ERR_IO_PENDING;
|
||||
+}
|
||||
+
|
||||
+void MemoryFileStreamReader::OnGetLengthCompleted(
|
||||
+ net::Int64CompletionOnceCallback callback,
|
||||
+ int64_t result) {
|
||||
+ std::move(callback).Run(result);
|
||||
}
|
||||
|
||||
} // namespace storage
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_reader.h b/storage/browser/file_system/memory_file_stream_reader.h
|
||||
index 909db6b1178bc329af5e4694538045bba243310b..4f05d450522613e668549e59d58c36552650773e 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_reader.h
|
||||
+++ b/storage/browser/file_system/memory_file_stream_reader.h
|
||||
@@ -32,17 +32,25 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) MemoryFileStreamReader
|
||||
friend class FileStreamReader;
|
||||
|
||||
MemoryFileStreamReader(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset,
|
||||
const base::Time& expected_modification_time);
|
||||
|
||||
+ void OnReadCompleted(net::CompletionOnceCallback callback, int result);
|
||||
+ void OnGetLengthCompleted(net::Int64CompletionOnceCallback callback,
|
||||
+ int64_t result);
|
||||
+
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_;
|
||||
|
||||
+ const scoped_refptr<base::TaskRunner> task_runner_;
|
||||
const base::FilePath file_path_;
|
||||
const base::Time expected_modification_time_;
|
||||
int64_t offset_;
|
||||
|
||||
+ base::WeakPtrFactory<MemoryFileStreamReader> weak_factory_{this};
|
||||
+
|
||||
DISALLOW_COPY_AND_ASSIGN(MemoryFileStreamReader);
|
||||
};
|
||||
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_reader_unittest.cc b/storage/browser/file_system/memory_file_stream_reader_unittest.cc
|
||||
index 7cbaf6e06f82e792a52d549f963a0044a0a5fbd5..99bcfcbeb7e5dcdced47be3df1820f518558a78b 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_reader_unittest.cc
|
||||
+++ b/storage/browser/file_system/memory_file_stream_reader_unittest.cc
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
#include "base/macros.h"
|
||||
+#include "base/test/task_environment.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "storage/browser/file_system/file_stream_reader.h"
|
||||
@@ -62,9 +63,9 @@ class MemoryFileStreamReaderTest : public testing::Test {
|
||||
const base::FilePath& path,
|
||||
int64_t initial_offset,
|
||||
const base::Time& expected_modification_time) {
|
||||
- return FileStreamReader::CreateForMemoryFile(file_util_->GetWeakPtr(), path,
|
||||
- initial_offset,
|
||||
- expected_modification_time);
|
||||
+ return FileStreamReader::CreateForMemoryFile(
|
||||
+ base::ThreadTaskRunnerHandle::Get(), file_util_->GetWeakPtr(), path,
|
||||
+ initial_offset, expected_modification_time);
|
||||
}
|
||||
|
||||
void TouchTestFile(base::TimeDelta delta) {
|
||||
@@ -83,6 +84,7 @@ class MemoryFileStreamReaderTest : public testing::Test {
|
||||
}
|
||||
|
||||
private:
|
||||
+ base::test::TaskEnvironment task_environment_;
|
||||
base::ScopedTempDir file_system_directory_;
|
||||
std::unique_ptr<ObfuscatedFileUtilMemoryDelegate> file_util_;
|
||||
base::Time test_file_modification_time_;
|
||||
@@ -113,14 +115,14 @@ TEST_F(MemoryFileStreamReaderTest, Empty) {
|
||||
ASSERT_EQ(net::OK, result);
|
||||
ASSERT_EQ(0U, data.size());
|
||||
|
||||
- int64_t length_result = reader->GetLength(base::DoNothing());
|
||||
+ int64_t length_result = GetLengthFromReader(reader.get());
|
||||
ASSERT_EQ(0, length_result);
|
||||
}
|
||||
|
||||
TEST_F(MemoryFileStreamReaderTest, GetLengthNormal) {
|
||||
std::unique_ptr<FileStreamReader> reader(
|
||||
CreateFileReader(test_path(), 0, test_file_modification_time()));
|
||||
- int64_t result = reader->GetLength(base::DoNothing());
|
||||
+ int64_t result = GetLengthFromReader(reader.get());
|
||||
ASSERT_EQ(kTestDataSize, result);
|
||||
}
|
||||
|
||||
@@ -131,7 +133,7 @@ TEST_F(MemoryFileStreamReaderTest, GetLengthAfterModified) {
|
||||
|
||||
std::unique_ptr<FileStreamReader> reader(
|
||||
CreateFileReader(test_path(), 0, test_file_modification_time()));
|
||||
- int64_t result = reader->GetLength(base::DoNothing());
|
||||
+ int64_t result = GetLengthFromReader(reader.get());
|
||||
ASSERT_EQ(net::ERR_UPLOAD_FILE_CHANGED, result);
|
||||
}
|
||||
|
||||
@@ -142,14 +144,14 @@ TEST_F(MemoryFileStreamReaderTest, GetLengthAfterModifiedWithNoExpectedTime) {
|
||||
|
||||
std::unique_ptr<FileStreamReader> reader(
|
||||
CreateFileReader(test_path(), 0, base::Time()));
|
||||
- int64_t result = reader->GetLength(base::DoNothing());
|
||||
+ int64_t result = GetLengthFromReader(reader.get());
|
||||
ASSERT_EQ(kTestDataSize, result);
|
||||
}
|
||||
|
||||
TEST_F(MemoryFileStreamReaderTest, GetLengthWithOffset) {
|
||||
std::unique_ptr<FileStreamReader> reader(
|
||||
CreateFileReader(test_path(), 3, base::Time()));
|
||||
- int64_t result = reader->GetLength(base::DoNothing());
|
||||
+ int64_t result = GetLengthFromReader(reader.get());
|
||||
// Initial offset does not affect the result of GetLength.
|
||||
ASSERT_EQ(kTestDataSize, result);
|
||||
}
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_writer.cc b/storage/browser/file_system/memory_file_stream_writer.cc
|
||||
index 9c421145866cd4425f752e343abcfca6260178a2..b36c4b5e4bbb5d7280fba11ab73e8c4a4d39c088 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_writer.cc
|
||||
+++ b/storage/browser/file_system/memory_file_stream_writer.cc
|
||||
@@ -8,43 +8,68 @@
|
||||
#include <utility>
|
||||
|
||||
#include "base/memory/ptr_util.h"
|
||||
+#include "base/task_runner_util.h"
|
||||
+#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
|
||||
namespace storage {
|
||||
|
||||
std::unique_ptr<FileStreamWriter> FileStreamWriter::CreateForMemoryFile(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset) {
|
||||
return base::WrapUnique(new MemoryFileStreamWriter(
|
||||
- std::move(memory_file_util), file_path, initial_offset));
|
||||
+ std::move(task_runner), std::move(memory_file_util), file_path,
|
||||
+ initial_offset));
|
||||
}
|
||||
|
||||
MemoryFileStreamWriter::MemoryFileStreamWriter(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset)
|
||||
: memory_file_util_(std::move(memory_file_util)),
|
||||
+ task_runner_(std::move(task_runner)),
|
||||
file_path_(file_path),
|
||||
offset_(initial_offset) {
|
||||
- DCHECK(memory_file_util_);
|
||||
+ DCHECK(memory_file_util_.MaybeValid());
|
||||
}
|
||||
|
||||
MemoryFileStreamWriter::~MemoryFileStreamWriter() = default;
|
||||
|
||||
int MemoryFileStreamWriter::Write(net::IOBuffer* buf,
|
||||
int buf_len,
|
||||
- net::CompletionOnceCallback /*callback*/) {
|
||||
- base::File::Info file_info;
|
||||
- if (memory_file_util_->GetFileInfo(file_path_, &file_info) !=
|
||||
- base::File::FILE_OK) {
|
||||
- return net::ERR_FILE_NOT_FOUND;
|
||||
- }
|
||||
-
|
||||
- int result = memory_file_util_->WriteFile(file_path_, offset_, buf, buf_len);
|
||||
+ net::CompletionOnceCallback callback) {
|
||||
+ task_runner_->PostTaskAndReplyWithResult(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(
|
||||
+ [](base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> util,
|
||||
+ const base::FilePath& path, int64_t offset,
|
||||
+ scoped_refptr<net::IOBuffer> buf, int buf_len) -> int {
|
||||
+ if (!util)
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+ base::File::Info file_info;
|
||||
+ if (util->GetFileInfo(path, &file_info) != base::File::FILE_OK)
|
||||
+ return net::ERR_FILE_NOT_FOUND;
|
||||
+
|
||||
+ return util->WriteFile(path, offset, std::move(buf), buf_len);
|
||||
+ },
|
||||
+ memory_file_util_, file_path_, offset_, base::WrapRefCounted(buf),
|
||||
+ buf_len),
|
||||
+ base::BindOnce(&MemoryFileStreamWriter::OnWriteCompleted,
|
||||
+ weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
+
|
||||
+ return net::ERR_IO_PENDING;
|
||||
+}
|
||||
+
|
||||
+void MemoryFileStreamWriter::OnWriteCompleted(
|
||||
+ net::CompletionOnceCallback callback,
|
||||
+ int result) {
|
||||
if (result > 0)
|
||||
offset_ += result;
|
||||
- return result;
|
||||
+
|
||||
+ std::move(callback).Run(result);
|
||||
}
|
||||
|
||||
int MemoryFileStreamWriter::Cancel(net::CompletionOnceCallback /*callback*/) {
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_writer.h b/storage/browser/file_system/memory_file_stream_writer.h
|
||||
index fe1c9d17932e2c4398295bc0ed6359f86281be91..74f6213f0f80b619083779184d04a62c0f983835 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_writer.h
|
||||
+++ b/storage/browser/file_system/memory_file_stream_writer.h
|
||||
@@ -30,15 +30,21 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) MemoryFileStreamWriter
|
||||
private:
|
||||
friend class FileStreamWriter;
|
||||
MemoryFileStreamWriter(
|
||||
+ scoped_refptr<base::TaskRunner> task_runner,
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util,
|
||||
const base::FilePath& file_path,
|
||||
int64_t initial_offset);
|
||||
|
||||
+ void OnWriteCompleted(net::CompletionOnceCallback callback, int result);
|
||||
+
|
||||
base::WeakPtr<ObfuscatedFileUtilMemoryDelegate> memory_file_util_;
|
||||
|
||||
+ const scoped_refptr<base::TaskRunner> task_runner_;
|
||||
const base::FilePath file_path_;
|
||||
int64_t offset_;
|
||||
|
||||
+ base::WeakPtrFactory<MemoryFileStreamWriter> weak_factory_{this};
|
||||
+
|
||||
DISALLOW_COPY_AND_ASSIGN(MemoryFileStreamWriter);
|
||||
};
|
||||
|
||||
diff --git a/storage/browser/file_system/memory_file_stream_writer_unittest.cc b/storage/browser/file_system/memory_file_stream_writer_unittest.cc
|
||||
index 7fcda3dfd5e533e8d501a5b56ae5b2abd9486f2f..44342a33c66f21eed35287a4bb9b94f82de21521 100644
|
||||
--- a/storage/browser/file_system/memory_file_stream_writer_unittest.cc
|
||||
+++ b/storage/browser/file_system/memory_file_stream_writer_unittest.cc
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "base/bind_helpers.h"
|
||||
#include "base/files/file_util.h"
|
||||
#include "base/files/scoped_temp_dir.h"
|
||||
+#include "base/test/task_environment.h"
|
||||
#include "net/base/io_buffer.h"
|
||||
#include "net/base/net_errors.h"
|
||||
#include "storage/browser/file_system/file_stream_test_utils.h"
|
||||
@@ -59,11 +60,13 @@ class MemoryFileStreamWriterTest : public testing::Test {
|
||||
|
||||
std::unique_ptr<FileStreamWriter> CreateWriter(const base::FilePath& path,
|
||||
int64_t offset) {
|
||||
- return FileStreamWriter::CreateForMemoryFile(file_util_->GetWeakPtr(), path,
|
||||
- offset);
|
||||
+ return FileStreamWriter::CreateForMemoryFile(
|
||||
+ base::ThreadTaskRunnerHandle::Get(), file_util_->GetWeakPtr(), path,
|
||||
+ offset);
|
||||
}
|
||||
|
||||
private:
|
||||
+ base::test::TaskEnvironment task_environment_;
|
||||
base::ScopedTempDir file_system_directory_;
|
||||
std::unique_ptr<ObfuscatedFileUtilMemoryDelegate> file_util_;
|
||||
};
|
||||
diff --git a/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc b/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc
|
||||
index 5919d1f1c2c4c80fd73cfbb0586af0e505d43152..3a3d8563e3c91d3b9ca15a980a709a8fd96e8c6c 100644
|
||||
--- a/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc
|
||||
+++ b/storage/browser/file_system/obfuscated_file_util_memory_delegate.cc
|
||||
@@ -56,13 +56,17 @@ struct ObfuscatedFileUtilMemoryDelegate::DecomposedPath {
|
||||
ObfuscatedFileUtilMemoryDelegate::ObfuscatedFileUtilMemoryDelegate(
|
||||
const base::FilePath& file_system_directory)
|
||||
: root_(std::make_unique<Entry>(Entry::kDirectory)) {
|
||||
+ DETACH_FROM_SEQUENCE(sequence_checker_);
|
||||
file_system_directory.GetComponents(&root_path_components_);
|
||||
}
|
||||
|
||||
-ObfuscatedFileUtilMemoryDelegate::~ObfuscatedFileUtilMemoryDelegate() = default;
|
||||
+ObfuscatedFileUtilMemoryDelegate::~ObfuscatedFileUtilMemoryDelegate() {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
+}
|
||||
|
||||
base::Optional<ObfuscatedFileUtilMemoryDelegate::DecomposedPath>
|
||||
ObfuscatedFileUtilMemoryDelegate::ParsePath(const base::FilePath& path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DecomposedPath dp;
|
||||
|
||||
path.GetComponents(&dp.components);
|
||||
@@ -118,6 +122,7 @@ ObfuscatedFileUtilMemoryDelegate::ParsePath(const base::FilePath& path) {
|
||||
|
||||
bool ObfuscatedFileUtilMemoryDelegate::DirectoryExists(
|
||||
const base::FilePath& path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
return dp && dp->entry && dp->entry->type == Entry::kDirectory;
|
||||
}
|
||||
@@ -126,6 +131,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateDirectory(
|
||||
const base::FilePath& path,
|
||||
bool exclusive,
|
||||
bool recursive) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp)
|
||||
return base::File::FILE_ERROR_NOT_FOUND;
|
||||
@@ -169,6 +175,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateDirectory(
|
||||
bool ObfuscatedFileUtilMemoryDelegate::DeleteFileOrDirectory(
|
||||
const base::FilePath& path,
|
||||
bool recursive) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp)
|
||||
return false;
|
||||
@@ -185,11 +192,13 @@ bool ObfuscatedFileUtilMemoryDelegate::DeleteFileOrDirectory(
|
||||
}
|
||||
|
||||
bool ObfuscatedFileUtilMemoryDelegate::IsLink(const base::FilePath& file_path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
// In-memory file system does not support links.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool ObfuscatedFileUtilMemoryDelegate::PathExists(const base::FilePath& path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
return dp && dp->entry;
|
||||
}
|
||||
@@ -197,6 +206,7 @@ bool ObfuscatedFileUtilMemoryDelegate::PathExists(const base::FilePath& path) {
|
||||
base::File ObfuscatedFileUtilMemoryDelegate::CreateOrOpen(
|
||||
const base::FilePath& path,
|
||||
int file_flags) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
// TODO:(https://crbug.com/936722): Once the output of this function is
|
||||
// changed to base::File::Error, it can use CreateOrOpenInternal to perform
|
||||
// the task and return the result.
|
||||
@@ -206,6 +216,7 @@ base::File ObfuscatedFileUtilMemoryDelegate::CreateOrOpen(
|
||||
void ObfuscatedFileUtilMemoryDelegate::CreateOrOpenInternal(
|
||||
const DecomposedPath& dp,
|
||||
int file_flags) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
if (!dp.entry) {
|
||||
dp.parent->directory_content.emplace(dp.components.back(), Entry::kFile);
|
||||
return;
|
||||
@@ -221,6 +232,7 @@ void ObfuscatedFileUtilMemoryDelegate::CreateOrOpenInternal(
|
||||
|
||||
base::File::Error ObfuscatedFileUtilMemoryDelegate::DeleteFile(
|
||||
const base::FilePath& path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || !dp->entry)
|
||||
return base::File::FILE_ERROR_NOT_FOUND;
|
||||
@@ -235,6 +247,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::DeleteFile(
|
||||
base::File::Error ObfuscatedFileUtilMemoryDelegate::EnsureFileExists(
|
||||
const base::FilePath& path,
|
||||
bool* created) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
*created = false;
|
||||
if (!dp || !dp->parent)
|
||||
@@ -253,6 +266,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::EnsureFileExists(
|
||||
base::File::Error ObfuscatedFileUtilMemoryDelegate::GetFileInfo(
|
||||
const base::FilePath& path,
|
||||
base::File::Info* file_info) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || !dp->entry)
|
||||
return base::File::FILE_ERROR_NOT_FOUND;
|
||||
@@ -272,6 +286,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::Touch(
|
||||
const base::FilePath& path,
|
||||
const base::Time& last_access_time,
|
||||
const base::Time& last_modified_time) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || !dp->entry)
|
||||
return base::File::FILE_ERROR_FAILED;
|
||||
@@ -285,6 +300,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::Touch(
|
||||
base::File::Error ObfuscatedFileUtilMemoryDelegate::Truncate(
|
||||
const base::FilePath& path,
|
||||
int64_t length) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || !dp->entry || dp->entry->type != Entry::kFile)
|
||||
return base::File::FILE_ERROR_NOT_FOUND;
|
||||
@@ -297,6 +313,7 @@ NativeFileUtil::CopyOrMoveMode
|
||||
ObfuscatedFileUtilMemoryDelegate::CopyOrMoveModeForDestination(
|
||||
const FileSystemURL& /*dest_url*/,
|
||||
bool copy) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
return copy ? NativeFileUtil::CopyOrMoveMode::COPY_SYNC
|
||||
: NativeFileUtil::CopyOrMoveMode::MOVE;
|
||||
}
|
||||
@@ -306,6 +323,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFile(
|
||||
const base::FilePath& dest_path,
|
||||
FileSystemOperation::CopyOrMoveOption option,
|
||||
NativeFileUtil::CopyOrMoveMode mode) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> src_dp = ParsePath(src_path);
|
||||
base::Optional<DecomposedPath> dest_dp = ParsePath(dest_path);
|
||||
|
||||
@@ -361,6 +379,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFile(
|
||||
bool ObfuscatedFileUtilMemoryDelegate::MoveDirectoryInternal(
|
||||
const DecomposedPath& src_dp,
|
||||
const DecomposedPath& dest_dp) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(src_dp.entry->type == Entry::kDirectory);
|
||||
if (!dest_dp.entry) {
|
||||
dest_dp.parent->directory_content.insert(
|
||||
@@ -379,6 +398,7 @@ bool ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFileInternal(
|
||||
const DecomposedPath& src_dp,
|
||||
const DecomposedPath& dest_dp,
|
||||
bool move) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(src_dp.entry->type == Entry::kFile);
|
||||
if (dest_dp.entry)
|
||||
dest_dp.parent->directory_content.erase(dest_dp.components.back());
|
||||
@@ -404,6 +424,7 @@ bool ObfuscatedFileUtilMemoryDelegate::CopyOrMoveFileInternal(
|
||||
|
||||
size_t ObfuscatedFileUtilMemoryDelegate::ComputeDirectorySize(
|
||||
const base::FilePath& path) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || !dp->entry || dp->entry->type != Entry::kDirectory)
|
||||
return 0;
|
||||
@@ -427,8 +448,9 @@ size_t ObfuscatedFileUtilMemoryDelegate::ComputeDirectorySize(
|
||||
|
||||
int ObfuscatedFileUtilMemoryDelegate::ReadFile(const base::FilePath& path,
|
||||
int64_t offset,
|
||||
- net::IOBuffer* buf,
|
||||
+ scoped_refptr<net::IOBuffer> buf,
|
||||
int buf_len) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
if (!dp || dp->entry->type != Entry::kFile)
|
||||
return net::ERR_FILE_NOT_FOUND;
|
||||
@@ -445,13 +467,15 @@ int ObfuscatedFileUtilMemoryDelegate::ReadFile(const base::FilePath& path,
|
||||
return buf_len;
|
||||
}
|
||||
|
||||
-int ObfuscatedFileUtilMemoryDelegate::WriteFile(const base::FilePath& path,
|
||||
- int64_t offset,
|
||||
- net::IOBuffer* buf,
|
||||
- int buf_len) {
|
||||
+int ObfuscatedFileUtilMemoryDelegate::WriteFile(
|
||||
+ const base::FilePath& path,
|
||||
+ int64_t offset,
|
||||
+ scoped_refptr<net::IOBuffer> buf,
|
||||
+ int buf_len) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dp = ParsePath(path);
|
||||
|
||||
- if (!dp || dp->entry->type != Entry::kFile)
|
||||
+ if (!dp || !dp->entry || dp->entry->type != Entry::kFile)
|
||||
return net::ERR_FILE_NOT_FOUND;
|
||||
|
||||
size_t offset_u = static_cast<size_t>(offset);
|
||||
@@ -479,6 +503,7 @@ int ObfuscatedFileUtilMemoryDelegate::WriteFile(const base::FilePath& path,
|
||||
base::File::Error ObfuscatedFileUtilMemoryDelegate::CreateFileForTesting(
|
||||
const base::FilePath& path,
|
||||
base::span<const char> content) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
bool created;
|
||||
base::File::Error result = EnsureFileExists(path, &created);
|
||||
if (result != base::File::FILE_OK)
|
||||
@@ -498,6 +523,7 @@ base::File::Error ObfuscatedFileUtilMemoryDelegate::CopyInForeignFile(
|
||||
const base::FilePath& dest_path,
|
||||
FileSystemOperation::CopyOrMoveOption /* option */,
|
||||
NativeFileUtil::CopyOrMoveMode /* mode */) {
|
||||
+ DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
base::Optional<DecomposedPath> dest_dp = ParsePath(dest_path);
|
||||
|
||||
if (!dest_dp || !dest_dp->parent)
|
||||
diff --git a/storage/browser/file_system/obfuscated_file_util_memory_delegate.h b/storage/browser/file_system/obfuscated_file_util_memory_delegate.h
|
||||
index 4dd25b48affa901251ec4ec54dc6221a60626d19..d1240511303860e67603543e5795c893ef0db482 100644
|
||||
--- a/storage/browser/file_system/obfuscated_file_util_memory_delegate.h
|
||||
+++ b/storage/browser/file_system/obfuscated_file_util_memory_delegate.h
|
||||
@@ -88,7 +88,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilMemoryDelegate
|
||||
// bytes are returned. Otherwise a net::Error value is returned.
|
||||
int ReadFile(const base::FilePath& path,
|
||||
int64_t offset,
|
||||
- net::IOBuffer* buf,
|
||||
+ scoped_refptr<net::IOBuffer> buf,
|
||||
int buf_len);
|
||||
|
||||
// Writes |buf_len| bytes to the file at |path|, starting from |offset|.
|
||||
@@ -96,7 +96,7 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilMemoryDelegate
|
||||
// net::Error value is returned.
|
||||
int WriteFile(const base::FilePath& path,
|
||||
int64_t offset,
|
||||
- net::IOBuffer* buf,
|
||||
+ scoped_refptr<net::IOBuffer> buf,
|
||||
int buf_len);
|
||||
|
||||
base::File::Error CreateFileForTesting(const base::FilePath& path,
|
||||
@@ -126,6 +126,8 @@ class COMPONENT_EXPORT(STORAGE_BROWSER) ObfuscatedFileUtilMemoryDelegate
|
||||
const DecomposedPath& dest_dp,
|
||||
bool move);
|
||||
|
||||
+ SEQUENCE_CHECKER(sequence_checker_);
|
||||
+
|
||||
// The root of the directory tree.
|
||||
std::unique_ptr<Entry> root_;
|
||||
|
||||
diff --git a/storage/browser/file_system/sandbox_file_stream_writer.cc b/storage/browser/file_system/sandbox_file_stream_writer.cc
|
||||
index 21495aee42684fcbe7c79fa5d26ad4f2006da875..d344e8ae71e254c2fc758e6a8f6b219d4b145805 100644
|
||||
--- a/storage/browser/file_system/sandbox_file_stream_writer.cc
|
||||
+++ b/storage/browser/file_system/sandbox_file_stream_writer.cc
|
||||
@@ -155,6 +155,7 @@ void SandboxFileStreamWriter::DidCreateSnapshotFile(
|
||||
file_system_context_->sandbox_delegate()->memory_file_util_delegate();
|
||||
}
|
||||
file_writer_ = FileStreamWriter::CreateForMemoryFile(
|
||||
+ file_system_context_->default_file_task_runner(),
|
||||
memory_file_util_delegate, platform_path, initial_offset_);
|
||||
|
||||
} else {
|
||||
64
patches/chromium/cherry-pick-138b748dd0a4.patch
Normal file
64
patches/chromium/cherry-pick-138b748dd0a4.patch
Normal file
@@ -0,0 +1,64 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Alexander Cooper <alcooper@chromium.org>
|
||||
Date: Tue, 4 Aug 2020 00:31:54 +0000
|
||||
Subject: Update FocusChanged notifiers to operate on a copy
|
||||
|
||||
These focus changed calls ultimately trigger javascript events. These
|
||||
events could potentially run code that would modify the list of items
|
||||
that the FocusChanged notifiers are notifying, and thus invalidate their
|
||||
in-use iterators.
|
||||
|
||||
Fix this by having these methods iterate over a copy instead of the
|
||||
member list.
|
||||
|
||||
(cherry picked from commit d8f526f4e25c24ed29e60b46b3416bfabd5e8f11)
|
||||
|
||||
Fixed: 1107815
|
||||
Change-Id: I03fa08eeadc60736f3a3fae079253dbd3ee26476
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2314158
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Reviewed-by: Klaus Weidner <klausw@chromium.org>
|
||||
Commit-Queue: Daniel Cheng <dcheng@chromium.org>
|
||||
Auto-Submit: Alexander Cooper <alcooper@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#791261}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2335893
|
||||
Reviewed-by: Alexander Cooper <alcooper@chromium.org>
|
||||
Commit-Queue: Alexander Cooper <alcooper@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#1015}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/page/focus_controller.cc b/third_party/blink/renderer/core/page/focus_controller.cc
|
||||
index 225ff4339c3a9b0bd79b3a188e28cf615e6ed97c..19215d532094c340dd146660b062aeb3293b7bc3 100644
|
||||
--- a/third_party/blink/renderer/core/page/focus_controller.cc
|
||||
+++ b/third_party/blink/renderer/core/page/focus_controller.cc
|
||||
@@ -1335,7 +1335,12 @@ void FocusController::RegisterFocusChangedObserver(
|
||||
}
|
||||
|
||||
void FocusController::NotifyFocusChangedObservers() const {
|
||||
- for (const auto& it : focus_changed_observers_)
|
||||
+ // Since this eventually dispatches an event to the page, the page could add
|
||||
+ // new observer, which would invalidate our iterators; so iterate over a copy
|
||||
+ // of the observer list.
|
||||
+ HeapHashSet<WeakMember<FocusChangedObserver>> observers =
|
||||
+ focus_changed_observers_;
|
||||
+ for (const auto& it : observers)
|
||||
it->FocusedFrameChanged();
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/xr/xr_system.cc b/third_party/blink/renderer/modules/xr/xr_system.cc
|
||||
index a94164360dcfe0e0686e5d48e64ee8a4dc9ef125..8b22f66e7f0c9e905d9a6503abb557287c6e456b 100644
|
||||
--- a/third_party/blink/renderer/modules/xr/xr_system.cc
|
||||
+++ b/third_party/blink/renderer/modules/xr/xr_system.cc
|
||||
@@ -682,7 +682,11 @@ XRSystem::XRSystem(LocalFrame& frame, int64_t ukm_source_id)
|
||||
|
||||
void XRSystem::FocusedFrameChanged() {
|
||||
// Tell all sessions that focus changed.
|
||||
- for (const auto& session : sessions_) {
|
||||
+ // Since this eventually dispatches an event to the page, the page could
|
||||
+ // create a new session which would invalidate our iterators; so iterate over
|
||||
+ // a copy of the session map.
|
||||
+ HeapHashSet<WeakMember<XRSession>> processing_sessions = sessions_;
|
||||
+ for (const auto& session : processing_sessions) {
|
||||
session->OnFocusChanged();
|
||||
}
|
||||
|
||||
160
patches/chromium/cherry-pick-1ed869ad4bb3.patch
Normal file
160
patches/chromium/cherry-pick-1ed869ad4bb3.patch
Normal file
@@ -0,0 +1,160 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Reilly Grant <reillyg@chromium.org>
|
||||
Date: Wed, 7 Oct 2020 23:26:36 +0000
|
||||
Subject: usb: Prevent parallel calls to UsbDevice::Open
|
||||
|
||||
This change adds a check to prevent a Mojo client from calling Open()
|
||||
multiple times while the open is in progress.
|
||||
|
||||
Bug: 1135857
|
||||
Change-Id: Ib467de9129673710b883d9e186c32c359f8592d8
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2454846
|
||||
Auto-Submit: Reilly Grant <reillyg@chromium.org>
|
||||
Reviewed-by: Matt Reynolds <mattreynolds@chromium.org>
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#814940}
|
||||
|
||||
diff --git a/services/device/usb/mojo/device_impl.cc b/services/device/usb/mojo/device_impl.cc
|
||||
index 6507b470afd2756878cd0990cfa7da2b9c730036..3dc07f879d70bc7755e59be1864a17f9a8e0ef10 100644
|
||||
--- a/services/device/usb/mojo/device_impl.cc
|
||||
+++ b/services/device/usb/mojo/device_impl.cc
|
||||
@@ -160,6 +160,7 @@ void DeviceImpl::OnOpen(base::WeakPtr<DeviceImpl> self,
|
||||
return;
|
||||
}
|
||||
|
||||
+ self->opening_ = false;
|
||||
self->device_handle_ = std::move(handle);
|
||||
if (self->device_handle_ && self->client_)
|
||||
self->client_->OnDeviceOpened();
|
||||
@@ -175,16 +176,19 @@ void DeviceImpl::OnPermissionGrantedForOpen(OpenCallback callback,
|
||||
device_->Open(base::BindOnce(
|
||||
&DeviceImpl::OnOpen, weak_factory_.GetWeakPtr(), std::move(callback)));
|
||||
} else {
|
||||
+ opening_ = false;
|
||||
std::move(callback).Run(mojom::UsbOpenDeviceError::ACCESS_DENIED);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceImpl::Open(OpenCallback callback) {
|
||||
- if (device_handle_) {
|
||||
+ if (opening_ || device_handle_) {
|
||||
std::move(callback).Run(mojom::UsbOpenDeviceError::ALREADY_OPEN);
|
||||
return;
|
||||
}
|
||||
|
||||
+ opening_ = true;
|
||||
+
|
||||
if (!device_->permission_granted()) {
|
||||
device_->RequestPermission(
|
||||
base::BindOnce(&DeviceImpl::OnPermissionGrantedForOpen,
|
||||
diff --git a/services/device/usb/mojo/device_impl.h b/services/device/usb/mojo/device_impl.h
|
||||
index 60ccbcc2e1e3ed964341a7bb8581c142eb27cf40..ab0a3797ae0031708b42f9f1cbc5bddb6f42efac 100644
|
||||
--- a/services/device/usb/mojo/device_impl.h
|
||||
+++ b/services/device/usb/mojo/device_impl.h
|
||||
@@ -104,7 +104,9 @@ class DeviceImpl : public mojom::UsbDevice, public device::UsbDevice::Observer {
|
||||
ScopedObserver<device::UsbDevice, device::UsbDevice::Observer> observer_;
|
||||
|
||||
// The device handle. Will be null before the device is opened and after it
|
||||
- // has been closed.
|
||||
+ // has been closed. |opening_| is set to true while the asynchronous open is
|
||||
+ // in progress.
|
||||
+ bool opening_ = false;
|
||||
scoped_refptr<UsbDeviceHandle> device_handle_;
|
||||
|
||||
mojo::SelfOwnedReceiverRef<mojom::UsbDevice> receiver_;
|
||||
diff --git a/services/device/usb/mojo/device_impl_unittest.cc b/services/device/usb/mojo/device_impl_unittest.cc
|
||||
index f0cd0eab4cf04d6f922c1748274d8f5f07a9452e..81045373bb3fa306b78f580f87424eacba36cd3d 100644
|
||||
--- a/services/device/usb/mojo/device_impl_unittest.cc
|
||||
+++ b/services/device/usb/mojo/device_impl_unittest.cc
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "base/memory/ref_counted_memory.h"
|
||||
#include "base/run_loop.h"
|
||||
#include "base/stl_util.h"
|
||||
+#include "base/test/bind_test_util.h"
|
||||
#include "base/test/task_environment.h"
|
||||
#include "mojo/public/cpp/bindings/interface_request.h"
|
||||
#include "mojo/public/cpp/bindings/receiver.h"
|
||||
@@ -265,7 +266,10 @@ class USBDeviceImplTest : public testing::Test {
|
||||
void OpenMockHandle(UsbDevice::OpenCallback& callback) {
|
||||
EXPECT_FALSE(is_device_open_);
|
||||
is_device_open_ = true;
|
||||
- std::move(callback).Run(mock_handle_);
|
||||
+ // Simulate the asynchronous device opening process.
|
||||
+ base::SequencedTaskRunnerHandle::Get()->PostDelayedTask(
|
||||
+ FROM_HERE, base::BindOnce(std::move(callback), mock_handle_),
|
||||
+ base::TimeDelta::FromMilliseconds(1));
|
||||
}
|
||||
|
||||
void CloseMockHandle() {
|
||||
@@ -515,17 +519,39 @@ TEST_F(USBDeviceImplTest, OpenFailure) {
|
||||
GetMockDeviceProxy(device_client.CreateInterfacePtrAndBind());
|
||||
|
||||
EXPECT_CALL(mock_device(), OpenInternal(_))
|
||||
- .WillOnce(Invoke([](UsbDevice::OpenCallback& callback) {
|
||||
+ .WillOnce([](UsbDevice::OpenCallback& callback) {
|
||||
std::move(callback).Run(nullptr);
|
||||
- }));
|
||||
+ });
|
||||
EXPECT_CALL(device_client, OnDeviceOpened()).Times(0);
|
||||
EXPECT_CALL(device_client, OnDeviceClosed()).Times(0);
|
||||
|
||||
- base::RunLoop loop;
|
||||
- device->Open(base::BindOnce(&ExpectOpenAndThen,
|
||||
- mojom::UsbOpenDeviceError::ACCESS_DENIED,
|
||||
- loop.QuitClosure()));
|
||||
- loop.Run();
|
||||
+ {
|
||||
+ base::RunLoop loop;
|
||||
+ device->Open(
|
||||
+ base::BindLambdaForTesting([&](mojom::UsbOpenDeviceError result) {
|
||||
+ EXPECT_EQ(result, mojom::UsbOpenDeviceError::ACCESS_DENIED);
|
||||
+ loop.Quit();
|
||||
+ }));
|
||||
+ loop.Run();
|
||||
+ }
|
||||
+
|
||||
+ // A second attempt can succeed.
|
||||
+ EXPECT_CALL(mock_device(), OpenInternal(_));
|
||||
+ EXPECT_CALL(device_client, OnDeviceOpened());
|
||||
+ EXPECT_CALL(device_client, OnDeviceClosed());
|
||||
+
|
||||
+ {
|
||||
+ base::RunLoop loop;
|
||||
+ device->Open(
|
||||
+ base::BindLambdaForTesting([&](mojom::UsbOpenDeviceError result) {
|
||||
+ EXPECT_EQ(result, mojom::UsbOpenDeviceError::OK);
|
||||
+ loop.Quit();
|
||||
+ }));
|
||||
+ loop.Run();
|
||||
+ }
|
||||
+
|
||||
+ device.reset();
|
||||
+ base::RunLoop().RunUntilIdle();
|
||||
}
|
||||
|
||||
TEST_F(USBDeviceImplTest, OpenDelayedFailure) {
|
||||
@@ -549,6 +575,24 @@ TEST_F(USBDeviceImplTest, OpenDelayedFailure) {
|
||||
std::move(saved_callback).Run(nullptr);
|
||||
}
|
||||
|
||||
+TEST_F(USBDeviceImplTest, MultipleOpenNotAllowed) {
|
||||
+ MockUsbDeviceClient device_client;
|
||||
+ mojo::Remote<mojom::UsbDevice> device =
|
||||
+ GetMockDeviceProxy(device_client.CreateInterfacePtrAndBind());
|
||||
+
|
||||
+ base::RunLoop loop;
|
||||
+ device->Open(
|
||||
+ base::BindLambdaForTesting([&](mojom::UsbOpenDeviceError result) {
|
||||
+ EXPECT_EQ(result, mojom::UsbOpenDeviceError::OK);
|
||||
+ }));
|
||||
+ device->Open(
|
||||
+ base::BindLambdaForTesting([&](mojom::UsbOpenDeviceError result) {
|
||||
+ EXPECT_EQ(result, mojom::UsbOpenDeviceError::ALREADY_OPEN);
|
||||
+ loop.Quit();
|
||||
+ }));
|
||||
+ loop.Run();
|
||||
+}
|
||||
+
|
||||
TEST_F(USBDeviceImplTest, Close) {
|
||||
MockUsbDeviceClient device_client;
|
||||
mojo::Remote<mojom::UsbDevice> device =
|
||||
64
patches/chromium/cherry-pick-229fdaf8fc05.patch
Normal file
64
patches/chromium/cherry-pick-229fdaf8fc05.patch
Normal file
@@ -0,0 +1,64 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Wed, 14 Oct 2020 19:40:12 +0000
|
||||
Subject: Validate input of MediaStreamDispatcherHost::OpenDevice()
|
||||
|
||||
This method forwards to MediaStreamManager::OpenDevice(), which
|
||||
DCHECKs for the stream type to be device video or audio capture
|
||||
(i.e., webcam or mic). However, MSDH admits other stream types,
|
||||
which cause MSM::OpenDevice to hit this DCHECK.
|
||||
|
||||
This CL ensures that a message containing an incorrect stream type,
|
||||
which could be sent by a malicious renderer, results in killing the
|
||||
renderer process.
|
||||
|
||||
Bug: 1135018
|
||||
Change-Id: I3884dde95d92c41f44966a8ab1dd7bdfd4b23b9b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2472397
|
||||
Auto-Submit: Guido Urdaneta <guidou@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Reviewed-by: Avi Drissman <avi@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#817151}
|
||||
|
||||
diff --git a/content/browser/bad_message.h b/content/browser/bad_message.h
|
||||
index 473a6a93edc4491e36ebc28b28e8a05b9fb64d62..3a2bcf0655dd02b95425c43caa3b8e5d896d7375 100644
|
||||
--- a/content/browser/bad_message.h
|
||||
+++ b/content/browser/bad_message.h
|
||||
@@ -253,6 +253,7 @@ enum BadMessageReason {
|
||||
RFH_BAD_DOCUMENT_POLICY_HEADER = 225,
|
||||
RFMF_INVALID_PLUGIN_EMBEDDER_ORIGIN = 226,
|
||||
RFH_INVALID_CALL_FROM_NOT_MAIN_FRAME = 227,
|
||||
+ MSDH_INVALID_STREAM_TYPE = 234,
|
||||
|
||||
// Please add new elements here. The naming convention is abbreviated class
|
||||
// name (e.g. RenderFrameHost becomes RFH) plus a unique description of the
|
||||
diff --git a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
|
||||
index 1a3b5b446bbff28e60278bfe5f29e13acc3c5306..488b6746a3545f687159dabfee4dd278c1eaea0e 100644
|
||||
--- a/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
|
||||
+++ b/content/browser/renderer_host/media/media_stream_dispatcher_host.cc
|
||||
@@ -196,6 +196,13 @@ void MediaStreamDispatcherHost::OpenDevice(int32_t page_request_id,
|
||||
blink::mojom::MediaStreamType type,
|
||||
OpenDeviceCallback callback) {
|
||||
DCHECK_CURRENTLY_ON(BrowserThread::IO);
|
||||
+ // OpenDevice is only supported for microphone or webcam capture.
|
||||
+ if (type != blink::mojom::MediaStreamType::DEVICE_AUDIO_CAPTURE &&
|
||||
+ type != blink::mojom::MediaStreamType::DEVICE_VIDEO_CAPTURE) {
|
||||
+ bad_message::ReceivedBadMessage(
|
||||
+ render_process_id_, bad_message::MDDH_INVALID_DEVICE_TYPE_REQUEST);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
base::PostTaskAndReplyWithResult(
|
||||
base::CreateSingleThreadTaskRunner({BrowserThread::UI}).get(), FROM_HERE,
|
||||
diff --git a/tools/metrics/histograms/enums.xml b/tools/metrics/histograms/enums.xml
|
||||
index d69575e355a2692531a9c76ccdb6bb69eae07da8..21dc7d1d1b07e246232d128cd6a7084915ca0c6c 100644
|
||||
--- a/tools/metrics/histograms/enums.xml
|
||||
+++ b/tools/metrics/histograms/enums.xml
|
||||
@@ -5668,6 +5668,7 @@ Unknown properties are collapsed to zero. -->
|
||||
<int value="225" label="RFH_BAD_DOCUMENT_POLICY_HEADER"/>
|
||||
<int value="226" label="RFMF_INVALID_PLUGIN_EMBEDDER_ORIGIN"/>
|
||||
<int value="227" label="RFH_INVALID_CALL_FROM_NOT_MAIN_FRAME"/>
|
||||
+ <int value="234" label="MSDH_INVALID_STREAM_TYPE"/>
|
||||
</enum>
|
||||
|
||||
<enum name="BadMessageReasonExtensions">
|
||||
29
patches/chromium/cherry-pick-30261f9de11e.patch
Normal file
29
patches/chromium/cherry-pick-30261f9de11e.patch
Normal file
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lei Zhang <thestig@chromium.org>
|
||||
Date: Thu, 1 Oct 2020 19:18:54 +0000
|
||||
Subject: Check RF is alive In PrintRenderFrameHelper::PreviewPageRendered().
|
||||
|
||||
Do not take an accessibility snapshot if the RenderFrame is gone.
|
||||
|
||||
Bug: 1133983
|
||||
Change-Id: I612cc72936a1dcedc5180c24eae067e47237b09b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2442375
|
||||
Reviewed-by: Dominic Mazzoni <dmazzoni@chromium.org>
|
||||
Commit-Queue: Lei Zhang <thestig@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#812851}
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index 9dd56e9df0d91ccd1d6789e3b3f261a533d373e8..340c31dc77d719dcf37f23770f16ca9e64536b03 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -2403,6 +2403,10 @@ bool PrintRenderFrameHelper::PreviewPageRendered(
|
||||
DCHECK(print_preview_context_.IsModifiable());
|
||||
|
||||
#if BUILDFLAG(ENABLE_TAGGED_PDF)
|
||||
+ // Make sure the RenderFrame is alive before taking the snapshot.
|
||||
+ if (render_frame_gone_)
|
||||
+ snapshotter_.reset();
|
||||
+
|
||||
// For tagged PDF exporting, send a snapshot of the accessibility tree
|
||||
// along with page 0. The accessibility tree contains the content for
|
||||
// all of the pages of the main frame.
|
||||
61
patches/chromium/cherry-pick-3abc372c9c00.patch
Normal file
61
patches/chromium/cherry-pick-3abc372c9c00.patch
Normal file
@@ -0,0 +1,61 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Date: Tue, 3 Nov 2020 23:00:29 +0000
|
||||
Subject: Apply markup sanitizer in CompositeEditCommand::MoveParagraphs()
|
||||
|
||||
CompositeEditCommand::MoveParagraphs() serailizes part of the DOM and
|
||||
then re-parse it and insert it at some other place of the document. This
|
||||
is essentially a copy-and-paste, and can be exploited in the same way
|
||||
how copy-and-paste is exploited. So we should also sanitize markup in
|
||||
the function.
|
||||
|
||||
(cherry picked from commit c529cbcc1bb0f72af944c30f03c2b3b435317bc7)
|
||||
|
||||
Bug: 1141350
|
||||
Change-Id: I25c1dfc61c20b9134b23e057c5a3a0f56c190b5c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2500633
|
||||
Commit-Queue: Yoshifumi Inoue <yosin@chromium.org>
|
||||
Reviewed-by: Yoshifumi Inoue <yosin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#821098}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2518088
|
||||
Reviewed-by: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Commit-Queue: Xiaocheng Hu <xiaochengh@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4280@{#1099}
|
||||
Cr-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
|
||||
index a665fe438041cce473b195a606378ee26500ebc4..2ba9c0cd368b3b907320ef2d6de550ae7598779e 100644
|
||||
--- a/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
|
||||
+++ b/third_party/blink/renderer/core/editing/commands/composite_edit_command.cc
|
||||
@@ -1492,19 +1492,18 @@ void CompositeEditCommand::MoveParagraphs(
|
||||
// FIXME: This is an inefficient way to preserve style on nodes in the
|
||||
// paragraph to move. It shouldn't matter though, since moved paragraphs will
|
||||
// usually be quite small.
|
||||
- DocumentFragment* fragment =
|
||||
- start_of_paragraph_to_move.DeepEquivalent() !=
|
||||
- end_of_paragraph_to_move.DeepEquivalent()
|
||||
- ? CreateFragmentFromMarkup(
|
||||
- GetDocument(),
|
||||
- CreateMarkup(start.ParentAnchoredEquivalent(),
|
||||
- end.ParentAnchoredEquivalent(),
|
||||
- CreateMarkupOptions::Builder()
|
||||
- .SetShouldConvertBlocksToInlines(true)
|
||||
- .SetConstrainingAncestor(constraining_ancestor)
|
||||
- .Build()),
|
||||
- "", kDisallowScriptingAndPluginContent)
|
||||
- : nullptr;
|
||||
+ DocumentFragment* fragment = nullptr;
|
||||
+ if (start_of_paragraph_to_move.DeepEquivalent() !=
|
||||
+ end_of_paragraph_to_move.DeepEquivalent()) {
|
||||
+ const String paragraphs_markup = CreateMarkup(
|
||||
+ start.ParentAnchoredEquivalent(), end.ParentAnchoredEquivalent(),
|
||||
+ CreateMarkupOptions::Builder()
|
||||
+ .SetShouldConvertBlocksToInlines(true)
|
||||
+ .SetConstrainingAncestor(constraining_ancestor)
|
||||
+ .Build());
|
||||
+ fragment = CreateSanitizedFragmentFromMarkupWithContext(
|
||||
+ GetDocument(), paragraphs_markup, 0, paragraphs_markup.length(), "");
|
||||
+ }
|
||||
|
||||
// A non-empty paragraph's style is moved when we copy and move it. We don't
|
||||
// move anything if we're given an empty paragraph, but an empty paragraph can
|
||||
115
patches/chromium/cherry-pick-52dceba66599.patch
Normal file
115
patches/chromium/cherry-pick-52dceba66599.patch
Normal file
@@ -0,0 +1,115 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Rahul Arakeri <arakeri@microsoft.com>
|
||||
Date: Tue, 8 Sep 2020 20:36:24 +0000
|
||||
Subject: Fix for UAF when referencing a deleted scrollbar layer.
|
||||
|
||||
This CL fixes an issue where autoscroll may be called on a scrollbar
|
||||
layer that is deleted. When the pointer is pressed down, an autoscroll
|
||||
task is scheduled to be executed after ~250ms. The task will execute if
|
||||
the pointer remains held down. In LayerTreeImpl::UnregisterScrollbar,
|
||||
DidUnregisterScrollbarLayer only gets called after both scrollbars are
|
||||
removed. So if you go from 2 to 1 scrollbar while an autoscroll task is
|
||||
queued, the autoscroll task won't get cancelled. At this point, the
|
||||
ScrollbarController tries to access the deleted scrollbar and that
|
||||
leads to an access violation. The fix here is to ensure that the call
|
||||
to DidUnregisterScrollbarLayer happens for each scrollbar.
|
||||
|
||||
Bug: 1106612
|
||||
Change-Id: I4f1d684830012db8fdd73258c9a9e5231807bcb6
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2356809
|
||||
Reviewed-by: Robert Flack <flackr@chromium.org>
|
||||
Commit-Queue: Rahul Arakeri <arakeri@microsoft.com>
|
||||
Cr-Commit-Position: refs/heads/master@{#805057}
|
||||
(cherry picked from commit 52dceba66599f0892fb649717fc462ff016d2fa2)
|
||||
|
||||
diff --git a/cc/input/scrollbar_controller.cc b/cc/input/scrollbar_controller.cc
|
||||
index b4d2ef531e2f5ccee157babb67522c454c720c9e..be80b5e07f5330ac636946f32f6cf713e0bb77a5 100644
|
||||
--- a/cc/input/scrollbar_controller.cc
|
||||
+++ b/cc/input/scrollbar_controller.cc
|
||||
@@ -433,9 +433,12 @@ void ScrollbarController::ResetState() {
|
||||
captured_scrollbar_metadata_ = base::nullopt;
|
||||
}
|
||||
|
||||
-void ScrollbarController::DidUnregisterScrollbar(ElementId element_id) {
|
||||
+void ScrollbarController::DidUnregisterScrollbar(
|
||||
+ ElementId element_id,
|
||||
+ ScrollbarOrientation orientation) {
|
||||
if (captured_scrollbar_metadata_.has_value() &&
|
||||
- captured_scrollbar_metadata_->scroll_element_id == element_id)
|
||||
+ captured_scrollbar_metadata_->scroll_element_id == element_id &&
|
||||
+ captured_scrollbar_metadata_->orientation == orientation)
|
||||
ResetState();
|
||||
}
|
||||
|
||||
@@ -531,6 +534,7 @@ void ScrollbarController::StartAutoScrollAnimation(
|
||||
// the same time.
|
||||
DCHECK(!drag_state_.has_value());
|
||||
DCHECK_NE(velocity, 0);
|
||||
+ DCHECK(ScrollbarLayer());
|
||||
|
||||
// scroll_node is set up while handling GSB. If there's no node to scroll, we
|
||||
// don't need to create any animation for it.
|
||||
diff --git a/cc/input/scrollbar_controller.h b/cc/input/scrollbar_controller.h
|
||||
index ab93bde692dfc48f3d2e2f95ca56c984e8d0eb88..c9faf8ca505776b1b2764225427e28008ae74c8e 100644
|
||||
--- a/cc/input/scrollbar_controller.h
|
||||
+++ b/cc/input/scrollbar_controller.h
|
||||
@@ -135,7 +135,8 @@ class CC_EXPORT ScrollbarController {
|
||||
const ScrollbarLayerImplBase* scrollbar,
|
||||
ScrollbarPart pressed_scrollbar_part);
|
||||
bool ScrollbarScrollIsActive() { return scrollbar_scroll_is_active_; }
|
||||
- void DidUnregisterScrollbar(ElementId element_id);
|
||||
+ void DidUnregisterScrollbar(ElementId element_id,
|
||||
+ ScrollbarOrientation orientation);
|
||||
ScrollbarLayerImplBase* ScrollbarLayer();
|
||||
void WillBeginImplFrame();
|
||||
|
||||
diff --git a/cc/trees/layer_tree_host_impl.cc b/cc/trees/layer_tree_host_impl.cc
|
||||
index 688a0905c997c86b63bcc607033ec82a74741114..46821befb4f1720a93cb9e4b8e9d33bd45a6292a 100644
|
||||
--- a/cc/trees/layer_tree_host_impl.cc
|
||||
+++ b/cc/trees/layer_tree_host_impl.cc
|
||||
@@ -5326,9 +5326,10 @@ void LayerTreeHostImpl::RegisterScrollbarAnimationController(
|
||||
}
|
||||
|
||||
void LayerTreeHostImpl::DidUnregisterScrollbarLayer(
|
||||
- ElementId scroll_element_id) {
|
||||
+ ElementId scroll_element_id,
|
||||
+ ScrollbarOrientation orientation) {
|
||||
scrollbar_animation_controllers_.erase(scroll_element_id);
|
||||
- scrollbar_controller_->DidUnregisterScrollbar(scroll_element_id);
|
||||
+ scrollbar_controller_->DidUnregisterScrollbar(scroll_element_id, orientation);
|
||||
}
|
||||
|
||||
ScrollbarAnimationController*
|
||||
diff --git a/cc/trees/layer_tree_host_impl.h b/cc/trees/layer_tree_host_impl.h
|
||||
index 2352d8e17c316542f2d65f6e1c6b075db9cf66bd..f2272d0c760f3301b0b64d81d6372758110798e9 100644
|
||||
--- a/cc/trees/layer_tree_host_impl.h
|
||||
+++ b/cc/trees/layer_tree_host_impl.h
|
||||
@@ -464,7 +464,8 @@ class CC_EXPORT LayerTreeHostImpl : public InputHandler,
|
||||
|
||||
void RegisterScrollbarAnimationController(ElementId scroll_element_id,
|
||||
float initial_opacity);
|
||||
- void DidUnregisterScrollbarLayer(ElementId scroll_element_id);
|
||||
+ void DidUnregisterScrollbarLayer(ElementId scroll_element_id,
|
||||
+ ScrollbarOrientation orientation);
|
||||
ScrollbarAnimationController* ScrollbarAnimationControllerForElementId(
|
||||
ElementId scroll_element_id) const;
|
||||
void FlashAllScrollbars(bool did_scroll);
|
||||
diff --git a/cc/trees/layer_tree_impl.cc b/cc/trees/layer_tree_impl.cc
|
||||
index 45f7e5707a0ab5b983294964369d549e2981bf7d..2b6ea7532e954babe7150386209e958546b9bc40 100644
|
||||
--- a/cc/trees/layer_tree_impl.cc
|
||||
+++ b/cc/trees/layer_tree_impl.cc
|
||||
@@ -1933,9 +1933,11 @@ void LayerTreeImpl::UnregisterScrollbar(
|
||||
if (scrollbar_ids.horizontal == Layer::INVALID_ID &&
|
||||
scrollbar_ids.vertical == Layer::INVALID_ID) {
|
||||
element_id_to_scrollbar_layer_ids_.erase(scroll_element_id);
|
||||
- if (IsActiveTree()) {
|
||||
- host_impl_->DidUnregisterScrollbarLayer(scroll_element_id);
|
||||
- }
|
||||
+ }
|
||||
+
|
||||
+ if (IsActiveTree()) {
|
||||
+ host_impl_->DidUnregisterScrollbarLayer(scroll_element_id,
|
||||
+ scrollbar_layer->orientation());
|
||||
}
|
||||
}
|
||||
|
||||
37
patches/chromium/cherry-pick-5ffbb7ed173a.patch
Normal file
37
patches/chromium/cherry-pick-5ffbb7ed173a.patch
Normal file
@@ -0,0 +1,37 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Darwin Huang <huangdarwin@chromium.org>
|
||||
Date: Fri, 13 Nov 2020 10:07:05 +0000
|
||||
Subject: Pepper: Ensure weak pointer is still valid before use (M86).
|
||||
|
||||
TBR=bbudge@chromium.org
|
||||
(cherry picked from commit f24c213293752250db05e11c5e4b77adce002d38)
|
||||
|
||||
Bug: 1146675
|
||||
Change-Id: I382dcb5c0b09a26e3c397ebef46947f626e2aef9
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2527065
|
||||
Reviewed-by: Bill Budge <bbudge@chromium.org>
|
||||
Commit-Queue: Darwin Huang <huangdarwin@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#825558}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536757
|
||||
Reviewed-by: Darwin Huang <huangdarwin@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1448}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
|
||||
index bd68358ddb41529bf946d10d7eb66ff4b6d20519..ae42a62622724d4aee85a066f1931deea7f00037 100644
|
||||
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc
|
||||
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
|
||||
@@ -248,7 +248,12 @@ void PepperFileIOHost::GotUIThreadStuffForInternalFileSystems(
|
||||
return;
|
||||
}
|
||||
|
||||
- DCHECK(file_system_host_.get());
|
||||
+ if (!file_system_host_.get()) {
|
||||
+ reply_context.params.set_result(PP_ERROR_FAILED);
|
||||
+ SendOpenErrorReply(reply_context);
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
DCHECK(file_system_host_->GetFileSystemOperationRunner());
|
||||
|
||||
file_system_host_->GetFileSystemOperationRunner()->OpenFile(
|
||||
78
patches/chromium/cherry-pick-70579363ce7b.patch
Normal file
78
patches/chromium/cherry-pick-70579363ce7b.patch
Normal file
@@ -0,0 +1,78 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Reilly Grant <reillyg@chromium.org>
|
||||
Date: Wed, 22 Jul 2020 04:00:16 +0000
|
||||
Subject: usb: Prevent iterator invalidation during Promise resolution
|
||||
|
||||
This change swaps sets of ScriptPromiseResolvers into local variables in
|
||||
a number of places where it was possible for script to execute during
|
||||
the call to Resolve() or Reject() and modify the set being iterated
|
||||
over, thus invalidating the iterator.
|
||||
|
||||
(cherry picked from commit dbc6c3c3652680e287c60b3c6551622748543439)
|
||||
|
||||
Bug: 1106773
|
||||
Change-Id: Id4eb0cd444a7dbb5de23038ec80f44fee649cfe4
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2304538
|
||||
Auto-Submit: Reilly Grant <reillyg@chromium.org>
|
||||
Commit-Queue: James Hollyer <jameshollyer@chromium.org>
|
||||
Reviewed-by: James Hollyer <jameshollyer@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#790217}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2310964
|
||||
Reviewed-by: Reilly Grant <reillyg@chromium.org>
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4183@{#842}
|
||||
Cr-Branched-From: 740e9e8a40505392ba5c8e022a8024b3d018ca65-refs/heads/master@{#782793}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webusb/usb.cc b/third_party/blink/renderer/modules/webusb/usb.cc
|
||||
index de66613d20851dee9a96a8fdcfaec30da9f05b53..e3dc44eb208946aac4a2f836365127ba88c08edd 100644
|
||||
--- a/third_party/blink/renderer/modules/webusb/usb.cc
|
||||
+++ b/third_party/blink/renderer/modules/webusb/usb.cc
|
||||
@@ -254,15 +254,22 @@ void USB::OnDeviceRemoved(UsbDeviceInfoPtr device_info) {
|
||||
void USB::OnServiceConnectionError() {
|
||||
service_.reset();
|
||||
client_receiver_.reset();
|
||||
- for (ScriptPromiseResolver* resolver : get_devices_requests_)
|
||||
+
|
||||
+ // Move the set to a local variable to prevent script execution in Resolve()
|
||||
+ // from invalidating the iterator used by the loop.
|
||||
+ HeapHashSet<Member<ScriptPromiseResolver>> get_devices_requests;
|
||||
+ get_devices_requests.swap(get_devices_requests_);
|
||||
+ for (auto& resolver : get_devices_requests)
|
||||
resolver->Resolve(HeapVector<Member<USBDevice>>(0));
|
||||
- get_devices_requests_.clear();
|
||||
|
||||
- for (ScriptPromiseResolver* resolver : get_permission_requests_) {
|
||||
+ // Move the set to a local variable to prevent script execution in Reject()
|
||||
+ // from invalidating the iterator used by the loop.
|
||||
+ HeapHashSet<Member<ScriptPromiseResolver>> get_permission_requests;
|
||||
+ get_permission_requests.swap(get_permission_requests_);
|
||||
+ for (auto& resolver : get_permission_requests) {
|
||||
resolver->Reject(MakeGarbageCollected<DOMException>(
|
||||
DOMExceptionCode::kNotFoundError, kNoDeviceSelected));
|
||||
}
|
||||
- get_permission_requests_.clear();
|
||||
}
|
||||
|
||||
void USB::AddedEventListener(const AtomicString& event_type,
|
||||
diff --git a/third_party/blink/renderer/modules/webusb/usb_device.cc b/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
index 655212ee5dd6c27498b83b8eb5b9e13a14c38a40..17f52e86a134ceb137923b65d1686ce3cbf3bf85 100644
|
||||
--- a/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
+++ b/third_party/blink/renderer/modules/webusb/usb_device.cc
|
||||
@@ -1125,11 +1125,15 @@ void USBDevice::AsyncReset(ScriptPromiseResolver* resolver, bool success) {
|
||||
void USBDevice::OnConnectionError() {
|
||||
device_.reset();
|
||||
opened_ = false;
|
||||
- for (ScriptPromiseResolver* resolver : device_requests_) {
|
||||
+
|
||||
+ // Move the set to a local variable to prevent script execution in Reject()
|
||||
+ // from invalidating the iterator used by the loop.
|
||||
+ HeapHashSet<Member<ScriptPromiseResolver>> device_requests;
|
||||
+ device_requests.swap(device_requests_);
|
||||
+ for (auto& resolver : device_requests) {
|
||||
resolver->Reject(MakeGarbageCollected<DOMException>(
|
||||
DOMExceptionCode::kNotFoundError, kDeviceDisconnected));
|
||||
}
|
||||
- device_requests_.clear();
|
||||
}
|
||||
|
||||
bool USBDevice::MarkRequestComplete(ScriptPromiseResolver* resolver) {
|
||||
83
patches/chromium/cherry-pick-72ee7c437c88.patch
Normal file
83
patches/chromium/cherry-pick-72ee7c437c88.patch
Normal file
@@ -0,0 +1,83 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hiroki Nakagawa <nhiroki@chromium.org>
|
||||
Date: Fri, 7 Aug 2020 15:27:06 +0000
|
||||
Subject: Worker: Fix a race condition on task runner handling
|
||||
|
||||
WebSharedWorkerImpl accesses WorkerScheduler from the main thread to
|
||||
take a task runner, and then dispatches a connect event to
|
||||
SharedWorkerGlobalScope using the task runner.
|
||||
|
||||
This causes a race condition if close() is called on the global scope
|
||||
on the worker thread while the task runner is being taken on the main
|
||||
thread: close() call disposes of WorkerScheduler, and accessing the
|
||||
scheduler after that is not allowed. See the issue for details.
|
||||
|
||||
To fix this, this CL makes WebSharedWorkerImpl capture the task runner
|
||||
between starting a worker thread (initializing WorkerScheduler) and
|
||||
posting a task to evaluate worker scripts that may call close(). This
|
||||
ensures that WebSharedWorkerImpl accesses WorkerScheduler before the
|
||||
scheduler is disposed of.
|
||||
|
||||
(cherry picked from commit c7bbec3e595c4359e36e5472b7265c4b6d047f2c)
|
||||
|
||||
Bug: 1104046
|
||||
Change-Id: I145cd39f706019c33220fcb01ed81f76963ffff0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2308550
|
||||
Commit-Queue: Hiroki Nakagawa <nhiroki@chromium.org>
|
||||
Reviewed-by: Kenichi Ishibashi <bashi@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#790284}
|
||||
Tbr: bashi@chromium.org
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2342337
|
||||
Reviewed-by: Hiroki Nakagawa <nhiroki@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#1050}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
|
||||
index 7582cdbd3a1ee5e8a58686715020f304319860d8..9942e60d41f4add60bf28388902e08bc1d071dc7 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.cc
|
||||
@@ -145,11 +145,8 @@ void WebSharedWorkerImpl::Connect(MessagePortChannel web_channel) {
|
||||
DCHECK(IsMainThread());
|
||||
if (asked_to_terminate_)
|
||||
return;
|
||||
- // The HTML spec requires to queue a connect event using the DOM manipulation
|
||||
- // task source.
|
||||
- // https://html.spec.whatwg.org/C/#shared-workers-and-the-sharedworker-interface
|
||||
PostCrossThreadTask(
|
||||
- *GetWorkerThread()->GetTaskRunner(TaskType::kDOMManipulation), FROM_HERE,
|
||||
+ *task_runner_for_connect_event_, FROM_HERE,
|
||||
CrossThreadBindOnce(&WebSharedWorkerImpl::ConnectTaskOnWorkerThread,
|
||||
WTF::CrossThreadUnretained(this),
|
||||
WTF::Passed(std::move(web_channel))));
|
||||
@@ -269,6 +266,18 @@ void WebSharedWorkerImpl::StartWorkerContext(
|
||||
|
||||
GetWorkerThread()->Start(std::move(creation_params), thread_startup_data,
|
||||
std::move(devtools_params));
|
||||
+
|
||||
+ // Capture the task runner for dispatching connect events. This is necessary
|
||||
+ // for avoiding race condition with WorkerScheduler termination induced by
|
||||
+ // close() call on SharedWorkerGlobalScope. See https://crbug.com/1104046 for
|
||||
+ // details.
|
||||
+ //
|
||||
+ // The HTML spec requires to queue a connect event using the DOM manipulation
|
||||
+ // task source.
|
||||
+ // https://html.spec.whatwg.org/C/#shared-workers-and-the-sharedworker-interface
|
||||
+ task_runner_for_connect_event_ =
|
||||
+ GetWorkerThread()->GetTaskRunner(TaskType::kDOMManipulation);
|
||||
+
|
||||
switch (script_type) {
|
||||
case mojom::ScriptType::kClassic:
|
||||
GetWorkerThread()->FetchAndRunClassicScript(
|
||||
diff --git a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
|
||||
index 13006f67bd3e10b8d6c38e504d4bf235aa2f9022..98374fb9031e200a225e6e2982ff2d364fa007f5 100644
|
||||
--- a/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
|
||||
+++ b/third_party/blink/renderer/core/exported/web_shared_worker_impl.h
|
||||
@@ -114,6 +114,8 @@ class CORE_EXPORT WebSharedWorkerImpl final : public WebSharedWorker {
|
||||
// |client_| owns |this|.
|
||||
WebSharedWorkerClient* client_;
|
||||
|
||||
+ scoped_refptr<base::SingleThreadTaskRunner> task_runner_for_connect_event_;
|
||||
+
|
||||
bool asked_to_terminate_ = false;
|
||||
|
||||
base::WeakPtrFactory<WebSharedWorkerImpl> weak_ptr_factory_{this};
|
||||
54
patches/chromium/cherry-pick-814a27f8522b.patch
Normal file
54
patches/chromium/cherry-pick-814a27f8522b.patch
Normal file
@@ -0,0 +1,54 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andrey Kosyakov <caseq@chromium.org>
|
||||
Date: Fri, 28 Aug 2020 18:55:17 +0000
|
||||
Subject: Delegate TargetHandler::Session permission checks to the root client
|
||||
|
||||
Bug: 1114636
|
||||
Change-Id: Iba3865206d7e80b363ec69180ac05e20b56aade2
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2380855
|
||||
Reviewed-by: Dmitry Gozman <dgozman@chromium.org>
|
||||
Reviewed-by: Devlin <rdevlin.cronin@chromium.org>
|
||||
Commit-Queue: Andrey Kosyakov <caseq@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#802736}
|
||||
(cherry picked from commit 814a27f8522b6ccddcce1a8f6a3b8fb37128ecf9)
|
||||
|
||||
diff --git a/content/browser/devtools/protocol/target_handler.cc b/content/browser/devtools/protocol/target_handler.cc
|
||||
index 4614ecae2110e5577539cffba02fcab153af301f..bcd054f2dc388908cf92bae3ff0254422960dc12 100644
|
||||
--- a/content/browser/devtools/protocol/target_handler.cc
|
||||
+++ b/content/browser/devtools/protocol/target_handler.cc
|
||||
@@ -436,7 +436,7 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
|
||||
// was introduced. Try a DCHECK instead and possibly remove the check.
|
||||
if (!handler_->root_session_->HasChildSession(id_))
|
||||
return;
|
||||
- handler_->root_session_->GetClient()->DispatchProtocolMessage(
|
||||
+ GetRootClient()->DispatchProtocolMessage(
|
||||
handler_->root_session_->GetAgentHost(), message);
|
||||
return;
|
||||
}
|
||||
@@ -454,6 +454,26 @@ class TargetHandler::Session : public DevToolsAgentHostClient {
|
||||
Detach(true);
|
||||
}
|
||||
|
||||
+ bool MayAttachToURL(const GURL& url, bool is_webui) override {
|
||||
+ return GetRootClient()->MayAttachToURL(url, is_webui);
|
||||
+ }
|
||||
+
|
||||
+ bool MayAttachToBrowser() override {
|
||||
+ return GetRootClient()->MayAttachToBrowser();
|
||||
+ }
|
||||
+
|
||||
+ bool MayReadLocalFiles() override {
|
||||
+ return GetRootClient()->MayReadLocalFiles();
|
||||
+ }
|
||||
+
|
||||
+ bool MayWriteLocalFiles() override {
|
||||
+ return GetRootClient()->MayWriteLocalFiles();
|
||||
+ }
|
||||
+
|
||||
+ content::DevToolsAgentHostClient* GetRootClient() {
|
||||
+ return handler_->root_session_->GetClient();
|
||||
+ }
|
||||
+
|
||||
TargetHandler* handler_;
|
||||
scoped_refptr<DevToolsAgentHost> agent_host_;
|
||||
std::string id_;
|
||||
292
patches/chromium/cherry-pick-8629cd7f8af3.patch
Normal file
292
patches/chromium/cherry-pick-8629cd7f8af3.patch
Normal file
@@ -0,0 +1,292 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Raymond Toy <rtoy@chromium.org>
|
||||
Date: Tue, 29 Sep 2020 17:56:16 +0000
|
||||
Subject: Add mutex for allowing the graph to be pulled
|
||||
|
||||
Basically add a mutex to protect access to
|
||||
allow_pulling_audio_graph_. The main thread waits until it has the
|
||||
lock before setting this. This prevents the main thread from deleting
|
||||
things while the audio thread is pulling on the graph.
|
||||
|
||||
A try lock is used so as not to block the audio thread if it can't get
|
||||
lock.
|
||||
|
||||
This is applied to both real time and offline contexts which required
|
||||
moving the original real-time-only implementation to
|
||||
audio_destination_node so we can use the same methods for the offline
|
||||
context.
|
||||
|
||||
Tested the repro case from 1125635, and the issue does not reproduce.
|
||||
We're assuming this will fix 1115901, but I've not been able to
|
||||
reproduce that locally.
|
||||
|
||||
(cherry picked from commit 6785a406fd652f7a2f40933620ef4c979643c56b)
|
||||
|
||||
Bug: 1125635, 1115901
|
||||
Change-Id: I1037d8c44225c6dcc8fe906c29a5a86740a15e1d
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2410743
|
||||
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
|
||||
Commit-Queue: Raymond Toy <rtoy@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#809393}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2436324
|
||||
Reviewed-by: Raymond Toy <rtoy@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1083}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/audio_destination_node.cc
|
||||
index c85f6d2e26f2e34b8633c29754028afbd8f2cbb9..9b1a5ec495f8f3614e8e77fdeaf9eaa159b3e3ae 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_destination_node.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_destination_node.cc
|
||||
@@ -30,7 +30,8 @@
|
||||
namespace blink {
|
||||
|
||||
AudioDestinationHandler::AudioDestinationHandler(AudioNode& node)
|
||||
- : AudioHandler(kNodeTypeDestination, node, 0) {
|
||||
+ : AudioHandler(kNodeTypeDestination, node, 0),
|
||||
+ allow_pulling_audio_graph_(false) {
|
||||
AddInput();
|
||||
}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/audio_destination_node.h b/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
|
||||
index c35722c9296b6c98832444799124334d382225df..ce7bf61ef9ad18a5aa9669edb990542d2899acc2 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/audio_destination_node.h
|
||||
@@ -71,6 +71,53 @@ class AudioDestinationHandler : public AudioHandler {
|
||||
return is_execution_context_destroyed_;
|
||||
}
|
||||
|
||||
+ // Should only be called from
|
||||
+ // RealtimeAudioDestinationHandler::StartPlatformDestination for a realtime
|
||||
+ // context or OfflineAudioDestinationHandler::StartRendering for an offline
|
||||
+ // context---basically wherever the context has started rendering.
|
||||
+ // TODO(crbug.com/1128121): Consider removing this if possible
|
||||
+ void EnablePullingAudioGraph() {
|
||||
+ MutexLocker lock(allow_pulling_audio_graph_mutex_);
|
||||
+ allow_pulling_audio_graph_.store(true, std::memory_order_release);
|
||||
+ }
|
||||
+
|
||||
+ // Should only be called from
|
||||
+ // RealtimeAudioDestinationHandler::StopPlatformDestination for a realtime
|
||||
+ // context or from OfflineAudioDestinationHandler::Uninitialize for an offline
|
||||
+ // context---basically whenever the context is being stopped.
|
||||
+ // TODO(crbug.com/1128121): Consider removing this if possible
|
||||
+ void DisablePullingAudioGraph() {
|
||||
+ MutexLocker lock(allow_pulling_audio_graph_mutex_);
|
||||
+ allow_pulling_audio_graph_.store(false, std::memory_order_release);
|
||||
+ }
|
||||
+
|
||||
+ // TODO(crbug.com/1128121): Consider removing this if possible
|
||||
+ bool IsPullingAudioGraphAllowed() const {
|
||||
+ return allow_pulling_audio_graph_.load(std::memory_order_acquire);
|
||||
+ }
|
||||
+
|
||||
+ // If true, the audio graph will be pulled to get new data. Otherwise, the
|
||||
+ // graph is not pulled, even if the audio thread is still running and
|
||||
+ // requesting data.
|
||||
+ //
|
||||
+ // For an AudioContext, this MUST be modified only in
|
||||
+ // RealtimeAudioDestinationHandler::StartPlatformDestination (via
|
||||
+ // AudioDestinationHandler::EnablePullingAudioGraph) or
|
||||
+ // RealtimeAudioDestinationHandler::StopPlatformDestination (via
|
||||
+ // AudioDestinationHandler::DisablePullingAudioGraph), including destroying
|
||||
+ // the the realtime context.
|
||||
+ //
|
||||
+ // For an OfflineAudioContext, this MUST be modified only when the the context
|
||||
+ // is started or it has stopped rendering, including destroying the offline
|
||||
+ // context.
|
||||
+
|
||||
+ // TODO(crbug.com/1128121): Consider removing this if possible
|
||||
+ std::atomic_bool allow_pulling_audio_graph_;
|
||||
+
|
||||
+ // Protects allow_pulling_audio_graph_ from race conditions. Must use try
|
||||
+ // lock on the audio thread.
|
||||
+ mutable Mutex allow_pulling_audio_graph_mutex_;
|
||||
+
|
||||
protected:
|
||||
void AdvanceCurrentSampleFrame(size_t number_of_frames) {
|
||||
current_sample_frame_.fetch_add(number_of_frames,
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
index 2b0d87395cef31793273ef69f61eb540be897fcf..697a3e684e9bc582a93b20ac163ceb790dfb62cc 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
@@ -92,6 +92,7 @@ void OfflineAudioDestinationHandler::Uninitialize() {
|
||||
|
||||
render_thread_.reset();
|
||||
|
||||
+ DisablePullingAudioGraph();
|
||||
AudioHandler::Uninitialize();
|
||||
}
|
||||
|
||||
@@ -111,6 +112,7 @@ void OfflineAudioDestinationHandler::StartRendering() {
|
||||
// Rendering was not started. Starting now.
|
||||
if (!is_rendering_started_) {
|
||||
is_rendering_started_ = true;
|
||||
+ EnablePullingAudioGraph();
|
||||
PostCrossThreadTask(
|
||||
*render_thread_task_runner_, FROM_HERE,
|
||||
CrossThreadBindOnce(
|
||||
@@ -292,20 +294,34 @@ bool OfflineAudioDestinationHandler::RenderIfNotSuspended(
|
||||
|
||||
DCHECK_GE(NumberOfInputs(), 1u);
|
||||
|
||||
- // This will cause the node(s) connected to us to process, which in turn will
|
||||
- // pull on their input(s), all the way backwards through the rendering graph.
|
||||
- scoped_refptr<AudioBus> rendered_bus =
|
||||
- Input(0).Pull(destination_bus, number_of_frames);
|
||||
+ {
|
||||
+ // The entire block that relies on |IsPullingAudioGraphAllowed| needs
|
||||
+ // locking to prevent pulling audio graph being disallowed (i.e. a
|
||||
+ // destruction started) in the middle of processing
|
||||
+ MutexTryLocker try_locker(allow_pulling_audio_graph_mutex_);
|
||||
+
|
||||
+ if (IsPullingAudioGraphAllowed() && try_locker.Locked()) {
|
||||
+ // This will cause the node(s) connected to us to process, which in turn
|
||||
+ // will pull on their input(s), all the way backwards through the
|
||||
+ // rendering graph.
|
||||
+ scoped_refptr<AudioBus> rendered_bus =
|
||||
+ Input(0).Pull(destination_bus, number_of_frames);
|
||||
+
|
||||
+ if (!rendered_bus) {
|
||||
+ destination_bus->Zero();
|
||||
+ } else if (rendered_bus != destination_bus) {
|
||||
+ // in-place processing was not possible - so copy
|
||||
+ destination_bus->CopyFrom(*rendered_bus);
|
||||
+ }
|
||||
|
||||
- if (!rendered_bus) {
|
||||
- destination_bus->Zero();
|
||||
- } else if (rendered_bus != destination_bus) {
|
||||
- // in-place processing was not possible - so copy
|
||||
- destination_bus->CopyFrom(*rendered_bus);
|
||||
+ } else {
|
||||
+ // Not allowed to pull on the graph or couldn't get the lock.
|
||||
+ destination_bus->Zero();
|
||||
+ }
|
||||
}
|
||||
|
||||
- // Process nodes which need a little extra help because they are not connected
|
||||
- // to anything, but still need to process.
|
||||
+ // Process nodes which need a little extra help because they are not
|
||||
+ // connected to anything, but still need to process.
|
||||
Context()->GetDeferredTaskHandler().ProcessAutomaticPullNodes(
|
||||
number_of_frames);
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.cc
|
||||
index 743cddb2d4bd7f04d8bdef7ce70241cbe2255430..dd183350f603d2c5997e89a62756a92c8ad566dc 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.cc
|
||||
@@ -52,8 +52,7 @@ RealtimeAudioDestinationHandler::RealtimeAudioDestinationHandler(
|
||||
base::Optional<float> sample_rate)
|
||||
: AudioDestinationHandler(node),
|
||||
latency_hint_(latency_hint),
|
||||
- sample_rate_(sample_rate),
|
||||
- allow_pulling_audio_graph_(false) {
|
||||
+ sample_rate_(sample_rate) {
|
||||
// Node-specific default channel count and mixing rules.
|
||||
channel_count_ = 2;
|
||||
SetInternalChannelCountMode(kExplicit);
|
||||
@@ -198,28 +197,38 @@ void RealtimeAudioDestinationHandler::Render(
|
||||
// Only pull on the audio graph if we have not stopped the destination. It
|
||||
// takes time for the destination to stop, but we want to stop pulling before
|
||||
// the destination has actually stopped.
|
||||
- if (IsPullingAudioGraphAllowed()) {
|
||||
- // Renders the graph by pulling all the inputs to this node. This will in
|
||||
- // turn pull on their inputs, all the way backwards through the graph.
|
||||
- scoped_refptr<AudioBus> rendered_bus =
|
||||
- Input(0).Pull(destination_bus, number_of_frames);
|
||||
-
|
||||
- DCHECK(rendered_bus);
|
||||
- if (!rendered_bus) {
|
||||
- // AudioNodeInput might be in the middle of destruction. Then the internal
|
||||
- // summing bus will return as nullptr. Then zero out the output.
|
||||
+ {
|
||||
+ // The entire block that relies on |IsPullingAudioGraphAllowed| needs
|
||||
+ // locking to prevent pulling audio graph being disallowed (i.e. a
|
||||
+ // destruction started) in the middle of processing.
|
||||
+ MutexTryLocker try_locker(allow_pulling_audio_graph_mutex_);
|
||||
+
|
||||
+ if (IsPullingAudioGraphAllowed() && try_locker.Locked()) {
|
||||
+ // Renders the graph by pulling all the inputs to this node. This will in
|
||||
+ // turn pull on their inputs, all the way backwards through the graph.
|
||||
+ scoped_refptr<AudioBus> rendered_bus =
|
||||
+ Input(0).Pull(destination_bus, number_of_frames);
|
||||
+
|
||||
+ DCHECK(rendered_bus);
|
||||
+ if (!rendered_bus) {
|
||||
+ // AudioNodeInput might be in the middle of destruction. Then the
|
||||
+ // internal summing bus will return as nullptr. Then zero out the
|
||||
+ // output.
|
||||
+ destination_bus->Zero();
|
||||
+ } else if (rendered_bus != destination_bus) {
|
||||
+ // In-place processing was not possible. Copy the rendered result to the
|
||||
+ // given |destination_bus| buffer.
|
||||
+ destination_bus->CopyFrom(*rendered_bus);
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Not allowed to pull on the graph or couldn't get the lock.
|
||||
destination_bus->Zero();
|
||||
- } else if (rendered_bus != destination_bus) {
|
||||
- // In-place processing was not possible. Copy the rendered result to the
|
||||
- // given |destination_bus| buffer.
|
||||
- destination_bus->CopyFrom(*rendered_bus);
|
||||
}
|
||||
- } else {
|
||||
- destination_bus->Zero();
|
||||
}
|
||||
|
||||
- // Processes "automatic" nodes that are not connected to anything. This can
|
||||
- // be done after copying because it does not affect the rendered result.
|
||||
+ // Processes "automatic" nodes that are not connected to anything. This
|
||||
+ // can be done after copying because it does not affect the rendered
|
||||
+ // result.
|
||||
context->GetDeferredTaskHandler().ProcessAutomaticPullNodes(number_of_frames);
|
||||
|
||||
context->HandlePostRenderTasks();
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.h b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.h
|
||||
index 9c8653880c37a02c87b2e82558dd2940a1b9a425..89e33ec6a9eb2b60ad1c2d46dcb748415bf2be33 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.h
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/realtime_audio_destination_node.h
|
||||
@@ -81,10 +81,6 @@ class RealtimeAudioDestinationHandler final : public AudioDestinationHandler,
|
||||
// Returns a given frames-per-buffer size from audio infra.
|
||||
int GetFramesPerBuffer() const;
|
||||
|
||||
- bool IsPullingAudioGraphAllowed() const {
|
||||
- return allow_pulling_audio_graph_.load(std::memory_order_acquire);
|
||||
- }
|
||||
-
|
||||
private:
|
||||
explicit RealtimeAudioDestinationHandler(AudioNode&,
|
||||
const WebAudioLatencyHint&,
|
||||
@@ -94,32 +90,12 @@ class RealtimeAudioDestinationHandler final : public AudioDestinationHandler,
|
||||
void StartPlatformDestination();
|
||||
void StopPlatformDestination();
|
||||
|
||||
- // Should only be called from StartPlatformDestination.
|
||||
- void EnablePullingAudioGraph() {
|
||||
- allow_pulling_audio_graph_.store(true, std::memory_order_release);
|
||||
- }
|
||||
-
|
||||
- // Should only be called from StopPlatformDestination.
|
||||
- void DisablePullingAudioGraph() {
|
||||
- allow_pulling_audio_graph_.store(false, std::memory_order_release);
|
||||
- }
|
||||
-
|
||||
const WebAudioLatencyHint latency_hint_;
|
||||
|
||||
// Holds the audio device thread that runs the real time audio context.
|
||||
scoped_refptr<AudioDestination> platform_destination_;
|
||||
|
||||
base::Optional<float> sample_rate_;
|
||||
-
|
||||
- // If true, the audio graph will be pulled to get new data. Otherwise, the
|
||||
- // graph is not pulled, even if the audio thread is still running and
|
||||
- // requesting data.
|
||||
- //
|
||||
- // Must be modified only in StartPlatformDestination (via
|
||||
- // EnablePullingAudioGraph) or StopPlatformDestination (via
|
||||
- // DisablePullingAudioGraph) . This is modified only by the main threda and
|
||||
- // the audio thread only reads this.
|
||||
- std::atomic_bool allow_pulling_audio_graph_;
|
||||
};
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
265
patches/chromium/cherry-pick-88f263f401b4.patch
Normal file
265
patches/chromium/cherry-pick-88f263f401b4.patch
Normal file
@@ -0,0 +1,265 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Will Cassella <cassew@google.com>
|
||||
Date: Thu, 24 Sep 2020 22:54:27 +0000
|
||||
Subject: Add callback to WebMediaPlayerImpl to notify when a redirect occurs
|
||||
|
||||
(cherry picked from commit 8b18bcfd9aa8096c4551ec34c0225b6017cd211e)
|
||||
|
||||
Bug: 1128657
|
||||
Change-Id: I9548e1f3bfe5693871a56e23c3373f45147e52e0
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2422091
|
||||
Reviewed-by: Dale Curtis <dalecurtis@chromium.org>
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#809217}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2425223
|
||||
Commit-Queue: Will Cassella <cassew@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#993}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/media/blink/multibuffer_data_source.cc b/media/blink/multibuffer_data_source.cc
|
||||
index 0f6ae1fb8b4ff9f24ce3f407b7359e016fc6de5f..4ec77cf8a6b56002e601fb89eb0dee059f3ab31b 100644
|
||||
--- a/media/blink/multibuffer_data_source.cc
|
||||
+++ b/media/blink/multibuffer_data_source.cc
|
||||
@@ -145,7 +145,7 @@ MultibufferDataSource::MultibufferDataSource(
|
||||
DCHECK(url_data_.get());
|
||||
url_data_->Use();
|
||||
url_data_->OnRedirect(
|
||||
- base::BindOnce(&MultibufferDataSource::OnRedirect, weak_ptr_));
|
||||
+ base::BindOnce(&MultibufferDataSource::OnRedirected, weak_ptr_));
|
||||
}
|
||||
|
||||
MultibufferDataSource::~MultibufferDataSource() {
|
||||
@@ -219,10 +219,10 @@ void MultibufferDataSource::Initialize(InitializeCB init_cb) {
|
||||
}
|
||||
}
|
||||
|
||||
-void MultibufferDataSource::OnRedirect(
|
||||
- const scoped_refptr<UrlData>& destination) {
|
||||
- if (!destination) {
|
||||
- // A failure occured.
|
||||
+void MultibufferDataSource::OnRedirected(
|
||||
+ const scoped_refptr<UrlData>& new_destination) {
|
||||
+ if (!new_destination) {
|
||||
+ // A failure occurred.
|
||||
failed_ = true;
|
||||
if (init_cb_) {
|
||||
render_task_runner_->PostTask(
|
||||
@@ -235,38 +235,39 @@ void MultibufferDataSource::OnRedirect(
|
||||
StopLoader();
|
||||
return;
|
||||
}
|
||||
- if (url_data_->url().GetOrigin() != destination->url().GetOrigin()) {
|
||||
+ if (url_data_->url().GetOrigin() != new_destination->url().GetOrigin()) {
|
||||
single_origin_ = false;
|
||||
}
|
||||
SetReader(nullptr);
|
||||
- url_data_ = std::move(destination);
|
||||
+ url_data_ = std::move(new_destination);
|
||||
|
||||
- if (url_data_) {
|
||||
- url_data_->OnRedirect(
|
||||
- base::BindOnce(&MultibufferDataSource::OnRedirect, weak_ptr_));
|
||||
+ url_data_->OnRedirect(
|
||||
+ base::BindOnce(&MultibufferDataSource::OnRedirected, weak_ptr_));
|
||||
|
||||
- if (init_cb_) {
|
||||
- CreateResourceLoader(0, kPositionNotSpecified);
|
||||
- if (reader_->Available()) {
|
||||
- render_task_runner_->PostTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&MultibufferDataSource::StartCallback, weak_ptr_));
|
||||
- } else {
|
||||
- reader_->Wait(1, base::BindOnce(&MultibufferDataSource::StartCallback,
|
||||
- weak_ptr_));
|
||||
- }
|
||||
- } else if (read_op_) {
|
||||
- CreateResourceLoader(read_op_->position(), kPositionNotSpecified);
|
||||
- if (reader_->Available()) {
|
||||
- render_task_runner_->PostTask(
|
||||
- FROM_HERE,
|
||||
- base::BindOnce(&MultibufferDataSource::ReadTask, weak_ptr_));
|
||||
- } else {
|
||||
- reader_->Wait(
|
||||
- 1, base::BindOnce(&MultibufferDataSource::ReadTask, weak_ptr_));
|
||||
- }
|
||||
+ if (init_cb_) {
|
||||
+ CreateResourceLoader(0, kPositionNotSpecified);
|
||||
+ if (reader_->Available()) {
|
||||
+ render_task_runner_->PostTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&MultibufferDataSource::StartCallback, weak_ptr_));
|
||||
+ } else {
|
||||
+ reader_->Wait(
|
||||
+ 1, base::BindOnce(&MultibufferDataSource::StartCallback, weak_ptr_));
|
||||
+ }
|
||||
+ } else if (read_op_) {
|
||||
+ CreateResourceLoader(read_op_->position(), kPositionNotSpecified);
|
||||
+ if (reader_->Available()) {
|
||||
+ render_task_runner_->PostTask(
|
||||
+ FROM_HERE,
|
||||
+ base::BindOnce(&MultibufferDataSource::ReadTask, weak_ptr_));
|
||||
+ } else {
|
||||
+ reader_->Wait(
|
||||
+ 1, base::BindOnce(&MultibufferDataSource::ReadTask, weak_ptr_));
|
||||
}
|
||||
}
|
||||
+
|
||||
+ if (redirect_cb_)
|
||||
+ redirect_cb_.Run();
|
||||
}
|
||||
|
||||
void MultibufferDataSource::SetPreload(Preload preload) {
|
||||
@@ -287,6 +288,10 @@ bool MultibufferDataSource::IsCorsCrossOrigin() const {
|
||||
return url_data_->is_cors_cross_origin();
|
||||
}
|
||||
|
||||
+void MultibufferDataSource::OnRedirect(RedirectCB callback) {
|
||||
+ redirect_cb_ = std::move(callback);
|
||||
+}
|
||||
+
|
||||
bool MultibufferDataSource::HasAccessControl() const {
|
||||
return url_data_->has_access_control();
|
||||
}
|
||||
diff --git a/media/blink/multibuffer_data_source.h b/media/blink/multibuffer_data_source.h
|
||||
index 3da5a7bba5e7cc0f54998a81649f4dd9d78aa7be..da316964ff1543086865d7c85597f381ca8a3296 100644
|
||||
--- a/media/blink/multibuffer_data_source.h
|
||||
+++ b/media/blink/multibuffer_data_source.h
|
||||
@@ -38,6 +38,7 @@ class MultiBufferReader;
|
||||
class MEDIA_BLINK_EXPORT MultibufferDataSource : public DataSource {
|
||||
public:
|
||||
using DownloadingCB = base::RepeatingCallback<void(bool)>;
|
||||
+ using RedirectCB = base::RepeatingCallback<void()>;
|
||||
|
||||
// Used to specify video preload states. They are "hints" to the browser about
|
||||
// how aggressively the browser should load and buffer data.
|
||||
@@ -82,6 +83,9 @@ class MEDIA_BLINK_EXPORT MultibufferDataSource : public DataSource {
|
||||
// This must be called after the response arrives.
|
||||
bool IsCorsCrossOrigin() const;
|
||||
|
||||
+ // Provides a callback to be run when the underlying url is redirected.
|
||||
+ void OnRedirect(RedirectCB callback);
|
||||
+
|
||||
// Returns true if the response includes an Access-Control-Allow-Origin
|
||||
// header (that is not "null").
|
||||
bool HasAccessControl() const;
|
||||
@@ -128,7 +132,7 @@ class MEDIA_BLINK_EXPORT MultibufferDataSource : public DataSource {
|
||||
bool cancel_on_defer_for_testing() const { return cancel_on_defer_; }
|
||||
|
||||
protected:
|
||||
- void OnRedirect(const scoped_refptr<UrlData>& destination);
|
||||
+ void OnRedirected(const scoped_refptr<UrlData>& new_destination);
|
||||
|
||||
// A factory method to create a BufferedResourceLoader based on the read
|
||||
// parameters.
|
||||
@@ -243,6 +247,9 @@ class MEDIA_BLINK_EXPORT MultibufferDataSource : public DataSource {
|
||||
// go between different origins.
|
||||
bool single_origin_;
|
||||
|
||||
+ // Callback used when a redirect occurs.
|
||||
+ RedirectCB redirect_cb_;
|
||||
+
|
||||
// Close the connection when we have enough data.
|
||||
bool cancel_on_defer_;
|
||||
|
||||
diff --git a/media/blink/webmediaplayer_impl.cc b/media/blink/webmediaplayer_impl.cc
|
||||
index bf58056d7826e2d56e927ceaf07cb14090cf5e9f..189c71a54e313acae735471d3c67f9895c4c2cf3 100644
|
||||
--- a/media/blink/webmediaplayer_impl.cc
|
||||
+++ b/media/blink/webmediaplayer_impl.cc
|
||||
@@ -764,6 +764,8 @@ void WebMediaPlayerImpl::DoLoad(LoadType load_type,
|
||||
base::BindRepeating(&WebMediaPlayerImpl::NotifyDownloading,
|
||||
weak_this_));
|
||||
data_source_.reset(mb_data_source_);
|
||||
+ mb_data_source_->OnRedirect(base::BindRepeating(
|
||||
+ &WebMediaPlayerImpl::OnDataSourceRedirected, weak_this_));
|
||||
mb_data_source_->SetPreload(preload_);
|
||||
mb_data_source_->SetIsClientAudioElement(client_->IsAudioElement());
|
||||
mb_data_source_->Initialize(
|
||||
@@ -2589,6 +2591,16 @@ void WebMediaPlayerImpl::DataSourceInitialized(bool success) {
|
||||
StartPipeline();
|
||||
}
|
||||
|
||||
+void WebMediaPlayerImpl::OnDataSourceRedirected() {
|
||||
+ DVLOG(1) << __func__;
|
||||
+ DCHECK(main_task_runner_->BelongsToCurrentThread());
|
||||
+ DCHECK(mb_data_source_);
|
||||
+
|
||||
+ if (WouldTaintOrigin()) {
|
||||
+ audio_source_provider_->TaintOrigin();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
void WebMediaPlayerImpl::NotifyDownloading(bool is_downloading) {
|
||||
DVLOG(1) << __func__ << "(" << is_downloading << ")";
|
||||
if (!is_downloading && network_state_ == WebMediaPlayer::kNetworkStateLoading)
|
||||
diff --git a/media/blink/webmediaplayer_impl.h b/media/blink/webmediaplayer_impl.h
|
||||
index 69e853bb93eb53cdd20d40b7b01050ac2094cffc..72627e8a97781515065aeb564d829679cb4dfe41 100644
|
||||
--- a/media/blink/webmediaplayer_impl.h
|
||||
+++ b/media/blink/webmediaplayer_impl.h
|
||||
@@ -379,6 +379,9 @@ class MEDIA_BLINK_EXPORT WebMediaPlayerImpl
|
||||
// Called after asynchronous initialization of a data source completed.
|
||||
void DataSourceInitialized(bool success);
|
||||
|
||||
+ // Called if the |MultiBufferDataSource| is redirected.
|
||||
+ void OnDataSourceRedirected();
|
||||
+
|
||||
// Called when the data source is downloading or paused.
|
||||
void NotifyDownloading(bool is_downloading);
|
||||
|
||||
diff --git a/third_party/blink/public/platform/webaudiosourceprovider_impl.h b/third_party/blink/public/platform/webaudiosourceprovider_impl.h
|
||||
index 5383074dcbffbb77a102de6fb551628ff5b964b8..bbf2a0b3d28282587625d6a5cd0103f6a5378b54 100644
|
||||
--- a/third_party/blink/public/platform/webaudiosourceprovider_impl.h
|
||||
+++ b/third_party/blink/public/platform/webaudiosourceprovider_impl.h
|
||||
@@ -75,6 +75,7 @@ class BLINK_PLATFORM_EXPORT WebAudioSourceProviderImpl
|
||||
bool CurrentThreadIsRenderingThread() override;
|
||||
void SwitchOutputDevice(const std::string& device_id,
|
||||
media::OutputDeviceStatusCB callback) override;
|
||||
+ void TaintOrigin();
|
||||
|
||||
// These methods allow a client to get a copy of the rendered audio.
|
||||
void SetCopyAudioCallback(CopyAudioCB callback);
|
||||
diff --git a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
|
||||
index a38efb3e55b268d3a40e14dea8d66478015a3369..37ceac48d3d7f49ba49ad623cd5c7e632aa89279 100644
|
||||
--- a/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
|
||||
+++ b/third_party/blink/renderer/platform/media/webaudiosourceprovider_impl.cc
|
||||
@@ -80,6 +80,10 @@ class WebAudioSourceProviderImpl::TeeFilter
|
||||
const int num_rendered_frames = renderer_->Render(
|
||||
delay, delay_timestamp, prior_frames_skipped, audio_bus);
|
||||
|
||||
+ // Zero out frames after rendering
|
||||
+ if (origin_tainted_.IsSet())
|
||||
+ audio_bus->Zero();
|
||||
+
|
||||
// Avoid taking the copy lock for the vast majority of cases.
|
||||
if (copy_required_) {
|
||||
base::AutoLock auto_lock(copy_lock_);
|
||||
@@ -113,11 +117,18 @@ class WebAudioSourceProviderImpl::TeeFilter
|
||||
copy_audio_bus_callback_ = std::move(callback);
|
||||
}
|
||||
|
||||
+ void TaintOrigin() { origin_tainted_.Set(); }
|
||||
+
|
||||
private:
|
||||
AudioRendererSink::RenderCallback* renderer_ = nullptr;
|
||||
int channels_ = 0;
|
||||
int sample_rate_ = 0;
|
||||
|
||||
+ // Indicates whether the audio source is tainted, and output should be muted.
|
||||
+ // This can happen if the media element source is a cross-origin source which
|
||||
+ // the page is not allowed to access due to CORS restrictions.
|
||||
+ base::AtomicFlag origin_tainted_;
|
||||
+
|
||||
// The vast majority of the time we're operating in passthrough mode. So only
|
||||
// acquire a lock to read |copy_audio_bus_callback_| when necessary.
|
||||
std::atomic<bool> copy_required_;
|
||||
@@ -317,6 +328,10 @@ void WebAudioSourceProviderImpl::SwitchOutputDevice(
|
||||
sink_->SwitchOutputDevice(device_id, std::move(callback));
|
||||
}
|
||||
|
||||
+void WebAudioSourceProviderImpl::TaintOrigin() {
|
||||
+ tee_filter_->TaintOrigin();
|
||||
+}
|
||||
+
|
||||
void WebAudioSourceProviderImpl::SetCopyAudioCallback(CopyAudioCB callback) {
|
||||
DCHECK(!callback.is_null());
|
||||
tee_filter_->SetCopyAudioCallback(std::move(callback));
|
||||
40
patches/chromium/cherry-pick-8f24f935c903.patch
Normal file
40
patches/chromium/cherry-pick-8f24f935c903.patch
Normal file
@@ -0,0 +1,40 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Adrian Taylor <adetaylor@chromium.org>
|
||||
Date: Thu, 5 Nov 2020 08:50:39 +0000
|
||||
Subject: Prevent overflow of drag image on Windows.
|
||||
|
||||
(cherry picked from commit 236b1a349111fc945c741f85e1b1e2e04d9c42ff)
|
||||
|
||||
(cherry picked from commit 5f61af8f3af5efd0d915a51da6df822678d959b9)
|
||||
|
||||
Bug: 1144489
|
||||
Change-Id: I130adffc1c69073295537aaff3ce7054260064fc
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2513345
|
||||
Reviewed-by: Krishna Govind <govind@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/branch-heads/4310@{#4}
|
||||
Cr-Original-Original-Branched-From: 3e31ebb7467fdc4295f123385825b8c95ef13332-refs/heads/master@{#822916}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2513349
|
||||
Reviewed-by: Adrian Taylor <adetaylor@chromium.org>
|
||||
Commit-Queue: Krishna Govind <govind@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4240@{#1373}
|
||||
Cr-Original-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2517728
|
||||
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
|
||||
Commit-Queue: Victor-Gabriel Savu <vsavu@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4240_112@{#18}
|
||||
Cr-Branched-From: 427c00d3874b6abcf4c4c2719768835fc3ef26d6-refs/branch-heads/4240@{#1291}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/ui/base/dragdrop/os_exchange_data_provider_win.cc b/ui/base/dragdrop/os_exchange_data_provider_win.cc
|
||||
index c5183eaab9986d668d7b109fef13205f54ff80fa..847920ada50bae2615c964fc82ea3dc696b86e8a 100644
|
||||
--- a/ui/base/dragdrop/os_exchange_data_provider_win.cc
|
||||
+++ b/ui/base/dragdrop/os_exchange_data_provider_win.cc
|
||||
@@ -714,7 +714,7 @@ void OSExchangeDataProviderWin::SetDragImage(
|
||||
int width = unpremul_bitmap.width();
|
||||
int height = unpremul_bitmap.height();
|
||||
size_t rowbytes = unpremul_bitmap.rowBytes();
|
||||
- DCHECK_EQ(rowbytes, static_cast<size_t>(width) * 4u);
|
||||
+ CHECK_EQ(rowbytes, static_cast<size_t>(width) * 4u);
|
||||
|
||||
void* bits;
|
||||
HBITMAP hbitmap;
|
||||
29
patches/chromium/cherry-pick-9746a4cde14a.patch
Normal file
29
patches/chromium/cherry-pick-9746a4cde14a.patch
Normal file
@@ -0,0 +1,29 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Andres Calderon Jaramillo <andrescj@chromium.org>
|
||||
Date: Mon, 20 Jul 2020 19:49:42 +0000
|
||||
Subject: blink: Disable WebP YUV image decoding by default.
|
||||
|
||||
JPEG YUV image decoding is already disabled by default.
|
||||
|
||||
Bug: 1102054,1091347
|
||||
Test: WebP images in bug 1091347 don't have artifacts on Linux
|
||||
Change-Id: Icf7f9ef46da97ba80d4e3b4aac4196f789bdf6d5
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2283409
|
||||
Reviewed-by: Andres Calderon Jaramillo <andrescj@chromium.org>
|
||||
Commit-Queue: Andres Calderon Jaramillo <andrescj@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#901}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/common/features.cc b/third_party/blink/common/features.cc
|
||||
index ad1c48f2d727f5fee33b2f5bd9d39682da2ba085..5f87b90e6cf3a3e3cb5f68e13fcbed06d039b18f 100644
|
||||
--- a/third_party/blink/common/features.cc
|
||||
+++ b/third_party/blink/common/features.cc
|
||||
@@ -257,7 +257,7 @@ const base::Feature kDecodeJpeg420ImagesToYUV{
|
||||
// Decodes lossy WebP images to YUV instead of RGBX and stores in this format
|
||||
// in the image decode cache. See crbug.com/900264 for details on the feature.
|
||||
const base::Feature kDecodeLossyWebPImagesToYUV{
|
||||
- "DecodeLossyWebPImagesToYUV", base::FEATURE_ENABLED_BY_DEFAULT};
|
||||
+ "DecodeLossyWebPImagesToYUV", base::FEATURE_DISABLED_BY_DEFAULT};
|
||||
|
||||
// Enables cache-aware WebFonts loading. See https://crbug.com/570205.
|
||||
// The feature is disabled on Android for WebView API issue discussed at
|
||||
42
patches/chromium/cherry-pick-9ad8c9610d0a.patch
Normal file
42
patches/chromium/cherry-pick-9ad8c9610d0a.patch
Normal file
@@ -0,0 +1,42 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Tue, 4 Aug 2020 21:25:10 +0000
|
||||
Subject: Use copy of source map in
|
||||
MediaElementElementListener::UpdateSources()
|
||||
|
||||
Prior to this CL, this function iterated over a source map that could
|
||||
be modified by a re-entrant call triggered by JS code.
|
||||
|
||||
(cherry picked from commit 292ac9aa5ba263f63f761e03b8214cae21e667c9)
|
||||
|
||||
Bug: 1105426
|
||||
Change-Id: I47e49e4132cba98e12ee7c195720ac9ecc1f485b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2312703
|
||||
Reviewed-by: Marina Ciocea <marinaciocea@chromium.org>
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#790894}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2332823
|
||||
Reviewed-by: Guido Urdaneta <guidou@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#1026}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
|
||||
index 03ba68236c511ba2d2767af3c796b37a90dce476..80f36cb236adee50aefc505ff64f092cbc4e82b9 100644
|
||||
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_media_element_capture.cc
|
||||
@@ -242,9 +242,14 @@ void MediaElementEventListener::UpdateSources(ExecutionContext* context) {
|
||||
for (auto track : media_stream_->getTracks())
|
||||
sources_.insert(track->Component()->Source());
|
||||
|
||||
+ // Handling of the ended event in JS triggered by DidStopMediaStreamSource()
|
||||
+ // may cause a reentrant call to this function, which can modify |sources_|.
|
||||
+ // Iterate over a copy of |sources_| to avoid invalidation of the iterator
|
||||
+ // when a reentrant call occurs.
|
||||
+ auto sources_copy = sources_;
|
||||
if (!media_element_->currentSrc().IsEmpty() &&
|
||||
!media_element_->IsMediaDataCorsSameOrigin()) {
|
||||
- for (auto source : sources_)
|
||||
+ for (auto source : sources_copy)
|
||||
DidStopMediaStreamSource(source.Get());
|
||||
}
|
||||
}
|
||||
160
patches/chromium/cherry-pick-9d100199c92b.patch
Normal file
160
patches/chromium/cherry-pick-9d100199c92b.patch
Normal file
@@ -0,0 +1,160 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Yutaka Hirano <yhirano@chromium.org>
|
||||
Date: Fri, 7 Aug 2020 09:06:23 +0000
|
||||
Subject: Fix UAF in ScriptPromiseProperty caused by reentrant code
|
||||
|
||||
v8::Promise::Resolve can run user code synchronously, which caused a UAF
|
||||
in ScriptPromiseProperty. Fix it.
|
||||
|
||||
Bug: 1108518
|
||||
Change-Id: Ia9baec6eef0887323cd88ceb1d3fa0c14fdb77ef
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2325499
|
||||
Reviewed-by: Yuki Shiino <yukishiino@chromium.org>
|
||||
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#792661}
|
||||
(cherry picked from commit 6d18e924b9c426905434cc280d7b602b3a3379ed)
|
||||
|
||||
TBR=yhirano@chromium.org
|
||||
|
||||
Change-Id: I3b7bfd5e8d932fb59c292159a4526cf70b44c58b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2342489
|
||||
Commit-Queue: Yutaka Hirano <yhirano@chromium.org>
|
||||
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#1049}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_property.h b/third_party/blink/renderer/bindings/core/v8/script_promise_property.h
|
||||
index 7c83ee35246486cf2a43227bf180904b2d9eb5f3..49ec9edc0d897e6f6e842a425cc2b0a4272702e2 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_property.h
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_property.h
|
||||
@@ -102,10 +102,11 @@ class ScriptPromiseProperty final
|
||||
}
|
||||
state_ = kResolved;
|
||||
resolved_ = value;
|
||||
- for (const Member<ScriptPromiseResolver>& resolver : resolvers_) {
|
||||
+ HeapVector<Member<ScriptPromiseResolver>> resolvers;
|
||||
+ resolvers.swap(resolvers_);
|
||||
+ for (const Member<ScriptPromiseResolver>& resolver : resolvers) {
|
||||
resolver->Resolve(resolved_);
|
||||
}
|
||||
- resolvers_.clear();
|
||||
}
|
||||
|
||||
void ResolveWithUndefined() {
|
||||
@@ -116,10 +117,11 @@ class ScriptPromiseProperty final
|
||||
}
|
||||
state_ = kResolved;
|
||||
resolved_with_undefined_ = true;
|
||||
- for (const Member<ScriptPromiseResolver>& resolver : resolvers_) {
|
||||
+ HeapVector<Member<ScriptPromiseResolver>> resolvers;
|
||||
+ resolvers.swap(resolvers_);
|
||||
+ for (const Member<ScriptPromiseResolver>& resolver : resolvers) {
|
||||
resolver->Resolve();
|
||||
}
|
||||
- resolvers_.clear();
|
||||
}
|
||||
|
||||
template <typename PassRejectedType>
|
||||
@@ -131,10 +133,11 @@ class ScriptPromiseProperty final
|
||||
}
|
||||
state_ = kRejected;
|
||||
rejected_ = value;
|
||||
- for (const Member<ScriptPromiseResolver>& resolver : resolvers_) {
|
||||
+ HeapVector<Member<ScriptPromiseResolver>> resolvers;
|
||||
+ resolvers.swap(resolvers_);
|
||||
+ for (const Member<ScriptPromiseResolver>& resolver : resolvers) {
|
||||
resolver->Reject(rejected_);
|
||||
}
|
||||
- resolvers_.clear();
|
||||
}
|
||||
|
||||
// Resets this property by unregistering the Promise property from the
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc b/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
|
||||
index c2dd607686e4ef76885036b4a678103c3869241e..95b6b1b83638b30918032fc4f76fec56a781c492 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/script_promise_property_test.cc
|
||||
@@ -96,6 +96,35 @@ class GarbageCollectedHolder final : public GarbageCollectedScriptWrappable {
|
||||
Member<Property> property_;
|
||||
};
|
||||
|
||||
+class ScriptPromisePropertyResetter : public ScriptFunction {
|
||||
+ public:
|
||||
+ using Property =
|
||||
+ ScriptPromiseProperty<Member<GarbageCollectedScriptWrappable>,
|
||||
+ Member<GarbageCollectedScriptWrappable>>;
|
||||
+ static v8::Local<v8::Function> CreateFunction(ScriptState* script_state,
|
||||
+ Property* property) {
|
||||
+ auto* self = MakeGarbageCollected<ScriptPromisePropertyResetter>(
|
||||
+ script_state, property);
|
||||
+ return self->BindToV8Function();
|
||||
+ }
|
||||
+
|
||||
+ ScriptPromisePropertyResetter(ScriptState* script_state, Property* property)
|
||||
+ : ScriptFunction(script_state), property_(property) {}
|
||||
+
|
||||
+ void Trace(Visitor* visitor) override {
|
||||
+ visitor->Trace(property_);
|
||||
+ ScriptFunction::Trace(visitor);
|
||||
+ }
|
||||
+
|
||||
+ private:
|
||||
+ ScriptValue Call(ScriptValue arg) override {
|
||||
+ property_->Reset();
|
||||
+ return ScriptValue();
|
||||
+ }
|
||||
+
|
||||
+ const Member<Property> property_;
|
||||
+};
|
||||
+
|
||||
class ScriptPromisePropertyTestBase {
|
||||
public:
|
||||
ScriptPromisePropertyTestBase()
|
||||
@@ -520,6 +549,48 @@ TEST_F(ScriptPromisePropertyGarbageCollectedTest, MarkAsHandled) {
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_F(ScriptPromisePropertyGarbageCollectedTest, SyncResolve) {
|
||||
+ // Call getters to create resolvers in the property.
|
||||
+ GetProperty()->Promise(DOMWrapperWorld::MainWorld());
|
||||
+ GetProperty()->Promise(OtherWorld());
|
||||
+
|
||||
+ auto* resolution =
|
||||
+ MakeGarbageCollected<GarbageCollectedScriptWrappable>("hi");
|
||||
+ v8::HandleScope handle_scope(GetIsolate());
|
||||
+ v8::Local<v8::Object> main_v8_resolution;
|
||||
+ v8::Local<v8::Object> other_v8_resolution;
|
||||
+ {
|
||||
+ ScriptState::Scope scope(MainScriptState());
|
||||
+ main_v8_resolution = ToV8(resolution, MainScriptState()).As<v8::Object>();
|
||||
+ v8::PropertyDescriptor descriptor(
|
||||
+ ScriptPromisePropertyResetter::CreateFunction(MainScriptState(),
|
||||
+ GetProperty()),
|
||||
+ v8::Undefined(GetIsolate()));
|
||||
+ ASSERT_EQ(
|
||||
+ v8::Just(true),
|
||||
+ main_v8_resolution->DefineProperty(
|
||||
+ MainScriptState()->GetContext(),
|
||||
+ v8::String::NewFromUtf8Literal(GetIsolate(), "then"), descriptor));
|
||||
+ }
|
||||
+ {
|
||||
+ ScriptState::Scope scope(OtherScriptState());
|
||||
+ other_v8_resolution = ToV8(resolution, OtherScriptState()).As<v8::Object>();
|
||||
+ v8::PropertyDescriptor descriptor(
|
||||
+ ScriptPromisePropertyResetter::CreateFunction(OtherScriptState(),
|
||||
+ GetProperty()),
|
||||
+ v8::Undefined(GetIsolate()));
|
||||
+ ASSERT_EQ(
|
||||
+ v8::Just(true),
|
||||
+ other_v8_resolution->DefineProperty(
|
||||
+ OtherScriptState()->GetContext(),
|
||||
+ v8::String::NewFromUtf8Literal(GetIsolate(), "then"), descriptor));
|
||||
+ }
|
||||
+
|
||||
+ // This shouldn't crash.
|
||||
+ GetProperty()->Resolve(resolution);
|
||||
+ EXPECT_EQ(GetProperty()->GetState(), Property::State::kPending);
|
||||
+}
|
||||
+
|
||||
TEST_F(ScriptPromisePropertyNonScriptWrappableResolutionTargetTest,
|
||||
ResolveWithUndefined) {
|
||||
Test(ToV8UndefinedGenerator(), "undefined", __FILE__, __LINE__);
|
||||
99
patches/chromium/cherry-pick-abc6ab85e704.patch
Normal file
99
patches/chromium/cherry-pick-abc6ab85e704.patch
Normal file
@@ -0,0 +1,99 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Guido Urdaneta <guidou@chromium.org>
|
||||
Date: Mon, 31 Aug 2020 09:01:16 +0000
|
||||
Subject: Do not produce frames if media player is tainted
|
||||
|
||||
This prevents potential cross-origin mid-stream redirects from
|
||||
braking the cross-origin restrictions.
|
||||
|
||||
Bug: 1111149
|
||||
Change-Id: I18d05a5836b9a390dec50e10c43d3d2b9ec5915a
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2377811
|
||||
Commit-Queue: Guido Urdaneta <guidou@chromium.org>
|
||||
Reviewed-by: Dan Sanders <sandersd@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#803036}
|
||||
(cherry picked from commit abc6ab85e704f599fa366344f9c5ce35585f3217)
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
|
||||
index 900d4534bc2c3f54d53cf4db3b2c3b6eb675b83a..a712281d52726c156035b00b3408f0f6baa18a5f 100644
|
||||
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source.cc
|
||||
@@ -116,8 +116,10 @@ void HtmlVideoElementCapturerSource::sendNewFrame() {
|
||||
TRACE_EVENT0("media", "HtmlVideoElementCapturerSource::sendNewFrame");
|
||||
DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
|
||||
|
||||
- if (!web_media_player_ || new_frame_callback_.is_null())
|
||||
+ if (!web_media_player_ || new_frame_callback_.is_null() ||
|
||||
+ web_media_player_->WouldTaintOrigin()) {
|
||||
return;
|
||||
+ }
|
||||
|
||||
const base::TimeTicks current_time = base::TimeTicks::Now();
|
||||
if (start_capture_time_.is_null())
|
||||
diff --git a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
|
||||
index 4d24f214880bfad608dbd151ed4fe00bb22c1aad..6e9960f4bbf60eb72097406ef4e835dcba6fba78 100644
|
||||
--- a/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
|
||||
+++ b/third_party/blink/renderer/modules/mediacapturefromelement/html_video_element_capturer_source_unittest.cc
|
||||
@@ -71,7 +71,7 @@ class MockWebMediaPlayer : public WebMediaPlayer {
|
||||
WebString GetErrorMessage() const override { return WebString(); }
|
||||
|
||||
bool DidLoadingProgress() override { return true; }
|
||||
- bool WouldTaintOrigin() const override { return false; }
|
||||
+ bool WouldTaintOrigin() const override { return would_taint_origin_; }
|
||||
double MediaTimeForTimeValue(double timeValue) const override { return 0.0; }
|
||||
unsigned DecodedFrameCount() const override { return 0; }
|
||||
unsigned DroppedFrameCount() const override { return 0; }
|
||||
@@ -79,6 +79,8 @@ class MockWebMediaPlayer : public WebMediaPlayer {
|
||||
uint64_t AudioDecodedByteCount() const override { return 0; }
|
||||
uint64_t VideoDecodedByteCount() const override { return 0; }
|
||||
|
||||
+ void SetWouldTaintOrigin(bool taint) { would_taint_origin_ = taint; }
|
||||
+
|
||||
void Paint(cc::PaintCanvas* canvas,
|
||||
const WebRect& rect,
|
||||
cc::PaintFlags&,
|
||||
@@ -98,6 +100,7 @@ class MockWebMediaPlayer : public WebMediaPlayer {
|
||||
|
||||
bool is_video_opaque_ = true;
|
||||
gfx::Size size_ = gfx::Size(16, 10);
|
||||
+ bool would_taint_origin_ = false;
|
||||
|
||||
base::WeakPtrFactory<MockWebMediaPlayer> weak_factory_{this};
|
||||
};
|
||||
@@ -326,4 +329,36 @@ TEST_F(HTMLVideoElementCapturerSourceTest, SizeChange) {
|
||||
Mock::VerifyAndClearExpectations(this);
|
||||
}
|
||||
|
||||
+// Checks that the usual sequence of GetPreferredFormats() ->
|
||||
+// StartCapture() -> StopCapture() works as expected and let it capture two
|
||||
+// frames, that are tested for format vs the expected source opacity.
|
||||
+TEST_F(HTMLVideoElementCapturerSourceTest, TaintedPlayerDoesNotDeliverFrames) {
|
||||
+ InSequence s;
|
||||
+ media::VideoCaptureFormats formats =
|
||||
+ html_video_capturer_->GetPreferredFormats();
|
||||
+ ASSERT_EQ(1u, formats.size());
|
||||
+ EXPECT_EQ(web_media_player_->NaturalSize(), formats[0].frame_size);
|
||||
+ web_media_player_->SetWouldTaintOrigin(true);
|
||||
+
|
||||
+ media::VideoCaptureParams params;
|
||||
+ params.requested_format = formats[0];
|
||||
+
|
||||
+ EXPECT_CALL(*this, DoOnRunning(true)).Times(1);
|
||||
+
|
||||
+ // No frames should be delivered.
|
||||
+ EXPECT_CALL(*this, DoOnDeliverFrame(_, _)).Times(0);
|
||||
+ html_video_capturer_->StartCapture(
|
||||
+ params,
|
||||
+ WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnDeliverFrame,
|
||||
+ base::Unretained(this)),
|
||||
+ WTF::BindRepeating(&HTMLVideoElementCapturerSourceTest::OnRunning,
|
||||
+ base::Unretained(this)));
|
||||
+
|
||||
+ // Wait for frames to be potentially sent in a follow-up task.
|
||||
+ base::RunLoop().RunUntilIdle();
|
||||
+
|
||||
+ html_video_capturer_->StopCapture();
|
||||
+ Mock::VerifyAndClearExpectations(this);
|
||||
+}
|
||||
+
|
||||
} // namespace blink
|
||||
82
patches/chromium/cherry-pick-adc731d678c4.patch
Normal file
82
patches/chromium/cherry-pick-adc731d678c4.patch
Normal file
@@ -0,0 +1,82 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Reilly Grant <reillyg@chromium.org>
|
||||
Date: Tue, 8 Sep 2020 19:29:40 +0000
|
||||
Subject: serial: Check that port is open before reading or writing
|
||||
|
||||
This change adds checks to the platform-specific implementations
|
||||
of Read() and Write() to make sure that the file descriptor is
|
||||
valid before. This makes the assumptions validated by later DCHECK
|
||||
correct.
|
||||
|
||||
This cannot be done in the platform-independent layer because test
|
||||
code depends on being able to call some SerialIoHandler methods
|
||||
without an actual file descriptor.
|
||||
|
||||
Bug: 1121836
|
||||
Change-Id: If182404cf10a2f3b445b9c80b75fed5df6b5ab4b
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2393001
|
||||
Reviewed-by: James Hollyer <jameshollyer@chromium.org>
|
||||
Commit-Queue: Reilly Grant <reillyg@chromium.org>
|
||||
Cr-Commit-Position: refs/heads/master@{#805016}
|
||||
(cherry picked from commit adc731d678c4c795e7c4c74133a624310e7bc9ae)
|
||||
|
||||
diff --git a/services/device/serial/serial_io_handler_posix.cc b/services/device/serial/serial_io_handler_posix.cc
|
||||
index 452d81538fd34ceb8f4267b8ceee0f39588d2528..7f2a2c421b3f5a890652bac470c945ef4534728c 100644
|
||||
--- a/services/device/serial/serial_io_handler_posix.cc
|
||||
+++ b/services/device/serial/serial_io_handler_posix.cc
|
||||
@@ -126,7 +126,11 @@ scoped_refptr<SerialIoHandler> SerialIoHandler::Create(
|
||||
void SerialIoHandlerPosix::ReadImpl() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(pending_read_buffer());
|
||||
- DCHECK(file().IsValid());
|
||||
+
|
||||
+ if (!file().IsValid()) {
|
||||
+ QueueReadCompleted(0, mojom::SerialReceiveError::DISCONNECTED);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
// Try to read immediately. This is needed because on some platforms
|
||||
// (e.g., OSX) there may not be a notification from the message loop
|
||||
@@ -138,7 +142,11 @@ void SerialIoHandlerPosix::ReadImpl() {
|
||||
void SerialIoHandlerPosix::WriteImpl() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(pending_write_buffer());
|
||||
- DCHECK(file().IsValid());
|
||||
+
|
||||
+ if (!file().IsValid()) {
|
||||
+ QueueWriteCompleted(0, mojom::SerialSendError::DISCONNECTED);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
EnsureWatchingWrites();
|
||||
}
|
||||
diff --git a/services/device/serial/serial_io_handler_win.cc b/services/device/serial/serial_io_handler_win.cc
|
||||
index 1501ce9081c3dc5a2b2fd2cfd681aea98ed16efe..5696ab995dc999fc0357230fb930652fa13a4c92 100644
|
||||
--- a/services/device/serial/serial_io_handler_win.cc
|
||||
+++ b/services/device/serial/serial_io_handler_win.cc
|
||||
@@ -266,7 +266,11 @@ bool SerialIoHandlerWin::PostOpen() {
|
||||
void SerialIoHandlerWin::ReadImpl() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(pending_read_buffer());
|
||||
- DCHECK(file().IsValid());
|
||||
+
|
||||
+ if (!file().IsValid()) {
|
||||
+ QueueReadCompleted(0, mojom::SerialReceiveError::DISCONNECTED);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
if (!SetCommMask(file().GetPlatformFile(), EV_RXCHAR)) {
|
||||
VPLOG(1) << "Failed to set serial event flags";
|
||||
@@ -285,7 +289,11 @@ void SerialIoHandlerWin::ReadImpl() {
|
||||
void SerialIoHandlerWin::WriteImpl() {
|
||||
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
|
||||
DCHECK(pending_write_buffer());
|
||||
- DCHECK(file().IsValid());
|
||||
+
|
||||
+ if (!file().IsValid()) {
|
||||
+ QueueWriteCompleted(0, mojom::SerialSendError::DISCONNECTED);
|
||||
+ return;
|
||||
+ }
|
||||
|
||||
BOOL ok = ::WriteFile(file().GetPlatformFile(), pending_write_buffer(),
|
||||
pending_write_buffer_len(), NULL,
|
||||
187
patches/chromium/cherry-pick-bbc6ab5bb49c.patch
Normal file
187
patches/chromium/cherry-pick-bbc6ab5bb49c.patch
Normal file
@@ -0,0 +1,187 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Adam Rice <ricea@chromium.org>
|
||||
Date: Wed, 2 Dec 2020 20:26:52 +0000
|
||||
Subject: Add ports 5060 and 5061 to the restricted list
|
||||
|
||||
Some NAT devices examine traffic on port 5060 to look for a valid SIP
|
||||
message. If they find one, they will forward a port back to the origin
|
||||
host. A carefully crafted HTTP request can trick these NAT devices into
|
||||
forwarding an arbitrary port. See https://samy.pl/slipstream for more
|
||||
details on the attack and sample code.
|
||||
|
||||
Block port 5060 for HTTP. Out of an abundance of caution, and to match
|
||||
the Fetch standard (https://github.com/whatwg/fetch/pull/1109), also
|
||||
block port 5061 (SIP over TLS).
|
||||
|
||||
Also reduce the whitespace before protocol description comments. This
|
||||
was insisted on by clang-format and is not worth fighting.
|
||||
|
||||
BUG=1145680
|
||||
|
||||
(cherry picked from commit 90d1302aec437166b383eabc08af741bf24f7ea8)
|
||||
|
||||
(cherry picked from commit dbb0452e69a49e803e0e4cbb6921d5ccad338716)
|
||||
|
||||
Change-Id: I3a556fbbb4dc6099caa4418addaf1e89bf254ae3
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2519174
|
||||
Reviewed-by: Matt Menke <mmenke@chromium.org>
|
||||
Commit-Queue: Adam Rice <ricea@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/master@{#824254}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2525474
|
||||
Reviewed-by: Adam Rice <ricea@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4280@{#1247}
|
||||
Cr-Original-Branched-From: ea420fb963f9658c9969b6513c56b8f47efa1a2a-refs/heads/master@{#812852}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2560585
|
||||
Reviewed-by: Achuith Bhandarkar <achuith@chromium.org>
|
||||
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
|
||||
Commit-Queue: Artem Sumaneev <asumaneev@google.com>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1474}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/net/base/port_util.cc b/net/base/port_util.cc
|
||||
index 63a7c35c39eb965d8a752bd262c115a8263733f9..41deaaded2f251d6153c01203b68cc6bdc06554f 100644
|
||||
--- a/net/base/port_util.cc
|
||||
+++ b/net/base/port_util.cc
|
||||
@@ -20,73 +20,75 @@ namespace {
|
||||
// The general list of blocked ports. Will be blocked unless a specific
|
||||
// protocol overrides it. (Ex: ftp can use ports 20 and 21)
|
||||
const int kRestrictedPorts[] = {
|
||||
- 1, // tcpmux
|
||||
- 7, // echo
|
||||
- 9, // discard
|
||||
- 11, // systat
|
||||
- 13, // daytime
|
||||
- 15, // netstat
|
||||
- 17, // qotd
|
||||
- 19, // chargen
|
||||
- 20, // ftp data
|
||||
- 21, // ftp access
|
||||
- 22, // ssh
|
||||
- 23, // telnet
|
||||
- 25, // smtp
|
||||
- 37, // time
|
||||
- 42, // name
|
||||
- 43, // nicname
|
||||
- 53, // domain
|
||||
- 77, // priv-rjs
|
||||
- 79, // finger
|
||||
- 87, // ttylink
|
||||
- 95, // supdup
|
||||
- 101, // hostriame
|
||||
- 102, // iso-tsap
|
||||
- 103, // gppitnp
|
||||
- 104, // acr-nema
|
||||
- 109, // pop2
|
||||
- 110, // pop3
|
||||
- 111, // sunrpc
|
||||
- 113, // auth
|
||||
- 115, // sftp
|
||||
- 117, // uucp-path
|
||||
- 119, // nntp
|
||||
- 123, // NTP
|
||||
- 135, // loc-srv /epmap
|
||||
- 139, // netbios
|
||||
- 143, // imap2
|
||||
- 179, // BGP
|
||||
- 389, // ldap
|
||||
- 427, // SLP (Also used by Apple Filing Protocol)
|
||||
- 465, // smtp+ssl
|
||||
- 512, // print / exec
|
||||
- 513, // login
|
||||
- 514, // shell
|
||||
- 515, // printer
|
||||
- 526, // tempo
|
||||
- 530, // courier
|
||||
- 531, // chat
|
||||
- 532, // netnews
|
||||
- 540, // uucp
|
||||
- 548, // AFP (Apple Filing Protocol)
|
||||
- 556, // remotefs
|
||||
- 563, // nntp+ssl
|
||||
- 587, // smtp (rfc6409)
|
||||
- 601, // syslog-conn (rfc3195)
|
||||
- 636, // ldap+ssl
|
||||
- 993, // ldap+ssl
|
||||
- 995, // pop3+ssl
|
||||
- 2049, // nfs
|
||||
- 3659, // apple-sasl / PasswordServer
|
||||
- 4045, // lockd
|
||||
- 6000, // X11
|
||||
- 6665, // Alternate IRC [Apple addition]
|
||||
- 6666, // Alternate IRC [Apple addition]
|
||||
- 6667, // Standard IRC [Apple addition]
|
||||
- 6668, // Alternate IRC [Apple addition]
|
||||
- 6669, // Alternate IRC [Apple addition]
|
||||
- 6697, // IRC + TLS
|
||||
+ 1, // tcpmux
|
||||
+ 7, // echo
|
||||
+ 9, // discard
|
||||
+ 11, // systat
|
||||
+ 13, // daytime
|
||||
+ 15, // netstat
|
||||
+ 17, // qotd
|
||||
+ 19, // chargen
|
||||
+ 20, // ftp data
|
||||
+ 21, // ftp access
|
||||
+ 22, // ssh
|
||||
+ 23, // telnet
|
||||
+ 25, // smtp
|
||||
+ 37, // time
|
||||
+ 42, // name
|
||||
+ 43, // nicname
|
||||
+ 53, // domain
|
||||
+ 77, // priv-rjs
|
||||
+ 79, // finger
|
||||
+ 87, // ttylink
|
||||
+ 95, // supdup
|
||||
+ 101, // hostriame
|
||||
+ 102, // iso-tsap
|
||||
+ 103, // gppitnp
|
||||
+ 104, // acr-nema
|
||||
+ 109, // pop2
|
||||
+ 110, // pop3
|
||||
+ 111, // sunrpc
|
||||
+ 113, // auth
|
||||
+ 115, // sftp
|
||||
+ 117, // uucp-path
|
||||
+ 119, // nntp
|
||||
+ 123, // NTP
|
||||
+ 135, // loc-srv /epmap
|
||||
+ 139, // netbios
|
||||
+ 143, // imap2
|
||||
+ 179, // BGP
|
||||
+ 389, // ldap
|
||||
+ 427, // SLP (Also used by Apple Filing Protocol)
|
||||
+ 465, // smtp+ssl
|
||||
+ 512, // print / exec
|
||||
+ 513, // login
|
||||
+ 514, // shell
|
||||
+ 515, // printer
|
||||
+ 526, // tempo
|
||||
+ 530, // courier
|
||||
+ 531, // chat
|
||||
+ 532, // netnews
|
||||
+ 540, // uucp
|
||||
+ 548, // AFP (Apple Filing Protocol)
|
||||
+ 556, // remotefs
|
||||
+ 563, // nntp+ssl
|
||||
+ 587, // smtp (rfc6409)
|
||||
+ 601, // syslog-conn (rfc3195)
|
||||
+ 636, // ldap+ssl
|
||||
+ 993, // ldap+ssl
|
||||
+ 995, // pop3+ssl
|
||||
+ 2049, // nfs
|
||||
+ 3659, // apple-sasl / PasswordServer
|
||||
+ 4045, // lockd
|
||||
+ 5060, // sip
|
||||
+ 5061, // sips
|
||||
+ 6000, // X11
|
||||
+ 6665, // Alternate IRC [Apple addition]
|
||||
+ 6666, // Alternate IRC [Apple addition]
|
||||
+ 6667, // Standard IRC [Apple addition]
|
||||
+ 6668, // Alternate IRC [Apple addition]
|
||||
+ 6669, // Alternate IRC [Apple addition]
|
||||
+ 6697, // IRC + TLS
|
||||
};
|
||||
|
||||
// FTP overrides the following restricted port.
|
||||
112
patches/chromium/cherry-pick-bee371eeaf66.patch
Normal file
112
patches/chromium/cherry-pick-bee371eeaf66.patch
Normal file
@@ -0,0 +1,112 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Hongchan Choi <hongchan@chromium.org>
|
||||
Date: Tue, 4 Aug 2020 16:13:40 +0000
|
||||
Subject: Use SupportWeakPtr in OfflineAudioDestinationHandler
|
||||
|
||||
OfflineAudioDestinationHandler's render thread notifies the
|
||||
main thread when the rendering state changes. In this process,
|
||||
the associated audio context can be deleted when a posted task
|
||||
is performed sometime later in the task runner's queue.
|
||||
|
||||
By using WeakPtr, the task runner will not perform a scheduled task
|
||||
in the queue when the target object is no longer valid.
|
||||
|
||||
(cherry picked from commit 4f309b864587890acaefa9da5d580abb21ff9ca0)
|
||||
|
||||
Bug: 1095584
|
||||
Test: Locally confirmed that the repro case does not crash after 30 min.
|
||||
Change-Id: Ic1814b97f8d9a8d1027ef04f475112874cfa8137
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2285473
|
||||
Reviewed-by: Robert Sesek <rsesek@chromium.org>
|
||||
Reviewed-by: Raymond Toy <rtoy@chromium.org>
|
||||
Commit-Queue: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#786381}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2335487
|
||||
Reviewed-by: Hongchan Choi <hongchan@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4147@{#1019}
|
||||
Cr-Branched-From: 16307825352720ae04d898f37efa5449ad68b606-refs/heads/master@{#768962}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
index ec610b99c6758bc66cda07bd344f29825c8376a3..2b0d87395cef31793273ef69f61eb540be897fcf 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.cc
|
||||
@@ -51,17 +51,14 @@ OfflineAudioDestinationHandler::OfflineAudioDestinationHandler(
|
||||
frames_to_process_(frames_to_process),
|
||||
is_rendering_started_(false),
|
||||
number_of_channels_(number_of_channels),
|
||||
- sample_rate_(sample_rate) {
|
||||
- channel_count_ = number_of_channels;
|
||||
+ sample_rate_(sample_rate),
|
||||
+ main_thread_task_runner_(Context()->GetExecutionContext()->GetTaskRunner(
|
||||
+ TaskType::kInternalMedia)) {
|
||||
+ DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
|
||||
|
||||
+ channel_count_ = number_of_channels;
|
||||
SetInternalChannelCountMode(kExplicit);
|
||||
SetInternalChannelInterpretation(AudioBus::kSpeakers);
|
||||
-
|
||||
- if (Context()->GetExecutionContext()) {
|
||||
- main_thread_task_runner_ = Context()->GetExecutionContext()->GetTaskRunner(
|
||||
- TaskType::kMiscPlatformAPI);
|
||||
- DCHECK(main_thread_task_runner_->BelongsToCurrentThread());
|
||||
- }
|
||||
}
|
||||
|
||||
scoped_refptr<OfflineAudioDestinationHandler>
|
||||
@@ -218,7 +215,7 @@ void OfflineAudioDestinationHandler::SuspendOfflineRendering() {
|
||||
PostCrossThreadTask(
|
||||
*main_thread_task_runner_, FROM_HERE,
|
||||
CrossThreadBindOnce(&OfflineAudioDestinationHandler::NotifySuspend,
|
||||
- WrapRefCounted(this),
|
||||
+ GetWeakPtr(),
|
||||
Context()->CurrentSampleFrame()));
|
||||
}
|
||||
|
||||
@@ -229,7 +226,7 @@ void OfflineAudioDestinationHandler::FinishOfflineRendering() {
|
||||
PostCrossThreadTask(
|
||||
*main_thread_task_runner_, FROM_HERE,
|
||||
CrossThreadBindOnce(&OfflineAudioDestinationHandler::NotifyComplete,
|
||||
- WrapRefCounted(this)));
|
||||
+ GetWeakPtr()));
|
||||
}
|
||||
|
||||
void OfflineAudioDestinationHandler::NotifySuspend(size_t frame) {
|
||||
diff --git a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
|
||||
index e4d2d8bfcd5d90d233ca8c761f07e8f518f83018..07d80e4cff535ee7230ea14d96c292bacaa7c19e 100644
|
||||
--- a/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
|
||||
+++ b/third_party/blink/renderer/modules/webaudio/offline_audio_destination_node.h
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include <memory>
|
||||
#include "base/memory/scoped_refptr.h"
|
||||
+#include "base/memory/weak_ptr.h"
|
||||
#include "third_party/blink/renderer/modules/webaudio/audio_buffer.h"
|
||||
#include "third_party/blink/renderer/modules/webaudio/audio_destination_node.h"
|
||||
#include "third_party/blink/renderer/modules/webaudio/offline_audio_context.h"
|
||||
@@ -124,6 +125,17 @@ class OfflineAudioDestinationHandler final : public AudioDestinationHandler {
|
||||
// from AudioWorkletThread will be used until the rendering is finished.
|
||||
void PrepareTaskRunnerForRendering();
|
||||
|
||||
+ // For cross-thread posting, this object uses two different targets.
|
||||
+ // 1. rendering thread -> main thread: WeakPtr
|
||||
+ // When the main thread starts deleting this object, a task posted with
|
||||
+ // a WeakPtr from the rendering thread will be cancelled.
|
||||
+ // 2. main thread -> rendering thread: scoped_refptr
|
||||
+ // |render_thread_| is owned by this object, so it is safe to target with
|
||||
+ // WrapRefCounted() instead of GetWeakPtr().
|
||||
+ base::WeakPtr<OfflineAudioDestinationHandler> GetWeakPtr() {
|
||||
+ return weak_factory_.GetWeakPtr();
|
||||
+ }
|
||||
+
|
||||
// This AudioHandler renders into this SharedAudioBuffer.
|
||||
std::unique_ptr<SharedAudioBuffer> shared_render_target_;
|
||||
// Temporary AudioBus for each render quantum.
|
||||
@@ -148,6 +160,8 @@ class OfflineAudioDestinationHandler final : public AudioDestinationHandler {
|
||||
|
||||
scoped_refptr<base::SingleThreadTaskRunner> render_thread_task_runner_;
|
||||
scoped_refptr<base::SingleThreadTaskRunner> main_thread_task_runner_;
|
||||
+
|
||||
+ base::WeakPtrFactory<OfflineAudioDestinationHandler> weak_factory_{this};
|
||||
};
|
||||
|
||||
class OfflineAudioDestinationNode final : public AudioDestinationNode {
|
||||
132
patches/chromium/cherry-pick-d8d64b7cd244.patch
Normal file
132
patches/chromium/cherry-pick-d8d64b7cd244.patch
Normal file
@@ -0,0 +1,132 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Xianzhu Wang <wangxianzhu@chromium.org>
|
||||
Date: Mon, 16 Nov 2020 17:26:33 +0000
|
||||
Subject: Ensure change type for OverflowControlsClip is returned
|
||||
|
||||
This at least ensures that we will update the paint properites for the
|
||||
composited overflow control layers in pre-CompositeAfterPaint to avoid
|
||||
stale properties on the layers.
|
||||
|
||||
The test doesn't actually reproduce the bug because any test simpler
|
||||
than the bug case couldn't reproduce the bug as the update would be
|
||||
triggered in other code paths (any style change, layout change, etc.).
|
||||
|
||||
Anyway this CL does fix the bug case.
|
||||
|
||||
TBR=wangxianzhu@chromium.org
|
||||
|
||||
(cherry picked from commit c20bb9897ef6d26a46391a4dc1658c5d33e0c100)
|
||||
|
||||
(cherry picked from commit cfb81e677a508871f56d8bec958d0b585298ae0c)
|
||||
|
||||
Bug: 1137603
|
||||
Change-Id: I5cca970bcf8cda6085527f79a97f269c4e3e9986
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2500264
|
||||
Reviewed-by: Stefan Zager <szager@chromium.org>
|
||||
Commit-Queue: Xianzhu Wang <wangxianzhu@chromium.org>
|
||||
Cr-Original-Original-Commit-Position: refs/heads/master@{#820986}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536910
|
||||
Reviewed-by: Xianzhu Wang <wangxianzhu@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/branch-heads/4240@{#1446}
|
||||
Cr-Original-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2540592
|
||||
Reviewed-by: Victor-Gabriel Savu <vsavu@google.com>
|
||||
Commit-Queue: Jana Grill <janagrill@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240_112@{#26}
|
||||
Cr-Branched-From: 427c00d3874b6abcf4c4c2719768835fc3ef26d6-refs/branch-heads/4240@{#1291}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
|
||||
index b7946eb567463938066b54ecd54ca710f649380e..f7ff1d68e36840c8647b863943f8c9134233c8ee 100644
|
||||
--- a/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
|
||||
+++ b/third_party/blink/renderer/core/paint/compositing/compositing_layer_property_updater_test.cc
|
||||
@@ -174,4 +174,56 @@ TEST_F(CompositingLayerPropertyUpdaterTest,
|
||||
}
|
||||
}
|
||||
|
||||
+TEST_F(CompositingLayerPropertyUpdaterTest, OverflowControlsClip) {
|
||||
+ SetBodyInnerHTML(R"HTML(
|
||||
+ <style>
|
||||
+ ::-webkit-scrollbar { width: 20px; }
|
||||
+ #container {
|
||||
+ width: 5px;
|
||||
+ height: 100px;
|
||||
+ }
|
||||
+ #target {
|
||||
+ overflow: scroll;
|
||||
+ will-change: transform;
|
||||
+ width: 100%;
|
||||
+ height: 100%;
|
||||
+ }
|
||||
+ </style>
|
||||
+ <div id="container">
|
||||
+ <div id="target"></div>
|
||||
+ </div>
|
||||
+ )HTML");
|
||||
+
|
||||
+ // Initially the vertical scrollbar overflows the narrow border box.
|
||||
+ auto* container = GetDocument().getElementById("container");
|
||||
+ auto* target = ToLayoutBox(GetLayoutObjectByElementId("target"));
|
||||
+ auto* scrollbar_layer =
|
||||
+ target->GetScrollableArea()->GraphicsLayerForVerticalScrollbar();
|
||||
+ auto target_state = target->FirstFragment().LocalBorderBoxProperties();
|
||||
+ auto scrollbar_state = target_state;
|
||||
+ auto* overflow_controls_clip =
|
||||
+ target->FirstFragment().PaintProperties()->OverflowControlsClip();
|
||||
+ ASSERT_TRUE(overflow_controls_clip);
|
||||
+ scrollbar_state.SetClip(*overflow_controls_clip);
|
||||
+ EXPECT_EQ(scrollbar_state, scrollbar_layer->GetPropertyTreeState());
|
||||
+
|
||||
+ // Widen target to make the vertical scrollbar contained by the border box.
|
||||
+ container->setAttribute(html_names::kStyleAttr, "width: 100px");
|
||||
+ UpdateAllLifecyclePhasesForTest();
|
||||
+ LOG(ERROR) << target->Size();
|
||||
+ EXPECT_FALSE(
|
||||
+ target->FirstFragment().PaintProperties()->OverflowControlsClip());
|
||||
+ EXPECT_EQ(target_state, scrollbar_layer->GetPropertyTreeState());
|
||||
+
|
||||
+ // Narrow down target back.
|
||||
+ container->removeAttribute(html_names::kStyleAttr);
|
||||
+ UpdateAllLifecyclePhasesForTest();
|
||||
+ scrollbar_state = target_state;
|
||||
+ overflow_controls_clip =
|
||||
+ target->FirstFragment().PaintProperties()->OverflowControlsClip();
|
||||
+ ASSERT_TRUE(overflow_controls_clip);
|
||||
+ scrollbar_state.SetClip(*overflow_controls_clip);
|
||||
+ EXPECT_EQ(scrollbar_state, scrollbar_layer->GetPropertyTreeState());
|
||||
+}
|
||||
+
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
|
||||
index 6810fb3e4f7ba1c994812c3fa983009792e00cc4..7d391839432a7d11102db78ef84b6369357eb77f 100644
|
||||
--- a/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
|
||||
+++ b/third_party/blink/renderer/core/paint/paint_property_tree_builder.cc
|
||||
@@ -1525,21 +1525,21 @@ void FragmentPaintPropertyTreeBuilder::UpdateOverflowControlsClip() {
|
||||
|
||||
if (NeedsOverflowControlsClip()) {
|
||||
// Clip overflow controls to the border box rect. Not wrapped with
|
||||
- // OnUpdateClip() because this clip doesn't affect descendants.
|
||||
+ // OnUpdateClip() because this clip doesn't affect descendants. Wrap with
|
||||
+ // OnUpdate() to let PrePaintTreeWalk see the change. This may cause
|
||||
+ // unnecessary subtree update, but is not a big deal because it is rare.
|
||||
const auto& clip_rect = PhysicalRect(context_.current.paint_offset,
|
||||
ToLayoutBox(object_).Size());
|
||||
- properties_->UpdateOverflowControlsClip(
|
||||
+ OnUpdate(properties_->UpdateOverflowControlsClip(
|
||||
*context_.current.clip,
|
||||
ClipPaintPropertyNode::State(context_.current.transform,
|
||||
FloatRoundedRect(FloatRect(clip_rect)),
|
||||
- ToSnappedClipRect(clip_rect)));
|
||||
+ ToSnappedClipRect(clip_rect))));
|
||||
} else {
|
||||
- properties_->ClearOverflowControlsClip();
|
||||
+ OnClear(properties_->ClearOverflowControlsClip());
|
||||
}
|
||||
|
||||
- // No need to set force_subtree_update_reasons and clip_changed because
|
||||
- // OverflowControlsClip applies to overflow controls only, not descendants.
|
||||
- // We also don't walk into custom scrollbars in PrePaintTreeWalk and
|
||||
+ // We don't walk into custom scrollbars in PrePaintTreeWalk because
|
||||
// LayoutObjects under custom scrollbars don't support paint properties.
|
||||
}
|
||||
|
||||
70
patches/chromium/cherry-pick-ecdec1fb0f42.patch
Normal file
70
patches/chromium/cherry-pick-ecdec1fb0f42.patch
Normal file
@@ -0,0 +1,70 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Etienne Bergeron <etienneb@chromium.org>
|
||||
Date: Fri, 13 Nov 2020 17:40:59 +0000
|
||||
Subject: Fix text eliding for single-codepoint text with BiDi
|
||||
|
||||
This CL is fixing a corner case where RenderText::Elide(...) may
|
||||
produce a text with more codepoints than the original one. This is
|
||||
an issue since the breaklists are not resized and the overflow
|
||||
will lead the render_text code to perfoarm an out-of-bound memory
|
||||
access by deferencing breaks_.end() while rendering the text. This
|
||||
is causing chrome to crash.
|
||||
|
||||
See crbug/1142020 for details.
|
||||
|
||||
The bug was happening when:
|
||||
1) The text to elide was a single codepoint
|
||||
2) The width of the glyph of the codepoint is larger than the width
|
||||
of the ellipsis glyph
|
||||
3) Eliding is set to ELIDING_TAIL
|
||||
4) The display_rect width will trigger eliding
|
||||
(smaller than codepoint width, but larger than ellipsis width)
|
||||
5) The render text is set to RTL
|
||||
|
||||
A possible solution is to adjust the breaklist but this required
|
||||
larger refactoring and cannot be a minimal patch to be merge on
|
||||
other channels.
|
||||
|
||||
TBR=msw@chromium.org
|
||||
(cherry picked from commit e54920751871321474e0b953329c8aedcc8702c3)
|
||||
|
||||
Bug: 1142020
|
||||
Change-Id: I9854651175562ec5f0d0bf7083a8da99fede0e29
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2522892
|
||||
Commit-Queue: Etienne Bergeron <etienneb@chromium.org>
|
||||
Reviewed-by: Michael Wasserman <msw@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#824878}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2537931
|
||||
Reviewed-by: Etienne Bergeron <etienneb@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1450}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/ui/gfx/render_text.cc b/ui/gfx/render_text.cc
|
||||
index 7d5fb0c4d6e609d99533a10f26cf5ef195b4c18a..5a32f3f0987f7c4f94ba471876e9a0ff4ff91751 100644
|
||||
--- a/ui/gfx/render_text.cc
|
||||
+++ b/ui/gfx/render_text.cc
|
||||
@@ -2067,8 +2067,10 @@ base::string16 RenderText::Elide(const base::string16& text,
|
||||
}
|
||||
|
||||
// Append the ellipsis and the optional directional marker characters.
|
||||
+ // Do not append the BiDi marker if the only codepoint in the text is
|
||||
+ // an ellipsis.
|
||||
new_text.append(ellipsis);
|
||||
- if (trailing_text_direction != text_direction) {
|
||||
+ if (new_text.size() != 1 && trailing_text_direction != text_direction) {
|
||||
if (trailing_text_direction == base::i18n::LEFT_TO_RIGHT)
|
||||
new_text += base::i18n::kLeftToRightMark;
|
||||
else
|
||||
diff --git a/ui/gfx/render_text_unittest.cc b/ui/gfx/render_text_unittest.cc
|
||||
index 6796016d97a6c167a31482e353e4faac652ce2a4..80b9d756a52f8df2a4420ffd3c275d529ef95bfb 100644
|
||||
--- a/ui/gfx/render_text_unittest.cc
|
||||
+++ b/ui/gfx/render_text_unittest.cc
|
||||
@@ -1851,7 +1851,7 @@ const ElideTextCase kElideTailTextCases[] = {
|
||||
{"ltr_0", L"abc", L""},
|
||||
{"rtl_3", L"\u05d0\u05d1\u05d2", L"\u05d0\u05d1\u05d2"},
|
||||
{"rtl_2", L"\u05d0\u05d1\u05d2", L"\u05d0\u2026"},
|
||||
- {"rtl_1", L"\u05d0\u05d1\u05d2", L"\u2026\x200E"},
|
||||
+ {"rtl_1", L"\u05d0\u05d1\u05d2", L"\u2026"},
|
||||
{"rtl_0", L"\u05d0\u05d1\u05d2", L""},
|
||||
{"ltr_rtl_5", L"abc\u05d0\u05d1\u05d2", L"abc\u05d0\u2026\x200F"},
|
||||
{"ltr_rtl_4", L"abc\u05d0\u05d1\u05d2", L"abc\u2026"},
|
||||
77
patches/chromium/cherry-pick-eec5025668f8.patch
Normal file
77
patches/chromium/cherry-pick-eec5025668f8.patch
Normal file
@@ -0,0 +1,77 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Bill Budge <bbudge@chromium.org>
|
||||
Date: Fri, 13 Nov 2020 09:02:09 +0000
|
||||
Subject: Merged: [wasm][code cache] Match response to cached raw resource
|
||||
|
||||
- Verifies that the retrieved resource has the same response time, and
|
||||
that the source matches (i.e. both are from service worker, or both
|
||||
are not).
|
||||
|
||||
Bug: chromium:1146673
|
||||
|
||||
(cherry picked from commit a8b46244ecaa1647ee2d70304878c0365ee04087)
|
||||
|
||||
Change-Id: I6243ec9017b2405687056aa6ea199c67b1c16063
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2526802
|
||||
Reviewed-by: Yutaka Hirano <yhirano@chromium.org>
|
||||
Reviewed-by: Andreas Haas <ahaas@chromium.org>
|
||||
Commit-Queue: Bill Budge <bbudge@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#826277}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2537531
|
||||
Commit-Queue: Clemens Backes <clemensb@chromium.org>
|
||||
Commit-Queue: Andreas Haas <ahaas@chromium.org>
|
||||
Auto-Submit: Clemens Backes <clemensb@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1447}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
|
||||
index 6023c25e49ae6459cae350a3aae9b03c43da738a..978fb874469ad6e2a0ce2f70737c4a5c5b16aee3 100644
|
||||
--- a/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
|
||||
+++ b/third_party/blink/renderer/bindings/core/v8/v8_wasm_response_extensions.cc
|
||||
@@ -210,7 +210,8 @@ class ExceptionToAbortStreamingScope {
|
||||
};
|
||||
|
||||
RawResource* GetRawResource(ScriptState* script_state,
|
||||
- const String& url_string) {
|
||||
+ const String& url_string,
|
||||
+ Response* response) {
|
||||
ExecutionContext* execution_context = ExecutionContext::From(script_state);
|
||||
if (!execution_context)
|
||||
return nullptr;
|
||||
@@ -224,6 +225,18 @@ RawResource* GetRawResource(ScriptState* script_state,
|
||||
if (!resource)
|
||||
return nullptr;
|
||||
|
||||
+ // Make sure the resource matches the |response|. To check that, we make sure
|
||||
+ // the response times match, and the response sources match.
|
||||
+ const ResourceResponse& resource_response = resource->GetResponse();
|
||||
+ const FetchResponseData* fetch_response_data =
|
||||
+ response->GetResponse()->InternalResponse();
|
||||
+ if (resource_response.ResponseTime() != fetch_response_data->ResponseTime())
|
||||
+ return nullptr;
|
||||
+ bool from_service_worker = fetch_response_data->ResponseSource() ==
|
||||
+ network::mojom::FetchResponseSource::kUnspecified;
|
||||
+ if (resource_response.WasFetchedViaServiceWorker() != from_service_worker)
|
||||
+ return nullptr;
|
||||
+
|
||||
// Wasm modules should be fetched as raw resources.
|
||||
DCHECK_EQ(ResourceType::kRaw, resource->GetType());
|
||||
return ToRawResource(resource);
|
||||
@@ -354,13 +367,12 @@ void StreamFromResponseCallback(
|
||||
String url = response->url();
|
||||
const std::string& url_utf8 = url.Utf8();
|
||||
streaming->SetUrl(url_utf8.c_str(), url_utf8.size());
|
||||
- RawResource* raw_resource = GetRawResource(script_state, url);
|
||||
- if (raw_resource) {
|
||||
- SingleCachedMetadataHandler* cache_handler =
|
||||
- raw_resource->ScriptCacheHandler();
|
||||
+ RawResource* resource = GetRawResource(script_state, url, response);
|
||||
+ if (resource) {
|
||||
+ SingleCachedMetadataHandler* cache_handler = resource->ScriptCacheHandler();
|
||||
if (cache_handler) {
|
||||
auto client = std::make_shared<WasmStreamingClient>(
|
||||
- url, raw_resource->GetResponse().ResponseTime());
|
||||
+ url, resource->GetResponse().ResponseTime());
|
||||
streaming->SetClient(client);
|
||||
scoped_refptr<CachedMetadata> cached_module =
|
||||
cache_handler->GetCachedMetadata(kWasmModuleTag);
|
||||
206
patches/chromium/cherry-pick-f06a6cb3a38e.patch
Normal file
206
patches/chromium/cherry-pick-f06a6cb3a38e.patch
Normal file
@@ -0,0 +1,206 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: John Rummell <jrummell@chromium.org>
|
||||
Date: Wed, 16 Sep 2020 00:43:28 +0000
|
||||
Subject: (merge) Check for context destroyed in MediaKeys
|
||||
|
||||
Don't allow calls to proceed once the associated content has been
|
||||
destroyed.
|
||||
|
||||
(cherry picked from commit 1257ea7e0601a4a2a2a86bcc4a428573813f6cd7)
|
||||
|
||||
Bug: 1121414
|
||||
Test: example in the bug no longer crashes
|
||||
Change-Id: I3bdeb86f2020f684958b624fcc30438babfb5004
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2378889
|
||||
Reviewed-by: Kentaro Hara <haraken@chromium.org>
|
||||
Reviewed-by: Xiaohan Wang <xhwang@chromium.org>
|
||||
Reviewed-by: Daniel Cheng <dcheng@chromium.org>
|
||||
Commit-Queue: John Rummell <jrummell@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#805561}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2412559
|
||||
Reviewed-by: John Rummell <jrummell@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4183@{#1836}
|
||||
Cr-Branched-From: 740e9e8a40505392ba5c8e022a8024b3d018ca65-refs/heads/master@{#782793}
|
||||
|
||||
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc b/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
|
||||
index 82a2c622ebe5bd70f99c5effd730c063e7b63ab3..2d3b0a526d9cbcec248019826bdc4b40ec8f6f7f 100644
|
||||
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
|
||||
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys.cc
|
||||
@@ -228,6 +228,13 @@ MediaKeySession* MediaKeys::createSession(ScriptState* script_state,
|
||||
DVLOG(MEDIA_KEYS_LOG_LEVEL)
|
||||
<< __func__ << "(" << this << ") " << session_type_string;
|
||||
|
||||
+ // If the context for MediaKeys has been destroyed, fail.
|
||||
+ if (!GetExecutionContext()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
|
||||
+ "The context provided is invalid.");
|
||||
+ return nullptr;
|
||||
+ }
|
||||
+
|
||||
// [RuntimeEnabled] does not work with enum values. So we have to check it
|
||||
// here. See https://crbug.com/871867 for details.
|
||||
if (!RuntimeEnabledFeatures::
|
||||
@@ -274,6 +281,13 @@ ScriptPromise MediaKeys::setServerCertificate(
|
||||
ScriptState* script_state,
|
||||
const DOMArrayPiece& server_certificate,
|
||||
ExceptionState& exception_state) {
|
||||
+ // If the context for MediaKeys has been destroyed, fail.
|
||||
+ if (!GetExecutionContext()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
|
||||
+ "The context provided is invalid.");
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
+
|
||||
// From https://w3c.github.io/encrypted-media/#setServerCertificate
|
||||
// The setServerCertificate(serverCertificate) method provides a server
|
||||
// certificate to be used to encrypt messages to the license server.
|
||||
@@ -317,6 +331,15 @@ void MediaKeys::SetServerCertificateTask(
|
||||
ContentDecryptionModuleResult* result) {
|
||||
DVLOG(MEDIA_KEYS_LOG_LEVEL) << __func__ << "(" << this << ")";
|
||||
|
||||
+ // If the context has been destroyed, don't proceed. Try to have the promise
|
||||
+ // be rejected.
|
||||
+ if (!GetExecutionContext()) {
|
||||
+ result->CompleteWithError(
|
||||
+ kWebContentDecryptionModuleExceptionInvalidStateError, 0,
|
||||
+ "The context provided is invalid.");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
// 5.1 Let cdm be the cdm during the initialization of this object.
|
||||
WebContentDecryptionModule* cdm = ContentDecryptionModule();
|
||||
|
||||
@@ -333,7 +356,15 @@ void MediaKeys::SetServerCertificateTask(
|
||||
|
||||
ScriptPromise MediaKeys::getStatusForPolicy(
|
||||
ScriptState* script_state,
|
||||
- const MediaKeysPolicy* media_keys_policy) {
|
||||
+ const MediaKeysPolicy* media_keys_policy,
|
||||
+ ExceptionState& exception_state) {
|
||||
+ // If the context for MediaKeys has been destroyed, fail.
|
||||
+ if (!GetExecutionContext()) {
|
||||
+ exception_state.ThrowDOMException(DOMExceptionCode::kInvalidAccessError,
|
||||
+ "The context provided is invalid.");
|
||||
+ return ScriptPromise();
|
||||
+ }
|
||||
+
|
||||
// TODO(xhwang): Pass MediaKeysPolicy classes all the way to Chromium when
|
||||
// we have more than one policy to check.
|
||||
String min_hdcp_version = media_keys_policy->minHdcpVersion();
|
||||
@@ -358,6 +389,15 @@ void MediaKeys::GetStatusForPolicyTask(const String& min_hdcp_version,
|
||||
ContentDecryptionModuleResult* result) {
|
||||
DVLOG(MEDIA_KEYS_LOG_LEVEL) << __func__ << ": " << min_hdcp_version;
|
||||
|
||||
+ // If the context has been destroyed, don't proceed. Try to have the promise
|
||||
+ // be rejected.
|
||||
+ if (!GetExecutionContext()) {
|
||||
+ result->CompleteWithError(
|
||||
+ kWebContentDecryptionModuleExceptionInvalidStateError, 0,
|
||||
+ "The context provided is invalid.");
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
WebContentDecryptionModule* cdm = ContentDecryptionModule();
|
||||
cdm->GetStatusForPolicy(min_hdcp_version, result->Result());
|
||||
}
|
||||
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys.h b/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
|
||||
index ba2d0093ba83ca0c391f0edf03bf44502723e4cb..d24ad3d6e39f65d84200d3b198a59aca4c1c3c1f 100644
|
||||
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
|
||||
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys.h
|
||||
@@ -71,9 +71,11 @@ class MediaKeys : public ScriptWrappable,
|
||||
|
||||
ScriptPromise setServerCertificate(ScriptState*,
|
||||
const DOMArrayPiece& server_certificate,
|
||||
- ExceptionState& exception_state);
|
||||
+ ExceptionState&);
|
||||
|
||||
- ScriptPromise getStatusForPolicy(ScriptState*, const MediaKeysPolicy*);
|
||||
+ ScriptPromise getStatusForPolicy(ScriptState*,
|
||||
+ const MediaKeysPolicy*,
|
||||
+ ExceptionState&);
|
||||
|
||||
// Indicates that the provided HTMLMediaElement wants to use this object.
|
||||
// Returns true if no other HTMLMediaElement currently references this
|
||||
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.cc b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.cc
|
||||
index 0b12f4d3a03158b3d3e83845612416a6ef67a3f5..c6e7ff4a754c3edfc258bb3ecdf652a38febfa77 100644
|
||||
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.cc
|
||||
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.cc
|
||||
@@ -14,10 +14,12 @@ namespace blink {
|
||||
ScriptPromise MediaKeysGetStatusForPolicy::getStatusForPolicy(
|
||||
ScriptState* script_state,
|
||||
MediaKeys& media_keys,
|
||||
- const MediaKeysPolicy* media_keys_policy) {
|
||||
+ const MediaKeysPolicy* media_keys_policy,
|
||||
+ ExceptionState& exception_state) {
|
||||
DVLOG(1) << __func__;
|
||||
|
||||
- return media_keys.getStatusForPolicy(script_state, media_keys_policy);
|
||||
+ return media_keys.getStatusForPolicy(script_state, media_keys_policy,
|
||||
+ exception_state);
|
||||
}
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.h b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.h
|
||||
index 246e7a5aac85c37cbbafab5b9fb6f2f4726ffbf2..62317f6c03724d2a6294a4516ef680fb89581481 100644
|
||||
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.h
|
||||
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.h
|
||||
@@ -20,7 +20,8 @@ class MediaKeysGetStatusForPolicy {
|
||||
public:
|
||||
static ScriptPromise getStatusForPolicy(ScriptState*,
|
||||
MediaKeys&,
|
||||
- const MediaKeysPolicy*);
|
||||
+ const MediaKeysPolicy*,
|
||||
+ ExceptionState&);
|
||||
};
|
||||
|
||||
} // namespace blink
|
||||
diff --git a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
|
||||
index 15a6ca073ec19700a778f963a2697c4cf5c1f99d..671ba323111b6450288b55d9be95dbd216540b54 100644
|
||||
--- a/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
|
||||
+++ b/third_party/blink/renderer/modules/encryptedmedia/media_keys_get_status_for_policy.idl
|
||||
@@ -8,5 +8,5 @@
|
||||
ImplementedAs=MediaKeysGetStatusForPolicy,
|
||||
SecureContext
|
||||
] partial interface MediaKeys {
|
||||
- [Measure, CallWith=ScriptState] Promise<MediaKeyStatus> getStatusForPolicy(MediaKeysPolicy policy);
|
||||
+ [Measure, CallWith=ScriptState, RaisesException] Promise<MediaKeyStatus> getStatusForPolicy(MediaKeysPolicy policy);
|
||||
};
|
||||
diff --git a/third_party/blink/web_tests/media/encrypted-media/encrypted-media-context-destroyed.html b/third_party/blink/web_tests/media/encrypted-media/encrypted-media-context-destroyed.html
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..2d54624b0fa76b59a4341ed41a876654d135bc0e
|
||||
--- /dev/null
|
||||
+++ b/third_party/blink/web_tests/media/encrypted-media/encrypted-media-context-destroyed.html
|
||||
@@ -0,0 +1,33 @@
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+ <head>
|
||||
+ <title>Test context destruction.</title>
|
||||
+ <script src="encrypted-media-utils.js"></script>
|
||||
+ <script src="../../resources/testharness.js"></script>
|
||||
+ <script src="../../resources/testharnessreport.js"></script>
|
||||
+ </head>
|
||||
+ <body>
|
||||
+ <script>
|
||||
+ function allociframe() {
|
||||
+ iframe = document.createElement('iframe');
|
||||
+ iframe.height = 50;
|
||||
+ iframe.width = 50;
|
||||
+ document.body.appendChild(iframe);
|
||||
+ return iframe;
|
||||
+ }
|
||||
+
|
||||
+ async_test(async function(test)
|
||||
+ {
|
||||
+ iframe = allociframe();
|
||||
+ keySystemAccess = await iframe.contentWindow.navigator.requestMediaKeySystemAccess('org.w3.clearkey', getSimpleConfiguration());
|
||||
+ keys = await keySystemAccess.createMediaKeys();
|
||||
+ document.body.removeChild(iframe);
|
||||
+ keys.getStatusForPolicy({minHdcpVersion : '1.0'}).then(function(result) {
|
||||
+ assert_unreached('getStatusforPolicy() should fail');
|
||||
+ }, function(error) {
|
||||
+ test.done();
|
||||
+ });
|
||||
+ }, 'Test context destruction.');
|
||||
+ </script>
|
||||
+ </body>
|
||||
+</html>
|
||||
155
patches/chromium/cherry-pick-f440137cd96a.patch
Normal file
155
patches/chromium/cherry-pick-f440137cd96a.patch
Normal file
@@ -0,0 +1,155 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Stephen Chenney <schenney@chromium.org>
|
||||
Date: Wed, 14 Oct 2020 02:52:47 +0000
|
||||
Subject: Implement WebGL image-orientation
|
||||
|
||||
M-86 merge.
|
||||
|
||||
When creating textures for WebGL, always orient images
|
||||
with EXIF orientation data.
|
||||
|
||||
This change also corrects the transposed size reported by
|
||||
ImageBitmap. And it removes superfluous arguments from
|
||||
CopyImageData.
|
||||
|
||||
(cherry picked from commit f373458c504c2d115c42f31b29ff5c19674acbbc)
|
||||
|
||||
Bug: 1100470, 1125337
|
||||
Change-Id: I79aa798327a3582939aa574723926b3325c80e7c
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2459400
|
||||
Reviewed-by: Kenneth Russell <kbr@chromium.org>
|
||||
Commit-Queue: Stephen Chenney <schenney@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#815359}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2469776
|
||||
Reviewed-by: Stephen Chenney <schenney@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4240@{#1237}
|
||||
Cr-Branched-From: f297677702651916bbf65e59c0d4bbd4ce57d1ee-refs/heads/master@{#800218}
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
|
||||
index 234ae964ad1ac8df7fd369ff8b62a9917757517d..f0bf8d0f5c2d74d942dfbfd194753dd03e3de758 100644
|
||||
--- a/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
|
||||
+++ b/third_party/blink/renderer/core/imagebitmap/image_bitmap.cc
|
||||
@@ -195,14 +195,16 @@ SkImageInfo GetSkImageInfo(const scoped_refptr<Image>& input) {
|
||||
|
||||
// This function results in a readback due to using SkImage::readPixels().
|
||||
// Returns transparent black pixels if the input SkImageInfo.bounds() does
|
||||
-// not intersect with the input image boundaries.
|
||||
+// not intersect with the input image boundaries. When apply_orientation
|
||||
+// is true this method will orient the data according to the source's EXIF
|
||||
+// information.
|
||||
Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input,
|
||||
const SkImageInfo& info,
|
||||
- const unsigned x = 0,
|
||||
- const unsigned y = 0) {
|
||||
+ bool apply_orientation = true) {
|
||||
if (info.isEmpty())
|
||||
return {};
|
||||
- sk_sp<SkImage> sk_image = input->PaintImageForCurrentFrame().GetSkImage();
|
||||
+ PaintImage paint_image = input->PaintImageForCurrentFrame();
|
||||
+ sk_sp<SkImage> sk_image = paint_image.GetSkImage();
|
||||
if (sk_image->bounds().isEmpty())
|
||||
return {};
|
||||
|
||||
@@ -211,16 +213,30 @@ Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input,
|
||||
Vector<uint8_t> dst_buffer(byte_length);
|
||||
|
||||
bool read_pixels_successful =
|
||||
- sk_image->readPixels(info, dst_buffer.data(), info.minRowBytes(), x, y);
|
||||
+ sk_image->readPixels(info, dst_buffer.data(), info.minRowBytes(), 0, 0);
|
||||
DCHECK(read_pixels_successful);
|
||||
if (!read_pixels_successful)
|
||||
return {};
|
||||
+
|
||||
+ // Orient the data, and re-read the pixels.
|
||||
+ if (apply_orientation && !input->HasDefaultOrientation()) {
|
||||
+ paint_image = Image::ResizeAndOrientImage(
|
||||
+ paint_image, input->CurrentFrameOrientation(), FloatSize(1, 1), 1,
|
||||
+ kInterpolationNone);
|
||||
+ sk_image = paint_image.GetSkImage();
|
||||
+ read_pixels_successful = sk_image->readPixels(info, dst_buffer.data(),
|
||||
+ info.minRowBytes(), 0, 0);
|
||||
+ DCHECK(read_pixels_successful);
|
||||
+ if (!read_pixels_successful)
|
||||
+ return {};
|
||||
+ }
|
||||
+
|
||||
return dst_buffer;
|
||||
}
|
||||
|
||||
Vector<uint8_t> CopyImageData(const scoped_refptr<StaticBitmapImage>& input) {
|
||||
SkImageInfo info = GetSkImageInfo(input);
|
||||
- return CopyImageData(std::move(input), info);
|
||||
+ return CopyImageData(std::move(input), info, false);
|
||||
}
|
||||
|
||||
static inline bool ShouldAvoidPremul(
|
||||
@@ -1055,12 +1071,13 @@ Vector<uint8_t> ImageBitmap::CopyBitmapData(AlphaDisposition alpha_op,
|
||||
auto color_type = info.colorType();
|
||||
if (color_type == kN32_SkColorType && u8_color_type == kRGBAColorType)
|
||||
color_type = kRGBA_8888_SkColorType;
|
||||
+ // Note that width() and height() here apply EXIF orientation
|
||||
info =
|
||||
SkImageInfo::Make(width(), height(), color_type,
|
||||
(alpha_op == kPremultiplyAlpha) ? kPremul_SkAlphaType
|
||||
: kUnpremul_SkAlphaType,
|
||||
info.refColorSpace());
|
||||
- return CopyImageData(image_, info);
|
||||
+ return CopyImageData(image_, info, true);
|
||||
}
|
||||
|
||||
Vector<uint8_t> ImageBitmap::CopyBitmapData() {
|
||||
@@ -1090,7 +1107,7 @@ IntSize ImageBitmap::Size() const {
|
||||
return IntSize();
|
||||
DCHECK_GT(image_->width(), 0);
|
||||
DCHECK_GT(image_->height(), 0);
|
||||
- return IntSize(image_->width(), image_->height());
|
||||
+ return image_->SizeRespectingOrientation();
|
||||
}
|
||||
|
||||
ScriptPromise ImageBitmap::CreateImageBitmap(ScriptState* script_state,
|
||||
diff --git a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
|
||||
index 39d00937e8a17183c22dcfc99692aed9a8638ac6..fe5d33eca1ae6564a2528c60e880e619d1f59b62 100644
|
||||
--- a/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
|
||||
+++ b/third_party/blink/renderer/modules/webgl/webgl_rendering_context_base.cc
|
||||
@@ -5212,10 +5212,12 @@ void WebGLRenderingContextBase::TexImageHelperHTMLImageElement(
|
||||
return;
|
||||
|
||||
scoped_refptr<Image> image_for_render = image->CachedImage()->GetImage();
|
||||
- if (IsA<SVGImage>(image_for_render.get())) {
|
||||
- if (canvas()) {
|
||||
+ bool have_svg_image = IsA<SVGImage>(image_for_render.get());
|
||||
+ if (have_svg_image || !image_for_render->HasDefaultOrientation()) {
|
||||
+ if (have_svg_image && canvas()) {
|
||||
UseCounter::Count(canvas()->GetDocument(), WebFeature::kSVGInWebGL);
|
||||
}
|
||||
+ // DrawImageIntoBuffer always respects orientation
|
||||
image_for_render =
|
||||
DrawImageIntoBuffer(std::move(image_for_render), image->width(),
|
||||
image->height(), func_name);
|
||||
@@ -5751,6 +5753,7 @@ void WebGLRenderingContextBase::TexImageHelperImageBitmap(
|
||||
level, internalformat, width, height, depth, 0, format,
|
||||
type, xoffset, yoffset, zoffset))
|
||||
return;
|
||||
+
|
||||
scoped_refptr<StaticBitmapImage> image = bitmap->BitmapImage();
|
||||
DCHECK(image);
|
||||
|
||||
@@ -5777,9 +5780,16 @@ void WebGLRenderingContextBase::TexImageHelperImageBitmap(
|
||||
return;
|
||||
}
|
||||
|
||||
+ // Apply orientation if necessary
|
||||
+ PaintImage paint_image = bitmap->BitmapImage()->PaintImageForCurrentFrame();
|
||||
+ if (!image->HasDefaultOrientation()) {
|
||||
+ paint_image = Image::ResizeAndOrientImage(
|
||||
+ paint_image, image->CurrentFrameOrientation(), FloatSize(1, 1), 1,
|
||||
+ kInterpolationNone);
|
||||
+ }
|
||||
+
|
||||
// TODO(kbr): refactor this away to use TexImageImpl on image.
|
||||
- sk_sp<SkImage> sk_image =
|
||||
- bitmap->BitmapImage()->PaintImageForCurrentFrame().GetSkImage();
|
||||
+ sk_sp<SkImage> sk_image = paint_image.GetSkImage();
|
||||
if (!sk_image) {
|
||||
SynthesizeGLError(GL_OUT_OF_MEMORY, func_name,
|
||||
"ImageBitmap unexpectedly empty");
|
||||
284
patches/chromium/cherry-pick-f6cb89728f04.patch
Normal file
284
patches/chromium/cherry-pick-f6cb89728f04.patch
Normal file
@@ -0,0 +1,284 @@
|
||||
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||
From: Lei Zhang <thestig@chromium.org>
|
||||
Date: Tue, 28 Jul 2020 22:47:48 +0000
|
||||
Subject: M85: Correctly retrieve the plugin when printing.
|
||||
|
||||
The logic in PrintRenderFrameHelper to retrieve a plugin is out of sync
|
||||
with the logic in WebLocalFrameImpl::PrintBegin(). If
|
||||
PrintRenderFrameHelper thinks it is printing a webpage, while
|
||||
WebLocalFrameImpl thinks it is printing a plugin, bad things happen.
|
||||
|
||||
Fix this by adding WebLocalFrame::GetPluginToPrint(), to expose the
|
||||
plugin finding logic in WebLocalFrameImpl. With GetPluginToPrint()
|
||||
available, PrintRenderFrameHelper can delete its own GetPlugin() helper,
|
||||
and switch the GetPlugin() callers to use GetPluginToPrint() instead.
|
||||
|
||||
Once synchronized, some use cases for printing Flash now work correctly.
|
||||
|
||||
(cherry picked from commit f8d7d428b1549ff1f87e3d34c5ca0b53d6ce4e84)
|
||||
|
||||
Tbr: japhet@chromium.org
|
||||
Bug: 1098860
|
||||
Change-Id: I9500db9ed2d6da0f87dad84c197f738d3a1e3c84
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2317168
|
||||
Reviewed-by: Nate Chapin <japhet@chromium.org>
|
||||
Commit-Queue: Lei Zhang <thestig@chromium.org>
|
||||
Cr-Original-Commit-Position: refs/heads/master@{#791564}
|
||||
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2324664
|
||||
Reviewed-by: Lei Zhang <thestig@chromium.org>
|
||||
Cr-Commit-Position: refs/branch-heads/4183@{#1009}
|
||||
Cr-Branched-From: 740e9e8a40505392ba5c8e022a8024b3d018ca65-refs/heads/master@{#782793}
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.cc b/components/printing/renderer/print_render_frame_helper.cc
|
||||
index 8456ec0c453345e5cab96728e501d341053d8cf2..9dd56e9df0d91ccd1d6789e3b3f261a533d373e8 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.cc
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.cc
|
||||
@@ -61,8 +61,6 @@
|
||||
#include "third_party/blink/public/web/web_local_frame_client.h"
|
||||
#include "third_party/blink/public/web/web_navigation_control.h"
|
||||
#include "third_party/blink/public/web/web_plugin.h"
|
||||
-#include "third_party/blink/public/web/web_plugin_container.h"
|
||||
-#include "third_party/blink/public/web/web_plugin_document.h"
|
||||
#include "third_party/blink/public/web/web_print_params.h"
|
||||
#include "third_party/blink/public/web/web_print_preset_options.h"
|
||||
#include "third_party/blink/public/web/web_script_source.h"
|
||||
@@ -343,28 +341,14 @@ void ComputeWebKitPrintParamsInDesiredDpi(
|
||||
webkit_print_params->pages_per_sheet = print_params.pages_per_sheet;
|
||||
}
|
||||
|
||||
-blink::WebPlugin* GetPlugin(const blink::WebLocalFrame* frame) {
|
||||
- return frame->GetDocument().IsPluginDocument()
|
||||
- ? frame->GetDocument().To<blink::WebPluginDocument>().Plugin()
|
||||
- : nullptr;
|
||||
-}
|
||||
-
|
||||
-bool IsPrintingNodeOrPdfFrame(const blink::WebLocalFrame* frame,
|
||||
+bool IsPrintingNodeOrPdfFrame(blink::WebLocalFrame* frame,
|
||||
const blink::WebNode& node) {
|
||||
- if (!node.IsNull())
|
||||
- return true;
|
||||
- blink::WebPlugin* plugin = GetPlugin(frame);
|
||||
+ blink::WebPlugin* plugin = frame->GetPluginToPrint(node);
|
||||
return plugin && plugin->SupportsPaginatedPrint();
|
||||
}
|
||||
|
||||
bool IsPrintingPdf(blink::WebLocalFrame* frame, const blink::WebNode& node) {
|
||||
- blink::WebPlugin* plugin;
|
||||
- if (node.IsNull()) {
|
||||
- plugin = GetPlugin(frame);
|
||||
- } else {
|
||||
- blink::WebPluginContainer* plugin_container = node.PluginContainer();
|
||||
- plugin = plugin_container ? plugin_container->Plugin() : nullptr;
|
||||
- }
|
||||
+ blink::WebPlugin* plugin = frame->GetPluginToPrint(node);
|
||||
return plugin && plugin->IsPdfPlugin();
|
||||
}
|
||||
|
||||
@@ -2337,7 +2321,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
|
||||
// 2. PrintHostMsg_ShowScriptedPrintPreview shows preview once the
|
||||
// document has been loaded.
|
||||
is_scripted_preview_delayed_ = true;
|
||||
- if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
|
||||
+ if (is_loading_ && print_preview_context_.IsPlugin()) {
|
||||
// Wait for DidStopLoading. Plugins may not know the correct
|
||||
// |is_modifiable| value until they are fully loaded, which occurs when
|
||||
// DidStopLoading() is called. Defer showing the preview until then.
|
||||
@@ -2364,7 +2348,7 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
|
||||
// Wait for DidStopLoading. Continuing with this function while
|
||||
// |is_loading_| is true will cause print preview to hang when try to
|
||||
// print a PDF document.
|
||||
- if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
|
||||
+ if (is_loading_ && print_preview_context_.IsPlugin()) {
|
||||
on_stop_loading_closure_ =
|
||||
base::BindOnce(&PrintRenderFrameHelper::RequestPrintPreview,
|
||||
weak_ptr_factory_.GetWeakPtr(), type);
|
||||
@@ -2375,12 +2359,12 @@ void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
|
||||
}
|
||||
case PRINT_PREVIEW_USER_INITIATED_SELECTION: {
|
||||
DCHECK(has_selection);
|
||||
- DCHECK(!GetPlugin(print_preview_context_.source_frame()));
|
||||
+ DCHECK(!print_preview_context_.IsPlugin());
|
||||
params.selection_only = has_selection;
|
||||
break;
|
||||
}
|
||||
case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
|
||||
- if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
|
||||
+ if (is_loading_ && print_preview_context_.IsPlugin()) {
|
||||
on_stop_loading_closure_ =
|
||||
base::BindOnce(&PrintRenderFrameHelper::RequestPrintPreview,
|
||||
weak_ptr_factory_.GetWeakPtr(), type);
|
||||
@@ -2465,8 +2449,7 @@ void PrintRenderFrameHelper::PrintPreviewContext::InitWithFrame(
|
||||
state_ = INITIALIZED;
|
||||
source_frame_.Reset(web_frame);
|
||||
source_node_.Reset();
|
||||
- CalculateIsModifiable();
|
||||
- CalculateIsPdf();
|
||||
+ CalculatePluginAttributes();
|
||||
}
|
||||
|
||||
void PrintRenderFrameHelper::PrintPreviewContext::InitWithNode(
|
||||
@@ -2477,8 +2460,7 @@ void PrintRenderFrameHelper::PrintPreviewContext::InitWithNode(
|
||||
state_ = INITIALIZED;
|
||||
source_frame_.Reset(web_node.GetDocument().GetFrame());
|
||||
source_node_ = web_node;
|
||||
- CalculateIsModifiable();
|
||||
- CalculateIsPdf();
|
||||
+ CalculatePluginAttributes();
|
||||
}
|
||||
|
||||
void PrintRenderFrameHelper::PrintPreviewContext::OnPrintPreview() {
|
||||
@@ -2621,6 +2603,11 @@ bool PrintRenderFrameHelper::PrintPreviewContext::IsForArc() const {
|
||||
return is_for_arc_;
|
||||
}
|
||||
|
||||
+bool PrintRenderFrameHelper::PrintPreviewContext::IsPlugin() const {
|
||||
+ DCHECK(state_ != UNINITIALIZED);
|
||||
+ return is_plugin_;
|
||||
+}
|
||||
+
|
||||
bool PrintRenderFrameHelper::PrintPreviewContext::IsModifiable() const {
|
||||
DCHECK(state_ != UNINITIALIZED);
|
||||
return is_modifiable_;
|
||||
@@ -2713,11 +2700,9 @@ void PrintRenderFrameHelper::PrintPreviewContext::ClearContext() {
|
||||
error_ = PREVIEW_ERROR_NONE;
|
||||
}
|
||||
|
||||
-void PrintRenderFrameHelper::PrintPreviewContext::CalculateIsModifiable() {
|
||||
+void PrintRenderFrameHelper::PrintPreviewContext::CalculatePluginAttributes() {
|
||||
+ is_plugin_ = !!source_frame()->GetPluginToPrint(source_node_);
|
||||
is_modifiable_ = !IsPrintingNodeOrPdfFrame(source_frame(), source_node_);
|
||||
-}
|
||||
-
|
||||
-void PrintRenderFrameHelper::PrintPreviewContext::CalculateIsPdf() {
|
||||
is_pdf_ = IsPrintingPdf(source_frame(), source_node_);
|
||||
}
|
||||
|
||||
diff --git a/components/printing/renderer/print_render_frame_helper.h b/components/printing/renderer/print_render_frame_helper.h
|
||||
index 81df566a5908f1b35b9da5c2aad35ea7dec1dc3b..30cb90cab8a971b1b4eb11bb89e05b09853b7721 100644
|
||||
--- a/components/printing/renderer/print_render_frame_helper.h
|
||||
+++ b/components/printing/renderer/print_render_frame_helper.h
|
||||
@@ -503,6 +503,7 @@ class PrintRenderFrameHelper
|
||||
int GetNextPageNumber();
|
||||
bool IsRendering() const;
|
||||
bool IsForArc() const;
|
||||
+ bool IsPlugin() const;
|
||||
bool IsModifiable() const;
|
||||
bool IsPdf() const;
|
||||
bool HasSelection();
|
||||
@@ -543,9 +544,7 @@ class PrintRenderFrameHelper
|
||||
// Reset some of the internal rendering context.
|
||||
void ClearContext();
|
||||
|
||||
- void CalculateIsModifiable();
|
||||
-
|
||||
- void CalculateIsPdf();
|
||||
+ void CalculatePluginAttributes();
|
||||
|
||||
// Specifies what to render for print preview.
|
||||
FrameReference source_frame_;
|
||||
@@ -565,6 +564,9 @@ class PrintRenderFrameHelper
|
||||
// List of page indices that need to be rendered.
|
||||
std::vector<int> pages_to_render_;
|
||||
|
||||
+ // True, if the document source is a plugin.
|
||||
+ bool is_plugin_ = false;
|
||||
+
|
||||
// True, if the document source is modifiable. e.g. HTML and not PDF.
|
||||
bool is_modifiable_ = true;
|
||||
|
||||
diff --git a/third_party/blink/public/web/web_local_frame.h b/third_party/blink/public/web/web_local_frame.h
|
||||
index c5d9cd52989c0d776ac12a5c0b88782d2c40b213..ecb810fecebd4ecb8c93630490cfb8ad5fe856c6 100644
|
||||
--- a/third_party/blink/public/web/web_local_frame.h
|
||||
+++ b/third_party/blink/public/web/web_local_frame.h
|
||||
@@ -59,6 +59,7 @@ class WebLocalFrameClient;
|
||||
class WebFrameWidget;
|
||||
class WebInputMethodController;
|
||||
class WebPerformance;
|
||||
+class WebPlugin;
|
||||
class WebRange;
|
||||
class WebSecurityOrigin;
|
||||
class WebScriptExecutionCallback;
|
||||
@@ -655,13 +656,16 @@ class WebLocalFrame : public WebFrame {
|
||||
// This function should be called before pairs of PrintBegin() and PrintEnd().
|
||||
virtual void DispatchBeforePrintEvent() = 0;
|
||||
|
||||
+ // Get the plugin to print, if any. The |constrain_to_node| parameter is the
|
||||
+ // same as the one for PrintBegin() below.
|
||||
+ virtual WebPlugin* GetPluginToPrint(const WebNode& constrain_to_node) = 0;
|
||||
+
|
||||
// Reformats the WebFrame for printing. WebPrintParams specifies the printable
|
||||
// content size, paper size, printable area size, printer DPI and print
|
||||
- // scaling option. If constrainToNode node is specified, then only the given
|
||||
+ // scaling option. If |constrain_to_node| is specified, then only the given
|
||||
// node is printed (for now only plugins are supported), instead of the entire
|
||||
// frame.
|
||||
- // Returns the number of pages that can be printed at the given
|
||||
- // page size.
|
||||
+ // Returns the number of pages that can be printed at the given page size.
|
||||
virtual int PrintBegin(const WebPrintParams&,
|
||||
const WebNode& constrain_to_node = WebNode()) = 0;
|
||||
|
||||
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
|
||||
index 9cb4f3d02fccd6f1098c9b8080f1057642aead5f..52e57b11169ec19c2f890545560a5784af071029 100644
|
||||
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
|
||||
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.cc
|
||||
@@ -1537,19 +1537,29 @@ void WebLocalFrameImpl::DispatchPrintEventRecursively(
|
||||
}
|
||||
}
|
||||
|
||||
-int WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
|
||||
- const WebNode& constrain_to_node) {
|
||||
- WebPluginContainerImpl* plugin_container = nullptr;
|
||||
+WebPluginContainerImpl* WebLocalFrameImpl::GetPluginToPrintHelper(
|
||||
+ const WebNode& constrain_to_node) {
|
||||
if (constrain_to_node.IsNull()) {
|
||||
// If this is a plugin document, check if the plugin supports its own
|
||||
// printing. If it does, we will delegate all printing to that.
|
||||
- plugin_container = GetFrame()->GetWebPluginContainer();
|
||||
- } else {
|
||||
- // We only support printing plugin nodes for now.
|
||||
- plugin_container =
|
||||
- To<WebPluginContainerImpl>(constrain_to_node.PluginContainer());
|
||||
+ return GetFrame()->GetWebPluginContainer();
|
||||
}
|
||||
|
||||
+ // We only support printing plugin nodes for now.
|
||||
+ return To<WebPluginContainerImpl>(constrain_to_node.PluginContainer());
|
||||
+}
|
||||
+
|
||||
+WebPlugin* WebLocalFrameImpl::GetPluginToPrint(
|
||||
+ const WebNode& constrain_to_node) {
|
||||
+ WebPluginContainerImpl* plugin_container =
|
||||
+ GetPluginToPrintHelper(constrain_to_node);
|
||||
+ return plugin_container ? plugin_container->Plugin() : nullptr;
|
||||
+}
|
||||
+
|
||||
+int WebLocalFrameImpl::PrintBegin(const WebPrintParams& print_params,
|
||||
+ const WebNode& constrain_to_node) {
|
||||
+ WebPluginContainerImpl* plugin_container =
|
||||
+ GetPluginToPrintHelper(constrain_to_node);
|
||||
if (plugin_container && plugin_container->SupportsPaginatedPrint()) {
|
||||
print_context_ = MakeGarbageCollected<ChromePluginPrintContext>(
|
||||
GetFrame(), plugin_container, print_params);
|
||||
diff --git a/third_party/blink/renderer/core/frame/web_local_frame_impl.h b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
|
||||
index d7582f9c2f733d4beeb294df34dcbf09ce3970ce..f93ce60b7dd67c49feadc7679f2dc40dab0fb47e 100644
|
||||
--- a/third_party/blink/renderer/core/frame/web_local_frame_impl.h
|
||||
+++ b/third_party/blink/renderer/core/frame/web_local_frame_impl.h
|
||||
@@ -279,6 +279,7 @@ class CORE_EXPORT WebLocalFrameImpl final
|
||||
bool HasVisibleContent() const override;
|
||||
WebRect VisibleContentRect() const override;
|
||||
void DispatchBeforePrintEvent() override;
|
||||
+ WebPlugin* GetPluginToPrint(const WebNode& constrain_to_node) override;
|
||||
int PrintBegin(const WebPrintParams&,
|
||||
const WebNode& constrain_to_node) override;
|
||||
float GetPrintPageShrink(int page) override;
|
||||
@@ -470,6 +471,9 @@ class CORE_EXPORT WebLocalFrameImpl final
|
||||
// A helper for DispatchBeforePrintEvent() and DispatchAfterPrintEvent().
|
||||
void DispatchPrintEventRecursively(const AtomicString& event_type);
|
||||
|
||||
+ WebPluginContainerImpl* GetPluginToPrintHelper(
|
||||
+ const WebNode& constrain_to_node);
|
||||
+
|
||||
Node* ContextMenuNodeInner() const;
|
||||
|
||||
WebLocalFrameClient* client_;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user