Merge autoland to mozilla-central a=merge

This commit is contained in:
Andreea Pavel 2020-08-06 00:42:27 +03:00
Родитель 9753c66eef 9712c504bc
Коммит da3293e62c
193 изменённых файлов: 11563 добавлений и 4103 удалений

Просмотреть файл

@ -60,7 +60,7 @@ rev = "3224e2dee65c0726c448484d4c3c43956b9330ec"
[source."https://github.com/bytecodealliance/wasmtime"]
git = "https://github.com/bytecodealliance/wasmtime"
replace-with = "vendored-sources"
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"
[source."https://github.com/badboy/failure"]
git = "https://github.com/badboy/failure"

Просмотреть файл

@ -316,6 +316,16 @@ jobs:
when:
- {hour: 4, minute: 00}
- name: perftest-on-autoland
job:
type: decision-task
treeherder-symbol: perftest-auto
target-tasks-method: perftest-on-autoland
run-on-projects:
- autoland
when:
- {hour: 4, minute: 00}
- name: scriptworker-canary
job:
type: trigger-action

14
Cargo.lock сгенерированный
Просмотреть файл

@ -753,7 +753,7 @@ dependencies = [
[[package]]
name = "cranelift-bforest"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
dependencies = [
"cranelift-entity 0.66.0",
]
@ -761,7 +761,7 @@ dependencies = [
[[package]]
name = "cranelift-codegen"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
dependencies = [
"byteorder",
"cranelift-bforest",
@ -778,7 +778,7 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
dependencies = [
"cranelift-codegen-shared",
"cranelift-entity 0.66.0",
@ -787,7 +787,7 @@ dependencies = [
[[package]]
name = "cranelift-codegen-shared"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
[[package]]
name = "cranelift-entity"
@ -797,12 +797,12 @@ source = "git+https://github.com/PLSysSec/lucet_sandbox_compiler?rev=6594bb9dfab
[[package]]
name = "cranelift-entity"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
[[package]]
name = "cranelift-frontend"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
dependencies = [
"cranelift-codegen",
"log",
@ -813,7 +813,7 @@ dependencies = [
[[package]]
name = "cranelift-wasm"
version = "0.66.0"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=25e31739a63b7a33a4a34c961b88606c76670e46#25e31739a63b7a33a4a34c961b88606c76670e46"
source = "git+https://github.com/bytecodealliance/wasmtime?rev=fc88898e9ad7766feadfa0954c4594fcccd86b92#fc88898e9ad7766feadfa0954c4594fcccd86b92"
dependencies = [
"cranelift-codegen",
"cranelift-entity 0.66.0",

Просмотреть файл

@ -75,8 +75,8 @@ failure_derive = { git = "https://github.com/badboy/failure", rev = "64af847bc5f
[patch.crates-io.cranelift-codegen]
git = "https://github.com/bytecodealliance/wasmtime"
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"
[patch.crates-io.cranelift-wasm]
git = "https://github.com/bytecodealliance/wasmtime"
rev = "25e31739a63b7a33a4a34c961b88606c76670e46"
rev = "fc88898e9ad7766feadfa0954c4594fcccd86b92"

Просмотреть файл

@ -67,6 +67,7 @@ const MONITOR_RESPONSE_PROPS = [
let gTestOverride = null;
let monitorResponse = null;
let entrypoint = "direct";
class AboutProtectionsParent extends JSWindowActorParent {
constructor() {
@ -379,6 +380,13 @@ class AboutProtectionsParent extends JSWindowActorParent {
case "GetShowProxyCard":
let card = await this.shouldShowProxyCard();
return card;
case "RecordEntryPoint":
entrypoint = aMessage.data.entrypoint;
break;
case "FetchEntryPoint":
return entrypoint;
}
return undefined;

Просмотреть файл

@ -62,8 +62,6 @@ support-files =
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_beforeunload_duplicate_dialogs.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_blob-channelname.js]
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.
[browser_bug321000.js]
skip-if = true # browser_bug321000.js is disabled because newline handling is shaky (bug 592528)
# DO NOT ADD MORE TESTS HERE. USE A TOPICAL DIRECTORY INSTEAD.

Просмотреть файл

@ -1,17 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
var { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
function test() {
var file = new File(
[new Blob(["test"], { type: "text/plain" })],
"test-name"
);
var url = URL.createObjectURL(file);
var channel = NetUtil.newChannel({
uri: url,
loadUsingSystemPrincipal: true,
});
is(channel.contentDispositionFilename, "test-name", "filename matches");
}

Просмотреть файл

@ -201,7 +201,7 @@ let JSWINDOWACTORS = {
},
},
matches: ["about:protections"],
matches: ["about:protections", "about:protections?*"],
},
AboutReader: {

Просмотреть файл

@ -527,6 +527,19 @@ class WelcomeScreen extends react__WEBPACK_IMPORTED_MODULE_0___default.a.PureCom
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "text"
})))))))) : null;
case "video":
return this.props.content.tiles.source ? react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: `tiles-media-section ${this.props.content.tiles.media_type}`
}, react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("div", {
className: "fade"
}), react__WEBPACK_IMPORTED_MODULE_0___default.a.createElement("video", {
className: "media",
autoPlay: "true",
loop: "true",
muted: "true",
src: _lib_aboutwelcome_utils__WEBPACK_IMPORTED_MODULE_3__["AboutWelcomeUtils"].hasDarkMode() ? this.props.content.tiles.source.dark : this.props.content.tiles.source.default
})) : null;
}
return null;
@ -771,6 +784,10 @@ const AboutWelcomeUtils = {
bubbles: true,
detail
}));
},
hasDarkMode() {
return document.body.hasAttribute("lwt-newtab-brighttext");
}
};

Просмотреть файл

@ -100,6 +100,7 @@ body {
--welcome-button-text-color: #FFF;
--welcome-button-background-hover-color: #003EAA;
--welcome-button-background-active-color: #002275;
--about-welcome-media-fade: linear-gradient(transparent, transparent 40%, #F9F9FA);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu', 'Helvetica Neue', sans-serif;
font-size: 16px;
position: relative;
@ -122,7 +123,8 @@ body {
--welcome-card-button-background-color: rgba(12, 12, 13, 0.3);
--welcome-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
--welcome-card-button-background-active-color: rgba(12, 12, 13, 0.7);
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2); }
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2);
--about-welcome-media-fade: linear-gradient(transparent, transparent 35%, #1D1133, #1D1133); }
.welcomeCardGrid {
margin: 0;
@ -316,7 +318,9 @@ body {
font-weight: normal;
margin: 0 6px;
color: var(--grey-subtitle-1);
line-height: 28px; }
line-height: 28px;
max-width: 750px;
letter-spacing: -0.01em; }
.multistageContainer .tiles-theme-container {
margin: 10px auto;
border: 0; }
@ -423,6 +427,30 @@ body {
background-color: #E25920; }
.multistageContainer .tiles-topsites-section .site:nth-child(5) .icon {
background-color: #0250BB; }
.multistageContainer .tiles-media-section {
align-self: center;
position: relative;
margin-top: -12px;
height: 400px;
margin-bottom: -155px; }
.multistageContainer .tiles-media-section .fade {
height: 390px;
width: 800px;
position: absolute;
background-image: var(--about-welcome-media-fade); }
.multistageContainer .tiles-media-section .media {
height: 390px;
width: 800px; }
@media (prefers-reduced-motion) {
.multistageContainer .tiles-media-section {
height: 200px;
width: 800px;
margin-top: 20px;
margin-bottom: 12px; }
.multistageContainer .tiles-media-section.privacy {
background: top no-repeat url("../data/content/assets/firefox-protections.svg"); }
.multistageContainer .tiles-media-section .media {
opacity: 0; } }
.multistageContainer button {
font-family: inherit;
cursor: pointer;
@ -435,7 +463,9 @@ body {
white-space: nowrap;
background-color: var(--newtab-button-primary-color);
color: var(--welcome-button-text-color);
border-radius: 4px; }
border-radius: 4px;
position: relative;
z-index: 1; }
.multistageContainer button.primary:focus {
background: var(--welcome-button-background-hover-color);
box-shadow: 0 0 0 1px var(--welcome-button-box-shadow-inset-color) inset, 0 0 0 1px var(--welcome-button-box-shadow-inset-color), 0 0 0 4px var(--welcome-button-box-shadow-color); }
@ -474,7 +504,8 @@ body {
flex-direction: row;
justify-content: center;
margin-top: auto;
padding: 32px 0 66px; }
padding: 32px 0 66px;
z-index: 1; }
.multistageContainer .steps.has-disclaimer {
padding-bottom: 0; }
.multistageContainer .steps .indicator {

Просмотреть файл

@ -6,7 +6,7 @@
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src resource: chrome:;">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; object-src 'none'; script-src resource: chrome:; media-src resource: chrome:; connect-src https:; img-src https: data: blob:; style-src resource: chrome:;">
<title data-l10n-id="onboarding-welcome-header"></title>
<link rel="icon" type="image/png" href="chrome://branding/content/icon32.png">
<link rel="stylesheet" href="resource://activity-stream/aboutwelcome/aboutwelcome.css">

Просмотреть файл

@ -36,6 +36,7 @@ body {
--welcome-button-text-color: #FFF;
--welcome-button-background-hover-color: #003EAA;
--welcome-button-background-active-color: #002275;
--about-welcome-media-fade: linear-gradient(transparent, transparent 40%, #F9F9FA);
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Ubuntu',
'Helvetica Neue', sans-serif;
@ -62,6 +63,7 @@ body {
--welcome-card-button-background-hover-color: rgba(12, 12, 13, 0.5);
--welcome-card-button-background-active-color: rgba(12, 12, 13, 0.7);
--welcome-button-box-shadow-color: rgba(249, 249, 250, 0.2);
--about-welcome-media-fade: linear-gradient(transparent, transparent 35%, #1D1133, #1D1133);
}
}
@ -318,6 +320,8 @@ body {
margin: 0 6px;
color: var(--grey-subtitle-1);
line-height: 28px;
max-width: 750px;
letter-spacing: -0.01em;
}
}
@ -488,6 +492,41 @@ body {
}
}
.tiles-media-section {
align-self: center;
position: relative;
margin-top: -12px;
height: 400px;
margin-bottom: -155px;
.fade {
height: 390px;
width: 800px;
position: absolute;
background-image: var(--about-welcome-media-fade);
}
.media {
height: 390px;
width: 800px;
}
@media (prefers-reduced-motion) {
height: 200px;
width: 800px;
margin-top: 20px;
margin-bottom: 12px;
&.privacy {
background: top no-repeat url('../data/content/assets/firefox-protections.svg');
}
.media {
opacity: 0;
}
}
}
button {
font-family: inherit;
cursor: pointer;
@ -502,6 +541,8 @@ body {
background-color: var(--newtab-button-primary-color);
color: var(--welcome-button-text-color);
border-radius: 4px;
position: relative;
z-index: 1;
&:focus {
background: var(--welcome-button-background-hover-color);
@ -565,6 +606,7 @@ body {
justify-content: center;
margin-top: auto;
padding: 32px 0 66px;
z-index: 1;
&.has-disclaimer {
padding-bottom: 0;

Просмотреть файл

@ -281,6 +281,25 @@ export class WelcomeScreen extends React.PureComponent {
</div>
</div>
) : null;
case "video":
return this.props.content.tiles.source ? (
<div
className={`tiles-media-section ${this.props.content.tiles.media_type}`}
>
<div className="fade" />
<video
className="media"
autoPlay="true"
loop="true"
muted="true"
src={
AboutWelcomeUtils.hasDarkMode()
? this.props.content.tiles.source.dark
: this.props.content.tiles.source.default
}
/>
</div>
) : null;
}
return null;
}

Просмотреть файл

@ -49,6 +49,9 @@ export const AboutWelcomeUtils = {
})
);
},
hasDarkMode() {
return document.body.hasAttribute("lwt-newtab-brighttext");
},
};
export const DEFAULT_WELCOME_CONTENT = {

Различия файлов скрыты, потому что одна или несколько строк слишком длинны

После

Ширина:  |  Высота:  |  Размер: 5.7 KiB

Двоичный файл не отображается.

Двоичный файл не отображается.

Просмотреть файл

@ -8,18 +8,21 @@ const BASE_URI =
"privatebrowsing/test/browser/empty_file.html";
add_task(async function test() {
info("Creating a normal window...");
let win = await BrowserTestUtils.openNewBrowserWindow();
let tab = win.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(tab, BASE_URI);
await BrowserTestUtils.browserLoaded(tab);
const loaded = BrowserTestUtils.browserLoaded(
gBrowser.selectedBrowser,
false,
BASE_URI
);
await BrowserTestUtils.loadURI(gBrowser.selectedBrowser, BASE_URI);
await loaded;
let blobURL;
info("Creating a blob URL...");
await SpecialPowers.spawn(tab, [], function() {
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function() {
return Promise.resolve(
content.window.URL.createObjectURL(new content.window.Blob([123]))
content.window.URL.createObjectURL(
new Blob([123], { type: "text/plain" })
)
);
}).then(newURL => {
blobURL = newURL;
@ -28,12 +31,19 @@ add_task(async function test() {
info("Blob URL: " + blobURL);
info("Creating a private window...");
let privateWin = await BrowserTestUtils.openNewBrowserWindow({
private: true,
});
let privateTab = privateWin.gBrowser.selectedBrowser;
BrowserTestUtils.loadURI(privateTab, BASE_URI);
await BrowserTestUtils.browserLoaded(privateTab);
const privateTabLoaded = BrowserTestUtils.browserLoaded(
privateTab,
false,
BASE_URI
);
await BrowserTestUtils.loadURI(privateTab, BASE_URI);
await privateTabLoaded;
await SpecialPowers.spawn(privateTab, [blobURL], function(url) {
return new Promise(resolve => {
@ -55,6 +65,5 @@ add_task(async function test() {
);
});
await BrowserTestUtils.closeWindow(win);
await BrowserTestUtils.closeWindow(privateWin);
});

Просмотреть файл

@ -8,12 +8,49 @@ import LockwiseCard from "./lockwise-card.js";
import MonitorCard from "./monitor-card.js";
import ProxyCard from "./proxy-card.js";
// We need to send the close telemetry before unload while we still have a connection to RPM.
window.addEventListener("beforeunload", () => {
document.sendTelemetryEvent("close", "protection_report");
});
let cbCategory = RPMGetStringPref("browser.contentblocking.category");
document.sendTelemetryEvent = (action, object, value = "") => {
// eslint-disable-next-line no-undef
RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
category: cbCategory,
});
};
let { protocol, pathname, searchParams } = new URL(document.location);
let searchParamsChanged = false;
if (searchParams.has("entrypoint")) {
RPMSendAsyncMessage("RecordEntryPoint", {
entrypoint: searchParams.get("entrypoint"),
});
// Remove this parameter from the URL (after recording above) to make it
// cleaner for bookmarking and switch-to-tab and so that bookmarked values
// don't skew telemetry.
searchParams.delete("entrypoint");
searchParamsChanged = true;
}
document.addEventListener("DOMContentLoaded", e => {
if (searchParamsChanged) {
let newURL = protocol + pathname;
let params = searchParams.toString();
if (params) {
newURL += "?" + params;
}
window.location.replace(newURL);
return;
}
RPMSendQuery("FetchEntryPoint", {}).then(entrypoint => {
// Send telemetry on arriving on this page
document.sendTelemetryEvent("show", "protection_report", entrypoint);
});
// We need to send the close telemetry before unload while we still have a connection to RPM.
window.addEventListener("beforeunload", () => {
document.sendTelemetryEvent("close", "protection_report");
});
let todayInMs = Date.now();
let weekAgoInMs = todayInMs - 6 * 24 * 60 * 60 * 1000;
@ -53,22 +90,10 @@ document.addEventListener("DOMContentLoaded", e => {
manageProtections.addEventListener("click", protectionSettingsEvtHandler);
manageProtections.addEventListener("keypress", protectionSettingsEvtHandler);
let cbCategory = RPMGetStringPref("browser.contentblocking.category");
let legend = document.getElementById("legend");
legend.style.gridTemplateAreas =
"'social cookie tracker fingerprinter cryptominer'";
document.sendTelemetryEvent = (action, object, value = "") => {
// eslint-disable-next-line no-undef
RPMRecordTelemetryEvent("security.ui.protections", action, object, value, {
category: cbCategory,
});
};
// Send telemetry on arriving and closing this page
document.sendTelemetryEvent("show", "protection_report");
let createGraph = data => {
let graph = document.getElementById("graph");
let summary = document.getElementById("graph-total-summary");

Просмотреть файл

@ -820,3 +820,90 @@ add_task(async function test_save_telemetry() {
// Use the TrackingDBService API to delete the data.
await TrackingDBService.clearAll();
});
// Test that telemetry is sent if entrypoint param is included,
// and test that it is recorded as default if entrypoint param is not properly included
add_task(async function checkTelemetryLoadEventForEntrypoint() {
// There's an arbitrary interval of 2 seconds in which the content
// processes sync their event data with the parent process, we wait
// this out to ensure that we clear everything that is left over from
// previous tests and don't receive random events in the middle of our tests.
// eslint-disable-next-line mozilla/no-arbitrary-setTimeout
await new Promise(c => setTimeout(c, 2000));
// Clear everything.
Services.telemetry.clearEvents();
await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
true
).content;
return !events || !events.length;
});
Services.telemetry.setEventRecordingEnabled("security.ui.protections", true);
info("Typo in 'entrypoint' should not be recorded");
let tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections?entryPoint=newPage",
gBrowser,
});
let loadEvents = await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
true
).content;
if (events && events.length) {
events = events.filter(
e =>
e[1] == "security.ui.protections" &&
e[2] == "show" &&
e[4] == "direct"
);
if (events.length == 1) {
return events;
}
}
return null;
}, "recorded telemetry for showing the report contains default 'direct' entrypoint");
is(
loadEvents.length,
1,
`recorded telemetry for showing the report contains default 'direct' entrypoint`
);
await BrowserTestUtils.removeTab(tab);
tab = await BrowserTestUtils.openNewForegroundTab({
url: "about:protections?entrypoint=page",
gBrowser,
});
loadEvents = await TestUtils.waitForCondition(() => {
let events = Services.telemetry.snapshotEvents(
Ci.nsITelemetry.DATASET_PRERELEASE_CHANNELS,
true
).content;
if (events && events.length) {
events = events.filter(
e =>
e[1] == "security.ui.protections" && e[2] == "show" && e[4] == "page"
);
if (events.length == 1) {
return events;
}
}
return null;
}, "recorded telemetry for showing the report contains correct entrypoint");
is(
loadEvents.length,
1,
"recorded telemetry for showing the report contains correct entrypoint"
);
// Clean up.
await BrowserTestUtils.removeTab(tab);
});

Просмотреть файл

@ -323,11 +323,26 @@ async function openPopupAndGetEngineButton(
);
} else {
let aliases = UrlbarSearchUtils.aliasesForEngine(oneOffButton.engine);
Assert.equal(
oneOffButton.getAttribute("tooltiptext"),
engineName + (aliases.length ? ` (${aliases[0]})` : ""),
"One-off should have the tooltip set to the engine name"
);
if (!aliases.length) {
Assert.equal(
oneOffButton.getAttribute("tooltiptext"),
engineName,
"One-off without alias should have the tooltip set to the engine name"
);
} else {
let l10n = {
id: "search-one-offs-engine-with-alias",
args: {
engineName,
alias: aliases[0],
},
};
Assert.deepEqual(
win.document.l10n.getAttributes(oneOffButton),
l10n,
"One-off with alias has expected tooltip l10n values"
);
}
}
Assert.equal(
oneOffButton.id,

Просмотреть файл

@ -1206,6 +1206,11 @@ class UrlbarInput {
if (this.searchMode) {
this.toggleAttribute("searchmode", true);
// Search mode should only be active when pageproxystate is invalid.
if (this.getAttribute("pageproxystate") == "valid") {
this.value = "";
this.setPageProxyState("invalid", true);
}
} else {
this.removeAttribute("searchmode");
}

Просмотреть файл

@ -233,7 +233,16 @@ class Preferences {
*/
constructor() {
this._map = new Map();
this._observer = new UrlbarPrefsObserver(pref => this._onPrefChanged(pref));
this.QueryInterface = ChromeUtils.generateQI([
"nsIObserver",
"nsISupportsWeakReference",
]);
Services.prefs.addObserver(PREF_URLBAR_BRANCH, this, true);
for (let pref of PREF_OTHER_DEFAULTS.keys()) {
Services.prefs.addObserver(pref, this, true);
}
this._observerWeakRefs = [];
this.addObserver(this);
}
/**
@ -271,6 +280,44 @@ class Preferences {
setter(pref, value);
}
/**
* Adds a preference observer. Observers are held weakly.
*
* @param {object} observer
* An object that must have a method named `onPrefChanged`, which will
* be called when a urlbar preference changes. It will be passed the
* pref name. For prefs in the `browser.urlbar.` branch, the name will
* be relative to the branch. For other prefs, the name will be the
* full name.
*/
addObserver(observer) {
this._observerWeakRefs.push(Cu.getWeakReference(observer));
}
/**
* Observes preference changes.
*
* @param {nsISupports} subject
* @param {string} topic
* @param {string} data
*/
observe(subject, topic, data) {
let pref = data.replace(PREF_URLBAR_BRANCH, "");
if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref)) {
return;
}
for (let i = 0; i < this._observerWeakRefs.length; ) {
let observer = this._observerWeakRefs[i].get();
if (!observer) {
// The observer has been GC'ed, so remove it from our list.
this._observerWeakRefs.splice(i, 1);
} else {
observer.onPrefChanged(pref);
++i;
}
}
}
/**
* Called when a pref tracked by UrlbarPrefs changes.
*
@ -278,7 +325,7 @@ class Preferences {
* The name of the pref, relative to `browser.urlbar.` if the pref is
* in that branch.
*/
_onPrefChanged(pref) {
onPrefChanged(pref) {
this._map.delete(pref);
// Some prefs may influence others.
if (pref == "matchBuckets") {
@ -403,45 +450,4 @@ class Preferences {
}
}
/**
* A weak preferences observer. You must hold on to instances of this class
* because otherwise they will be garbage collected.
*/
class UrlbarPrefsObserver {
/**
* Constructor.
*
* @param {function} callback
* Called when a urlbar preference changes. It will be passed the pref
* name. For prefs in the `browser.urlbar.` branch, the name will be
* relative to the branch. For other prefs, the name will be the full name.
*/
constructor(callback) {
this._callback = callback;
this.QueryInterface = ChromeUtils.generateQI([
"nsIObserver",
"nsISupportsWeakReference",
]);
Services.prefs.addObserver(PREF_URLBAR_BRANCH, this, true);
for (let pref of PREF_OTHER_DEFAULTS.keys()) {
Services.prefs.addObserver(pref, this, true);
}
}
/**
* Observes preference changes.
*
* @param {nsISupports} subject
* @param {string} topic
* @param {string} data
*/
observe(subject, topic, data) {
let pref = data.replace(PREF_URLBAR_BRANCH, "");
if (!PREF_URLBAR_DEFAULTS.has(pref) && !PREF_OTHER_DEFAULTS.has(pref)) {
return;
}
this._callback(pref);
}
}
var UrlbarPrefs = new Preferences();

Просмотреть файл

@ -12,7 +12,6 @@ const { XPCOMUtils } = ChromeUtils.import(
XPCOMUtils.defineLazyModuleGetters(this, {
SearchOneOffs: "resource:///modules/SearchOneOffs.jsm",
UrlbarPrefs: "resource:///modules/UrlbarPrefs.jsm",
UrlbarPrefsObserver: "resource:///modules/UrlbarPrefs.jsm",
UrlbarSearchUtils: "resource:///modules/UrlbarSearchUtils.jsm",
UrlbarTokenizer: "resource:///modules/UrlbarTokenizer.jsm",
UrlbarUtils: "resource:///modules/UrlbarUtils.jsm",
@ -57,9 +56,7 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
super(view.panel.querySelector(".search-one-offs"));
this.view = view;
this.input = view.input;
this._prefObserver = new UrlbarPrefsObserver(pref =>
this._onPrefChanged(pref)
);
UrlbarPrefs.addObserver(this);
}
/**
@ -194,6 +191,23 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
);
}
/**
* Called when a pref tracked by UrlbarPrefs changes.
*
* @param {string} changedPref
* The name of the pref, relative to `browser.urlbar.` if the pref is in
* that branch.
*/
onPrefChanged(changedPref) {
// Null out this._engines when the local-one-offs-related prefs change so
// that they rebuild themselves the next time the view opens.
let prefs = [...LOCAL_MODES.values()].map(({ pref }) => pref);
prefs.push("update2", "update2.localOneOffs", "update2.oneOffsRefresh");
if (prefs.includes(changedPref)) {
this._engines = null;
}
}
/**
* Overrides _rebuildEngineList to add the local one-offs.
*
@ -251,21 +265,4 @@ class UrlbarSearchOneOffs extends SearchOneOffs {
this.handleSearchCommand(event, engineOrSource);
}
/**
* Called when a pref tracked by UrlbarPrefs changes.
*
* @param {string} changedPref
* The name of the pref, relative to `browser.urlbar.` if the pref is in
* that branch.
*/
_onPrefChanged(changedPref) {
// Null out this._engines when the local-one-offs-related prefs change so
// that they rebuild themselves the next time the view opens.
let prefs = [...LOCAL_MODES.values()].map(({ pref }) => pref);
prefs.push("update2", "update2.localOneOffs", "update2.oneOffsRefresh");
if (prefs.includes(changedPref)) {
this._engines = null;
}
}
}

Просмотреть файл

@ -261,3 +261,27 @@ add_task(async function click_close() {
gURLBar.setSearchMode(null);
}
});
// Tests that entering search mode invalidates pageproxystate and exits search
// mode.
add_task(async function invalidate_pageproxystate() {
await BrowserTestUtils.withNewTab("about:robots", async function(browser) {
await UrlbarTestUtils.promisePopupOpen(window, () => {
EventUtils.synthesizeMouseAtCenter(gURLBar.inputField, {});
});
Assert.equal(gURLBar.getAttribute("pageproxystate"), "valid");
await enterSearchMode(window);
Assert.equal(
gURLBar.getAttribute("pageproxystate"),
"invalid",
"Entering search mode should clear pageproxystate."
);
Assert.equal(gURLBar.value, "", "Urlbar value should be cleared.");
await exitSearchMode(window, { clickClose: true });
Assert.equal(
gURLBar.getAttribute("pageproxystate"),
"invalid",
"Pageproxystate should still be invalid after exiting search mode."
);
});
});

Просмотреть файл

@ -15,6 +15,7 @@ support-files =
!/browser/components/search/test/browser/testEngine.xml
!/browser/components/search/test/browser/testEngine_diacritics.xml
testEngine_chromeicon.xml
skip-if = (debug && os == "linux" && bits == 64 && os_version == "18.04") # Bug 1649755
[browser_EveryWindow.js]
[browser_LiveBookmarkMigrator.js]
[browser_PageActions.js]

Просмотреть файл

@ -217,14 +217,11 @@ def old_configure_options(*options):
'--enable-extensions',
'--enable-libproxy',
'--enable-logrefcnt',
'--enable-mobile-optimize',
'--enable-necko-wifi',
'--enable-negotiateauth',
'--enable-official-branding',
'--enable-parental-controls',
'--enable-pref-extensions',
'--enable-sandbox',
'--enable-startupcache',
'--enable-system-cairo',
'--enable-system-extension-dirs',
'--enable-system-pixman',

Просмотреть файл

@ -9,13 +9,15 @@ import { setupEvents, clientEvents } from "./firefox/events";
import { features, prefs } from "../utils/prefs";
let actions;
let targetList;
export async function onConnect(
connection: any,
_actions: Object
): Promise<void> {
const { devToolsClient, targetList } = connection;
const { devToolsClient, targetList: _targetList } = connection;
actions = _actions;
targetList = _targetList;
setupCommands({ devToolsClient, targetList });
setupEvents({ actions, devToolsClient });
@ -40,6 +42,19 @@ async function onTargetAvailable({
targetFront,
isTargetSwitching,
}): Promise<void> {
const isBrowserToolbox = targetList.targetFront.isParentProcess;
const isNonTopLevelFrameTarget =
!targetFront.isTopLevel &&
targetFront.targetType === targetList.TYPES.FRAME;
if (isBrowserToolbox && isNonTopLevelFrameTarget) {
// In the BrowserToolbox, non-top-level frame targets are already
// debugged via content-process targets.
// Do not attach the thread here, as it was already done by the
// corresponding content-process target.
return;
}
if (!targetFront.isTopLevel) {
await actions.addTarget(targetFront);
return;

Просмотреть файл

@ -738,7 +738,8 @@ Toolbox.prototype = {
const isBrowserToolbox = this.targetList.targetFront.isParentProcess;
const isNonTopLevelFrameTarget =
!targetFront.isTopLevel && targetFront.type === TargetList.TYPES.FRAME;
!targetFront.isTopLevel &&
targetFront.targetType === TargetList.TYPES.FRAME;
if (isBrowserToolbox && isNonTopLevelFrameTarget) {
// In the BrowserToolbox, non-top-level frame targets are already
@ -766,7 +767,7 @@ Toolbox.prototype = {
_attachAndResumeThread: async function(target) {
if (target.threadFront) {
// if threadFront already exists, the thread is already attached.
if (target.type !== TargetList.TYPES.SERVICE_WORKER) {
if (target.targetType === TargetList.TYPES.SERVICE_WORKER) {
// This can legitimately happen for service workers. See Bug 1655439.
console.warn(
"Attaching to an already attached thread for a service worker target"
@ -778,7 +779,7 @@ Toolbox.prototype = {
// This should not happen for non-server-worker targets, throw otherwise.
throw new Error(
`Attaching to an already attached thread for a target of type "${target.type}"`
`Attaching to an already attached thread for a target of type "${target.targetType}"`
);
}

Просмотреть файл

@ -476,9 +476,9 @@ NetworkObserver.prototype = {
const fromServiceWorker = this.interceptedChannels.has(channel);
this.interceptedChannels.delete(channel);
// If this is a cached response, there never was a request event
// so we need to construct one here so the frontend gets all the
// expected events.
// If this is a cached response (which are also emitted by service worker requests),
// there never was a request event so we need to construct one here
// so the frontend gets all the expected events.
let httpActivity = this.createOrGetActivityObject(channel);
if (!httpActivity.owner) {
httpActivity = this._createNetworkEvent(channel, {
@ -486,6 +486,12 @@ NetworkObserver.prototype = {
fromServiceWorker: fromServiceWorker,
});
}
// We need to send the request body to the frontend for
// the faked (cached/service worker request) event.
this._onRequestBodySent(httpActivity);
this._sendRequestBody(httpActivity);
httpActivity.owner.addResponseStart(
{
httpVersion: response.httpVersion,
@ -569,20 +575,7 @@ NetworkObserver.prototype = {
switch (activitySubtype) {
case gActivityDistributor.ACTIVITY_SUBTYPE_REQUEST_BODY_SENT:
this._onRequestBodySent(httpActivity);
if (httpActivity.sentBody !== null) {
const limit = Services.prefs.getIntPref(
"devtools.netmonitor.requestBodyLimit"
);
const size = httpActivity.sentBody.length;
if (size > limit && limit > 0) {
httpActivity.sentBody = httpActivity.sentBody.substr(0, limit);
}
httpActivity.owner.addRequestPostData({
text: httpActivity.sentBody,
size: size,
});
httpActivity.sentBody = null;
}
this._sendRequestBody(httpActivity);
break;
case gActivityDistributor.ACTIVITY_SUBTYPE_RESPONSE_HEADER:
this._onResponseHeader(httpActivity, extraStringData);
@ -1517,6 +1510,23 @@ NetworkObserver.prototype = {
};
},
_sendRequestBody: function(httpActivity) {
if (httpActivity.sentBody !== null) {
const limit = Services.prefs.getIntPref(
"devtools.netmonitor.requestBodyLimit"
);
const size = httpActivity.sentBody.length;
if (size > limit && limit > 0) {
httpActivity.sentBody = httpActivity.sentBody.substr(0, limit);
}
httpActivity.owner.addRequestPostData({
text: httpActivity.sentBody,
size: size,
});
httpActivity.sentBody = null;
}
},
/**
* Suspend observer activity. This is called when the Network monitor actor stops
* listening.

Просмотреть файл

@ -3581,14 +3581,8 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
// If the HTTPS-Only Mode upgraded this request and the upgrade might have
// caused this error, we replace the error-page with about:httpsonlyerror
if (aFailedChannel && nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aError)) {
nsCOMPtr<nsILoadInfo> loadInfo = aFailedChannel->LoadInfo();
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
if ((httpsOnlyStatus &
nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED) &&
!(httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT)) {
errorPage.AssignLiteral("httpsonlyerror");
}
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aFailedChannel, aError)) {
errorPage.AssignLiteral("httpsonlyerror");
}
if (nsCOMPtr<nsILoadURIDelegate> loadURIDelegate = GetLoadURIDelegate()) {

Просмотреть файл

@ -10246,6 +10246,37 @@ void Document::RetrieveRelevantHeaders(nsIChannel* aChannel) {
}
}
void Document::ProcessMETATag(HTMLMetaElement* aMetaElement) {
// set any HTTP-EQUIV data into document's header data as well as url
nsAutoString header;
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (!header.IsEmpty()) {
// Ignore META REFRESH when document is sandboxed from automatic features.
nsContentUtils::ASCIIToLower(header);
if (nsGkAtoms::refresh->Equals(header) &&
(GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES)) {
return;
}
nsAutoString result;
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
if (!result.IsEmpty()) {
RefPtr<nsAtom> fieldAtom(NS_Atomize(header));
SetHeaderData(fieldAtom, result);
}
}
if (aMetaElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::handheldFriendly, eIgnoreCase)) {
nsAutoString result;
aMetaElement->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
if (!result.IsEmpty()) {
nsContentUtils::ASCIIToLower(result);
SetHeaderData(nsGkAtoms::handheldFriendly, result);
}
}
}
already_AddRefed<Element> Document::CreateElem(const nsAString& aName,
nsAtom* aPrefix,
int32_t aNamespaceID,

Просмотреть файл

@ -2161,6 +2161,7 @@ class Document : public nsINode,
mIsContentDocument = aIsContentDocument;
}
void ProcessMETATag(HTMLMetaElement* aMetaElement);
/**
* Create an element with the specified name, prefix and namespace ID.
* Returns null if element name parsing failed.

Просмотреть файл

@ -249,17 +249,6 @@ nsresult nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) {
return NS_OK;
}
nsresult nsContentSink::ProcessHeaderData(nsAtom* aHeader,
const nsAString& aValue,
nsIContent* aContent) {
nsresult rv = NS_OK;
// necko doesn't process headers coming in from the parser
mDocument->SetHeaderData(aHeader, aValue);
return rv;
}
void nsContentSink::DoProcessLinkHeader() {
nsAutoString value;
mDocument->GetHeaderData(nsGkAtoms::link, value);
@ -733,47 +722,6 @@ nsresult nsContentSink::ProcessStyleLinkFromHeader(
return NS_OK;
}
nsresult nsContentSink::ProcessMETATag(nsIContent* aContent) {
NS_ASSERTION(aContent, "missing meta-element");
MOZ_ASSERT(aContent->IsElement());
Element* element = aContent->AsElement();
nsresult rv = NS_OK;
// set any HTTP-EQUIV data into document's header data as well as url
nsAutoString header;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::httpEquiv, header);
if (!header.IsEmpty()) {
// Ignore META REFRESH when document is sandboxed from automatic features.
nsContentUtils::ASCIIToLower(header);
if (nsGkAtoms::refresh->Equals(header) &&
(mDocument->GetSandboxFlags() & SANDBOXED_AUTOMATIC_FEATURES)) {
return NS_OK;
}
nsAutoString result;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
if (!result.IsEmpty()) {
RefPtr<nsAtom> fieldAtom(NS_Atomize(header));
rv = ProcessHeaderData(fieldAtom, result, element);
}
}
NS_ENSURE_SUCCESS(rv, rv);
if (element->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name,
nsGkAtoms::handheldFriendly, eIgnoreCase)) {
nsAutoString result;
element->GetAttr(kNameSpaceID_None, nsGkAtoms::content, result);
if (!result.IsEmpty()) {
nsContentUtils::ASCIIToLower(result);
mDocument->SetHeaderData(nsGkAtoms::handheldFriendly, result);
}
}
return rv;
}
void nsContentSink::PrefetchHref(const nsAString& aHref, const nsAString& aAs,
const nsAString& aType,
const nsAString& aMedia) {

Просмотреть файл

@ -93,8 +93,6 @@ class nsContentSink : public nsICSSLoaderObserver,
NS_IMETHOD StyleSheetLoaded(mozilla::StyleSheet* aSheet, bool aWasDeferred,
nsresult aStatus) override;
virtual nsresult ProcessMETATag(nsIContent* aContent);
// nsIContentSink implementation helpers
nsresult WillParseImpl(void);
nsresult WillInterruptImpl(void);
@ -147,8 +145,6 @@ class nsContentSink : public nsICSSLoaderObserver,
nsIChannel* aChannel);
nsresult ProcessHTTPHeaders(nsIChannel* aChannel);
nsresult ProcessHeaderData(nsAtom* aHeader, const nsAString& aValue,
nsIContent* aContent = nullptr);
nsresult ProcessLinkHeader(const nsAString& aLinkData);
nsresult ProcessLinkFromHeader(
const nsAString& aAnchor, const nsAString& aHref, const nsAString& aRel,

Просмотреть файл

@ -760,7 +760,7 @@ ClientWebGLContext::SetContextOptions(JSContext* cx,
newOpts.xrCompatible = attributes.mXrCompatible;
newOpts.powerPreference = attributes.mPowerPreference;
newOpts.enableDebugRendererInfo =
Preferences::GetBool("webgl.enable-debug-renderer-info", false);
StaticPrefs::webgl_enable_debug_renderer_info();
MOZ_ASSERT(mCanvasElement || mOffscreenCanvas);
newOpts.shouldResistFingerprinting =
mCanvasElement ?
@ -5099,7 +5099,7 @@ static bool IsExtensionForbiddenForCaller(const WebGLExtensionID ext,
case WebGLExtensionID::WEBGL_debug_renderer_info:
return resistFingerprinting ||
!Preferences::GetBool("webgl.enable-debug-renderer-info", false);
!StaticPrefs::webgl_enable_debug_renderer_info();
case WebGLExtensionID::WEBGL_debug_shaders:
return resistFingerprinting;

Просмотреть файл

@ -6,11 +6,14 @@
#include "BlobURLChannel.h"
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/dom/BlobURL.h"
#include "mozilla/dom/BlobURLInputStream.h"
#include "mozilla/ScopeExit.h"
using namespace mozilla::dom;
BlobURLChannel::BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo)
: mInitialized(false) {
: mContentStreamOpened(false) {
SetURI(aURI);
SetOriginalURI(aURI);
SetLoadInfo(aLoadInfo);
@ -24,59 +27,49 @@ BlobURLChannel::BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo)
BlobURLChannel::~BlobURLChannel() = default;
void BlobURLChannel::InitFailed() {
MOZ_ASSERT(!mInitialized);
MOZ_ASSERT(!mInputStream);
mInitialized = true;
}
void BlobURLChannel::Initialize(BlobImpl* aBlobImpl) {
MOZ_ASSERT(!mInitialized);
nsAutoString contentType;
aBlobImpl->GetType(contentType);
SetContentType(NS_ConvertUTF16toUTF8(contentType));
if (aBlobImpl->IsFile()) {
nsString filename;
aBlobImpl->GetName(filename);
SetContentDispositionFilename(filename);
}
ErrorResult rv;
uint64_t size = aBlobImpl->GetSize(rv);
if (NS_WARN_IF(rv.Failed())) {
InitFailed();
return;
}
SetContentLength(size);
aBlobImpl->CreateInputStream(getter_AddRefs(mInputStream), rv);
if (NS_WARN_IF(rv.Failed())) {
InitFailed();
return;
}
MOZ_ASSERT(mInputStream);
mInitialized = true;
}
nsresult BlobURLChannel::OpenContentStream(bool aAsync,
nsIInputStream** aResult,
nsIChannel** aChannel) {
MOZ_ASSERT(mInitialized);
if (mContentStreamOpened) {
return NS_ERROR_ALREADY_OPENED;
}
if (!mInputStream) {
mContentStreamOpened = true;
nsCOMPtr<nsIURI> uri;
nsresult rv = GetURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, NS_ERROR_MALFORMED_URI);
RefPtr<BlobURL> blobURL;
rv = uri->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(blobURL));
if (NS_WARN_IF(NS_FAILED(rv)) || NS_WARN_IF(!blobURL)) {
return NS_ERROR_MALFORMED_URI;
}
if (blobURL->Revoked()) {
#ifdef MOZ_WIDGET_ANDROID
nsCOMPtr<nsILoadInfo> loadInfo;
GetLoadInfo(getter_AddRefs(loadInfo));
// if the channel was not triggered by the system principal,
// then we return here because the URL had been revoked
if (loadInfo && !loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
return NS_ERROR_MALFORMED_URI;
}
#else
return NS_ERROR_MALFORMED_URI;
#endif
}
nsCOMPtr<nsIInputStream> inputStream =
BlobURLInputStream::Create(this, blobURL);
if (NS_WARN_IF(!inputStream)) {
return NS_ERROR_MALFORMED_URI;
}
EnableSynthesizedProgressEvents(true);
nsCOMPtr<nsIInputStream> stream = mInputStream;
stream.forget(aResult);
inputStream.forget(aResult);
return NS_OK;
}
void BlobURLChannel::OnChannelDone() { mInputStream = nullptr; }
}

Просмотреть файл

@ -22,28 +22,13 @@ class BlobURLChannel final : public nsBaseChannel {
public:
BlobURLChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo);
// This method is called when there is not a valid BlobImpl for this channel.
// This method will make ::OpenContentStream to return NS_ERROR_MALFORMED_URI.
void InitFailed();
// There is a valid BlobImpl for the channel. The blob's inputStream will be
// used when ::OpenContentStream is called.
void Initialize(BlobImpl* aBlobImpl);
private:
~BlobURLChannel();
nsresult OpenContentStream(bool aAsync, nsIInputStream** aResult,
nsIChannel** aChannel) override;
void OnChannelDone() override;
// If Initialize() is called, this will contain the blob's inputStream.
nsCOMPtr<nsIInputStream> mInputStream;
// This boolean is used to check that InitFailed() or Initialize() are called
// just once.
bool mInitialized;
bool mContentStreamOpened;
};
} // namespace dom

Просмотреть файл

@ -0,0 +1,573 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BlobURLInputStream.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/IPCBlobUtils.h"
#include "nsStreamUtils.h"
namespace mozilla {
namespace dom {
NS_IMPL_ADDREF(BlobURLInputStream);
NS_IMPL_RELEASE(BlobURLInputStream);
NS_INTERFACE_MAP_BEGIN(BlobURLInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStream)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength)
NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStreamLength)
NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIAsyncInputStream)
NS_INTERFACE_MAP_END
/* static */
already_AddRefed<nsIInputStream> BlobURLInputStream::Create(
BlobURLChannel* const aChannel, BlobURL* const aBlobURL) {
MOZ_ASSERT(NS_IsMainThread());
if (NS_WARN_IF(!aChannel) || NS_WARN_IF(!aBlobURL)) {
return nullptr;
}
nsAutoCString spec;
nsresult rv = aBlobURL->GetSpec(spec);
if (NS_WARN_IF(NS_FAILED(rv))) {
return nullptr;
}
return MakeAndAddRef<BlobURLInputStream>(aChannel, spec);
}
// from nsIInputStream interface
NS_IMETHODIMP BlobURLInputStream::Close() {
return CloseWithStatus(NS_BASE_STREAM_CLOSED);
}
NS_IMETHODIMP BlobURLInputStream::Available(uint64_t* aLength) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::ERROR) {
MOZ_ASSERT(NS_FAILED(mError));
return mError;
}
if (mState == State::CLOSED) {
return NS_BASE_STREAM_CLOSED;
}
if (mState == State::READY) {
MOZ_ASSERT(mAsyncInputStream);
return mAsyncInputStream->Available(aLength);
}
return NS_BASE_STREAM_WOULD_BLOCK;
}
NS_IMETHODIMP BlobURLInputStream::Read(char* aBuffer, uint32_t aCount,
uint32_t* aReadCount) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::ERROR) {
MOZ_ASSERT(NS_FAILED(mError));
return mError;
}
// Read() should not return NS_BASE_STREAM_CLOSED if stream is closed.
// A read count of 0 should indicate closed or consumed stream.
// See:
// https://searchfox.org/mozilla-central/rev/559b25eb41c1cbffcb90a34e008b8288312fcd25/xpcom/io/nsIInputStream.idl#104
if (mState == State::CLOSED) {
*aReadCount = 0;
return NS_OK;
}
if (mState == State::READY) {
MOZ_ASSERT(mAsyncInputStream);
nsresult rv = mAsyncInputStream->Read(aBuffer, aCount, aReadCount);
if (NS_SUCCEEDED(rv) && aReadCount && !*aReadCount) {
mState = State::CLOSED;
ReleaseUnderlyingStream(lock);
}
return rv;
}
return NS_BASE_STREAM_WOULD_BLOCK;
}
NS_IMETHODIMP BlobURLInputStream::ReadSegments(nsWriteSegmentFun aWriter,
void* aClosure, uint32_t aCount,
uint32_t* aResult) {
// This means the caller will have to wrap the stream in an
// nsBufferedInputStream in order to use ReadSegments
return NS_ERROR_NOT_IMPLEMENTED;
}
NS_IMETHODIMP BlobURLInputStream::IsNonBlocking(bool* aNonBlocking) {
*aNonBlocking = true;
return NS_OK;
}
// from nsIAsyncInputStream interface
NS_IMETHODIMP BlobURLInputStream::CloseWithStatus(nsresult aStatus) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::READY) {
MOZ_ASSERT(mAsyncInputStream);
mAsyncInputStream->CloseWithStatus(aStatus);
}
mState = State::CLOSED;
ReleaseUnderlyingStream(lock);
return NS_OK;
}
NS_IMETHODIMP BlobURLInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
uint32_t aFlags,
uint32_t aRequestedCount,
nsIEventTarget* aEventTarget) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::ERROR) {
MOZ_ASSERT(NS_FAILED(mError));
return NS_ERROR_FAILURE;
}
// Pre-empting a valid callback with another is not allowed.
if (NS_WARN_IF(mAsyncWaitCallback && aCallback)) {
return NS_ERROR_FAILURE;
}
mAsyncWaitTarget = aEventTarget;
mAsyncWaitRequestedCount = aRequestedCount;
mAsyncWaitFlags = aFlags;
mAsyncWaitCallback = aCallback;
if (mState == State::INITIAL) {
mState = State::WAITING;
// RetrieveBlobData will execute NotifyWWaitTarget() when retrieve succeeds
// or fails
if (NS_IsMainThread()) {
RetrieveBlobData(lock);
return NS_OK;
}
nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
"BlobURLInputStream::CallRetrieveBlobData", this,
&BlobURLInputStream::CallRetrieveBlobData);
NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
return NS_OK;
}
if (mState == State::WAITING) {
// RetrieveBlobData is already in progress and will execute
// NotifyWaitTargets when retrieve succeeds or fails
return NS_OK;
}
if (mState == State::READY) {
// Ask the blob's input stream if reading is possible or not
return mAsyncInputStream->AsyncWait(
mAsyncWaitCallback ? this : nullptr, mAsyncWaitFlags,
mAsyncWaitRequestedCount, mAsyncWaitTarget);
}
MOZ_ASSERT(mState == State::CLOSED);
NotifyWaitTargets(lock);
return NS_OK;
}
// from nsIInputStreamLength interface
NS_IMETHODIMP BlobURLInputStream::Length(int64_t* aLength) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::CLOSED) {
return NS_BASE_STREAM_CLOSED;
}
if (mState == State::ERROR) {
MOZ_ASSERT(NS_FAILED(mError));
return NS_ERROR_FAILURE;
}
if (mState == State::READY) {
*aLength = mBlobSize;
return NS_OK;
}
return NS_BASE_STREAM_WOULD_BLOCK;
}
// from nsIAsyncInputStreamLength interface
NS_IMETHODIMP BlobURLInputStream::AsyncLengthWait(
nsIInputStreamLengthCallback* aCallback, nsIEventTarget* aEventTarget) {
MutexAutoLock lock(mStateMachineMutex);
if (mState == State::ERROR) {
MOZ_ASSERT(NS_FAILED(mError));
return mError;
}
// Pre-empting a valid callback with another is not allowed.
if (mAsyncLengthWaitCallback && aCallback) {
return NS_ERROR_FAILURE;
}
mAsyncLengthWaitTarget = aEventTarget;
mAsyncLengthWaitCallback = aCallback;
if (mState == State::INITIAL) {
mState = State::WAITING;
// RetrieveBlobData will execute NotifyWWaitTarget() when retrieve succeeds
// or fails
if (NS_IsMainThread()) {
RetrieveBlobData(lock);
return NS_OK;
}
nsCOMPtr<nsIRunnable> runnable = mozilla::NewRunnableMethod(
"BlobURLInputStream::CallRetrieveBlobData", this,
&BlobURLInputStream::CallRetrieveBlobData);
NS_DispatchToMainThread(runnable.forget(), NS_DISPATCH_NORMAL);
return NS_OK;
}
if (mState == State::WAITING) {
// RetrieveBlobData is already in progress and will execute
// NotifyWaitTargets when retrieve succeeds or fails
return NS_OK;
}
// Since here the state must be READY (in which case the size of the blob is
// already known) or CLOSED, callback can be called immediately
NotifyWaitTargets(lock);
return NS_OK;
}
// from nsIInputStreamCallback interface
NS_IMETHODIMP BlobURLInputStream::OnInputStreamReady(
nsIAsyncInputStream* aStream) {
nsCOMPtr<nsIInputStreamCallback> callback;
{
MutexAutoLock lock(mStateMachineMutex);
MOZ_ASSERT_IF(mAsyncInputStream, aStream == mAsyncInputStream);
// aborted in the meantime
if (!mAsyncWaitCallback) {
return NS_OK;
}
mAsyncWaitCallback.swap(callback);
mAsyncWaitTarget = nullptr;
}
MOZ_ASSERT(callback);
return callback->OnInputStreamReady(this);
}
// from nsIInputStreamLengthCallback interface
NS_IMETHODIMP BlobURLInputStream::OnInputStreamLengthReady(
nsIAsyncInputStreamLength* aStream, int64_t aLength) {
nsCOMPtr<nsIInputStreamLengthCallback> callback;
{
MutexAutoLock lock(mStateMachineMutex);
// aborted in the meantime
if (!mAsyncLengthWaitCallback) {
return NS_OK;
}
mAsyncLengthWaitCallback.swap(callback);
mAsyncLengthWaitCallback = nullptr;
}
return callback->OnInputStreamLengthReady(this, aLength);
}
// private:
BlobURLInputStream::~BlobURLInputStream() {
if (mChannel) {
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel", mChannel.forget());
}
}
BlobURLInputStream::BlobURLInputStream(BlobURLChannel* const aChannel,
nsACString& aBlobURLSpec)
: mChannel(aChannel),
mBlobURLSpec(std::move(aBlobURLSpec)),
mStateMachineMutex("BlobURLInputStream::mStateMachineMutex"),
mState(State::INITIAL),
mError(NS_OK),
mBlobSize(-1),
mAsyncWaitFlags(),
mAsyncWaitRequestedCount() {}
void BlobURLInputStream::WaitOnUnderlyingStream(
const MutexAutoLock& aProofOfLock) {
if (mAsyncWaitCallback || mAsyncWaitTarget) {
// AsyncWait should be called on the underlying stream
mAsyncInputStream->AsyncWait(mAsyncWaitCallback ? this : nullptr,
mAsyncWaitFlags, mAsyncWaitRequestedCount,
mAsyncWaitTarget);
}
if (mAsyncLengthWaitCallback || mAsyncLengthWaitTarget) {
// AsyncLengthWait should be called on the underlying stream
nsCOMPtr<nsIAsyncInputStreamLength> asyncStreamLength =
do_QueryInterface(mAsyncInputStream);
if (asyncStreamLength) {
asyncStreamLength->AsyncLengthWait(
mAsyncLengthWaitCallback ? this : nullptr, mAsyncLengthWaitTarget);
}
}
}
void BlobURLInputStream::CallRetrieveBlobData() {
MutexAutoLock lock(mStateMachineMutex);
RetrieveBlobData(lock);
}
void BlobURLInputStream::RetrieveBlobData(const MutexAutoLock& aProofOfLock) {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
MOZ_ASSERT(mState == State::WAITING);
auto cleanupOnEarlyExit = MakeScopeExit([&] {
mState = State::ERROR;
mError = NS_ERROR_FAILURE;
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel", mChannel.forget());
NotifyWaitTargets(aProofOfLock);
});
nsCOMPtr<nsILoadInfo> loadInfo;
if (NS_WARN_IF(NS_FAILED(mChannel->GetLoadInfo(getter_AddRefs(loadInfo))))) {
NS_WARNING("Failed to get owning channel's loadinfo");
return;
}
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
nsCOMPtr<nsIPrincipal> loadingPrincipal;
if (NS_WARN_IF(NS_FAILED(loadInfo->GetTriggeringPrincipal(
getter_AddRefs(triggeringPrincipal)))) ||
NS_WARN_IF(!triggeringPrincipal)) {
NS_WARNING("Failed to get owning channel's triggering principal");
return;
}
if (NS_WARN_IF(NS_FAILED(
loadInfo->GetLoadingPrincipal(getter_AddRefs(loadingPrincipal))))) {
NS_WARNING("Failed to get owning channel's loading principal");
return;
}
if (XRE_IsParentProcess() || !BlobURLSchemeIsHTTPOrHTTPS(mBlobURLSpec)) {
nsIPrincipal* const dataEntryPrincipal =
BlobURLProtocolHandler::GetDataEntryPrincipal(mBlobURLSpec,
true /* AlsoIfRevoked */);
// Since revoked blobs are also retrieved, it is possible that the blob no
// longer exists (due to the 5 second timeout) when execution reaches here
if (!dataEntryPrincipal) {
NS_WARNING("Failed to get data entry principal. URL revoked?");
return;
}
// We want to be sure that we stop the creation of the channel if the blob
// URL is copy-and-pasted on a different context (ex. private browsing or
// containers).
//
// We also allow the system principal to create the channel regardless of
// the OriginAttributes. This is primarily for the benefit of mechanisms
// like the Download API that explicitly create a channel with the system
// principal and which is never mutated to have a non-zero
// mPrivateBrowsingId or container.
if (NS_WARN_IF(!loadingPrincipal ||
!loadingPrincipal->IsSystemPrincipal()) &&
NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
loadInfo->GetOriginAttributes(),
BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) {
return;
}
if (NS_WARN_IF(!triggeringPrincipal->Subsumes(dataEntryPrincipal))) {
return;
}
RefPtr<BlobImpl> blobImpl;
nsresult rv = NS_GetBlobForBlobURISpec(
mBlobURLSpec, getter_AddRefs(blobImpl), true /* AlsoIfRevoked */);
if (NS_WARN_IF(NS_FAILED(rv)) || (NS_WARN_IF(!blobImpl))) {
return;
}
if (NS_WARN_IF(
NS_FAILED(StoreBlobImplStream(blobImpl.forget(), aProofOfLock)))) {
return;
}
mState = State::READY;
// By design, execution can only reach here when a caller has called
// AsyncWait or AsyncLengthWait on this stream. The underlying stream is
// valid, but the caller should not be informed until that stream has data
// to read or it is closed.
WaitOnUnderlyingStream(aProofOfLock);
cleanupOnEarlyExit.release();
return;
}
ContentChild* contentChild{ContentChild::GetSingleton()};
MOZ_ASSERT(contentChild);
const RefPtr<BlobURLInputStream> self = this;
cleanupOnEarlyExit.release();
contentChild
->SendBlobURLDataRequest(mBlobURLSpec, triggeringPrincipal,
loadingPrincipal,
loadInfo->GetOriginAttributes())
->Then(
GetCurrentSerialEventTarget(), __func__,
[self](const BlobURLDataRequestResult& aResult) {
MutexAutoLock lock(self->mStateMachineMutex);
if (aResult.type() == BlobURLDataRequestResult::TIPCBlob) {
if (self->mState == State::WAITING) {
RefPtr<BlobImpl> blobImpl =
IPCBlobUtils::Deserialize(aResult.get_IPCBlob());
if (blobImpl && self->StoreBlobImplStream(blobImpl.forget(),
lock) == NS_OK) {
self->mState = State::READY;
// By design, execution can only reach here when a caller has
// called AsyncWait or AsyncLengthWait on this stream. The
// underlying stream is valid, but the caller should not be
// informed until that stream has data to read or it is
// closed.
self->WaitOnUnderlyingStream(lock);
return;
}
} else {
MOZ_ASSERT(self->mState == State::CLOSED);
// Callback can be called immediately
self->NotifyWaitTargets(lock);
return;
}
}
NS_WARNING("Blob data was not retrieved!");
self->mState = State::ERROR;
self->mError = aResult.type() == BlobURLDataRequestResult::Tnsresult
? aResult.get_nsresult()
: NS_ERROR_FAILURE;
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel",
self->mChannel.forget());
self->NotifyWaitTargets(lock);
},
[self](mozilla::ipc::ResponseRejectReason aReason) {
MutexAutoLock lock(self->mStateMachineMutex);
NS_WARNING("IPC call to SendBlobURLDataRequest failed!");
self->mState = State::ERROR;
self->mError = NS_ERROR_FAILURE;
NS_ReleaseOnMainThread("BlobURLInputStream::mChannel",
self->mChannel.forget());
self->NotifyWaitTargets(lock);
});
}
nsresult BlobURLInputStream::StoreBlobImplStream(
already_AddRefed<BlobImpl> aBlobImpl, const MutexAutoLock& aProofOfLock) {
MOZ_ASSERT(NS_IsMainThread(), "Only call on main thread");
const RefPtr<BlobImpl> blobImpl = aBlobImpl;
nsAutoString contentType;
blobImpl->GetType(contentType);
mChannel->SetContentType(NS_ConvertUTF16toUTF8(contentType));
auto cleanupOnExit = MakeScopeExit([&] { mChannel = nullptr; });
if (blobImpl->IsFile()) {
nsAutoString filename;
blobImpl->GetName(filename);
if (!filename.IsEmpty()) {
mChannel->SetContentDispositionFilename(filename);
}
}
mozilla::ErrorResult errorResult;
mBlobSize = blobImpl->GetSize(errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
mChannel->SetContentLength(mBlobSize);
nsCOMPtr<nsIInputStream> inputStream;
blobImpl->CreateInputStream(getter_AddRefs(inputStream), errorResult);
if (NS_WARN_IF(errorResult.Failed())) {
return errorResult.StealNSResult();
}
if (NS_WARN_IF(!inputStream)) {
return NS_ERROR_NOT_AVAILABLE;
}
nsresult rv = NS_MakeAsyncNonBlockingInputStream(
inputStream.forget(), getter_AddRefs(mAsyncInputStream));
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
if (NS_WARN_IF(!mAsyncInputStream)) {
return NS_ERROR_NOT_AVAILABLE;
}
return NS_OK;
}
void BlobURLInputStream::NotifyWaitTargets(const MutexAutoLock& aProofOfLock) {
if (mAsyncWaitCallback) {
auto callback = mAsyncWaitTarget
? NS_NewInputStreamReadyEvent(
"BlobURLInputStream::OnInputStreamReady",
mAsyncWaitCallback, mAsyncWaitTarget)
: mAsyncWaitCallback;
mAsyncWaitCallback = nullptr;
mAsyncWaitTarget = nullptr;
callback->OnInputStreamReady(this);
}
if (mAsyncLengthWaitCallback) {
const RefPtr<BlobURLInputStream> self = this;
nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
"BlobURLInputStream::OnInputStreamLengthReady", [self] {
self->mAsyncLengthWaitCallback->OnInputStreamLengthReady(
self, self->mBlobSize);
});
mAsyncLengthWaitCallback = nullptr;
if (mAsyncLengthWaitTarget) {
mAsyncLengthWaitTarget->Dispatch(runnable, NS_DISPATCH_NORMAL);
mAsyncLengthWaitTarget = nullptr;
} else {
runnable->Run();
}
}
}
void BlobURLInputStream::ReleaseUnderlyingStream(
const MutexAutoLock& aProofOfLock) {
mAsyncInputStream = nullptr;
mBlobSize = -1;
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -0,0 +1,83 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_BlobURLInputStream_h
#define mozilla_dom_BlobURLInputStream_h
#include "mozilla/dom/BlobImpl.h"
#include "mozilla/Mutex.h"
#include "nsIAsyncInputStream.h"
#include "nsIInputStreamLength.h"
namespace mozilla {
namespace dom {
class BlobURL;
class BlobURLChannel;
class BlobURLInputStream final : public nsIAsyncInputStream,
public nsIInputStreamLength,
public nsIAsyncInputStreamLength,
public nsIInputStreamCallback,
public nsIInputStreamLengthCallback {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSIINPUTSTREAMLENGTH
NS_DECL_NSIASYNCINPUTSTREAMLENGTH
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSIINPUTSTREAMLENGTHCALLBACK
static already_AddRefed<nsIInputStream> Create(BlobURLChannel* const aChannel,
BlobURL* const aBlobURL);
BlobURLInputStream(BlobURLChannel* const aChannel, nsACString& aBlobURLSpec);
private:
enum class State { INITIAL, READY, WAITING, CLOSED, ERROR };
~BlobURLInputStream();
void WaitOnUnderlyingStream(const MutexAutoLock& aProofOfLock);
// This method should only be used to call RetrieveBlobData in a different
// thread
void CallRetrieveBlobData();
void RetrieveBlobData(const MutexAutoLock& aProofOfLock);
nsresult StoreBlobImplStream(already_AddRefed<BlobImpl> aBlobImpl,
const MutexAutoLock& aProofOfLock);
void NotifyWaitTargets(const MutexAutoLock& aProofOfLock);
void ReleaseUnderlyingStream(const MutexAutoLock& aProofOfLock);
RefPtr<BlobURLChannel> mChannel;
const nsCString mBlobURLSpec;
// Non-recursive mutex introduced in order to guard access to mState, mError
// and mAsyncInputStream
Mutex mStateMachineMutex;
State mState;
// Stores the error code if stream is in error state
nsresult mError;
int64_t mBlobSize;
nsCOMPtr<nsIAsyncInputStream> mAsyncInputStream;
nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
nsCOMPtr<nsIEventTarget> mAsyncWaitTarget;
uint32_t mAsyncWaitFlags;
uint32_t mAsyncWaitRequestedCount;
nsCOMPtr<nsIInputStreamLengthCallback> mAsyncLengthWaitCallback;
nsCOMPtr<nsIEventTarget> mAsyncLengthWaitTarget;
};
} // namespace dom
} // namespace mozilla
#endif /* mozilla_dom_BlobURLInputStream_h */

Просмотреть файл

@ -30,6 +30,7 @@
#include "nsIPrincipal.h"
#include "nsIUUIDGenerator.h"
#include "nsNetUtil.h"
#include "nsReadableUtils.h"
#define RELEASING_TIMER 5000
@ -688,14 +689,14 @@ nsresult BlobURLProtocolHandler::GenerateURIString(nsIPrincipal* aPrincipal,
/* static */
nsIPrincipal* BlobURLProtocolHandler::GetDataEntryPrincipal(
const nsACString& aUri) {
const nsACString& aUri, bool aAlsoIfRevoked) {
MOZ_ASSERT(NS_IsMainThread(),
"without locking gDataTable is main-thread only");
if (!gDataTable) {
return nullptr;
}
DataInfo* res = GetDataInfo(aUri);
DataInfo* res = GetDataInfo(aUri, aAlsoIfRevoked);
if (!res) {
return nullptr;
@ -779,60 +780,10 @@ BlobURLProtocolHandler::GetFlagsForURI(nsIURI* aURI, uint32_t* aResult) {
NS_IMETHODIMP
BlobURLProtocolHandler::NewChannel(nsIURI* aURI, nsILoadInfo* aLoadInfo,
nsIChannel** aResult) {
RefPtr<BlobURLChannel> channel = new BlobURLChannel(aURI, aLoadInfo);
auto raii = MakeScopeExit([&] {
channel->InitFailed();
channel.forget(aResult);
});
RefPtr<BlobURL> blobURL;
nsresult rv =
aURI->QueryInterface(kHOSTOBJECTURICID, getter_AddRefs(blobURL));
if (NS_FAILED(rv) || !blobURL) {
return NS_OK;
auto channel = MakeRefPtr<BlobURLChannel>(aURI, aLoadInfo);
if (!channel) {
return NS_ERROR_NOT_INITIALIZED;
}
MOZ_ASSERT(NS_IsMainThread(),
"without locking gDataTable is main-thread only");
DataInfo* info = GetDataInfoFromURI(aURI, true /*aAlsoIfRevoked */);
if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) {
return NS_OK;
}
if (blobURL->Revoked()) {
#ifdef MOZ_WIDGET_ANDROID
// if the channel was not triggered by the system principal,
// then we return here because the URL had been revoked
if (aLoadInfo && !aLoadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
return NS_OK;
}
#else
return NS_OK;
#endif
}
// We want to be sure that we stop the creation of the channel if the blob URL
// is copy-and-pasted on a different context (ex. private browsing or
// containers).
//
// We also allow the system principal to create the channel regardless of the
// OriginAttributes. This is primarily for the benefit of mechanisms like
// the Download API that explicitly create a channel with the system
// principal and which is never mutated to have a non-zero mPrivateBrowsingId
// or container.
if (aLoadInfo &&
(!aLoadInfo->GetLoadingPrincipal() ||
!aLoadInfo->GetLoadingPrincipal()->IsSystemPrincipal()) &&
!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
aLoadInfo->GetOriginAttributes(),
BasePrincipal::Cast(info->mPrincipal)->OriginAttributesRef())) {
return NS_OK;
}
raii.release();
channel->Initialize(info->mBlobImpl);
channel.forget(aResult);
return NS_OK;
}
@ -901,13 +852,14 @@ nsresult NS_GetBlobForBlobURI(nsIURI* aURI, BlobImpl** aBlob) {
return NS_OK;
}
nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob) {
nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec, BlobImpl** aBlob,
bool aAlsoIfRevoked) {
*aBlob = nullptr;
MOZ_ASSERT(NS_IsMainThread(),
"without locking gDataTable is main-thread only");
DataInfo* info = GetDataInfo(aSpec);
if (!info || info->mObjectType != DataInfo::eBlobImpl) {
DataInfo* info = GetDataInfo(aSpec, aAlsoIfRevoked);
if (!info || info->mObjectType != DataInfo::eBlobImpl || !info->mBlobImpl) {
return NS_ERROR_DOM_BAD_URI;
}
@ -947,6 +899,11 @@ bool IsType(nsIURI* aUri, DataInfo::ObjectType aType) {
bool IsBlobURI(nsIURI* aUri) { return IsType(aUri, DataInfo::eBlobImpl); }
bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri) {
return (StringBeginsWith(aUri, "blob:http://"_ns) ||
StringBeginsWith(aUri, "blob:https://"_ns));
}
bool IsMediaSourceURI(nsIURI* aUri) {
return IsType(aUri, DataInfo::eMediaSource);
}

Просмотреть файл

@ -59,7 +59,8 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler,
static bool HasDataEntry(const nsACString& aUri);
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri);
static nsIPrincipal* GetDataEntryPrincipal(const nsACString& aUri,
bool aAlsoIfRevoked = false);
static void Traverse(const nsACString& aUri,
nsCycleCollectionTraversalCallback& aCallback);
@ -98,6 +99,9 @@ class BlobURLProtocolHandler final : public nsIProtocolHandler,
bool IsBlobURI(nsIURI* aUri);
bool IsMediaSourceURI(nsIURI* aUri);
// Return true if inner scheme of blobURL is http or https, false otherwise.
bool BlobURLSchemeIsHTTPOrHTTPS(const nsACString& aUri);
} // namespace dom
} // namespace mozilla
@ -105,7 +109,8 @@ extern nsresult NS_GetBlobForBlobURI(nsIURI* aURI,
mozilla::dom::BlobImpl** aBlob);
extern nsresult NS_GetBlobForBlobURISpec(const nsACString& aSpec,
mozilla::dom::BlobImpl** aBlob);
mozilla::dom::BlobImpl** aBlob,
bool aAlsoIfRevoked = false);
extern nsresult NS_GetSourceForMediaSourceURI(
nsIURI* aURI, mozilla::dom::MediaSource** aSource);

Просмотреть файл

@ -9,6 +9,7 @@ with Files("**"):
EXPORTS.mozilla.dom += [
'BlobURL.h',
'BlobURLInputStream.h',
'BlobURLProtocolHandler.h',
'FontTableURIProtocolHandler.h',
]
@ -16,6 +17,7 @@ EXPORTS.mozilla.dom += [
UNIFIED_SOURCES += [
'BlobURL.cpp',
'BlobURLChannel.cpp',
'BlobURLInputStream.cpp',
'BlobURLProtocolHandler.cpp',
'FontTableURIProtocolHandler.cpp',
]

Просмотреть файл

@ -413,6 +413,10 @@ void nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition) {
Shutdown();
}
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
obs->NotifyObservers(wrapped, "geolocation-position-events",
u"location-updated");
nsAutoMicroTask mt;
if (mCallback.HasWebIDLCallback()) {
RefPtr<PositionCallback> callback = mCallback.GetWebIDLCallback();

Просмотреть файл

@ -14,7 +14,9 @@
#include "mozilla/Logging.h"
#include "mozilla/StaticPrefs_security.h"
#include "nsContentUtils.h"
#include "nsSandboxFlags.h"
#include "nsStyleConsts.h"
#include "nsIXMLContentSink.h"
static mozilla::LazyLogModule gMetaElementLog("nsMetaElement");
#define LOG(msg) MOZ_LOG(gMetaElementLog, mozilla::LogLevel::Debug, msg)
@ -86,6 +88,24 @@ nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
return rv;
}
Document& doc = aContext.OwnerDoc();
bool shouldProcessMeta = true;
// We don't want to call ProcessMETATag when we are pretty print
// the document
if (doc.IsXMLDocument()) {
if (nsCOMPtr<nsIXMLContentSink> xmlSink =
do_QueryInterface(doc.GetCurrentContentSink())) {
if (xmlSink->IsPrettyPrintXML() &&
xmlSink->IsPrettyPrintHasSpecialRoot()) {
shouldProcessMeta = false;
}
}
}
if (shouldProcessMeta) {
doc.ProcessMETATag(this);
}
if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, nsGkAtoms::viewport,
eIgnoreCase)) {
ProcessViewportContent(&doc);

Просмотреть файл

@ -6825,6 +6825,71 @@ PFileDescriptorSetParent* ContentParent::SendPFileDescriptorSetConstructor(
return PContentParent::SendPFileDescriptorSetConstructor(aFD);
}
mozilla::ipc::IPCResult ContentParent::RecvBlobURLDataRequest(
const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal,
nsIPrincipal* pLoadingPrincipal, const OriginAttributes& aOriginAttributes,
BlobURLDataRequestResolver&& aResolver) {
RefPtr<BlobImpl> blobImpl;
nsresult rv = NS_GetBlobForBlobURISpec(aBlobURL, getter_AddRefs(blobImpl),
true /* AlsoIfRevoked */);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(rv);
return IPC_OK();
}
if (NS_WARN_IF(!blobImpl)) {
aResolver(NS_ERROR_DOM_BAD_URI);
return IPC_OK();
}
// Since revoked blobs are also retrieved, it is possible that the blob no
// longer exists (due to the 5 second timeout) when execution reaches here
nsIPrincipal* const dataEntryPrincipal =
BlobURLProtocolHandler::GetDataEntryPrincipal(aBlobURL,
true /* AlsoIfRevoked */);
if (!dataEntryPrincipal) {
aResolver(NS_ERROR_DOM_BAD_URI);
return IPC_OK();
}
// We want to be sure that we stop the creation of the channel if the blob
// URL is copy-and-pasted on a different context (ex. private browsing or
// containers).
//
// We also allow the system principal to create the channel regardless of
// the OriginAttributes. This is primarily for the benefit of mechanisms
// like the Download API that explicitly create a channel with the system
// principal and which is never mutated to have a non-zero
// mPrivateBrowsingId or container.
if (NS_WARN_IF(!pLoadingPrincipal ||
!pLoadingPrincipal->IsSystemPrincipal()) &&
NS_WARN_IF(!ChromeUtils::IsOriginAttributesEqualIgnoringFPD(
aOriginAttributes,
BasePrincipal::Cast(dataEntryPrincipal)->OriginAttributesRef()))) {
aResolver(NS_ERROR_DOM_BAD_URI);
return IPC_OK();
}
if (!pTriggeringPrincipal->Subsumes(dataEntryPrincipal)) {
aResolver(NS_ERROR_DOM_BAD_URI);
return IPC_OK();
}
IPCBlob ipcBlob;
rv = IPCBlobUtils::Serialize(blobImpl, this, ipcBlob);
if (NS_WARN_IF(NS_FAILED(rv))) {
aResolver(rv);
return IPC_OK();
}
aResolver(ipcBlob);
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvReportServiceWorkerShutdownProgress(
uint32_t aShutdownStateId, ServiceWorkerShutdownState::Progress aProgress) {
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();

Просмотреть файл

@ -697,6 +697,12 @@ class ContentParent final
PFileDescriptorSetParent* SendPFileDescriptorSetConstructor(
const FileDescriptor& aFD) override;
mozilla::ipc::IPCResult RecvBlobURLDataRequest(
const nsCString& aBlobURL, nsIPrincipal* pTriggeringPrincipal,
nsIPrincipal* pLoadingPrincipal,
const OriginAttributes& aOriginAttributes,
BlobURLDataRequestResolver&& aResolver);
protected:
bool CheckBrowsingContextEmbedder(CanonicalBrowsingContext* aBC,
const char* aOperation) const;

Просмотреть файл

@ -381,6 +381,12 @@ union SyncedContextInitializer
WindowContextInitializer;
};
union BlobURLDataRequestResult
{
IPCBlob;
nsresult;
};
/**
* The PContent protocol is a top-level protocol between the UI process
* and a content process. There is exactly one PContentParent/PContentChild pair
@ -1658,6 +1664,8 @@ parent:
async HistoryGo(MaybeDiscardedBrowsingContext aContext,
int32_t aOffset) returns(int32_t requestedIndex);
async BlobURLDataRequest(nsCString aBlobURL, nsIPrincipal aTriggeringPrincipal, nsIPrincipal aLoadingPrincipal, OriginAttributes aOriginAttributes) returns (BlobURLDataRequestResult aResult);
both:
async ScriptError(nsString message, nsString sourceName, nsString sourceLine,
uint32_t lineNumber, uint32_t colNumber, uint32_t flags,

Просмотреть файл

@ -850,12 +850,26 @@ void MediaTrackGraphImpl::NotifyInputData(const AudioDataValue* aBuffer,
return;
}
#endif
mInputData = aBuffer;
mInputFrames = aFrames;
mInputChannelCount = aChannels;
}
void MediaTrackGraphImpl::ProcessInputData() {
if (!mInputData) {
return;
}
nsTArray<RefPtr<AudioDataListener>>* listeners =
mInputDeviceUsers.GetValue(mInputDeviceID);
MOZ_ASSERT(listeners);
for (auto& listener : *listeners) {
listener->NotifyInputData(this, aBuffer, aFrames, aRate, aChannels);
listener->NotifyInputData(this, mInputData, mInputFrames, GraphRate(), mInputChannelCount);
}
mInputData = nullptr;
mInputFrames = 0;
mInputChannelCount = 0;
}
void MediaTrackGraphImpl::DeviceChangedImpl() {
@ -1381,6 +1395,8 @@ auto MediaTrackGraphImpl::OneIterationImpl(GraphTime aStateEnd,
DemoteThreadFromRealTime();
}
ProcessInputData();
// Changes to LIFECYCLE_RUNNING occur before starting or reviving the graph
// thread, and so the monitor need not be held to check mLifecycleState.
// LIFECYCLE_THREAD_NOT_STARTED is possible when shutting down offline
@ -3013,6 +3029,9 @@ MediaTrackGraphImpl::MediaTrackGraphImpl(
mPortCount(0),
mInputDeviceID(nullptr),
mOutputDeviceID(aOutputDeviceID),
mInputData(nullptr),
mInputChannelCount(0),
mInputFrames(0),
mMonitor("MediaTrackGraphImpl"),
mLifecycleState(LIFECYCLE_THREAD_NOT_STARTED),
mPostedRunInStableStateEvent(false),

Просмотреть файл

@ -427,10 +427,14 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
/* Called on the graph thread before the first Notify*Data after an
* AudioCallbackDriver starts. */
void NotifyStarted() override;
/* Called on the graph thread when there is new input data for listeners. This
* is the raw audio input for this MediaTrackGraph. */
/* Called on the audio callback thread when there is new input data for
* listeners. This is the raw audio input for this MediaTrackGraph. Actual
* processing happens in ProcessInputData */
void NotifyInputData(const AudioDataValue* aBuffer, size_t aFrames,
TrackRate aRate, uint32_t aChannels) override;
/* Called on the graph thread to process the input data delivered in each
* iteration by NotifyInputData. */
void ProcessInputData();
/* Called every time there are changes to input/output audio devices like
* plug/unplug etc. This can be called on any thread, and posts a message to
* the main thread so that it can post a message to the graph thread. */
@ -776,6 +780,11 @@ class MediaTrackGraphImpl : public MediaTrackGraph,
nsDataHashtable<nsVoidPtrHashKey, nsTArray<RefPtr<AudioDataListener>>>
mInputDeviceUsers;
// Only valid for the current iteration: if non nullptr, there is input data.
const AudioDataValue* mInputData;
uint32_t mInputChannelCount;
uint32_t mInputFrames;
/**
* List of resume operations waiting for a switch to an AudioCallbackDriver.
*/

Просмотреть файл

@ -6,6 +6,8 @@
include protocol PGMPContent;
include GMPTypes;
include "GMPMessageUtils.h";
using cdm::HdcpVersion from "content_decryption_module.h";
include "GMPMessageUtils.h";
@ -64,7 +66,7 @@ child:
async GiveBuffer(Shmem aShmem);
async PurgeShmems();
parent:
async __delete__();

Просмотреть файл

@ -21,8 +21,8 @@
#define BUFFER_SIZE 65536
using namespace mozilla;
using namespace mozilla::dom;
namespace mozilla {
namespace dom {
class CopierCallbacks final : public nsIRequestObserver {
public:
@ -548,3 +548,6 @@ PresentationTCPSessionTransport::OnDataAvailable(nsIRequest* aRequest,
// Pass the incoming data to the listener.
return mCallback->NotifyData(data, false);
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -27,6 +27,7 @@ support-files =
file_presentation_mixed_security_contexts.html
[test_presentation_dc_sender.html]
skip-if = e10s # Bug 1656033
[test_presentation_dc_receiver.html]
skip-if = e10s # Bug 1129785
[test_presentation_dc_receiver_oop.html]

Просмотреть файл

@ -41,8 +41,8 @@ nsHTTPSOnlyStreamListener::OnStartRequest(nsIRequest* request) {
NS_IMETHODIMP
nsHTTPSOnlyStreamListener::OnStopRequest(nsIRequest* request,
nsresult aStatus) {
// DNS errors are unrelated to the HTTPS-Only mode, so they can be ignored.
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(aStatus)) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(request);
if (nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(channel, aStatus)) {
RecordUpgradeTelemetry(request, aStatus);
LogUpgradeFailure(request, aStatus);
}

Просмотреть файл

@ -125,9 +125,34 @@ bool nsHTTPSOnlyUtils::ShouldUpgradeWebSocket(nsIURI* aURI,
}
/* static */
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsresult aError) {
// This list of error codes is largely drawn from
// nsDocShell::DisplayLoadError()
bool nsHTTPSOnlyUtils::CouldBeHttpsOnlyError(nsIChannel* aChannel,
nsresult aError) {
// If there is no failed channel, then there is nothing to do here.
if (!aChannel) {
return false;
}
// If HTTPS-Only Mode is not enabled, then there is nothing to do here.
nsCOMPtr<nsILoadInfo> loadInfo = aChannel->LoadInfo();
bool isPrivateWin = loadInfo->GetOriginAttributes().mPrivateBrowsingId > 0;
if (!IsHttpsOnlyModeEnabled(isPrivateWin)) {
return false;
}
// If the listener is not registerd, then there is nothing to do here.
uint32_t httpsOnlyStatus = loadInfo->GetHttpsOnlyStatus();
if (!(httpsOnlyStatus &
nsILoadInfo::HTTPS_ONLY_UPGRADED_LISTENER_REGISTERED)) {
return false;
}
// If the load is exempt, then there is nothing to do here.
if (httpsOnlyStatus & nsILoadInfo::HTTPS_ONLY_EXEMPT) {
return false;
}
// If it's one of those errors, then most likely it's not a HTTPS-Only error
// (This list of errors is largely drawn from nsDocShell::DisplayLoadError())
return !(NS_ERROR_UNKNOWN_PROTOCOL == aError ||
NS_ERROR_FILE_NOT_FOUND == aError ||
NS_ERROR_FILE_ACCESS_DENIED == aError ||
@ -213,8 +238,8 @@ bool nsHTTPSOnlyUtils::LoopbackOrLocalException(nsIURI* aURI) {
nsresult rv = aURI->GetAsciiHost(asciiHost);
NS_ENSURE_SUCCESS(rv, false);
// Let's make a quick check if the host matches these loopback strings before
// we do anything else
// Let's make a quick check if the host matches these loopback strings
// before we do anything else
if (asciiHost.EqualsLiteral("localhost") || asciiHost.EqualsLiteral("::1")) {
return true;
}

Просмотреть файл

@ -44,10 +44,11 @@ class nsHTTPSOnlyUtils {
/**
* Checks if the error code is on a block-list of codes that are probably not
* related to a HTTPS-Only Mode upgrade.
* @param aChannel The failed Channel.
* @param aError Error Code from Request
* @return false if error is not related to upgrade
*/
static bool CouldBeHttpsOnlyError(nsresult aError);
static bool CouldBeHttpsOnlyError(nsIChannel* aChannel, nsresult aError);
/**
* Logs localized message to either content console or browser console

Просмотреть файл

@ -0,0 +1,100 @@
const { HttpServer } = ChromeUtils.import("resource://testing-common/httpd.js");
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
let geolocation = null;
let numRequests = 0;
let locations = [
[1, 2],
[3, 4],
[5, 6],
];
function geoHandler(metadata, response) {
numRequests++;
let [lat, lng] = locations.shift();
response.setStatusLine("1.0", 200, "OK");
response.setHeader("Cache-Control", "no-cache", false);
response.setHeader("Content-Type", "application/x-javascript", false);
response.write(
JSON.stringify({
status: "OK",
location: { lat, lng },
accuracy: 42,
})
);
}
function toJSON(pos) {
return { lat: pos.coords.latitude, lng: pos.coords.longitude };
}
function getPosition() {
return new Promise(function(resolve, reject) {
geolocation.getCurrentPosition(resolve, reject);
});
}
function watchPosition() {
let seen = 0;
return new Promise(function(resolve, reject) {
let id = geolocation.watchPosition(position => {
seen++;
if (seen === 1) {
Assert.deepEqual(toJSON(position), { lat: 3, lng: 4 });
Assert.deepEqual(observer._lastData, { lat: 3, lng: 4 });
Assert.equal(observer._countEvents, 2);
} else if (seen === 2) {
Assert.deepEqual(toJSON(position), { lat: 5, lng: 6 });
Assert.deepEqual(observer._lastData, { lat: 5, lng: 6 });
Assert.equal(observer._countEvents, 3);
geolocation.clearWatch(id);
resolve();
}
}, reject);
});
}
let observer = {
QueryInterface: ChromeUtils.generateQI(["nsIObserver"]),
observe(subject, topic, data) {
Assert.equal(topic, "geolocation-position-events");
observer._countEvents++;
observer._lastData = toJSON(subject);
},
_lastData: null,
_countEvents: 0,
};
add_task(async function test_resetClient() {
do_get_profile();
geolocation = Cc["@mozilla.org/geolocation;1"].getService(Ci.nsISupports);
let server = new HttpServer();
server.registerPathHandler("/geo", geoHandler);
server.start(-1);
Services.prefs.setCharPref(
"geo.provider.network.url",
"http://localhost:" + server.identity.primaryPort + "/geo"
);
Services.prefs.setBoolPref(
"geo.provider.network.debug.requestCache.enabled",
false
);
Services.prefs.setBoolPref("geo.provider.network.scan", false);
var obs = Cc["@mozilla.org/observer-service;1"].getService();
obs = obs.QueryInterface(Ci.nsIObserverService);
obs.addObserver(observer, "geolocation-position-events");
let position = await getPosition();
Assert.deepEqual(toJSON(position), { lat: 1, lng: 2 });
Assert.equal(observer._countEvents, 1);
Assert.deepEqual(observer._lastData, { lat: 1, lng: 2 });
await watchPosition();
await new Promise(resolve => server.stop(resolve));
});

Просмотреть файл

@ -5,6 +5,7 @@ head =
[test_bug465752.js]
[test_Fetch.js]
[test_geolocation_provider.js]
[test_geolocation_monitor.js]
[test_geolocation_timeout.js]
[test_geolocation_timeout_wrap.js]
skip-if = os == "mac" || os == "android"

Просмотреть файл

@ -50,6 +50,8 @@ class Document;
class nsIXMLContentSink : public nsIContentSink {
public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_IXMLCONTENT_SINK_IID)
virtual bool IsPrettyPrintXML() const { return false; }
virtual bool IsPrettyPrintHasSpecialRoot() const { return false; }
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIXMLContentSink, NS_IXMLCONTENT_SINK_IID)

Просмотреть файл

@ -565,14 +565,9 @@ nsresult nsXMLContentSink::CloseElement(nsIContent* aContent) {
}
nsresult rv = NS_OK;
if (nodeInfo->Equals(nsGkAtoms::meta, kNameSpaceID_XHTML) &&
// Need to check here to make sure this meta tag does not set
// mPrettyPrintXML to false when we have a special root!
(!mPrettyPrintXML || !mPrettyPrintHasSpecialRoot)) {
rv = ProcessMETATag(aContent);
} else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
if (auto* linkStyle = LinkStyle::FromNode(*aContent)) {
linkStyle->SetEnableUpdates(true);
auto updateOrError =

Просмотреть файл

@ -73,6 +73,10 @@ class nsXMLContentSink : public nsContentSink,
virtual nsISupports* GetTarget() override;
virtual bool IsScriptExecuting() override;
virtual void ContinueInterruptedParsingAsync() override;
bool IsPrettyPrintXML() const override { return mPrettyPrintXML; }
bool IsPrettyPrintHasSpecialRoot() const override {
return mPrettyPrintHasSpecialRoot;
}
// nsITransformObserver
NS_IMETHOD OnDocumentCreated(

Просмотреть файл

@ -0,0 +1,24 @@
<style>
body {
transform-style: preserve-3d;
}
div {
height: 100px;
background-color: rgba(0, 255, 0, 0.1);;
transform: translateX(1px);
}
</style>
<body>
<script>
var div = document.createElement('div');
div.style.width = "1px";
for (var i = 2; i < 1000; i++) {
var container = document.createElement('div');
container.style.width = i + "px";
container.appendChild(div);
div = container;
}
document.body.appendChild(div);
</script>
</body>

Просмотреть файл

@ -195,3 +195,4 @@ load 1647862.html
load 1647940.html
load 1650989-very-large-mask.html
load 1650990.html
skip-if(!webrender||AddressSanitizer) load 1652750-deep-scene-stack.html

Просмотреть файл

@ -2463,17 +2463,19 @@ bool js::array_pop(JSContext* cx, unsigned argc, Value* vp) {
return SetLengthProperty(cx, obj, index);
}
void js::ArrayShiftMoveElements(NativeObject* obj) {
void js::ArrayShiftMoveElements(ArrayObject* arr) {
AutoUnsafeCallWithABI unsafe;
MOZ_ASSERT(obj->isExtensible());
MOZ_ASSERT_IF(obj->is<ArrayObject>(),
obj->as<ArrayObject>().lengthIsWritable());
MOZ_ASSERT(arr->isExtensible());
MOZ_ASSERT(arr->lengthIsWritable());
MOZ_ASSERT_IF(jit::JitOptions.warpBuilder, IsPackedArray(arr));
MOZ_ASSERT(!arr->denseElementsAreCopyOnWrite());
MOZ_ASSERT(!arr->denseElementsHaveMaybeInIterationFlag());
size_t initlen = obj->getDenseInitializedLength();
size_t initlen = arr->getDenseInitializedLength();
MOZ_ASSERT(initlen > 0);
if (!obj->tryShiftDenseElements(1)) {
obj->moveDenseElementsNoPreBarrier(0, 1, initlen - 1);
if (!arr->tryShiftDenseElements(1)) {
arr->moveDenseElements(0, 1, initlen - 1);
}
}

Просмотреть файл

@ -145,7 +145,7 @@ extern bool array_pop(JSContext* cx, unsigned argc, js::Value* vp);
extern bool array_join(JSContext* cx, unsigned argc, js::Value* vp);
extern void ArrayShiftMoveElements(NativeObject* obj);
extern void ArrayShiftMoveElements(ArrayObject* arr);
extern bool array_shift(JSContext* cx, unsigned argc, js::Value* vp);

Просмотреть файл

@ -110,7 +110,8 @@
#include "wasm/WasmTypes.h" // for WasmInstanceObjectVector
#include "debugger/DebugAPI-inl.h"
#include "debugger/Frame-inl.h" // for DebuggerFrame::hasGeneratorInfo
#include "debugger/Environment-inl.h" // for DebuggerEnvironment::owner
#include "debugger/Frame-inl.h" // for DebuggerFrame::hasGeneratorInfo
#include "debugger/Object-inl.h" // for DebuggerObject::owner and isInstance.
#include "debugger/Script-inl.h" // for DebuggerScript::getReferent
#include "gc/GC-inl.h" // for ZoneCellIter

Просмотреть файл

@ -1,6 +1,8 @@
// |jit-test| skip-if: wasmCompilersPresent().match("cranelift")
// (Reason: the Cranelift backend does not support shared memory yet.)
// |jit-test| skip-if: wasmCompilersPresent().match("cranelift") && !getBuildConfiguration()['arm64']
//
// (Reason: the Cranelift backend does not support shared memory on non-AArch64
// hosts yet.)
//
// Tests of limits of memory and table types
const PageSize = 65536;

Просмотреть файл

@ -2030,6 +2030,7 @@ bool jit::FinishBailoutToBaseline(BaselineBailoutInfo* bailoutInfoArg) {
case BailoutKind::ProtoGuard:
case BailoutKind::NotProxyGuard:
case BailoutKind::NotArrayBufferMaybeSharedGuard:
case BailoutKind::ArrayPopShift:
// Do nothing.
break;

Просмотреть файл

@ -5099,6 +5099,59 @@ AttachDecision CallIRGenerator::tryAttachArrayPush(HandleFunction callee) {
return AttachDecision::Attach;
}
AttachDecision CallIRGenerator::tryAttachArrayPopShift(HandleFunction callee,
InlinableNative native) {
// Expecting no arguments.
if (argc_ != 0) {
return AttachDecision::NoAction;
}
// Only optimize if |this| is a packed array.
if (!thisval_.isObject() || !IsPackedArray(&thisval_.toObject())) {
return AttachDecision::NoAction;
}
// Other conditions:
//
// * The array length needs to be writable because we're changing it.
// * The elements must not be copy-on-write because we're deleting an element.
// * The array must be extensible. Non-extensible arrays require preserving
// the |initializedLength == capacity| invariant on ObjectElements.
// See NativeObject::shrinkCapacityToInitializedLength.
// This also ensures the elements aren't sealed/frozen.
// * There must not be a for-in iterator for the elements because the IC stub
// does not suppress deleted properties.
ArrayObject* arr = &thisval_.toObject().as<ArrayObject>();
if (!arr->lengthIsWritable() || arr->denseElementsAreCopyOnWrite() ||
!arr->isExtensible() || arr->denseElementsHaveMaybeInIterationFlag()) {
return AttachDecision::NoAction;
}
// Initialize the input operand.
Int32OperandId argcId(writer.setInputOperandId(0));
// Guard callee is the 'pop' or 'shift' native function.
emitNativeCalleeGuard(callee);
ValOperandId thisValId =
writer.loadArgumentFixedSlot(ArgumentKind::This, argc_);
ObjOperandId objId = writer.guardToObject(thisValId);
writer.guardClass(objId, GuardClassKind::Array);
if (native == InlinableNative::ArrayPop) {
writer.packedArrayPopResult(objId);
} else {
MOZ_ASSERT(native == InlinableNative::ArrayShift);
writer.packedArrayShiftResult(objId);
}
writer.typeMonitorResult();
cacheIRStubKind_ = BaselineCacheIRStubKind::Monitored;
trackAttached("ArrayPopShift");
return AttachDecision::Attach;
}
AttachDecision CallIRGenerator::tryAttachArrayJoin(HandleFunction callee) {
// Only handle argc <= 1.
if (argc_ > 1) {
@ -7432,6 +7485,9 @@ AttachDecision CallIRGenerator::tryAttachInlinableNative(
return tryAttachArrayConstructor(callee);
case InlinableNative::ArrayPush:
return tryAttachArrayPush(callee);
case InlinableNative::ArrayPop:
case InlinableNative::ArrayShift:
return tryAttachArrayPopShift(callee, native);
case InlinableNative::ArrayJoin:
return tryAttachArrayJoin(callee);
case InlinableNative::ArrayIsArray:

Просмотреть файл

@ -1612,6 +1612,8 @@ class MOZ_RAII CallIRGenerator : public IRGenerator {
void emitNativeCalleeGuard(HandleFunction callee);
AttachDecision tryAttachArrayPush(HandleFunction callee);
AttachDecision tryAttachArrayPopShift(HandleFunction callee,
InlinableNative native);
AttachDecision tryAttachArrayJoin(HandleFunction callee);
AttachDecision tryAttachArrayIsArray(HandleFunction callee);
AttachDecision tryAttachDataViewGet(HandleFunction callee, Scalar::Type type);

Просмотреть файл

@ -3860,6 +3860,44 @@ bool CacheIRCompiler::emitArrayJoinResult(ObjOperandId objId) {
return true;
}
bool CacheIRCompiler::emitPackedArrayPopResult(ObjOperandId arrayId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
AutoOutputRegister output(*this);
Register array = allocator.useRegister(masm, arrayId);
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
masm.packedArrayPop(array, output.valueReg(), scratch1, scratch2,
failure->label());
return true;
}
bool CacheIRCompiler::emitPackedArrayShiftResult(ObjOperandId arrayId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);
AutoOutputRegister output(*this);
Register array = allocator.useRegister(masm, arrayId);
AutoScratchRegister scratch1(allocator, masm);
AutoScratchRegister scratch2(allocator, masm);
FailurePath* failure;
if (!addFailurePath(&failure)) {
return false;
}
LiveRegisterSet volatileRegs(GeneralRegisterSet::Volatile(),
liveVolatileFloatRegs());
masm.packedArrayShift(array, output.valueReg(), scratch1, scratch2,
volatileRegs, failure->label());
return true;
}
bool CacheIRCompiler::emitIsObjectResult(ValOperandId inputId) {
JitSpew(JitSpew_Codegen, "%s", __FUNCTION__);

Просмотреть файл

@ -18,16 +18,27 @@ bool CacheIRHealth::spewStubHealth(AutoStructuredSpewer& spew, ICStub* stub) {
const CacheIRStubInfo* stubInfo = stub->cacheIRStubInfo();
CacheIRReader stubReader(stubInfo);
uint32_t totalStubHealth = 0;
spew->beginListProperty("cacheIROps");
while (stubReader.more()) {
CacheOp op = stubReader.readOp();
uint32_t opHealth = CacheIROpHealth[size_t(op)];
uint32_t argLength = CacheIROpArgLengths[size_t(op)];
const char* opName = CacheIROpNames[size_t(op)];
spew->beginObject();
if (opHealth == UINT32_MAX) {
const char* opName = CacheIROpNames[size_t(op)];
spew->property("unscoredOp", opName);
} else {
spew->property("cacheIROp", opName);
spew->property("opHealth", opHealth);
totalStubHealth += opHealth;
}
spew->endObject();
stubReader.skip(argLength);
}
spew->endList(); // cacheIROps
spew->property("stubHealth", totalStubHealth);
return true;

Просмотреть файл

@ -890,6 +890,20 @@
args:
obj: ObjId
- name: PackedArrayPopResult
shared: true
transpile: true
cost_estimate: 2
args:
array: ObjId
- name: PackedArrayShiftResult
shared: true
transpile: true
cost_estimate: 4
args:
array: ObjId
- name: IsArrayResult
shared: false
transpile: true

Просмотреть файл

@ -10303,10 +10303,24 @@ void CodeGenerator::emitArrayPopShift(LInstruction* lir,
void CodeGenerator::visitArrayPopShiftV(LArrayPopShiftV* lir) {
Register obj = ToRegister(lir->object());
Register elements = ToRegister(lir->temp0());
Register length = ToRegister(lir->temp1());
Register temp1 = ToRegister(lir->temp0());
Register temp2 = ToRegister(lir->temp1());
TypedOrValueRegister out(ToOutValue(lir));
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
if (JitOptions.warpBuilder) {
Label bail;
if (lir->mir()->mode() == MArrayPopShift::Pop) {
masm.packedArrayPop(obj, out.valueReg(), temp1, temp2, &bail);
} else {
MOZ_ASSERT(lir->mir()->mode() == MArrayPopShift::Shift);
LiveRegisterSet volatileRegs = liveVolatileRegs(lir);
masm.packedArrayShift(obj, out.valueReg(), temp1, temp2, volatileRegs,
&bail);
}
bailoutFrom(&bail, lir->snapshot());
} else {
emitArrayPopShift(lir, lir->mir(), obj, temp1, temp2, out);
}
}
void CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir) {
@ -10314,6 +10328,8 @@ void CodeGenerator::visitArrayPopShiftT(LArrayPopShiftT* lir) {
Register elements = ToRegister(lir->temp0());
Register length = ToRegister(lir->temp1());
TypedOrValueRegister out(lir->mir()->type(), ToAnyRegister(lir->output()));
MOZ_ASSERT(!JitOptions.warpBuilder);
emitArrayPopShift(lir, lir->mir(), obj, elements, length, out);
}

Просмотреть файл

@ -176,6 +176,9 @@ enum class BailoutKind : uint8_t {
// Bailout triggered by MGuardIsNotArrayBufferMaybeShared.
NotArrayBufferMaybeSharedGuard,
// Bailout triggered by MArrayPopShift.
ArrayPopShift,
// Bailout triggered by MGuardValue.
ValueGuard,
@ -266,6 +269,8 @@ inline const char* BailoutKindString(BailoutKind kind) {
return "BailoutKind::NotProxyGuard";
case BailoutKind::NotArrayBufferMaybeSharedGuard:
return "BailoutKind::NotArrayBufferMaybeSharedGuard";
case BailoutKind::ArrayPopShift:
return "BailoutKind::ArrayPopShift";
case BailoutKind::ValueGuard:
return "BailoutKind::ValueGuard";
case BailoutKind::NullOrUndefinedGuard:

Просмотреть файл

@ -3466,8 +3466,13 @@ void LIRGenerator::visitArrayPopShift(MArrayPopShift* ins) {
case MIRType::Value: {
LArrayPopShiftV* lir =
new (alloc()) LArrayPopShiftV(object, temp(), temp());
if (JitOptions.warpBuilder) {
assignSnapshot(lir, BailoutKind::ArrayPopShift);
}
defineBox(lir, ins);
assignSafepoint(lir, ins);
if (!JitOptions.warpBuilder || ins->mode() == MArrayPopShift::Shift) {
assignSafepoint(lir, ins);
}
break;
}
case MIRType::Undefined:

Просмотреть файл

@ -7892,7 +7892,9 @@ class MArrayPopShift : public MUnaryInstruction,
: MUnaryInstruction(classOpcode, object),
mode_(mode),
needsHoleCheck_(needsHoleCheck),
maybeUndefined_(maybeUndefined) {}
maybeUndefined_(maybeUndefined) {
setResultType(MIRType::Value);
}
public:
INSTRUCTION_HEADER(ArrayPopShift)

Просмотреть файл

@ -26,6 +26,7 @@
#include "jit/Lowering.h"
#include "jit/MIR.h"
#include "jit/MoveEmitter.h"
#include "jit/SharedICHelpers.h"
#include "jit/Simulator.h"
#include "js/Conversions.h"
#include "js/Printf.h"
@ -3894,6 +3895,122 @@ void MacroAssembler::setIsPackedArray(Register obj, Register output,
bind(&done);
}
void MacroAssembler::packedArrayPop(Register array, ValueOperand output,
Register temp1, Register temp2,
Label* fail) {
// Load obj->elements in temp1.
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
// Check flags.
static constexpr uint32_t UnhandledFlags =
ObjectElements::Flags::NON_PACKED | ObjectElements::Flags::COPY_ON_WRITE |
ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH |
ObjectElements::Flags::NOT_EXTENSIBLE |
ObjectElements::Flags::MAYBE_IN_ITERATION;
Address flags(temp1, ObjectElements::offsetOfFlags());
branchTest32(Assembler::NonZero, flags, Imm32(UnhandledFlags), fail);
// Load length in temp2. Ensure length == initializedLength.
Address lengthAddr(temp1, ObjectElements::offsetOfLength());
Address initLengthAddr(temp1, ObjectElements::offsetOfInitializedLength());
load32(lengthAddr, temp2);
branch32(Assembler::NotEqual, initLengthAddr, temp2, fail);
// Result is |undefined| if length == 0.
Label notEmpty, done;
branchTest32(Assembler::NonZero, temp2, temp2, &notEmpty);
{
moveValue(UndefinedValue(), output);
jump(&done);
}
bind(&notEmpty);
// Load the last element.
sub32(Imm32(1), temp2);
BaseObjectElementIndex elementAddr(temp1, temp2);
loadValue(elementAddr, output);
// Pre-barrier the element because we're removing it from the array.
EmitPreBarrier(*this, elementAddr, MIRType::Value);
// Update length and initializedLength.
store32(temp2, lengthAddr);
store32(temp2, initLengthAddr);
bind(&done);
}
void MacroAssembler::packedArrayShift(Register array, ValueOperand output,
Register temp1, Register temp2,
LiveRegisterSet volatileRegs,
Label* fail) {
// Load obj->elements in temp1.
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
// Check flags.
static constexpr uint32_t UnhandledFlags =
ObjectElements::Flags::NON_PACKED | ObjectElements::Flags::COPY_ON_WRITE |
ObjectElements::Flags::NONWRITABLE_ARRAY_LENGTH |
ObjectElements::Flags::NOT_EXTENSIBLE |
ObjectElements::Flags::MAYBE_IN_ITERATION;
Address flags(temp1, ObjectElements::offsetOfFlags());
branchTest32(Assembler::NonZero, flags, Imm32(UnhandledFlags), fail);
// Load length in temp2. Ensure length == initializedLength.
Address lengthAddr(temp1, ObjectElements::offsetOfLength());
Address initLengthAddr(temp1, ObjectElements::offsetOfInitializedLength());
load32(lengthAddr, temp2);
branch32(Assembler::NotEqual, initLengthAddr, temp2, fail);
// Result is |undefined| if length == 0.
Label notEmpty, done;
branchTest32(Assembler::NonZero, temp2, temp2, &notEmpty);
{
moveValue(UndefinedValue(), output);
jump(&done);
}
bind(&notEmpty);
// Load the first element.
Address elementAddr(temp1, 0);
loadValue(elementAddr, output);
// Pre-barrier the element because we're removing it from the array.
EmitPreBarrier(*this, elementAddr, MIRType::Value);
// Move the other elements.
{
// Ensure output and temp2 are in volatileRegs. Don't preserve temp1.
volatileRegs.takeUnchecked(temp1);
if (output.hasVolatileReg()) {
volatileRegs.addUnchecked(output);
}
if (temp2.volatile_()) {
volatileRegs.addUnchecked(temp2);
}
PushRegsInMask(volatileRegs);
setupUnalignedABICall(temp1);
passABIArg(array);
callWithABI(JS_FUNC_TO_DATA_PTR(void*, ArrayShiftMoveElements));
PopRegsInMask(volatileRegs);
// Reload the elements. The call may have updated it.
loadPtr(Address(array, NativeObject::offsetOfElements()), temp1);
}
// Update length and initializedLength.
sub32(Imm32(1), temp2);
store32(temp2, lengthAddr);
store32(temp2, initLengthAddr);
bind(&done);
}
static constexpr bool ValidateShiftRange(Scalar::Type from, Scalar::Type to) {
for (Scalar::Type type = from; type < to; type = Scalar::Type(type + 1)) {
if (TypedArrayShift(type) != TypedArrayShift(from)) {

Просмотреть файл

@ -3561,6 +3561,12 @@ class MacroAssembler : public MacroAssemblerSpecific {
void setIsPackedArray(Register obj, Register output, Register temp);
void packedArrayPop(Register array, ValueOperand output, Register temp1,
Register temp2, Label* fail);
void packedArrayShift(Register array, ValueOperand output, Register temp1,
Register temp2, LiveRegisterSet volatileRegs,
Label* fail);
void typedArrayElementShift(Register obj, Register output);
void branchIfClassIsNotTypedArray(Register clasp, Label* notTypedArray);

Просмотреть файл

@ -130,6 +130,9 @@ class ValueOperand {
return type_ == reg || payload_ == reg;
}
constexpr Register payloadOrValueReg() const { return payloadReg(); }
bool hasVolatileReg() const {
return type_.volatile_() || payload_.volatile_();
}
constexpr bool operator==(const ValueOperand& o) const {
return type_ == o.type_ && payload_ == o.payload_;
}
@ -147,6 +150,7 @@ class ValueOperand {
constexpr Register64 toRegister64() const { return Register64(valueReg()); }
constexpr bool aliases(Register reg) const { return value_ == reg; }
constexpr Register payloadOrValueReg() const { return valueReg(); }
bool hasVolatileReg() const { return value_.volatile_(); }
constexpr bool operator==(const ValueOperand& o) const {
return value_ == o.value_;
}

Просмотреть файл

@ -1773,6 +1773,36 @@ bool WarpCacheIRTranspiler::emitArrayPush(ObjOperandId objId,
return resumeAfter(ins);
}
bool WarpCacheIRTranspiler::emitPackedArrayPopResult(ObjOperandId arrayId) {
MDefinition* array = getOperand(arrayId);
// TODO(Warp): these flags only make sense for the Ion implementation. Remove
// them when IonBuilder is gone.
bool needsHoleCheck = true;
bool maybeUndefined = true;
auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Pop,
needsHoleCheck, maybeUndefined);
addEffectful(ins);
pushResult(ins);
return resumeAfter(ins);
}
bool WarpCacheIRTranspiler::emitPackedArrayShiftResult(ObjOperandId arrayId) {
MDefinition* array = getOperand(arrayId);
// TODO(Warp): these flags only make sense for the Ion implementation. Remove
// them when IonBuilder is gone.
bool needsHoleCheck = true;
bool maybeUndefined = true;
auto* ins = MArrayPopShift::New(alloc(), array, MArrayPopShift::Shift,
needsHoleCheck, maybeUndefined);
addEffectful(ins);
pushResult(ins);
return resumeAfter(ins);
}
bool WarpCacheIRTranspiler::emitHasClassResult(ObjOperandId objId,
uint32_t claspOffset) {
MDefinition* obj = getOperand(objId);

Просмотреть файл

@ -473,7 +473,6 @@ case "$target" in
;;
*-android*|*-linuxandroid*)
MOZ_GFX_OPTIMIZE_MOBILE=1
MOZ_OPTIMIZE_FLAGS="-O3"
if test -z "$CLANG_CC"; then
MOZ_OPTIMIZE_FLAGS="-freorder-blocks -fno-reorder-functions $MOZ_OPTIMIZE_FLAGS"

Просмотреть файл

@ -2661,30 +2661,35 @@ bool js::PreventExtensions(JSContext* cx, HandleObject obj,
// If the following assertion fails, there's somewhere else a missing
// call to shrinkCapacityToInitializedLength() which needs to be found
// and fixed.
MOZ_ASSERT_IF(obj->isNative(),
MOZ_ASSERT_IF(obj->is<NativeObject>(),
obj->as<NativeObject>().getDenseInitializedLength() ==
obj->as<NativeObject>().getDenseCapacity());
return result.succeed();
}
if (obj->isNative()) {
if (obj->is<NativeObject>()) {
// Force lazy properties to be resolved.
if (!ResolveLazyProperties(cx, obj.as<NativeObject>())) {
HandleNativeObject nobj = obj.as<NativeObject>();
if (!ResolveLazyProperties(cx, nobj)) {
return false;
}
// Prepare the elements. We have to do this before we mark the object
// non-extensible; that's fine because these changes are not observable.
if (!ObjectElements::PreventExtensions(cx, &obj->as<NativeObject>())) {
if (!ObjectElements::PrepareForPreventExtensions(cx, nobj)) {
return false;
}
}
// Finally, set the NOT_EXTENSIBLE flag on the BaseShape and ObjectElements.
if (!JSObject::setFlags(cx, obj, BaseShape::NOT_EXTENSIBLE,
JSObject::GENERATE_SHAPE)) {
return false;
}
if (obj->is<NativeObject>()) {
ObjectElements::PreventExtensions(&obj->as<NativeObject>());
}
return result.succeed();
}
@ -3553,10 +3558,13 @@ void JSObject::dump(js::GenericPrinter& out) const {
if (!nobj->denseElementsArePacked()) {
out.put(" non_packed_elements");
}
if (nobj->denseElementsAreSealed()) {
if (nobj->getElementsHeader()->isNotExtensible()) {
out.put(" not_extensible");
}
if (nobj->getElementsHeader()->isSealed()) {
out.put(" sealed_elements");
}
if (nobj->denseElementsAreFrozen()) {
if (nobj->getElementsHeader()->isFrozen()) {
out.put(" frozen_elements");
}
if (nobj->getElementsHeader()->maybeInIteration()) {

Просмотреть файл

@ -294,20 +294,6 @@ inline void NativeObject::moveDenseElements(uint32_t dstStart,
}
}
inline void NativeObject::moveDenseElementsNoPreBarrier(uint32_t dstStart,
uint32_t srcStart,
uint32_t count) {
MOZ_ASSERT(!zone()->needsIncrementalBarrier());
MOZ_ASSERT(dstStart + count <= getDenseCapacity());
MOZ_ASSERT(srcStart + count <= getDenseCapacity());
MOZ_ASSERT(!denseElementsAreCopyOnWrite());
MOZ_ASSERT(isExtensible());
memmove(elements_ + dstStart, elements_ + srcStart, count * sizeof(HeapSlot));
elementsRangeWriteBarrierPost(dstStart, count);
}
inline void NativeObject::reverseDenseElementsNoPreBarrier(uint32_t length) {
MOZ_ASSERT(!zone()->needsIncrementalBarrier());
@ -615,11 +601,18 @@ inline js::gc::AllocKind NativeObject::allocKindForTenure() const {
inline js::GlobalObject& NativeObject::global() const { return nonCCWGlobal(); }
inline bool NativeObject::denseElementsMaybeInIteration() {
inline bool NativeObject::denseElementsHaveMaybeInIterationFlag() {
if (!getElementsHeader()->maybeInIteration()) {
AssertDenseElementsNotIterated(this);
return false;
}
return true;
}
inline bool NativeObject::denseElementsMaybeInIteration() {
if (!denseElementsHaveMaybeInIterationFlag()) {
return false;
}
return ObjectRealm::get(this).objectMaybeInIteration(this);
}

Просмотреть файл

@ -129,7 +129,8 @@ bool ObjectElements::MakeElementsCopyOnWrite(JSContext* cx, NativeObject* obj) {
}
/* static */
bool ObjectElements::PreventExtensions(JSContext* cx, NativeObject* obj) {
bool ObjectElements::PrepareForPreventExtensions(JSContext* cx,
NativeObject* obj) {
if (!obj->maybeCopyElementsForWrite(cx)) {
return false;
}
@ -145,6 +146,18 @@ bool ObjectElements::PreventExtensions(JSContext* cx, NativeObject* obj) {
return true;
}
/* static */
void ObjectElements::PreventExtensions(NativeObject* obj) {
MOZ_ASSERT(!obj->denseElementsAreCopyOnWrite());
MOZ_ASSERT(!obj->isExtensible());
MOZ_ASSERT(obj->getElementsHeader()->numShiftedElements() == 0);
MOZ_ASSERT(obj->getDenseInitializedLength() == obj->getDenseCapacity());
if (!obj->hasEmptyElements()) {
obj->getElementsHeader()->setNotExtensible();
}
}
/* static */
bool ObjectElements::FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
IntegrityLevel level) {

Просмотреть файл

@ -200,9 +200,14 @@ class ObjectElements {
// is created and never changed.
SHARED_MEMORY = 0x8,
// These elements are set to integrity level "sealed". This flag should
// only be set on non-extensible objects.
SEALED = 0x10,
// These elements are not extensible. If this flag is set, the object's
// BaseShape must also have the NOT_EXTENSIBLE flag. This exists on
// ObjectElements in addition to BaseShape to simplify JIT code.
NOT_EXTENSIBLE = 0x10,
// These elements are set to integrity level "sealed". If this flag is
// set, the NOT_EXTENSIBLE flag must be set as well.
SEALED = 0x20,
// These elements are set to integrity level "frozen". If this flag is
// set, the SEALED flag must be set as well.
@ -211,17 +216,17 @@ class ObjectElements {
// The BaseShape flag ensures a shape guard can be used to guard against
// frozen elements. The ObjectElements flag is convenient for JIT code and
// ObjectElements assertions.
FROZEN = 0x20,
FROZEN = 0x40,
// If this flag is not set, the elements are guaranteed to contain no hole
// values (the JS_ELEMENTS_HOLE MagicValue) in [0, initializedLength).
NON_PACKED = 0x40,
NON_PACKED = 0x80,
// If this flag is not set, there's definitely no for-in iterator that
// covers these dense elements so elements can be deleted without calling
// SuppressDeletedProperty. This is used by fast paths for various Array
// builtins. See also NativeObject::denseElementsMaybeInIteration.
MAYBE_IN_ITERATION = 0x80,
MAYBE_IN_ITERATION = 0x100,
};
// The flags word stores both the flags and the number of shifted elements.
@ -295,8 +300,8 @@ class ObjectElements {
void addShiftedElements(uint32_t count) {
MOZ_ASSERT(count < capacity);
MOZ_ASSERT(count < initializedLength);
MOZ_ASSERT(!(flags &
(NONWRITABLE_ARRAY_LENGTH | SEALED | FROZEN | COPY_ON_WRITE)));
MOZ_ASSERT(!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE | SEALED |
FROZEN | COPY_ON_WRITE)));
uint32_t numShifted = numShiftedElements() + count;
MOZ_ASSERT(numShifted <= MaxShiftedElements);
flags = (numShifted << NumShiftedElementsShift) | (flags & FlagsMask);
@ -305,8 +310,8 @@ class ObjectElements {
}
void unshiftShiftedElements(uint32_t count) {
MOZ_ASSERT(count > 0);
MOZ_ASSERT(!(flags &
(NONWRITABLE_ARRAY_LENGTH | SEALED | FROZEN | COPY_ON_WRITE)));
MOZ_ASSERT(!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE | SEALED |
FROZEN | COPY_ON_WRITE)));
uint32_t numShifted = numShiftedElements();
MOZ_ASSERT(count <= numShifted);
numShifted -= count;
@ -324,13 +329,21 @@ class ObjectElements {
void markMaybeInIteration() { flags |= MAYBE_IN_ITERATION; }
bool maybeInIteration() { return flags & MAYBE_IN_ITERATION; }
void setNotExtensible() {
MOZ_ASSERT(!isNotExtensible());
flags |= NOT_EXTENSIBLE;
}
bool isNotExtensible() { return flags & NOT_EXTENSIBLE; }
void seal() {
MOZ_ASSERT(isNotExtensible());
MOZ_ASSERT(!isSealed());
MOZ_ASSERT(!isFrozen());
MOZ_ASSERT(!isCopyOnWrite());
flags |= SEALED;
}
void freeze() {
MOZ_ASSERT(isNotExtensible());
MOZ_ASSERT(isSealed());
MOZ_ASSERT(!isFrozen());
MOZ_ASSERT(!isCopyOnWrite());
@ -390,7 +403,9 @@ class ObjectElements {
static void ConvertElementsToDoubles(JSContext* cx, uintptr_t elements);
static bool MakeElementsCopyOnWrite(JSContext* cx, NativeObject* obj);
static MOZ_MUST_USE bool PreventExtensions(JSContext* cx, NativeObject* obj);
static MOZ_MUST_USE bool PrepareForPreventExtensions(JSContext* cx,
NativeObject* obj);
static void PreventExtensions(NativeObject* obj);
static MOZ_MUST_USE bool FreezeOrSeal(JSContext* cx, HandleNativeObject obj,
IntegrityLevel level);
@ -410,8 +425,9 @@ class ObjectElements {
uint32_t numShiftedElements() const {
uint32_t numShifted = flags >> NumShiftedElementsShift;
MOZ_ASSERT_IF(numShifted > 0, !(flags & (NONWRITABLE_ARRAY_LENGTH | SEALED |
FROZEN | COPY_ON_WRITE)));
MOZ_ASSERT_IF(numShifted > 0,
!(flags & (NONWRITABLE_ARRAY_LENGTH | NOT_EXTENSIBLE |
SEALED | FROZEN | COPY_ON_WRITE)));
return numShifted;
}
@ -1314,8 +1330,6 @@ class NativeObject : public JSObject {
uint32_t srcStart, uint32_t count);
inline void moveDenseElements(uint32_t dstStart, uint32_t srcStart,
uint32_t count);
inline void moveDenseElementsNoPreBarrier(uint32_t dstStart,
uint32_t srcStart, uint32_t count);
inline void reverseDenseElementsNoPreBarrier(uint32_t length);
inline DenseElementResult setOrExtendDenseElements(
@ -1360,6 +1374,7 @@ class NativeObject : public JSObject {
// Note that it's fine to return false if this object is on the prototype of
// another object: SuppressDeletedProperty only suppresses properties deleted
// from the iterated object itself.
inline bool denseElementsHaveMaybeInIterationFlag();
inline bool denseElementsMaybeInIteration();
// Ensures that the object can hold at least index + extra elements. This

Просмотреть файл

@ -281,7 +281,7 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle<JSScript*> script,
int64_t len = -1;
rv = chan->GetContentLength(&len);
if (NS_FAILED(rv) || len == -1) {
if (NS_FAILED(rv)) {
ReportError(cx, LOAD_ERROR_NOCONTENT, uri);
return false;
}
@ -295,6 +295,21 @@ bool mozJSSubScriptLoader::ReadScript(JS::MutableHandle<JSScript*> script,
rv = NS_ReadInputStreamToString(instream, buf, len);
NS_ENSURE_SUCCESS(rv, false);
if (len < 0) {
len = buf.Length();
}
#ifdef DEBUG
int64_t currentLength = -1;
// if getting content length succeeded above, it should not fail now
MOZ_ASSERT(chan->GetContentLength(&currentLength) == NS_OK);
// if content length was not known when GetContentLength() was called before,
// 'len' would be set to -1 until NS_ReadInputStreamToString() set its correct
// value. Every subsequent call to GetContentLength() should return the same
// length as that value.
MOZ_ASSERT(currentLength == len);
#endif
Maybe<JSAutoRealm> ar;
// Note that when using the ScriptPreloader cache with loadSubScript, there

Просмотреть файл

@ -2556,12 +2556,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
auto inlineAxisAlignment =
isOrthogonal ? stylePos->UsedAlignSelf(GetParent()->Style())._0
: stylePos->UsedJustifySelf(GetParent()->Style())._0;
// Note: 'normal' means 'start' for elements with an intrinsic size
// or ratio in the relevant dimension, otherwise 'stretch'.
// https://drafts.csswg.org/css-grid/#grid-item-sizing
if ((inlineAxisAlignment == StyleAlignFlags::NORMAL &&
!hasIntrinsicISize && !logicalRatio) ||
inlineAxisAlignment == StyleAlignFlags::STRETCH) {
if (inlineAxisAlignment == StyleAlignFlags::STRETCH) {
stretchI = eStretch;
}
}
@ -2624,12 +2619,7 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
auto blockAxisAlignment =
!isOrthogonal ? stylePos->UsedAlignSelf(GetParent()->Style())._0
: stylePos->UsedJustifySelf(GetParent()->Style())._0;
// Note: 'normal' means 'start' for elements with an intrinsic size
// or ratio in the relevant dimension, otherwise 'stretch'.
// https://drafts.csswg.org/css-grid/#grid-item-sizing
if ((blockAxisAlignment == StyleAlignFlags::NORMAL &&
!hasIntrinsicBSize && !logicalRatio) ||
blockAxisAlignment == StyleAlignFlags::STRETCH) {
if (blockAxisAlignment == StyleAlignFlags::STRETCH) {
stretchB = eStretch;
}
}
@ -2717,33 +2707,31 @@ LogicalSize nsContainerFrame::ComputeSizeWithIntrinsicDimensions(
stretchB = (stretchI == eStretch ? eStretch : eStretchPreservingRatio);
}
if (logicalRatio) {
if (stretchI == eStretch) {
tentISize = iSize; // * / 'stretch'
if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / 'stretch'
} else if (stretchB == eStretchPreservingRatio) {
// 'normal' / 'stretch'
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
}
} else if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / * (except 'stretch')
if (stretchI == eStretchPreservingRatio) {
// 'stretch' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchI == eStretchPreservingRatio) {
tentISize = iSize; // * (except 'stretch') / 'normal'
if (stretchI == eStretch) {
tentISize = iSize; // * / 'stretch'
if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / 'stretch'
} else if (stretchB == eStretchPreservingRatio && logicalRatio) {
// 'normal' / 'stretch'
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
// Stretch within the CB size with preserved intrinsic ratio.
tentBSize = bSize; // 'normal' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchB == eStretchPreservingRatio) {
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
}
} else if (stretchB == eStretch) {
tentBSize = bSize; // 'stretch' / * (except 'stretch')
if (stretchI == eStretchPreservingRatio && logicalRatio) {
// 'stretch' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchI == eStretchPreservingRatio && logicalRatio) {
tentISize = iSize; // * (except 'stretch') / 'normal'
tentBSize = logicalRatio.Inverted().ApplyTo(iSize);
if (stretchB == eStretchPreservingRatio && tentBSize > bSize) {
// Stretch within the CB size with preserved intrinsic ratio.
tentBSize = bSize; // 'normal' / 'normal'
tentISize = logicalRatio.ApplyTo(bSize);
}
} else if (stretchB == eStretchPreservingRatio && logicalRatio) {
tentBSize = bSize; // 'normal' / * (except 'normal' and 'stretch')
tentISize = logicalRatio.ApplyTo(bSize);
}
// ComputeAutoSizeWithIntrinsicDimensions preserves the ratio when

Просмотреть файл

@ -206,6 +206,21 @@ nsresult nsPrintObject::InitAsRootObject(nsIDocShell* aDocShell, Document* aDoc,
mozilla::Unused << nsDocShell::Cast(mDocShell)->GetDocument();
}
// If we are cloning from a document in a different BrowsingContext, we need
// to make sure to copy over our opener policy information from that
// BrowsingContext.
BrowsingContext* targetBC = mDocShell->GetBrowsingContext();
BrowsingContext* sourceBC = aDoc->GetBrowsingContext();
NS_ENSURE_STATE(sourceBC);
if (targetBC != sourceBC) {
MOZ_ASSERT(targetBC->IsTopContent());
// In the case where the source is an iframe, this information needs to be
// copied from the toplevel source BrowsingContext, as we may be making a
// static clone of a single subframe.
MOZ_ALWAYS_SUCCEEDS(
targetBC->SetOpenerPolicy(sourceBC->Top()->GetOpenerPolicy()));
}
mDocument = aDoc->CreateStaticClone(mDocShell);
NS_ENSURE_STATE(mDocument);
mHasSelection = CachePrintSelectionRanges(*aDoc, *mDocument);

Просмотреть файл

@ -88,7 +88,8 @@ if CONFIG['CPU_ARCH'] in ('x86', 'x86_64'):
'../../../third_party/dav1d/src/x86/itx.asm',
'../../../third_party/dav1d/src/x86/loopfilter.asm',
'../../../third_party/dav1d/src/x86/looprestoration.asm',
'../../../third_party/dav1d/src/x86/mc.asm',
'../../../third_party/dav1d/src/x86/mc_avx2.asm',
'../../../third_party/dav1d/src/x86/mc_avx512.asm',
]
SOURCES += [

Просмотреть файл

@ -20,11 +20,11 @@ origin:
# Human-readable identifier for this version/release
# Generally "version NNN", "tag SSS", "bookmark SSS"
release: commit be1fe18e2f2e6802bf696bc5cbddfd24fb2bc748 (2020-06-25T02:34:01.000+02:00).
release: commit 6cf58c8e7deb54e287afeee6710b2a3774eded9c (2020-07-20T15:40:01.000+02:00).
# Revision to pull in
# Must be a long or short commit SHA (long preferred)
revision: be1fe18e2f2e6802bf696bc5cbddfd24fb2bc748
revision: 6cf58c8e7deb54e287afeee6710b2a3774eded9c
# The package's license, where possible using the mnemonic from
# https://spdx.org/licenses/

Просмотреть файл

@ -1,2 +1,2 @@
/* auto-generated, do not edit */
#define DAV1D_VERSION "0.7.1-9-gbe1fe18"
#define DAV1D_VERSION "0.7.1-36-g6cf58c8"

Просмотреть файл

@ -555,6 +555,12 @@ WebrtcTCPSocket::OnTransportAvailable(nsISocketTransport* aTransport,
return NS_OK;
}
NS_IMETHODIMP
WebrtcTCPSocket::OnWebSocketConnectionAvailable(
nsIWebSocketConnection* aConnection) {
return NS_OK;
}
void WebrtcTCPSocket::FinishOpen() {
MOZ_ASSERT(OnSocketThread());
// mTransport, mSocketIn, and mSocketOut are all set. We may have set them in

Просмотреть файл

@ -9633,6 +9633,11 @@
value: false
mirror: always
- name: webgl.enable-debug-renderer-info
type: RelaxedAtomicBool
value: true
mirror: always
- name: webgl.enable-draft-extensions
type: RelaxedAtomicBool
value: false

Просмотреть файл

@ -3775,7 +3775,6 @@ pref("image.http.accept", "");
// Allows image locking of decoded image data in content processes.
pref("image.mem.allow_locking_in_content_processes", true);
pref("webgl.enable-debug-renderer-info", true);
pref("webgl.renderer-string-override", "");
pref("webgl.vendor-string-override", "");

Просмотреть файл

@ -11,6 +11,7 @@
#include "HttpTransactionChild.h"
#include "AltSvcTransactionChild.h"
#include "EventTokenBucket.h"
#include "mozilla/net/WebSocketConnectionChild.h"
#include "nsHttpConnectionInfo.h"
#include "nsHttpConnectionMgr.h"
#include "nsHttpHandler.h"
@ -177,5 +178,25 @@ mozilla::ipc::IPCResult HttpConnectionMgrChild::RecvSpeculativeConnect(
return IPC_OK();
}
already_AddRefed<PWebSocketConnectionChild>
HttpConnectionMgrChild::AllocPWebSocketConnectionChild(
PHttpTransactionChild* aTransWithStickyConn) {
RefPtr<WebSocketConnectionChild> actor = new WebSocketConnectionChild();
return actor.forget();
}
mozilla::ipc::IPCResult
HttpConnectionMgrChild::RecvPWebSocketConnectionConstructor(
PWebSocketConnectionChild* aActor,
PHttpTransactionChild* aTransWithStickyConn) {
RefPtr<WebSocketConnectionChild> child =
static_cast<WebSocketConnectionChild*>(aActor);
nsCOMPtr<nsIHttpUpgradeListener> listener =
static_cast<nsIHttpUpgradeListener*>(child.get());
Unused << mConnMgr->CompleteUpgrade(
ToRealHttpTransaction(aTransWithStickyConn), listener);
return IPC_OK();
}
} // namespace net
} // namespace mozilla

Просмотреть файл

@ -41,6 +41,12 @@ class HttpConnectionMgrChild final : public PHttpConnectionMgrChild {
Maybe<SpeculativeConnectionOverriderArgs> aOverriderArgs, uint32_t aCaps,
Maybe<PAltSvcTransactionChild*> aTrans);
already_AddRefed<PWebSocketConnectionChild> AllocPWebSocketConnectionChild(
PHttpTransactionChild* aTransWithStickyConn);
mozilla::ipc::IPCResult RecvPWebSocketConnectionConstructor(
PWebSocketConnectionChild* aActor,
PHttpTransactionChild* aTransWithStickyConn) override;
private:
virtual ~HttpConnectionMgrChild();

Просмотреть файл

@ -10,6 +10,7 @@
#include "HttpConnectionMgrParent.h"
#include "AltSvcTransactionParent.h"
#include "mozilla/net/HttpTransactionParent.h"
#include "mozilla/net/WebSocketConnectionParent.h"
#include "nsHttpConnectionInfo.h"
#include "nsIInterfaceRequestorUtils.h"
#include "nsISpeculativeConnect.h"
@ -252,8 +253,13 @@ nsresult HttpConnectionMgrParent::ClearConnectionHistory() {
nsresult HttpConnectionMgrParent::CompleteUpgrade(
HttpTransactionShell* aTrans, nsIHttpUpgradeListener* aUpgradeListener) {
// TODO: fix this in bug 1497249
return NS_ERROR_NOT_IMPLEMENTED;
MOZ_ASSERT(aTrans->AsHttpTransactionParent());
RefPtr<WebSocketConnectionParent> wsConnParent =
new WebSocketConnectionParent(aUpgradeListener);
Unused << SendPWebSocketConnectionConstructor(
wsConnParent, aTrans->AsHttpTransactionParent());
return NS_OK;
}
nsHttpConnectionMgr* HttpConnectionMgrParent::AsHttpConnectionMgr() {

Просмотреть файл

@ -8,6 +8,7 @@
include protocol PAltSvcTransaction;
include protocol PSocketProcess;
include protocol PHttpTransaction;
include protocol PWebSocketConnection;
include NeckoChannelParams;
@ -17,6 +18,7 @@ namespace net {
async refcounted protocol PHttpConnectionMgr
{
manager PSocketProcess;
manages PWebSocketConnection;
child:
async __delete__();
@ -33,6 +35,7 @@ child:
async SpeculativeConnect(HttpConnectionInfoCloneArgs aConnInfo,
SpeculativeConnectionOverriderArgs? aOverriderArgs,
uint32_t aCaps, PAltSvcTransaction? aTrans);
async PWebSocketConnection(PHttpTransaction aTransWithStickyConn);
};
} // namespace net

Просмотреть файл

@ -7956,6 +7956,13 @@ nsresult nsHttpChannel::ContinueOnStopRequestAfterAuthRetry(
mResponseHead->Status() == 200;
if (upgradeWebsocket || upgradeConnect) {
// TODO: Support connection upgrade for socket process in bug 1632809.
if (nsIOService::UseSocketProcess() && upgradeConnect) {
Unused << mUpgradeProtocolCallback->OnUpgradeFailed(
NS_ERROR_NOT_IMPLEMENTED);
return ContinueOnStopRequest(aStatus, aIsFromNet, aContentComplete);
}
nsresult rv = gHttpHandler->CompleteUpgrade(aTransWithStickyConn,
mUpgradeProtocolCallback);
if (NS_FAILED(rv)) {

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше