Merge autoland to mozilla-central. a=merge

This commit is contained in:
Cosmin Sabou 2020-08-25 00:49:19 +03:00
commit 12c2218baf
144 changed files with 4195 additions and 1435 deletions

View File

@ -171,8 +171,9 @@ const PluginManager = {
let pluginID = propertyBag.getPropertyAsUint32("pluginID");
let pluginDumpID = propertyBag.getPropertyAsAString("pluginDumpID");
let pluginName = propertyBag.getPropertyAsACString("pluginName");
if (pluginDumpID) {
this.gmpCrashes.set(pluginID, { pluginDumpID, pluginID });
this.gmpCrashes.set(pluginID, { pluginDumpID, pluginID, pluginName });
}
// Only the parent process gets the gmp-plugin-crash observer
@ -182,7 +183,6 @@ const PluginManager = {
// created, which will contact us again, when we'll use the
// gmpCrashes collection to respond.
if (Services.ppmm) {
let pluginName = propertyBag.getPropertyAsAString("pluginName");
Services.ppmm.broadcastAsyncMessage("gmp-plugin-crash", {
pluginName,
pluginID,

View File

@ -92,6 +92,12 @@ const processes = {
ignoreIfUnused: true,
stat: 1,
},
{
path: "*ShaderCache*", // Bug 1660480 - seen on hardware
condition: WIN,
ignoreIfUnused: true,
stat: 3,
},
],
"Privileged Content": [
{

View File

@ -449,6 +449,14 @@ const startupPhases = {
stat: 1,
close: 1,
},
{
// Bug 1660582 - access while running on windows10 hardware.
path: "ProfD:wmfvpxvideo.guard",
condition: WIN,
ignoreIfUnused: true,
stat: 1,
close: 1,
},
],
// Things that are expected to be completely out of the startup path

View File

@ -191,6 +191,18 @@ const startupPhases = {
ignoreIfUnused: true,
maxCount: 1,
},
{
name: "PContent::Reply_BeginDriverCrashGuard",
condition: WIN,
ignoreIfUnused: true, // Bug 1660590 - found while running test on windows hardware
maxCount: 1,
},
{
name: "PContent::Reply_EndDriverCrashGuard",
condition: WIN,
ignoreIfUnused: true, // Bug 1660590 - found while running test on windows hardware
maxCount: 1,
},
],
// Things that are expected to be completely out of the startup path
@ -258,6 +270,12 @@ const startupPhases = {
ignoreIfUnused: true,
maxCount: 1,
},
{
name: "PCompositorBridge::Msg_MakeSnapshot",
condition: WIN,
ignoreIfUnused: true,
maxCount: 1,
},
{
name: "PCompositorBridge::Msg_WillClose",
condition: WIN,

View File

@ -16,10 +16,13 @@ add_task(async function() {
async function(browser) {
// Ensure the parent has heard before the client.
// In practice, this is always true for GMP crashes (but not for NPAPI ones!)
PluginManager.gmpCrashes.set(1, {
pluginID: 1,
pluginName: "GlobalTestPlugin",
});
let props = Cc["@mozilla.org/hash-property-bag;1"].createInstance(
Ci.nsIWritablePropertyBag2
);
props.setPropertyAsUint32("pluginID", 1);
props.setPropertyAsACString("pluginName", "GlobalTestPlugin");
props.setPropertyAsACString("pluginDumpID", "1234");
Services.obs.notifyObservers(props, "gmp-plugin-crash");
await SpecialPowers.spawn(browser, [], async function() {
const GMP_CRASH_EVENT = {

View File

@ -539,6 +539,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
this.showButton("askOpenOrRemoveFile");
break;
case Downloads.Error.BLOCK_VERDICT_INSECURE:
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
this.showButton("askRemoveFileOrAllow");
break;
@ -626,6 +627,8 @@ DownloadsViewUI.DownloadElementShell.prototype = {
switch (this.download.error.reputationCheckVerdict) {
case Downloads.Error.BLOCK_VERDICT_UNCOMMON:
return [s.blockedUncommon2, [s.unblockTypeUncommon2, s.unblockTip2]];
case Downloads.Error.BLOCK_VERDICT_INSECURE:
return [s.blockedInsecure, [s.blockedInsecure, s.unblockTip2]];
case Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED:
return [
s.blockedPotentiallyUnwanted,

View File

@ -8,6 +8,7 @@ add_task(async function mainTest() {
Downloads.Error.BLOCK_VERDICT_UNCOMMON,
Downloads.Error.BLOCK_VERDICT_MALWARE,
Downloads.Error.BLOCK_VERDICT_POTENTIALLY_UNWANTED,
Downloads.Error.BLOCK_VERDICT_INSECURE,
];
await task_addDownloads(verdicts.map(v => makeDownload(v)));

View File

@ -2,6 +2,8 @@
head = head_migration.js
firefox-appdir = browser
skip-if = toolkit == 'android'
prefs =
browser.migrate.showBookmarksToolbarAfterMigration=true
support-files =
Library/**
AppData/**

View File

@ -41,3 +41,42 @@ add_task(async function test_default_bookmark_toolbar_visibility() {
"The bookmarks toolbar should be collapsed by default"
);
});
/**
* Ensure that the bookmarks toolbar is visible in a new profile
* if the toolbar has > 3 (NUM_TOOLBAR_BOOKMARKS_TO_UNHIDE) bookmarks.
*/
add_task(async function test_bookmark_toolbar_visible_when_populated() {
const { Bookmarks } = ChromeUtils.import(
"resource://gre/modules/Bookmarks.jsm"
);
const { PlacesUIUtils } = ChromeUtils.import(
"resource:///modules/PlacesUIUtils.jsm"
);
let bookmark = {
type: Bookmarks.TYPE_BOOKMARK,
parentGuid: Bookmarks.toolbarGuid,
};
let bookmarksInserted = await Promise.all([
Bookmarks.insert(Object.assign({ url: "https://example.com/1" }, bookmark)),
Bookmarks.insert(Object.assign({ url: "https://example.com/2" }, bookmark)),
Bookmarks.insert(Object.assign({ url: "https://example.com/3" }, bookmark)),
Bookmarks.insert(Object.assign({ url: "https://example.com/4" }, bookmark)),
Bookmarks.insert(Object.assign({ url: "https://example.com/5" }, bookmark)),
Bookmarks.insert(Object.assign({ url: "https://example.com/6" }, bookmark)),
]);
PlacesUIUtils.maybeToggleBookmarkToolbarVisibility();
const personalToolbar = document.getElementById("PersonalToolbar");
ok(
!personalToolbar.collapsed,
"The bookmarks toolbar should be visible since it has many bookmarks"
);
for (let insertedBookmark of bookmarksInserted) {
await Bookmarks.remove(insertedBookmark.guid);
}
personalToolbar.collapsed = true;
});

View File

@ -18,6 +18,7 @@
# This is done by taskgraph.
versions: ["<{version.major_number}.0"]
locales:
- an
- ca
- cs
- cy
@ -29,6 +30,7 @@
- es-AR
- es-CL
- fr
- hr
- hsb
- hu
- ia
@ -44,6 +46,7 @@
- pt-BR
- pt-PT
- ro
- ru
- sk
- sl
- sq

View File

@ -100,7 +100,3 @@ browser/chrome/browser/res/activity-stream/data/content/tippytop/favicons/duckdu
browser/chrome/browser/search-extensions/ddg/favicon.ico
browser/chrome/browser/res/activity-stream/data/content/tippytop/favicons/google-com.ico
browser/chrome/browser/search-extensions/google/favicon.ico
# Bug 1660483 - Upstream project files we don't have direct control over
chrome/pdfjs/content/web/images/findbarButton-next.svg
chrome/pdfjs/content/web/images/toolbarButton-menuArrow.svg

View File

@ -32,6 +32,7 @@ stateBlockedParentalControls=Blocked by Parental Controls
# be longer than the other existing status strings.
blockedMalware=This file contains a virus or malware.
blockedPotentiallyUnwanted=This file may harm your computer.
blockedInsecure = This file could not be downloaded securely.
blockedUncommon2=This file is not commonly downloaded.
# LOCALIZATION NOTE (fileMovedOrMissing):

View File

@ -120,15 +120,9 @@ ext.geckoBinariesOnlyIf = { task ->
return false
}
// Multi-l10n builds set `AB_CD=multi`, which isn't a valid locale. This
// causes the
//
// |mach build| > |mach gradle| >
// |mach build mobile/android/base/generated_android_code_and_resources| >
// AndroidManifest.xml > strings.xml > multi/brand.dtd
//
// dependency chain to fail, since multi isn't a real locale. To avoid
// this, if Gradle is invoked with AB_CD=multi, we don't invoke Make at all.
// Multi-l10n builds set `AB_CD=multi`, which isn't a valid locale. To
// avoid failures, if Gradle is invoked with AB_CD=multi, we don't invoke
// Make at all.
if ('multi' == System.env.AB_CD) {
rootProject.logger.lifecycle("Skipping task ${task.path} because: AB_CD=multi")
return false
@ -157,12 +151,6 @@ class MachExec extends Exec {
}
}
// Why |mach build mobile/android/base/...| and |mach build faster|? |mach
// build faster| generates dependentlibs.list, which in turn depends on compiled
// code. That causes a circular dependency between Java compilation/JNI wrapper
// generation/native code compilation. So we have the special target for
// Android-specific generated code, and the |mach build faster| target for all
// the stuff that goes into the omnijar.
task machBuildFaster(type: MachExec) {
onlyIf rootProject.ext.geckoBinariesOnlyIf
@ -183,42 +171,31 @@ task machBuildFaster(type: MachExec) {
errorOutput = standardOutput
}
def createMachStagePackageTask(name) {
return task(name, type: MachExec) {
onlyIf rootProject.ext.geckoBinariesOnlyIf
task machStagePackage(type: MachExec) {
onlyIf rootProject.ext.geckoBinariesOnlyIf
dependsOn rootProject.machBuildFaster
dependsOn rootProject.machBuildFaster
workingDir "${topobjdir}"
workingDir "${topobjdir}"
// We'd prefer this to be a `mach` invocation, but `mach build
// mobile/android/installer/stage-package` doesn't work as expected.
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/installer"
args 'stage-package'
// We'd prefer this to be a `mach` invocation, but `mach build
// mobile/android/installer/stage-package` doesn't work as expected.
commandLine mozconfig.substs.GMAKE
args '-C'
args "${topobjdir}/mobile/android/installer"
args 'stage-package'
outputs.file "${topobjdir}/dist/fennec/assets/${mozconfig.substs.ANDROID_CPU_ARCH}/libxul.so"
outputs.file "${topobjdir}/dist/fennec/lib/${mozconfig.substs.ANDROID_CPU_ARCH}/libmozglue.so"
// Force running `stage-package`.
outputs.upToDateWhen { false }
// `path` is like `:machStagePackage`.
standardOutput = new TaggedLogOutputStream("${path}>", logger)
errorOutput = standardOutput
}
}
createMachStagePackageTask("machStagePackageForFennec").with {
outputs.file "${topobjdir}/dist/fennec/assets/omni.ja"
}
createMachStagePackageTask("machStagePackageForGeckoview").with {
args 'MOZ_GECKOVIEW_JAR=1'
outputs.file "${topobjdir}/dist/geckoview/assets/omni.ja"
// Avoid races between stage-package invocations.
mustRunAfter tasks["machStagePackageForFennec"]
outputs.file "${topobjdir}/dist/geckoview/assets/${mozconfig.substs.ANDROID_CPU_ARCH}/libxul.so"
outputs.file "${topobjdir}/dist/geckoview/lib/${mozconfig.substs.ANDROID_CPU_ARCH}/libmozglue.so"
// Force running `stage-package`.
outputs.upToDateWhen { false }
// `path` is like `:machStagePackage`.
standardOutput = new TaggedLogOutputStream("${path}>", logger)
errorOutput = standardOutput
}
afterEvaluate {

View File

@ -731,7 +731,12 @@ def toolchain_search_path_for(host_or_target):
)]
# Also add the rustup install directory for cargo/rustc.
rustup_path = os.path.expanduser(os.path.join('~', '.cargo', 'bin'))
cargo_home = environ.get('CARGO_HOME', '')
if cargo_home:
cargo_home = os.path.abspath(cargo_home)
else:
cargo_home = os.path.expanduser(os.path.join('~', '.cargo'))
rustup_path = os.path.join(cargo_home, 'bin')
result.append(rustup_path)
if developer_options:

View File

@ -28,3 +28,9 @@ glob:**/moz.build
# Read to set the version of the docs.
path:config/milestone.txt
# metrics.yaml and pings.yaml files (and their index) are needed to generate
# Glean autodocs
glob:**/metrics.yaml
glob:**/pings.yaml
path:toolkit/components/glean/metrics_index.py

View File

@ -877,6 +877,26 @@ NS_IMETHODIMP BasePrincipal::GetIsIpAddress(bool* aIsIpAddress) {
return NS_OK;
}
NS_IMETHODIMP BasePrincipal::GetIsLocalIpAddress(bool* aIsIpAddress) {
*aIsIpAddress = false;
nsCOMPtr<nsIURI> prinURI;
nsresult rv = GetURI(getter_AddRefs(prinURI));
if (NS_FAILED(rv) || !prinURI) {
return NS_OK;
}
nsCOMPtr<nsIIOService> ioService = do_GetIOService(&rv);
if (NS_FAILED(rv) || !ioService) {
return NS_OK;
}
rv = ioService->HostnameIsLocalIPAddress(prinURI, aIsIpAddress);
if (NS_FAILED(rv)) {
*aIsIpAddress = false;
}
return NS_OK;
}
NS_IMETHODIMP
BasePrincipal::GetScheme(nsACString& aScheme) {
aScheme.Truncate();

View File

@ -140,6 +140,7 @@ class BasePrincipal : public nsJSPrincipals {
NS_IMETHOD GetFilePath(nsACString& aResult) override;
NS_IMETHOD GetOriginSuffix(nsACString& aOriginSuffix) final;
NS_IMETHOD GetIsIpAddress(bool* aIsIpAddress) override;
NS_IMETHOD GetIsLocalIpAddress(bool* aIsIpAddress) override;
NS_IMETHOD GetIsOnion(bool* aIsOnion) override;
NS_IMETHOD GetIsInIsolatedMozBrowserElement(
bool* aIsInIsolatedMozBrowserElement) final;

View File

@ -533,6 +533,12 @@ interface nsIPrincipal : nsISerializable
* Returns if the principal is for an IP address.
*/
[infallible] readonly attribute boolean isIpAddress;
/**
* Returns if the principal is for a local IP address.
*/
[infallible] readonly attribute boolean isLocalIpAddress;
};
/**

View File

@ -0,0 +1,62 @@
# Compatibility Panel
## Related files
The compatibility panel consists of the following files:
* Client:
* Main: `devtools/client/inspector/compatibility/`
* Style: `devtools/client/themes/compatibility.css`
* Shared:
* MDN compatibility dataset: `devtools/shared/compatibility/dataset/`
* MDN compatibility library: `devtools/shared/compatibility/MDNCompatibility.js`
* Server:
* Actor: `devtools/server/actors/compatibility.js`
* Front: `devtools/client/fronts/compatibility.js`
* Spec: `devtools/shared/specs/compatibility.js`
## How to update the MDN compatibility data
The Compatibility panel detects issues by comparing against official [MDN compatibility data](https://github.com/mdn/browser-compat-data). It uses a local snapshot of the dataset. This dataset needs to be manually synchronized periodically to `devtools/shared/compatibility/dataset` (ideally with every Firefox release).
The subsets from the dataset required by the Compatibility panel are:
* browsers: [https://github.com/mdn/browser-compat-data/tree/master/browsers](https://github.com/mdn/browser-compat-data/tree/master/browsers)
* css.properties: [https://github.com/mdn/browser-compat-data/tree/master/css](https://github.com/mdn/browser-compat-data/tree/master/css).
The MDN compatibility data is available as a node package ([mdn-browser-compat-data](https://www.npmjs.com/package/mdn-browser-compat-data)).
The following node program is a sample of how to download `browsers.json` and `css-properties.json` using the node package.
```javascript
'use strict';
const compatData = require("mdn-browser-compat-data");
const fs = require("fs")
const path = require("path")
function exportData(data, fileName) {
const content = `${ JSON.stringify(data) }`
fs.writeFile(
path.resolve(
__dirname,
fileName
),
content,
err => {
if (err) {
console.error(err)
}
}
)
}
exportData(compatData.css.properties, "css-properties.json");
exportData(compatData.browsers, "browsers.json");
```
Save the JSON files created by the script to `devtools/shared/compatibility/dataset/`.
Check that all tests still pass. It is possible that changes in the structure or contents of the latest dataset will cause tests to fail. If that is the case, fix the tests. **Do not manually change the contents or structure of the local dataset** because any changes will be overwritten by the next update from the official dataset.
## Tests
* Client: `devtools/client/inspector/compatibility/test`
* MDN compatibility library: `devtools/shared/compatibility/test`
* Server: `devtools/server/tests/browser/browser_compatibility_cssIssues.js`

View File

@ -207,6 +207,10 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
targetActor.chromeEventHandler
);
this.isOverflowDebuggingEnabled = Services.prefs.getBoolPref(
"devtools.overflow.debugging.enabled"
);
// In this map, the key-value pairs are the overflow causing elements and their
// respective ancestor scrollable node actor.
this.overflowCausingElementsMap = new Map();
@ -606,7 +610,7 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
actor.wasScrollable = isScrollable;
}
if (isScrollable) {
if (this.isOverflowDebuggingEnabled && isScrollable) {
this.updateOverflowCausingElements(
actor,
currentOverflowCausingElementsMap
@ -614,19 +618,25 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
}
}
// Get the NodeActor for each node in the symmetric difference of
// currentOverflowCausingElementsMap and this.overflowCausingElementsMap
const overflowStateChanges = [...currentOverflowCausingElementsMap.keys()]
.filter(node => !this.overflowCausingElementsMap.has(node))
.concat(
[...this.overflowCausingElementsMap.keys()].filter(
node => !currentOverflowCausingElementsMap.has(node)
if (this.isOverflowDebuggingEnabled) {
// Get the NodeActor for each node in the symmetric difference of
// currentOverflowCausingElementsMap and this.overflowCausingElementsMap
const overflowStateChanges = [...currentOverflowCausingElementsMap.keys()]
.filter(node => !this.overflowCausingElementsMap.has(node))
.concat(
[...this.overflowCausingElementsMap.keys()].filter(
node => !currentOverflowCausingElementsMap.has(node)
)
)
)
.filter(node => this.hasNode(node))
.map(node => this.getNode(node));
.filter(node => this.hasNode(node))
.map(node => this.getNode(node));
this.overflowCausingElementsMap = currentOverflowCausingElementsMap;
this.overflowCausingElementsMap = currentOverflowCausingElementsMap;
if (overflowStateChanges.length) {
this.emit("overflow-change", overflowStateChanges);
}
}
if (displayTypeChanges.length) {
this.emit("display-change", displayTypeChanges);
@ -635,10 +645,6 @@ var WalkerActor = protocol.ActorClassWithSpec(walkerSpec, {
if (scrollableStateChanges.length) {
this.emit("scrollable-change", scrollableStateChanges);
}
if (overflowStateChanges.length) {
this.emit("overflow-change", overflowStateChanges);
}
},
/**

View File

@ -27,6 +27,7 @@ EXTRA_PATHS = (
"third_party/python/futures",
"third_party/python/jsmin",
"third_party/python/which",
"toolkit/components/glean/sphinx",
)
sys.path[:0] = [os.path.join(topsrcdir, p) for p in EXTRA_PATHS]
@ -46,6 +47,7 @@ extensions = [
"recommonmark",
"sphinx_copybutton",
"sphinx_markdown_tables",
"glean",
]
# JSDoc must run successfully for dirs specified, so running

View File

@ -48,6 +48,8 @@ categories:
- python
fennec_doc:
- mobile/android
metrics_doc:
- metrics
redirects:
browser/browser: browser

View File

@ -44,6 +44,12 @@ Firefox Source Tree Documentation
{python_doc}
.. toctree::
:caption: Metrics Collected in Firefox
:maxdepth: 1
{metrics_doc}
Indices and tables
==================

View File

@ -51,6 +51,7 @@
#include "nsFocusManager.h"
#include "nsGlobalWindowOuter.h"
#include "nsIObserverService.h"
#include "nsISHistory.h"
#include "nsContentUtils.h"
#include "nsQueryObject.h"
#include "nsSandboxFlags.h"
@ -2595,6 +2596,50 @@ bool BrowsingContext::IsPopupAllowed() {
return false;
}
void BrowsingContext::SetActiveSessionHistoryEntryForTop(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
uint32_t aLoadType) {
if (XRE_IsContentProcess()) {
nsID changeID = {};
RefPtr<ChildSHistory> shistory = GetChildSessionHistory();
if (shistory) {
changeID = shistory->AddPendingHistoryChange(1, 1);
}
ContentChild::GetSingleton()->SendSetActiveSessionHistoryEntryForTop(
this, aPreviousScrollPos, *aInfo, aLoadType, changeID);
} else {
Canonical()->SetActiveSessionHistoryEntryForTop(aPreviousScrollPos, aInfo,
aLoadType, nsID());
}
}
void BrowsingContext::SetActiveSessionHistoryEntryForFrame(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
int32_t aChildOffset) {
if (XRE_IsContentProcess()) {
nsID changeID = {};
RefPtr<ChildSHistory> shistory = GetChildSessionHistory();
if (shistory) {
changeID = shistory->AddPendingHistoryChange(1, 1);
}
ContentChild::GetSingleton()->SendSetActiveSessionHistoryEntryForFrame(
this, aPreviousScrollPos, *aInfo, aChildOffset, changeID);
} else {
Canonical()->SetActiveSessionHistoryEntryForFrame(aPreviousScrollPos, aInfo,
aChildOffset, nsID());
}
}
void BrowsingContext::ReplaceActiveSessionHistoryEntry(
SessionHistoryInfo* aInfo) {
if (XRE_IsContentProcess()) {
ContentChild::GetSingleton()->SendReplaceActiveSessionHistoryEntry(this,
*aInfo);
} else {
Canonical()->ReplaceActiveSessionHistoryEntry(aInfo);
}
}
} // namespace dom
namespace ipc {

View File

@ -36,6 +36,7 @@ class nsGlobalWindowInner;
class nsGlobalWindowOuter;
class nsIPrincipal;
class nsOuterWindowProxy;
struct nsPoint;
class PickleIterator;
namespace IPC {
@ -63,6 +64,9 @@ class ContentParent;
class Element;
template <typename>
struct Nullable;
template <typename T>
class Sequence;
class SessionHistoryInfo;
class SessionStorageManager;
class StructuredCloneHolder;
class WindowContext;
@ -631,6 +635,24 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
// context or any of its ancestors.
bool IsPopupAllowed();
// Set a new active entry on this browsing context. Should only be called if
// IsTop() returns true. This is used for implementing
// history.pushState/replaceState.
void SetActiveSessionHistoryEntryForTop(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
uint32_t aLoadType);
// Set a new active entry on this browsing context. Should only be called if
// IsTop() returns false. This is used for implementing
// history.pushState/replaceState.
void SetActiveSessionHistoryEntryForFrame(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
int32_t aChildOffset);
// Replace the active entry for this browsing context. This is used for
// implementing history.replaceState.
void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo);
protected:
virtual ~BrowsingContext();
BrowsingContext(WindowContext* aParentWindow, BrowsingContextGroup* aGroup,

View File

@ -403,12 +403,74 @@ void CanonicalBrowsingContext::NotifyOnHistoryReload(
shistory->GetRequestedIndex(&requestedIndex);
shistory->GetCount(&length);
aLoadState.ref()->SetLoadIsFromSessionHistory(
requestedIndex >= 0 ? requestedIndex : index, length);
requestedIndex >= 0 ? requestedIndex : index, length,
aReloadActiveEntry.value());
}
// If we don't have an active entry and we don't have a loading entry then
// the nsDocShell will create a load state based on its document.
}
void CanonicalBrowsingContext::SetActiveSessionHistoryEntryForTop(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
uint32_t aLoadType, const nsID& aChangeID) {
RefPtr<SessionHistoryEntry> oldActiveEntry = mActiveEntry;
if (aPreviousScrollPos.isSome() && oldActiveEntry) {
oldActiveEntry->SetScrollPosition(aPreviousScrollPos.ref().x,
aPreviousScrollPos.ref().y);
}
RefPtr<SessionHistoryEntry> newEntry = new SessionHistoryEntry(aInfo);
mActiveEntry = newEntry;
Maybe<int32_t> previousEntryIndex, loadedEntryIndex;
nsISHistory* shistory = GetSessionHistory();
if (shistory) {
shistory->AddToRootSessionHistory(
true, oldActiveEntry, this, newEntry, aLoadType,
nsDocShell::ShouldAddToSessionHistory(aInfo->GetURI(), nullptr),
&previousEntryIndex, &loadedEntryIndex);
// FIXME Need to do the equivalent of EvictContentViewersOrReplaceEntry.
Group()->EachParent([&](ContentParent* aParent) {
int32_t index = 0;
shistory->GetIndex(&index);
Unused << aParent->SendHistoryCommitIndexAndLength(
Top(), index, shistory->GetCount(), aChangeID);
});
}
}
void CanonicalBrowsingContext::SetActiveSessionHistoryEntryForFrame(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
int32_t aChildOffset, const nsID& aChangeID) {
RefPtr<SessionHistoryEntry> oldActiveEntry = mActiveEntry;
if (aPreviousScrollPos.isSome() && oldActiveEntry) {
oldActiveEntry->SetScrollPosition(aPreviousScrollPos.ref().x,
aPreviousScrollPos.ref().y);
}
RefPtr<SessionHistoryEntry> newEntry = new SessionHistoryEntry(aInfo);
mActiveEntry = newEntry;
nsISHistory* shistory = GetSessionHistory();
if (oldActiveEntry) {
if (shistory) {
shistory->AddChildSHEntryHelper(oldActiveEntry, newEntry, Top(), true);
}
} else if (GetParent() && GetParent()->mActiveEntry) {
GetParent()->mActiveEntry->AddChild(newEntry, aChildOffset,
UseRemoteSubframes());
}
// FIXME Need to do the equivalent of EvictContentViewersOrReplaceEntry.
Group()->EachParent([&](ContentParent* aParent) {
int32_t index = 0;
shistory->GetIndex(&index);
Unused << aParent->SendHistoryCommitIndexAndLength(
Top(), index, shistory->GetCount(), aChangeID);
});
}
void CanonicalBrowsingContext::ReplaceActiveSessionHistoryEntry(
SessionHistoryInfo* aInfo) {
mActiveEntry->SetInfo(aInfo);
// FIXME Need to do the equivalent of EvictContentViewersOrReplaceEntry.
}
JSObject* CanonicalBrowsingContext::WrapObject(
JSContext* aCx, JS::Handle<JSObject*> aGivenProto) {
return CanonicalBrowsingContext_Binding::Wrap(aCx, this, aGivenProto);

View File

@ -112,6 +112,16 @@ class CanonicalBrowsingContext final : public BrowsingContext {
Maybe<RefPtr<nsDocShellLoadState>>& aLoadState,
Maybe<bool>& aReloadActiveEntry);
void SetActiveSessionHistoryEntryForTop(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
uint32_t aLoadType, const nsID& aChangeID);
void SetActiveSessionHistoryEntryForFrame(
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo* aInfo,
int32_t aChildOffset, const nsID& aChangeID);
void ReplaceActiveSessionHistoryEntry(SessionHistoryInfo* aInfo);
JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;

View File

@ -44,6 +44,7 @@
#include "mozilla/StartupTimeline.h"
#include "mozilla/StorageAccess.h"
#include "mozilla/Telemetry.h"
#include "mozilla/Tuple.h"
#include "mozilla/Unused.h"
#include "mozilla/WidgetUtils.h"
@ -801,7 +802,7 @@ nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
("nsDocShell[%p]: loading %s with flags 0x%08x", this,
aLoadState->URI()->GetSpecOrDefault().get(), aLoadState->LoadFlags()));
if (!aLoadState->SHEntry() &&
if (!aLoadState->LoadIsFromSessionHistory() &&
!LOAD_TYPE_HAS_FLAGS(aLoadState->LoadType(),
LOAD_FLAGS_REPLACE_HISTORY)) {
// This is possibly a subframe, so handle it accordingly.
@ -811,13 +812,19 @@ nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
MaybeHandleSubframeHistory(aLoadState);
}
if (aLoadState->SHEntry()) {
if (aLoadState->LoadIsFromSessionHistory()) {
#ifdef DEBUG
MOZ_LOG(gDocShellLog, LogLevel::Debug,
("nsDocShell[%p]: loading from session history", this));
#endif
return LoadHistoryEntry(aLoadState->SHEntry(), aLoadState->LoadType());
if (!StaticPrefs::fission_sessionHistoryInParent()) {
return LoadHistoryEntry(aLoadState->SHEntry(), aLoadState->LoadType());
}
// FIXME Null check aLoadState->GetLoadingSessionHistoryInfo()?
return LoadHistoryEntry(*aLoadState->GetLoadingSessionHistoryInfo(),
aLoadState->LoadType());
}
// On history navigation via Back/Forward buttons, don't execute
@ -849,8 +856,9 @@ nsDocShell::LoadURI(nsDocShellLoadState* aLoadState, bool aSetNavigating) {
"Typehint should be null when calling InternalLoad from LoadURI");
MOZ_ASSERT(aLoadState->FileName().IsVoid(),
"FileName should be null when calling InternalLoad from LoadURI");
MOZ_ASSERT(aLoadState->SHEntry() == nullptr,
"SHEntry should be null when calling InternalLoad from LoadURI");
MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory(),
"Shouldn't be loading from an entry when calling InternalLoad "
"from LoadURI");
rv = InternalLoad(aLoadState);
NS_ENSURE_SUCCESS(rv, rv);
@ -938,14 +946,14 @@ void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) {
if (parentBusy & BUSY_FLAGS_BUSY || selfBusy & BUSY_FLAGS_BUSY) {
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
aLoadState->SetSHEntry(nullptr);
aLoadState->ClearLoadIsFromSessionHistory();
}
return;
}
// This is a newly created frame. Check for exception cases first.
// By default the subframe will inherit the parent's loadType.
if (aLoadState->SHEntry() &&
if (aLoadState->LoadIsFromSessionHistory() &&
(parentLoadType == LOAD_NORMAL || parentLoadType == LOAD_LINK ||
parentLoadType == LOAD_NORMAL_EXTERNAL)) {
// The parent was loaded normally. In this case, this *brand new*
@ -958,14 +966,14 @@ void nsDocShell::MaybeHandleSubframeHistory(nsDocShellLoadState* aLoadState) {
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
if (inOnLoadHandler) {
aLoadState->SetLoadType(LOAD_NORMAL_REPLACE);
aLoadState->SetSHEntry(nullptr);
aLoadState->ClearLoadIsFromSessionHistory();
}
} else if (parentLoadType == LOAD_REFRESH) {
// Clear shEntry. For refresh loads, we have to load
// what comes through the pipe, not what's in history.
aLoadState->SetSHEntry(nullptr);
aLoadState->ClearLoadIsFromSessionHistory();
} else if ((parentLoadType == LOAD_BYPASS_HISTORY) ||
(aLoadState->SHEntry() &&
(aLoadState->LoadIsFromSessionHistory() &&
((parentLoadType & LOAD_CMD_HISTORY) ||
(parentLoadType == LOAD_RELOAD_NORMAL) ||
(parentLoadType == LOAD_RELOAD_CHARSET_CHANGE) ||
@ -5432,7 +5440,7 @@ nsresult nsDocShell::Embed(nsIContentViewer* aContentViewer,
} else {
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
if (rootSH) {
if (!loadingEntry->mIsLoadFromSessionHistory) {
if (!loadingEntry->mLoadIsFromSessionHistory) {
changeID = rootSH->AddPendingHistoryChange();
} else {
// This is a load from session history, so we can update
@ -8229,7 +8237,7 @@ nsresult nsDocShell::PerformRetargeting(nsDocShellLoadState* aLoadState) {
// LOAD_LINK.
MOZ_ASSERT(aLoadState->LoadType() == LOAD_LINK ||
aLoadState->LoadType() == LOAD_NORMAL_REPLACE);
MOZ_ASSERT(!aLoadState->SHEntry());
MOZ_ASSERT(!aLoadState->LoadIsFromSessionHistory());
MOZ_ASSERT(aLoadState->FirstParty()); // Windowwatcher will assume this.
RefPtr<nsDocShellLoadState> loadState =
@ -8359,25 +8367,32 @@ bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
}
}
if (mOSHE && aLoadState->SHEntry()) {
// We're doing a history load.
if (StaticPrefs::fission_sessionHistoryInParent()) {
if (mActiveEntry && aLoadState->LoadIsFromSessionHistory()) {
aState.mHistoryNavBetweenSameDoc = mActiveEntry->SharesDocumentWith(
aLoadState->GetLoadingSessionHistoryInfo()->mInfo);
}
} else {
if (mOSHE && aLoadState->LoadIsFromSessionHistory()) {
// We're doing a history load.
mOSHE->SharesDocumentWith(aLoadState->SHEntry(),
&aState.mHistoryNavBetweenSameDoc);
mOSHE->SharesDocumentWith(aLoadState->SHEntry(),
&aState.mHistoryNavBetweenSameDoc);
}
}
#ifdef DEBUG
if (aState.mHistoryNavBetweenSameDoc) {
nsCOMPtr<nsIInputStream> currentPostData;
if (StaticPrefs::fission_sessionHistoryInParent()) {
currentPostData = mActiveEntry->GetPostData();
} else {
currentPostData = mOSHE->GetPostData();
}
NS_ASSERTION(currentPostData == aLoadState->PostDataStream(),
"Different POST data for entries for the same page?");
if (aState.mHistoryNavBetweenSameDoc) {
nsCOMPtr<nsIInputStream> currentPostData;
if (StaticPrefs::fission_sessionHistoryInParent()) {
currentPostData = mActiveEntry->GetPostData();
} else {
currentPostData = mOSHE->GetPostData();
}
#endif
NS_ASSERTION(currentPostData == aLoadState->PostDataStream(),
"Different POST data for entries for the same page?");
}
#endif
// A same document navigation happens when we navigate between two SHEntries
// for the same document. We do a same document navigation under two
@ -8393,12 +8408,23 @@ bool nsDocShell::IsSameDocumentNavigation(nsDocShellLoadState* aLoadState,
// The restriction that the SHEntries in (a) must be different ensures
// that history.go(0) and the like trigger full refreshes, rather than
// same document navigations.
bool doSameDocumentNavigation =
(aState.mHistoryNavBetweenSameDoc && mOSHE != aLoadState->SHEntry()) ||
(!aLoadState->SHEntry() && !aLoadState->PostDataStream() &&
aState.mSameExceptHashes && aState.mNewURIHasRef);
if (!StaticPrefs::fission_sessionHistoryInParent()) {
bool doSameDocumentNavigation =
(aState.mHistoryNavBetweenSameDoc && mOSHE != aLoadState->SHEntry()) ||
(!aLoadState->SHEntry() && !aLoadState->PostDataStream() &&
aState.mSameExceptHashes && aState.mNewURIHasRef);
return doSameDocumentNavigation;
return doSameDocumentNavigation;
}
if (aState.mHistoryNavBetweenSameDoc &&
!aLoadState->GetLoadingSessionHistoryInfo()->mLoadingCurrentActiveEntry) {
return true;
}
return !aLoadState->LoadIsFromSessionHistory() &&
!aLoadState->PostDataStream() && aState.mSameExceptHashes &&
aState.mNewURIHasRef;
}
nsresult nsDocShell::HandleSameDocumentNavigation(
@ -8499,7 +8525,7 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
// Link our new SHEntry to the old SHEntry's back/forward
// cache data, since the two SHEntries correspond to the
// same document.
if (mLoadingEntry && !mLoadingEntry->mIsLoadFromSessionHistory) {
if (mLoadingEntry && !mLoadingEntry->mLoadIsFromSessionHistory) {
// If we're not doing a history load, scroll restoration
// should be inherited from the previous session history entry.
// XXX This needs most probably tweaks once fragment navigation is fixed
@ -8508,7 +8534,7 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
scrollRestorationIsManual);
}
if (mLSHE) {
if (!aLoadState->SHEntry()) {
if (!aLoadState->LoadIsFromSessionHistory()) {
// If we're not doing a history load, scroll restoration
// should be inherited from the previous session history entry.
SetScrollRestorationIsManualOnHistoryEntry(mLSHE,
@ -8520,11 +8546,13 @@ nsresult nsDocShell::HandleSameDocumentNavigation(
}
// If we're doing a history load, use its scroll restoration state.
if (aLoadState->SHEntry()) {
DebugOnly<nsresult> rv =
aLoadState->SHEntry()->GetScrollRestorationIsManual(
&scrollRestorationIsManual);
MOZ_ASSERT(NS_SUCCEEDED(rv), "Didn't expect this to fail.");
if (aLoadState->LoadIsFromSessionHistory()) {
if (StaticPrefs::fission_sessionHistoryInParent()) {
scrollRestorationIsManual = mActiveEntry->GetScrollRestorationIsManual();
} else {
scrollRestorationIsManual =
aLoadState->SHEntry()->GetScrollRestorationIsManual();
}
}
/* Assign mLSHE to mOSHE. This will either be a new entry created
@ -8910,7 +8938,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState) {
if (mLoadType != LOAD_ERROR_PAGE) {
SetHistoryEntryAndUpdateBC(Some<nsISHEntry*>(aLoadState->SHEntry()),
Nothing());
if (aLoadState->SHEntry()) {
if (aLoadState->LoadIsFromSessionHistory() &&
!StaticPrefs::fission_sessionHistoryInParent()) {
// We're making history navigation or a reload. Make sure our history ID
// points to the same ID as SHEntry's docshell ID.
aLoadState->SHEntry()->GetDocshellID(mHistoryID);
@ -8922,7 +8951,8 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState) {
mSavingOldViewer = savePresentation;
// If we have a saved content viewer in history, restore and show it now.
if (aLoadState->SHEntry() && (mLoadType & LOAD_CMD_HISTORY)) {
if (aLoadState->LoadIsFromSessionHistory() &&
(mLoadType & LOAD_CMD_HISTORY)) {
// https://html.spec.whatwg.org/#history-traversal:
// To traverse the history
// "If entry has a different Document object than the current entry, then
@ -8934,47 +8964,48 @@ nsresult nsDocShell::InternalLoad(nsDocShellLoadState* aLoadState) {
if (shistory) {
shistory->RemovePendingHistoryNavigations();
}
// It's possible that the previous viewer of mContentViewer is the
// viewer that will end up in aLoadState->SHEntry() when it gets closed. If
// that's the case, we need to go ahead and force it into its shentry so we
// can restore it.
if (mContentViewer) {
nsCOMPtr<nsIContentViewer> prevViewer =
mContentViewer->GetPreviousViewer();
if (prevViewer) {
if (!StaticPrefs::fission_sessionHistoryInParent()) {
// It's possible that the previous viewer of mContentViewer is the
// viewer that will end up in aLoadState->SHEntry() when it gets closed.
// If that's the case, we need to go ahead and force it into its shentry
// so we can restore it.
if (mContentViewer) {
nsCOMPtr<nsIContentViewer> prevViewer =
mContentViewer->GetPreviousViewer();
if (prevViewer) {
#ifdef DEBUG
nsCOMPtr<nsIContentViewer> prevPrevViewer =
prevViewer->GetPreviousViewer();
NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
nsCOMPtr<nsIContentViewer> prevPrevViewer =
prevViewer->GetPreviousViewer();
NS_ASSERTION(!prevPrevViewer, "Should never have viewer chain here");
#endif
nsCOMPtr<nsISHEntry> viewerEntry;
prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
if (viewerEntry == aLoadState->SHEntry()) {
// Make sure this viewer ends up in the right place
mContentViewer->SetPreviousViewer(nullptr);
prevViewer->Destroy();
nsCOMPtr<nsISHEntry> viewerEntry;
prevViewer->GetHistoryEntry(getter_AddRefs(viewerEntry));
if (viewerEntry == aLoadState->SHEntry()) {
// Make sure this viewer ends up in the right place
mContentViewer->SetPreviousViewer(nullptr);
prevViewer->Destroy();
}
}
}
}
nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
bool restoring;
rv = RestorePresentation(aLoadState->SHEntry(), &restoring);
if (restoring) {
Telemetry::Accumulate(Telemetry::BFCACHE_PAGE_RESTORED, true);
return rv;
}
Telemetry::Accumulate(Telemetry::BFCACHE_PAGE_RESTORED, false);
// We failed to restore the presentation, so clean up.
// Both the old and new history entries could potentially be in
// an inconsistent state.
if (NS_FAILED(rv)) {
if (oldEntry) {
oldEntry->SyncPresentationState();
nsCOMPtr<nsISHEntry> oldEntry = mOSHE;
bool restoring;
rv = RestorePresentation(aLoadState->SHEntry(), &restoring);
if (restoring) {
Telemetry::Accumulate(Telemetry::BFCACHE_PAGE_RESTORED, true);
return rv;
}
Telemetry::Accumulate(Telemetry::BFCACHE_PAGE_RESTORED, false);
aLoadState->SHEntry()->SyncPresentationState();
// We failed to restore the presentation, so clean up.
// Both the old and new history entries could potentially be in
// an inconsistent state.
if (NS_FAILED(rv)) {
if (oldEntry) {
oldEntry->SyncPresentationState();
}
aLoadState->SHEntry()->SyncPresentationState();
}
}
}
@ -10245,7 +10276,11 @@ bool nsDocShell::OnNewURI(nsIURI* aURI, nsIChannel* aChannel,
(IsForceReloadType(aLoadType) && IsFrame()));
// Create SH Entry (mLSHE) only if there is a SessionHistory object in the
// in the root browsing context.
// root browsing context.
// FIXME If session history in the parent is enabled then we only do this if
// the session history object is in process, otherwise we can't really
// use the mLSHE anyway. Once session history is only stored in the
// parent then this code will probably be removed anyway.
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
if (!rootSH) {
updateSHistory = false;
@ -10613,6 +10648,23 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
NS_ENSURE_TRUE(mOSHE || aReplace, NS_ERROR_FAILURE);
nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
// If this push/replaceState changed the document's current URI and the new
// URI differs from the old URI in more than the hash, or if the old
// SHEntry's URI was modified in this way by a push/replaceState call
// set URIWasModified to true for the current SHEntry (bug 669671).
bool sameExceptHashes = true;
aNewURI->EqualsExceptRef(aCurrentURI, &sameExceptHashes);
bool uriWasModified;
if (sameExceptHashes) {
if (StaticPrefs::fission_sessionHistoryInParent()) {
uriWasModified = mActiveEntry && mActiveEntry->GetURIWasModified();
} else {
uriWasModified = oldOSHE && oldOSHE->GetURIWasModified();
}
} else {
uriWasModified = true;
}
mLoadType = LOAD_PUSHSTATE;
nsCOMPtr<nsISHEntry> newSHEntry;
@ -10626,49 +10678,63 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
shistory->RemovePendingHistoryNavigations();
}
// Save the current scroll position (bug 590573). Step 2.3.
nsPoint scrollPos = GetCurScrollPos();
mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
bool scrollRestorationIsManual;
if (StaticPrefs::fission_sessionHistoryInParent()) {
scrollRestorationIsManual = mActiveEntry->GetScrollRestorationIsManual();
} else {
// Save the current scroll position (bug 590573). Step 2.3.
mOSHE->SetScrollPosition(scrollPos.x, scrollPos.y);
scrollRestorationIsManual = mOSHE->GetScrollRestorationIsManual();
}
nsCOMPtr<nsIContentSecurityPolicy> csp = aDocument->GetCsp();
// Since we're not changing which page we have loaded, pass
// true for aCloneChildren.
nsresult rv = AddToSessionHistory(
aNewURI, nullptr,
aDocument->NodePrincipal(), // triggeringPrincipal
nullptr, nullptr, csp, true, getter_AddRefs(newSHEntry));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
// Session history entries created by pushState inherit scroll restoration
// mode from the current entry.
newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
// Link the new SHEntry to the old SHEntry's BFCache entry, since the
// two entries correspond to the same document.
NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE), NS_ERROR_FAILURE);
// Set the new SHEntry's title (bug 655273).
nsString title;
if (StaticPrefs::fission_sessionHistoryInParent()) {
title = mActiveEntry->GetTitle();
nsString title(mActiveEntry->GetTitle());
UpdateActiveEntry(false,
/* aPreviousScrollPos = */ Some(scrollPos), aNewURI,
/* aOriginalURI = */ nullptr,
/* aTriggeringPrincipal = */ aDocument->NodePrincipal(),
csp, title, Some(scrollRestorationIsManual), aData,
uriWasModified);
} else {
mOSHE->GetTitle(title);
}
newSHEntry->SetTitle(title);
// Since we're not changing which page we have loaded, pass
// true for aCloneChildren.
nsresult rv = AddToSessionHistory(
aNewURI, nullptr,
aDocument->NodePrincipal(), // triggeringPrincipal
nullptr, nullptr, csp, true, getter_AddRefs(newSHEntry));
NS_ENSURE_SUCCESS(rv, rv);
// AddToSessionHistory may not modify mOSHE. In case it doesn't,
// we'll just set mOSHE here.
mOSHE = newSHEntry;
NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
// Session history entries created by pushState inherit scroll restoration
// mode from the current entry.
newSHEntry->SetScrollRestorationIsManual(scrollRestorationIsManual);
nsString title;
mOSHE->GetTitle(title);
// Set the new SHEntry's title (bug 655273).
newSHEntry->SetTitle(title);
// Link the new SHEntry to the old SHEntry's BFCache entry, since the
// two entries correspond to the same document.
NS_ENSURE_SUCCESS(newSHEntry->AdoptBFCacheEntry(oldOSHE),
NS_ERROR_FAILURE);
// AddToSessionHistory may not modify mOSHE. In case it doesn't,
// we'll just set mOSHE here.
mOSHE = newSHEntry;
}
} else if (StaticPrefs::fission_sessionHistoryInParent()) {
UpdateActiveEntry(
true, /* aPreviousScrollPos = */ Nothing(), aNewURI, aNewURI,
aDocument->NodePrincipal(), aDocument->GetCsp(), EmptyString(),
/* aScrollRestorationIsManual = */ Nothing(), aData, uriWasModified);
} else {
// Step 3.
newSHEntry = mOSHE;
@ -10684,6 +10750,7 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
NS_ENSURE_SUCCESS(rv, rv);
mOSHE = newSHEntry;
}
newSHEntry->SetURI(aNewURI);
newSHEntry->SetOriginalURI(aNewURI);
// Setting the resultPrincipalURI to nullptr is fine here: it will cause
@ -10693,31 +10760,26 @@ nsresult nsDocShell::UpdateURLAndHistory(Document* aDocument, nsIURI* aNewURI,
newSHEntry->SetLoadReplace(false);
}
// Step 2.4 and 3: Modify new/original session history entry and clear its
// POST data, if there is any.
newSHEntry->SetStateData(aData);
newSHEntry->SetPostData(nullptr);
if (!StaticPrefs::fission_sessionHistoryInParent()) {
// Step 2.4 and 3: Modify new/original session history entry and clear its
// POST data, if there is any.
newSHEntry->SetStateData(aData);
newSHEntry->SetPostData(nullptr);
// If this push/replaceState changed the document's current URI and the new
// URI differs from the old URI in more than the hash, or if the old
// SHEntry's URI was modified in this way by a push/replaceState call
// set URIWasModified to true for the current SHEntry (bug 669671).
bool sameExceptHashes = true;
aNewURI->EqualsExceptRef(aCurrentURI, &sameExceptHashes);
bool oldURIWasModified = oldOSHE && oldOSHE->GetURIWasModified();
newSHEntry->SetURIWasModified(!sameExceptHashes || oldURIWasModified);
newSHEntry->SetURIWasModified(uriWasModified);
// Step E as described at the top of AddState: If aReplace is false,
// indicating that we're doing a pushState rather than a replaceState, notify
// bfcache that we've added a page to the history so it can evict content
// viewers if appropriate. Otherwise call ReplaceEntry so that we notify
// nsIHistoryListeners that an entry was replaced. We may not have a root
// session history if this call is coming from a document.open() in a docshell
// subtree that disables session history.
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
if (rootSH) {
rootSH->LegacySHistory()->EvictContentViewersOrReplaceEntry(newSHEntry,
aReplace);
// Step E as described at the top of AddState: If aReplace is false,
// indicating that we're doing a pushState rather than a replaceState,
// notify bfcache that we've added a page to the history so it can evict
// content viewers if appropriate. Otherwise call ReplaceEntry so that we
// notify nsIHistoryListeners that an entry was replaced. We may not have a
// root session history if this call is coming from a document.open() in a
// docshell subtree that disables session history.
RefPtr<ChildSHistory> rootSH = GetRootSessionHistory();
if (rootSH) {
rootSH->LegacySHistory()->EvictContentViewersOrReplaceEntry(newSHEntry,
aReplace);
}
}
// Step 4: If the document's URI changed, update document's URI and update
@ -10827,6 +10889,7 @@ void nsDocShell::SetCacheKeyOnHistoryEntry(nsISHEntry* aSHEntry,
}
}
/* static */
bool nsDocShell::ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel) {
// I believe none of the about: urls should go in the history. But then
// that could just be me... If the intent is only deny about:blank then we
@ -11082,6 +11145,58 @@ nsresult nsDocShell::AddToSessionHistory(
return rv;
}
void nsDocShell::UpdateActiveEntry(
bool aReplace, const Maybe<nsPoint>& aPreviousScrollPos, nsIURI* aURI,
nsIURI* aOriginalURI, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, const nsAString& aTitle,
const Maybe<bool>& aScrollRestorationIsManual,
nsIStructuredCloneContainer* aData, bool aURIWasModified) {
MOZ_ASSERT(StaticPrefs::fission_sessionHistoryInParent());
MOZ_ASSERT(aURI, "uri is null");
MOZ_ASSERT(mLoadType == LOAD_PUSHSTATE,
"This code only deals with pushState");
MOZ_ASSERT_IF(aPreviousScrollPos.isSome(), !aReplace);
if (!aReplace || !mActiveEntry) {
if (mActiveEntry) {
// Link this entry to the previous active entry.
mActiveEntry =
MakeUnique<SessionHistoryInfo>(*mActiveEntry, aURI, HistoryID());
} else {
mActiveEntry = MakeUnique<SessionHistoryInfo>(
aURI, HistoryID(), aTriggeringPrincipal, aCsp, mContentTypeHint);
}
mActiveEntry->SetTitle(aTitle);
mActiveEntry->SetStateData(static_cast<nsStructuredCloneContainer*>(aData));
mActiveEntry->SetURIWasModified(aURIWasModified);
if (aScrollRestorationIsManual.isSome()) {
mActiveEntry->SetScrollRestorationIsManual(
aScrollRestorationIsManual.value());
}
if (mBrowsingContext->IsTop()) {
mBrowsingContext->SetActiveSessionHistoryEntryForTop(
aPreviousScrollPos, mActiveEntry.get(), mLoadType);
// FIXME Do we need to update mPreviousEntryIndex and mLoadedEntryIndex?
} else {
// FIXME We should probably just compute mChildOffset in the parent
// instead of passing it over IPC here.
mBrowsingContext->SetActiveSessionHistoryEntryForFrame(
aPreviousScrollPos, mActiveEntry.get(), mChildOffset);
}
} else {
mActiveEntry->SetResultPrincipalURI(nullptr);
mActiveEntry->SetLoadReplace(false);
mActiveEntry->SetStateData(static_cast<nsStructuredCloneContainer*>(aData));
mActiveEntry->SetPostData(nullptr);
mActiveEntry->SetURIWasModified(aURIWasModified);
if (aScrollRestorationIsManual.isSome()) {
mActiveEntry->SetScrollRestorationIsManual(
aScrollRestorationIsManual.value());
}
mBrowsingContext->ReplaceActiveSessionHistoryEntry(mActiveEntry.get());
}
}
nsresult nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) {
NS_ENSURE_TRUE(aEntry, NS_ERROR_FAILURE);
@ -11099,6 +11214,13 @@ nsresult nsDocShell::LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType) {
return LoadHistoryEntry(loadState, aLoadType, aEntry == mOSHE);
}
nsresult nsDocShell::LoadHistoryEntry(const LoadingSessionHistoryInfo& aEntry,
uint32_t aLoadType) {
RefPtr<nsDocShellLoadState> loadState = aEntry.CreateLoadInfo();
return LoadHistoryEntry(loadState, aLoadType,
aEntry.mLoadingCurrentActiveEntry);
}
nsresult nsDocShell::LoadHistoryEntry(nsDocShellLoadState* aLoadState,
uint32_t aLoadType,
bool aReloadingActiveEntry) {

View File

@ -502,6 +502,10 @@ class nsDocShell final : public nsDocLoader,
void SetLoadingSessionHistoryInfo(
const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo);
static bool ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel);
bool IsOSHE(nsISHEntry* aEntry) const { return mOSHE == aEntry; }
private: // member functions
friend class nsDSURIContentListener;
friend class FramingChecker;
@ -594,8 +598,6 @@ class nsDocShell final : public nsDocLoader,
// Session History
//
bool ShouldAddToSessionHistory(nsIURI* aURI, nsIChannel* aChannel);
// Either aChannel or aOwner must be null. If aChannel is
// present, the owner should be gotten from it.
// If aCloneChildren is true, then our current session history's
@ -614,6 +616,13 @@ class nsDocShell final : public nsDocLoader,
nsIContentSecurityPolicy* aCsp,
bool aCloneChildren, nsISHEntry** aNewEntry);
void UpdateActiveEntry(
bool aReplace, const mozilla::Maybe<nsPoint>& aPreviousScrollPos,
nsIURI* aURI, nsIURI* aOriginalURI, nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp, const nsAString& aTitle,
const mozilla::Maybe<bool>& aScrollRestorationIsManual,
nsIStructuredCloneContainer* aData, bool aURIWasModified);
nsresult AddChildSHEntryToParent(nsISHEntry* aNewEntry, int32_t aChildOffset,
bool aCloneChildren);
@ -981,6 +990,9 @@ class nsDocShell final : public nsDocLoader,
nsPresContext* GetEldestPresContext();
nsresult CheckLoadingPermissions();
nsresult LoadHistoryEntry(nsISHEntry* aEntry, uint32_t aLoadType);
nsresult LoadHistoryEntry(
const mozilla::dom::LoadingSessionHistoryInfo& aEntry,
uint32_t aLoadType);
nsresult LoadHistoryEntry(nsDocShellLoadState* aLoadState, uint32_t aLoadType,
bool aReloadingActiveEntry);
nsresult GetHttpChannel(nsIChannel* aChannel, nsIHttpChannel** aReturn);

View File

@ -78,7 +78,7 @@ nsDocShellLoadState::nsDocShellLoadState(
mChannelInitialized = aLoadState.ChannelInitialized();
if (aLoadState.loadingSessionHistoryInfo().isSome()) {
mLoadingSessionHistoryInfo = MakeUnique<LoadingSessionHistoryInfo>(
aLoadState.loadingSessionHistoryInfo().value());
aLoadState.loadingSessionHistoryInfo().ref());
}
}
@ -528,14 +528,30 @@ nsDocShellLoadState::GetLoadingSessionHistoryInfo() const {
}
void nsDocShellLoadState::SetLoadIsFromSessionHistory(
int32_t aRequestedIndex, int32_t aSessionHistoryLength) {
int32_t aRequestedIndex, int32_t aSessionHistoryLength,
bool aLoadingFromActiveEntry) {
if (mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo->mIsLoadFromSessionHistory = true;
mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = true;
mLoadingSessionHistoryInfo->mRequestedIndex = aRequestedIndex;
mLoadingSessionHistoryInfo->mSessionHistoryLength = aSessionHistoryLength;
mLoadingSessionHistoryInfo->mLoadingCurrentActiveEntry =
aLoadingFromActiveEntry;
}
}
void nsDocShellLoadState::ClearLoadIsFromSessionHistory() {
if (mLoadingSessionHistoryInfo) {
mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory = false;
}
mSHEntry = nullptr;
}
bool nsDocShellLoadState::LoadIsFromSessionHistory() const {
return mLoadingSessionHistoryInfo
? mLoadingSessionHistoryInfo->mLoadIsFromSessionHistory
: !!mSHEntry;
}
const nsString& nsDocShellLoadState::Target() const { return mTarget; }
void nsDocShellLoadState::SetTarget(const nsAString& aTarget) {

View File

@ -144,6 +144,8 @@ class nsDocShellLoadState final {
void SetLoadingSessionHistoryInfo(
const mozilla::dom::LoadingSessionHistoryInfo& aLoadingInfo);
bool LoadIsFromSessionHistory() const;
const nsString& Target() const;
void SetTarget(const nsAString& aTarget);
@ -279,7 +281,9 @@ class nsDocShellLoadState final {
mozilla::dom::DocShellLoadStateInit Serialize();
void SetLoadIsFromSessionHistory(int32_t aRequestedIndex,
int32_t aSessionHistoryLength);
int32_t aSessionHistoryLength,
bool aLoadingFromActiveEntry);
void ClearLoadIsFromSessionHistory();
protected:
// Destructor can't be defaulted or inlined, as header doesn't have all type

View File

@ -10,6 +10,7 @@
#include "nsStructuredCloneContainer.h"
#include "nsXULAppAPI.h"
#include "mozilla/PresState.h"
#include "mozilla/dom/nsCSPContext.h"
#include "mozilla/ipc/IPDLParamTraits.h"
namespace mozilla {
@ -23,15 +24,16 @@ SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
mReferrerInfo(aLoadState->GetReferrerInfo()),
mPostData(aLoadState->PostDataStream()),
mLoadType(aLoadState->LoadType()),
mScrollPositionX(0),
mScrollPositionY(0),
mSrcdocData(aLoadState->SrcdocData()),
mBaseURI(aLoadState->BaseURI()),
mLoadReplace(aLoadState->LoadReplace()),
mURIWasModified(false),
/* FIXME Should this be aLoadState->IsSrcdocLoad()? */
mIsSrcdocEntry(!aLoadState->SrcdocData().IsEmpty()),
mScrollRestorationIsManual(false) {
mSharedState(SharedState::Create(
aLoadState->TriggeringPrincipal(), aLoadState->PrincipalToInherit(),
aLoadState->PartitionedPrincipalToInherit(), aLoadState->Csp(),
/* FIXME Is this correct? */
aLoadState->TypeHint())) {
MaybeUpdateTitleFromURI();
bool isNoStore = false;
if (nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(aChannel)) {
@ -40,6 +42,61 @@ SessionHistoryInfo::SessionHistoryInfo(nsDocShellLoadState* aLoadState,
}
}
SessionHistoryInfo::SessionHistoryInfo(
const SessionHistoryInfo& aSharedStateFrom, nsIURI* aURI,
const nsID& aDocShellID)
: mURI(aURI), mSharedState(aSharedStateFrom.mSharedState) {
MaybeUpdateTitleFromURI();
}
SessionHistoryInfo::SessionHistoryInfo(nsIURI* aURI, const nsID& aDocShellID,
nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType)
: mURI(aURI),
mSharedState(SharedState::Create(aTriggeringPrincipal, nullptr, nullptr,
aCsp, aContentType)) {
MaybeUpdateTitleFromURI();
}
void SessionHistoryInfo::Reset(nsIURI* aURI, const nsID& aDocShellID,
bool aDynamicCreation,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType) {
mURI = aURI;
mOriginalURI = nullptr;
mResultPrincipalURI = nullptr;
mReferrerInfo = nullptr;
// Default title is the URL.
nsAutoCString spec;
if (NS_SUCCEEDED(mURI->GetSpec(spec))) {
CopyUTF8toUTF16(spec, mTitle);
}
mPostData = nullptr;
mLoadType = 0;
mScrollPositionX = 0;
mScrollPositionY = 0;
mStateData = nullptr;
mSrcdocData.Truncate();
mBaseURI = nullptr;
mLoadReplace = false;
mURIWasModified = false;
mIsSrcdocEntry = false;
mScrollRestorationIsManual = false;
mPersist = false;
mSharedState.Get()->mTriggeringPrincipal = aTriggeringPrincipal;
mSharedState.Get()->mPrincipalToInherit = aPrincipalToInherit;
mSharedState.Get()->mPartitionedPrincipalToInherit =
aPartitionedPrincipalToInherit;
mSharedState.Get()->mCsp = aCsp;
mSharedState.Get()->mContentType = aContentType;
mSharedState.Get()->mLayoutHistoryState = nullptr;
}
void SessionHistoryInfo::MaybeUpdateTitleFromURI() {
if (mTitle.IsEmpty() && mURI) {
// Default title is the URL.
@ -50,6 +107,127 @@ void SessionHistoryInfo::MaybeUpdateTitleFromURI() {
}
}
uint64_t SessionHistoryInfo::SharedId() const {
return mSharedState.Get()->mId;
}
nsILayoutHistoryState* SessionHistoryInfo::GetLayoutHistoryState() {
return mSharedState.Get()->mLayoutHistoryState;
}
void SessionHistoryInfo::SetLayoutHistoryState(nsILayoutHistoryState* aState) {
mSharedState.Get()->mLayoutHistoryState = aState;
}
void SessionHistoryInfo::FillLoadInfo(nsDocShellLoadState& aLoadState) const {
aLoadState.SetOriginalURI(mOriginalURI);
aLoadState.SetMaybeResultPrincipalURI(Some(mResultPrincipalURI));
aLoadState.SetLoadReplace(mLoadReplace);
aLoadState.SetPostDataStream(mPostData);
aLoadState.SetReferrerInfo(mReferrerInfo);
aLoadState.SetTypeHint(mSharedState.Get()->mContentType);
aLoadState.SetTriggeringPrincipal(mSharedState.Get()->mTriggeringPrincipal);
aLoadState.SetPrincipalToInherit(mSharedState.Get()->mPrincipalToInherit);
aLoadState.SetPartitionedPrincipalToInherit(
mSharedState.Get()->mPartitionedPrincipalToInherit);
aLoadState.SetCsp(mSharedState.Get()->mCsp);
// Do not inherit principal from document (security-critical!);
uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
// Passing nullptr as aSourceDocShell gives the same behaviour as before
// aSourceDocShell was introduced. According to spec we should be passing
// the source browsing context that was used when the history entry was
// first created. bug 947716 has been created to address this issue.
nsAutoString srcdoc;
nsCOMPtr<nsIURI> baseURI;
if (mIsSrcdocEntry) {
srcdoc = mSrcdocData;
baseURI = mBaseURI;
flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
} else {
srcdoc = VoidString();
}
aLoadState.SetSrcdocData(srcdoc);
aLoadState.SetBaseURI(baseURI);
aLoadState.SetLoadFlags(flags);
aLoadState.SetFirstParty(true);
}
/* static */
SessionHistoryInfo::SharedState SessionHistoryInfo::SharedState::Create(
nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp, const nsACString& aContentType) {
if (XRE_IsParentProcess()) {
return SharedState(new SHEntrySharedParentState(
aTriggeringPrincipal, aPrincipalToInherit,
aPartitionedPrincipalToInherit, aCsp, aContentType));
}
return SharedState(MakeUnique<SHEntrySharedState>(
aTriggeringPrincipal, aPrincipalToInherit, aPartitionedPrincipalToInherit,
aCsp, aContentType));
}
SessionHistoryInfo::SharedState::SharedState() {
if (XRE_IsParentProcess()) {
new (&mParent)
RefPtr<SHEntrySharedParentState>(new SHEntrySharedParentState());
} else {
new (&mChild)
UniquePtr<SHEntrySharedState>(MakeUnique<SHEntrySharedState>());
}
}
SessionHistoryInfo::SharedState::SharedState(
const SessionHistoryInfo::SharedState& aOther) {
if (XRE_IsParentProcess()) {
new (&mParent) RefPtr<SHEntrySharedParentState>(aOther.mParent);
} else {
new (&mChild) UniquePtr<SHEntrySharedState>(
MakeUnique<SHEntrySharedState>(*aOther.mChild));
}
}
SessionHistoryInfo::SharedState::~SharedState() {
if (XRE_IsParentProcess()) {
mParent
.RefPtr<SHEntrySharedParentState>::~RefPtr<SHEntrySharedParentState>();
} else {
mChild.UniquePtr<SHEntrySharedState>::~UniquePtr<SHEntrySharedState>();
}
}
SessionHistoryInfo::SharedState& SessionHistoryInfo::SharedState::operator=(
const SessionHistoryInfo::SharedState& aOther) {
if (this != &aOther) {
if (XRE_IsParentProcess()) {
mParent = aOther.mParent;
} else {
mChild = MakeUnique<SHEntrySharedState>(*aOther.mChild);
}
}
return *this;
}
SHEntrySharedState* SessionHistoryInfo::SharedState::Get() const {
if (XRE_IsParentProcess()) {
return mParent;
}
return mChild.get();
}
void SessionHistoryInfo::SharedState::ChangeId(uint64_t aId) {
if (XRE_IsParentProcess()) {
mParent->ChangeId(aId);
} else {
mChild->mId = aId;
}
}
static uint64_t gLoadingSessionHistoryInfoLoadId = 0;
nsDataHashtable<nsUint64HashKey, SessionHistoryEntry*>*
@ -65,6 +243,18 @@ LoadingSessionHistoryInfo::LoadingSessionHistoryInfo(
SessionHistoryEntry::sLoadIdToEntry->Put(mLoadId, aEntry);
}
already_AddRefed<nsDocShellLoadState>
LoadingSessionHistoryInfo::CreateLoadInfo() const {
RefPtr<nsDocShellLoadState> loadState(
new nsDocShellLoadState(mInfo.GetURI()));
mInfo.FillLoadInfo(*loadState);
loadState->SetLoadingSessionHistoryInfo(*this);
return loadState.forget();
}
static uint32_t gEntryID;
SessionHistoryEntry* SessionHistoryEntry::GetByLoadId(uint64_t aLoadId) {
@ -86,22 +276,14 @@ void SessionHistoryEntry::RemoveLoadId(uint64_t aLoadId) {
}
SessionHistoryEntry::SessionHistoryEntry()
: mInfo(new SessionHistoryInfo()),
mSharedInfo(new SHEntrySharedParentState()),
mID(++gEntryID) {}
: mInfo(new SessionHistoryInfo()), mID(++gEntryID) {}
SessionHistoryEntry::SessionHistoryEntry(nsDocShellLoadState* aLoadState,
nsIChannel* aChannel)
: mInfo(new SessionHistoryInfo(aLoadState, aChannel)),
mSharedInfo(new SHEntrySharedParentState()),
mID(++gEntryID) {
mSharedInfo->mTriggeringPrincipal = aLoadState->TriggeringPrincipal();
mSharedInfo->mPrincipalToInherit = aLoadState->PrincipalToInherit();
mSharedInfo->mPartitionedPrincipalToInherit =
aLoadState->PartitionedPrincipalToInherit();
mSharedInfo->mCsp = aLoadState->Csp();
// FIXME Set remaining shared fields!
}
: mInfo(new SessionHistoryInfo(aLoadState, aChannel)), mID(++gEntryID) {}
SessionHistoryEntry::SessionHistoryEntry(SessionHistoryInfo* aInfo)
: mInfo(MakeUnique<SessionHistoryInfo>(*aInfo)), mID(++gEntryID) {}
SessionHistoryEntry::~SessionHistoryEntry() {
if (sLoadIdToEntry) {
@ -181,13 +363,13 @@ SessionHistoryEntry::SetTitle(const nsAString& aTitle) {
NS_IMETHODIMP
SessionHistoryEntry::GetIsSubFrame(bool* aIsSubFrame) {
*aIsSubFrame = mSharedInfo->mIsFrameNavigation;
*aIsSubFrame = SharedInfo()->mIsFrameNavigation;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetIsSubFrame(bool aIsSubFrame) {
mSharedInfo->mIsFrameNavigation = aIsSubFrame;
SharedInfo()->mIsFrameNavigation = aIsSubFrame;
return NS_OK;
}
@ -232,13 +414,13 @@ SessionHistoryEntry::SetContentViewer(nsIContentViewer* aContentViewer) {
NS_IMETHODIMP
SessionHistoryEntry::GetSticky(bool* aSticky) {
*aSticky = mSharedInfo->mSticky;
*aSticky = SharedInfo()->mSticky;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetSticky(bool aSticky) {
mSharedInfo->mSticky = aSticky;
SharedInfo()->mSticky = aSticky;
return NS_OK;
}
@ -283,7 +465,7 @@ NS_IMETHODIMP
SessionHistoryEntry::GetLayoutHistoryState(
nsILayoutHistoryState** aLayoutHistoryState) {
nsCOMPtr<nsILayoutHistoryState> layoutHistoryState =
mSharedInfo->mLayoutHistoryState;
SharedInfo()->mLayoutHistoryState;
layoutHistoryState.forget(aLayoutHistoryState);
return NS_OK;
}
@ -291,7 +473,7 @@ SessionHistoryEntry::GetLayoutHistoryState(
NS_IMETHODIMP
SessionHistoryEntry::SetLayoutHistoryState(
nsILayoutHistoryState* aLayoutHistoryState) {
mSharedInfo->mLayoutHistoryState = aLayoutHistoryState;
SharedInfo()->mLayoutHistoryState = aLayoutHistoryState;
return NS_OK;
}
@ -334,37 +516,37 @@ SessionHistoryEntry::SetID(uint32_t aID) {
NS_IMETHODIMP
SessionHistoryEntry::GetCacheKey(uint32_t* aCacheKey) {
*aCacheKey = mSharedInfo->mCacheKey;
*aCacheKey = SharedInfo()->mCacheKey;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetCacheKey(uint32_t aCacheKey) {
mSharedInfo->mCacheKey = aCacheKey;
SharedInfo()->mCacheKey = aCacheKey;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetSaveLayoutStateFlag(bool* aSaveLayoutStateFlag) {
*aSaveLayoutStateFlag = mSharedInfo->mSaveLayoutState;
*aSaveLayoutStateFlag = SharedInfo()->mSaveLayoutState;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetSaveLayoutStateFlag(bool aSaveLayoutStateFlag) {
mSharedInfo->mSaveLayoutState = aSaveLayoutStateFlag;
SharedInfo()->mSaveLayoutState = aSaveLayoutStateFlag;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetContentType(nsACString& aContentType) {
aContentType = mSharedInfo->mContentType;
aContentType = SharedInfo()->mContentType;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetContentType(const nsACString& aContentType) {
mSharedInfo->mContentType = aContentType;
SharedInfo()->mContentType = aContentType;
return NS_OK;
}
@ -384,7 +566,7 @@ NS_IMETHODIMP
SessionHistoryEntry::GetTriggeringPrincipal(
nsIPrincipal** aTriggeringPrincipal) {
nsCOMPtr<nsIPrincipal> triggeringPrincipal =
mSharedInfo->mTriggeringPrincipal;
SharedInfo()->mTriggeringPrincipal;
triggeringPrincipal.forget(aTriggeringPrincipal);
return NS_OK;
}
@ -392,20 +574,20 @@ SessionHistoryEntry::GetTriggeringPrincipal(
NS_IMETHODIMP
SessionHistoryEntry::SetTriggeringPrincipal(
nsIPrincipal* aTriggeringPrincipal) {
mSharedInfo->mTriggeringPrincipal = aTriggeringPrincipal;
SharedInfo()->mTriggeringPrincipal = aTriggeringPrincipal;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetPrincipalToInherit(nsIPrincipal** aPrincipalToInherit) {
nsCOMPtr<nsIPrincipal> principalToInherit = mSharedInfo->mPrincipalToInherit;
nsCOMPtr<nsIPrincipal> principalToInherit = SharedInfo()->mPrincipalToInherit;
principalToInherit.forget(aPrincipalToInherit);
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetPrincipalToInherit(nsIPrincipal* aPrincipalToInherit) {
mSharedInfo->mPrincipalToInherit = aPrincipalToInherit;
SharedInfo()->mPrincipalToInherit = aPrincipalToInherit;
return NS_OK;
}
@ -413,7 +595,7 @@ NS_IMETHODIMP
SessionHistoryEntry::GetPartitionedPrincipalToInherit(
nsIPrincipal** aPartitionedPrincipalToInherit) {
nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit =
mSharedInfo->mPartitionedPrincipalToInherit;
SharedInfo()->mPartitionedPrincipalToInherit;
partitionedPrincipalToInherit.forget(aPartitionedPrincipalToInherit);
return NS_OK;
}
@ -421,20 +603,20 @@ SessionHistoryEntry::GetPartitionedPrincipalToInherit(
NS_IMETHODIMP
SessionHistoryEntry::SetPartitionedPrincipalToInherit(
nsIPrincipal* aPartitionedPrincipalToInherit) {
mSharedInfo->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
SharedInfo()->mPartitionedPrincipalToInherit = aPartitionedPrincipalToInherit;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetCsp(nsIContentSecurityPolicy** aCsp) {
nsCOMPtr<nsIContentSecurityPolicy> csp = mSharedInfo->mCsp;
nsCOMPtr<nsIContentSecurityPolicy> csp = SharedInfo()->mCsp;
csp.forget(aCsp);
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetCsp(nsIContentSecurityPolicy* aCsp) {
mSharedInfo->mCsp = aCsp;
SharedInfo()->mCsp = aCsp;
return NS_OK;
}
@ -452,7 +634,7 @@ SessionHistoryEntry::SetStateData(nsIStructuredCloneContainer* aStateData) {
}
const nsID& SessionHistoryEntry::DocshellID() const {
return mSharedInfo->mDocShellID;
return SharedInfo()->mDocShellID;
}
NS_IMETHODIMP
@ -463,7 +645,7 @@ SessionHistoryEntry::GetDocshellID(nsID& aDocshellID) {
NS_IMETHODIMP
SessionHistoryEntry::SetDocshellID(const nsID& aDocshellID) {
mSharedInfo->mDocShellID = aDocshellID;
SharedInfo()->mDocShellID = aDocshellID;
return NS_OK;
}
@ -521,7 +703,7 @@ SessionHistoryEntry::GetLoadedInThisProcess(bool* aLoadedInThisProcess) {
NS_IMETHODIMP
SessionHistoryEntry::GetShistory(nsISHistory** aShistory) {
nsCOMPtr<nsISHistory> sHistory = do_QueryReferent(mSharedInfo->mSHistory);
nsCOMPtr<nsISHistory> sHistory = do_QueryReferent(SharedInfo()->mSHistory);
sHistory.forget(aShistory);
return NS_OK;
}
@ -530,20 +712,20 @@ NS_IMETHODIMP
SessionHistoryEntry::SetShistory(nsISHistory* aShistory) {
nsWeakPtr shistory = do_GetWeakReference(aShistory);
// mSHistory can not be changed once it's set
MOZ_ASSERT(!mSharedInfo->mSHistory || (mSharedInfo->mSHistory == shistory));
mSharedInfo->mSHistory = shistory;
MOZ_ASSERT(!SharedInfo()->mSHistory || (SharedInfo()->mSHistory == shistory));
SharedInfo()->mSHistory = shistory;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetLastTouched(uint32_t* aLastTouched) {
*aLastTouched = mSharedInfo->mLastTouched;
*aLastTouched = SharedInfo()->mLastTouched;
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::SetLastTouched(uint32_t aLastTouched) {
mSharedInfo->mLastTouched = aLastTouched;
SharedInfo()->mLastTouched = aLastTouched;
return NS_OK;
}
@ -581,12 +763,12 @@ SessionHistoryEntry::SetScrollPosition(int32_t aX, int32_t aY) {
NS_IMETHODIMP_(void)
SessionHistoryEntry::GetViewerBounds(nsIntRect& bounds) {
bounds = mSharedInfo->mViewerBounds;
bounds = SharedInfo()->mViewerBounds;
}
NS_IMETHODIMP_(void)
SessionHistoryEntry::SetViewerBounds(const nsIntRect& bounds) {
mSharedInfo->mViewerBounds = bounds;
SharedInfo()->mViewerBounds = bounds;
}
NS_IMETHODIMP_(void)
@ -614,7 +796,7 @@ SessionHistoryEntry::SyncPresentationState() {
NS_IMETHODIMP
SessionHistoryEntry::InitLayoutHistoryState(
nsILayoutHistoryState** aLayoutHistoryState) {
if (!mSharedInfo->mLayoutHistoryState) {
if (!SharedInfo()->mLayoutHistoryState) {
nsCOMPtr<nsILayoutHistoryState> historyState;
historyState = NS_NewLayoutHistoryState();
SetLayoutHistoryState(historyState);
@ -662,7 +844,7 @@ SessionHistoryEntry::HasDetachedEditor() {
NS_IMETHODIMP_(bool)
SessionHistoryEntry::IsDynamicallyAdded() {
return mSharedInfo->mDynamicallyCreated;
return SharedInfo()->mDynamicallyCreated;
}
NS_IMETHODIMP
@ -698,8 +880,13 @@ SessionHistoryEntry::AbandonBFCacheEntry() {
NS_IMETHODIMP
SessionHistoryEntry::SharesDocumentWith(nsISHEntry* aEntry,
bool* aSharesDocumentWith) {
MOZ_CRASH("Might need to implement this");
return NS_ERROR_NOT_IMPLEMENTED;
SessionHistoryEntry* entry = static_cast<SessionHistoryEntry*>(aEntry);
MOZ_ASSERT_IF(entry->SharedInfo() != SharedInfo(),
entry->SharedInfo()->GetId() != SharedInfo()->GetId());
*aSharesDocumentWith = entry->SharedInfo() == SharedInfo();
return NS_OK;
}
NS_IMETHODIMP
@ -901,52 +1088,13 @@ SessionHistoryEntry::ClearEntry() {
NS_IMETHODIMP
SessionHistoryEntry::CreateLoadInfo(nsDocShellLoadState** aLoadState) {
nsCOMPtr<nsIURI> uri = GetURI();
RefPtr<nsDocShellLoadState> loadState(new nsDocShellLoadState(mInfo->mURI));
loadState->SetOriginalURI(mInfo->mOriginalURI);
loadState->SetMaybeResultPrincipalURI(Some(mInfo->mResultPrincipalURI));
loadState->SetLoadReplace(mInfo->mLoadReplace);
loadState->SetPostDataStream(mInfo->mPostData);
loadState->SetReferrerInfo(mInfo->mReferrerInfo);
loadState->SetTypeHint(mSharedInfo->mContentType);
loadState->SetTriggeringPrincipal(mSharedInfo->mTriggeringPrincipal);
loadState->SetPrincipalToInherit(mSharedInfo->mPrincipalToInherit);
loadState->SetPartitionedPrincipalToInherit(
mSharedInfo->mPartitionedPrincipalToInherit);
loadState->SetCsp(mSharedInfo->mCsp);
// Do not inherit principal from document (security-critical!);
uint32_t flags = nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_NONE;
// Passing nullptr as aSourceDocShell gives the same behaviour as before
// aSourceDocShell was introduced. According to spec we should be passing
// the source browsing context that was used when the history entry was
// first created. bug 947716 has been created to address this issue.
nsAutoString srcdoc;
nsCOMPtr<nsIURI> baseURI;
if (mInfo->mIsSrcdocEntry) {
srcdoc = mInfo->mSrcdocData;
baseURI = mInfo->mBaseURI;
flags |= nsDocShell::InternalLoad::INTERNAL_LOAD_FLAGS_IS_SRCDOC;
} else {
srcdoc = VoidString();
}
loadState->SetSrcdocData(srcdoc);
loadState->SetBaseURI(baseURI);
loadState->SetLoadFlags(flags);
loadState->SetFirstParty(true);
loadState->SetSHEntry(this);
loadState.forget(aLoadState);
NS_WARNING("We shouldn't be calling this!");
return NS_OK;
}
NS_IMETHODIMP
SessionHistoryEntry::GetBfcacheID(uint64_t* aBfcacheID) {
*aBfcacheID = mSharedInfo->mID;
*aBfcacheID = SharedInfo()->mId;
return NS_OK;
}
@ -957,60 +1105,175 @@ SessionHistoryEntry::SyncTreesForSubframeNavigation(
NS_WARNING("Need to implement this");
}
void SessionHistoryEntry::MaybeSynchronizeSharedStateToInfo(
nsISHEntry* aEntry) {
nsCOMPtr<SessionHistoryEntry> entry = do_QueryInterface(aEntry);
if (!entry) {
return;
}
SHEntrySharedParentState* SessionHistoryEntry::SharedInfo() const {
return static_cast<SHEntrySharedParentState*>(mInfo->mSharedState.Get());
}
entry->mInfo->mCacheKey = entry->mSharedInfo->mCacheKey;
// XXX Add other member variables which live in mSharedInfo.
void SessionHistoryEntry::SetInfo(SessionHistoryInfo* aInfo) {
// FIXME Assert that we're not changing shared state!
mInfo = MakeUnique<SessionHistoryInfo>(*aInfo);
}
} // namespace dom
namespace ipc {
void IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Write(
void IPDLParamTraits<dom::SessionHistoryInfo>::Write(
IPC::Message* aMsg, IProtocol* aActor,
const dom::LoadingSessionHistoryInfo& aParam) {
const dom::SessionHistoryInfo& aParam) {
Maybe<dom::ClonedMessageData> stateData;
if (aParam.mInfo.mStateData) {
if (aParam.mStateData) {
stateData.emplace();
JSStructuredCloneData& data = aParam.mInfo.mStateData->Data();
JSStructuredCloneData& data = aParam.mStateData->Data();
auto iter = data.Start();
bool success;
stateData->data().data = data.Borrow(iter, data.Size(), &success);
if (NS_WARN_IF(!success)) {
return;
}
MOZ_ASSERT(aParam.mInfo.mStateData->PortIdentifiers().IsEmpty() &&
aParam.mInfo.mStateData->BlobImpls().IsEmpty() &&
aParam.mInfo.mStateData->InputStreams().IsEmpty());
MOZ_ASSERT(aParam.mStateData->PortIdentifiers().IsEmpty() &&
aParam.mStateData->BlobImpls().IsEmpty() &&
aParam.mStateData->InputStreams().IsEmpty());
}
const dom::SessionHistoryInfo& info = aParam.mInfo;
WriteIPDLParam(aMsg, aActor, info.mURI);
WriteIPDLParam(aMsg, aActor, info.mOriginalURI);
WriteIPDLParam(aMsg, aActor, info.mResultPrincipalURI);
WriteIPDLParam(aMsg, aActor, info.mReferrerInfo);
WriteIPDLParam(aMsg, aActor, info.mTitle);
WriteIPDLParam(aMsg, aActor, info.mPostData);
WriteIPDLParam(aMsg, aActor, info.mLoadType);
WriteIPDLParam(aMsg, aActor, info.mScrollPositionX);
WriteIPDLParam(aMsg, aActor, info.mScrollPositionY);
WriteIPDLParam(aMsg, aActor, aParam.mURI);
WriteIPDLParam(aMsg, aActor, aParam.mOriginalURI);
WriteIPDLParam(aMsg, aActor, aParam.mResultPrincipalURI);
WriteIPDLParam(aMsg, aActor, aParam.mReferrerInfo);
WriteIPDLParam(aMsg, aActor, aParam.mTitle);
WriteIPDLParam(aMsg, aActor, aParam.mPostData);
WriteIPDLParam(aMsg, aActor, aParam.mLoadType);
WriteIPDLParam(aMsg, aActor, aParam.mScrollPositionX);
WriteIPDLParam(aMsg, aActor, aParam.mScrollPositionY);
WriteIPDLParam(aMsg, aActor, stateData);
WriteIPDLParam(aMsg, aActor, info.mSrcdocData);
WriteIPDLParam(aMsg, aActor, info.mBaseURI);
WriteIPDLParam(aMsg, aActor, info.mLayoutHistoryState);
WriteIPDLParam(aMsg, aActor, info.mLoadReplace);
WriteIPDLParam(aMsg, aActor, info.mURIWasModified);
WriteIPDLParam(aMsg, aActor, info.mIsSrcdocEntry);
WriteIPDLParam(aMsg, aActor, info.mScrollRestorationIsManual);
WriteIPDLParam(aMsg, aActor, info.mPersist);
WriteIPDLParam(aMsg, aActor, aParam.mSrcdocData);
WriteIPDLParam(aMsg, aActor, aParam.mBaseURI);
WriteIPDLParam(aMsg, aActor, aParam.mLoadReplace);
WriteIPDLParam(aMsg, aActor, aParam.mURIWasModified);
WriteIPDLParam(aMsg, aActor, aParam.mIsSrcdocEntry);
WriteIPDLParam(aMsg, aActor, aParam.mScrollRestorationIsManual);
WriteIPDLParam(aMsg, aActor, aParam.mPersist);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mId);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mTriggeringPrincipal);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mPrincipalToInherit);
WriteIPDLParam(aMsg, aActor,
aParam.mSharedState.Get()->mPartitionedPrincipalToInherit);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mCsp);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mContentType);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mLayoutHistoryState);
WriteIPDLParam(aMsg, aActor, aParam.mSharedState.Get()->mCacheKey);
}
bool IPDLParamTraits<dom::SessionHistoryInfo>::Read(
const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
dom::SessionHistoryInfo* aResult) {
Maybe<dom::ClonedMessageData> stateData;
uint64_t sharedId;
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mOriginalURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mResultPrincipalURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mReferrerInfo) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mTitle) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mPostData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mLoadType) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mScrollPositionX) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mScrollPositionY) ||
!ReadIPDLParam(aMsg, aIter, aActor, &stateData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSrcdocData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mBaseURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mLoadReplace) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mURIWasModified) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mIsSrcdocEntry) ||
!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mScrollRestorationIsManual) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mPersist) ||
!ReadIPDLParam(aMsg, aIter, aActor, &sharedId)) {
aActor->FatalError("Error reading fields for SessionHistoryInfo");
return false;
}
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
nsCOMPtr<nsIPrincipal> principalToInherit;
nsCOMPtr<nsIPrincipal> partitionedPrincipalToInherit;
nsCOMPtr<nsIContentSecurityPolicy> csp;
nsCString contentType;
if (!ReadIPDLParam(aMsg, aIter, aActor, &triggeringPrincipal) ||
!ReadIPDLParam(aMsg, aIter, aActor, &principalToInherit) ||
!ReadIPDLParam(aMsg, aIter, aActor, &partitionedPrincipalToInherit) ||
!ReadIPDLParam(aMsg, aIter, aActor, &csp) ||
!ReadIPDLParam(aMsg, aIter, aActor, &contentType)) {
aActor->FatalError("Error reading fields for SessionHistoryInfo");
return false;
}
dom::SHEntrySharedParentState* sharedState = nullptr;
if (XRE_IsParentProcess()) {
sharedState = dom::SHEntrySharedParentState::Lookup(sharedId);
}
if (sharedState) {
aResult->mSharedState.Set(sharedState);
MOZ_ASSERT(triggeringPrincipal
? triggeringPrincipal->Equals(
aResult->mSharedState.Get()->mTriggeringPrincipal)
: !aResult->mSharedState.Get()->mTriggeringPrincipal,
"We don't expect this to change!");
MOZ_ASSERT(principalToInherit
? principalToInherit->Equals(
aResult->mSharedState.Get()->mPrincipalToInherit)
: !aResult->mSharedState.Get()->mPrincipalToInherit,
"We don't expect this to change!");
MOZ_ASSERT(
partitionedPrincipalToInherit
? partitionedPrincipalToInherit->Equals(
aResult->mSharedState.Get()->mPartitionedPrincipalToInherit)
: !aResult->mSharedState.Get()->mPartitionedPrincipalToInherit,
"We don't expect this to change!");
MOZ_ASSERT(
csp ? nsCSPContext::Equals(csp, aResult->mSharedState.Get()->mCsp)
: !aResult->mSharedState.Get()->mCsp,
"We don't expect this to change!");
MOZ_ASSERT(contentType.Equals(aResult->mSharedState.Get()->mContentType),
"We don't expect this to change!");
} else {
aResult->mSharedState.ChangeId(sharedId);
aResult->mSharedState.Get()->mTriggeringPrincipal =
triggeringPrincipal.forget();
aResult->mSharedState.Get()->mPrincipalToInherit =
principalToInherit.forget();
aResult->mSharedState.Get()->mPartitionedPrincipalToInherit =
partitionedPrincipalToInherit.forget();
aResult->mSharedState.Get()->mCsp = csp.forget();
aResult->mSharedState.Get()->mContentType = contentType;
}
if (!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mSharedState.Get()->mLayoutHistoryState) ||
!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mSharedState.Get()->mCacheKey)) {
aActor->FatalError("Error reading fields for SessionHistoryInfo");
return false;
}
if (stateData.isSome()) {
aResult->mStateData = new nsStructuredCloneContainer();
if (aActor->GetSide() == ChildSide) {
UnpackClonedMessageDataForChild(stateData.ref(), *aResult->mStateData);
} else {
UnpackClonedMessageDataForParent(stateData.ref(), *aResult->mStateData);
}
}
MOZ_ASSERT_IF(stateData.isNothing(), !aResult->mStateData);
return true;
}
void IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Write(
IPC::Message* aMsg, IProtocol* aActor,
const dom::LoadingSessionHistoryInfo& aParam) {
WriteIPDLParam(aMsg, aActor, aParam.mInfo);
WriteIPDLParam(aMsg, aActor, aParam.mLoadId);
WriteIPDLParam(aMsg, aActor, aParam.mIsLoadFromSessionHistory);
WriteIPDLParam(aMsg, aActor, aParam.mLoadIsFromSessionHistory);
WriteIPDLParam(aMsg, aActor, aParam.mRequestedIndex);
WriteIPDLParam(aMsg, aActor, aParam.mSessionHistoryLength);
}
@ -1018,44 +1281,16 @@ void IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Write(
bool IPDLParamTraits<dom::LoadingSessionHistoryInfo>::Read(
const IPC::Message* aMsg, PickleIterator* aIter, IProtocol* aActor,
dom::LoadingSessionHistoryInfo* aResult) {
Maybe<dom::ClonedMessageData> stateData;
dom::SessionHistoryInfo& info = aResult->mInfo;
if (!ReadIPDLParam(aMsg, aIter, aActor, &info.mURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mOriginalURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mResultPrincipalURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mReferrerInfo) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mTitle) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mPostData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mLoadType) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mScrollPositionX) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mScrollPositionY) ||
!ReadIPDLParam(aMsg, aIter, aActor, &stateData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mSrcdocData) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mBaseURI) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mLayoutHistoryState) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mLoadReplace) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mURIWasModified) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mIsSrcdocEntry) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mScrollRestorationIsManual) ||
!ReadIPDLParam(aMsg, aIter, aActor, &info.mPersist) ||
if (!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mInfo) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mLoadId) ||
!ReadIPDLParam(aMsg, aIter, aActor,
&aResult->mIsLoadFromSessionHistory) ||
&aResult->mLoadIsFromSessionHistory) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mRequestedIndex) ||
!ReadIPDLParam(aMsg, aIter, aActor, &aResult->mSessionHistoryLength)) {
aActor->FatalError("Error reading fields for SessionHistoryInfo");
aActor->FatalError("Error reading fields for LoadingSessionHistoryInfo");
return false;
}
if (stateData.isSome()) {
info.mStateData = new nsStructuredCloneContainer();
if (aActor->GetSide() == ChildSide) {
UnpackClonedMessageDataForChild(stateData.ref(), *info.mStateData);
} else {
UnpackClonedMessageDataForParent(stateData.ref(), *info.mStateData);
}
}
MOZ_ASSERT_IF(stateData.isNothing(), !info.mStateData);
return true;
}

View File

@ -10,6 +10,7 @@
#include "mozilla/UniquePtr.h"
#include "nsILayoutHistoryState.h"
#include "nsISHEntry.h"
#include "nsSHEntryShared.h"
#include "nsStructuredCloneContainer.h"
#include "nsDataHashtable.h"
@ -32,13 +33,37 @@ class SHEntrySharedParentState;
class SessionHistoryInfo {
public:
SessionHistoryInfo() = default;
SessionHistoryInfo(const SessionHistoryInfo& aInfo) = default;
SessionHistoryInfo(nsDocShellLoadState* aLoadState, nsIChannel* aChannel);
SessionHistoryInfo(const SessionHistoryInfo& aSharedStateFrom, nsIURI* aURI,
const nsID& aDocShellID);
SessionHistoryInfo(nsIURI* aURI, const nsID& aDocShellID,
nsIPrincipal* aTriggeringPrincipal,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType);
void Reset(nsIURI* aURI, const nsID& aDocShellID, bool aDynamicCreation,
nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp, const nsACString& aContentType);
bool operator==(const SessionHistoryInfo& aInfo) const {
return false; // FIXME
}
nsIURI* GetURI() const { return mURI; }
void SetURI(nsIURI* aURI) { mURI = aURI; }
void SetOriginalURI(nsIURI* aOriginalURI) { mOriginalURI = aOriginalURI; }
void SetResultPrincipalURI(nsIURI* aResultPrincipalURI) {
mResultPrincipalURI = aResultPrincipalURI;
}
nsIInputStream* GetPostData() const { return mPostData; }
void SetPostData(nsIInputStream* aPostData) { mPostData = aPostData; }
void GetScrollPosition(int32_t* aScrollPositionX, int32_t* aScrollPositionY) {
*aScrollPositionX = mScrollPositionX;
*aScrollPositionY = mScrollPositionY;
@ -53,21 +78,31 @@ class SessionHistoryInfo {
mScrollRestorationIsManual = aIsManual;
}
void SetCacheKey(uint32_t aCacheKey) { mCacheKey = aCacheKey; }
void SetStateData(nsStructuredCloneContainer* aStateData) {
mStateData = aStateData;
}
nsIURI* GetURI() const { return mURI; }
void SetLoadReplace(bool aLoadReplace) { mLoadReplace = aLoadReplace; }
void SetURIWasModified(bool aURIWasModified) {
mURIWasModified = aURIWasModified;
}
bool GetURIWasModified() const { return mURIWasModified; }
nsILayoutHistoryState* GetLayoutHistoryState() { return mLayoutHistoryState; }
uint64_t SharedId() const;
void SetLayoutHistoryState(nsILayoutHistoryState* aState) {
mLayoutHistoryState = aState;
nsILayoutHistoryState* GetLayoutHistoryState();
void SetLayoutHistoryState(nsILayoutHistoryState* aState);
bool SharesDocumentWith(const SessionHistoryInfo& aOther) const {
return SharedId() == aOther.SharedId();
}
void FillLoadInfo(nsDocShellLoadState& aLoadState) const;
private:
friend class SessionHistoryEntry;
friend struct mozilla::ipc::IPDLParamTraits<LoadingSessionHistoryInfo>;
friend struct mozilla::ipc::IPDLParamTraits<SessionHistoryInfo>;
void MaybeUpdateTitleFromURI();
@ -83,25 +118,54 @@ class SessionHistoryInfo {
RefPtr<nsStructuredCloneContainer> mStateData;
nsString mSrcdocData;
nsCOMPtr<nsIURI> mBaseURI;
// mLayoutHistoryState is used to serialize layout history state across
// IPC. In the parent process this is then synchronized to
// SHEntrySharedParentState::mLayoutHistoryState
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
// mCacheKey is handled similar way to mLayoutHistoryState.
uint32_t mCacheKey = 0;
bool mLoadReplace = false;
bool mURIWasModified = false;
bool mIsSrcdocEntry = false;
bool mScrollRestorationIsManual = false;
bool mPersist = false;
union SharedState {
SharedState();
explicit SharedState(const SharedState& aOther);
~SharedState();
SharedState& operator=(const SharedState& aOther);
SHEntrySharedState* Get() const;
void Set(SHEntrySharedParentState* aState) { mParent = aState; }
void ChangeId(uint64_t aId);
static SharedState Create(nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType);
private:
explicit SharedState(SHEntrySharedParentState* aParent)
: mParent(aParent) {}
explicit SharedState(UniquePtr<SHEntrySharedState>&& aChild)
: mChild(std::move(aChild)) {}
// In the parent process this holds a strong reference to the refcounted
// SHEntrySharedParentState. In the child processes this holds an owning
// pointer to a SHEntrySharedState.
RefPtr<SHEntrySharedParentState> mParent;
UniquePtr<SHEntrySharedState> mChild;
};
SharedState mSharedState;
};
struct LoadingSessionHistoryInfo {
LoadingSessionHistoryInfo() = default;
explicit LoadingSessionHistoryInfo(SessionHistoryEntry* aEntry);
already_AddRefed<nsDocShellLoadState> CreateLoadInfo() const;
SessionHistoryInfo mInfo;
uint64_t mLoadId = 0;
@ -111,11 +175,14 @@ struct LoadingSessionHistoryInfo {
// an nsISHEntry in the nsDocShellLoadState and access to the nsISHistory,
// but session-history-in-parent needs to pass needed information explicitly
// to the relevant child process.
bool mIsLoadFromSessionHistory = false;
// mRequestedIndex and mSessionHistoryLength are relevant
// only if mIsLoadFromSessionHistory is true.
bool mLoadIsFromSessionHistory = false;
// mRequestedIndex, mSessionHistoryLength and mLoadingCurrentActiveEntry are
// relevant only if mLoadIsFromSessionHistory is true.
int32_t mRequestedIndex = -1;
int32_t mSessionHistoryLength = 0;
// If we're loading from the current active entry we want to treat it as not
// a same-document navigation (see nsDocShell::IsSameDocumentNavigation).
bool mLoadingCurrentActiveEntry = false;
};
// SessionHistoryEntry is used to store session history data in the parent
@ -132,6 +199,7 @@ class SessionHistoryEntry : public nsISHEntry {
public:
SessionHistoryEntry(nsDocShellLoadState* aLoadState, nsIChannel* aChannel);
SessionHistoryEntry();
explicit SessionHistoryEntry(SessionHistoryInfo* aInfo);
NS_DECL_ISUPPORTS
NS_DECL_NSISHENTRY
@ -139,6 +207,8 @@ class SessionHistoryEntry : public nsISHEntry {
const SessionHistoryInfo& Info() const { return *mInfo; }
SHEntrySharedParentState* SharedInfo() const;
void AddChild(SessionHistoryEntry* aChild, int32_t aOffset,
bool aUseRemoteSubframes);
void RemoveChild(SessionHistoryEntry* aChild);
@ -147,13 +217,13 @@ class SessionHistoryEntry : public nsISHEntry {
// then it returns false.
bool ReplaceChild(SessionHistoryEntry* aNewChild);
void SetInfo(SessionHistoryInfo* aInfo);
// Get an entry based on LoadingSessionHistoryInfo's mLoadId. Parent process
// only.
static SessionHistoryEntry* GetByLoadId(uint64_t aLoadId);
static void RemoveLoadId(uint64_t aLoadId);
static void MaybeSynchronizeSharedStateToInfo(nsISHEntry* aEntry);
private:
friend struct LoadingSessionHistoryInfo;
virtual ~SessionHistoryEntry();
@ -161,7 +231,6 @@ class SessionHistoryEntry : public nsISHEntry {
const nsID& DocshellID() const;
UniquePtr<SessionHistoryInfo> mInfo;
RefPtr<SHEntrySharedParentState> mSharedInfo;
nsISHEntry* mParent = nullptr;
uint32_t mID;
nsTArray<RefPtr<SessionHistoryEntry>> mChildren;
@ -175,6 +244,15 @@ NS_DEFINE_STATIC_IID_ACCESSOR(SessionHistoryEntry, NS_SESSIONHISTORYENTRY_IID)
namespace ipc {
// Allow sending SessionHistoryInfo objects over IPC.
template <>
struct IPDLParamTraits<dom::SessionHistoryInfo> {
static void Write(IPC::Message* aMsg, IProtocol* aActor,
const dom::SessionHistoryInfo& aParam);
static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
IProtocol* aActor, dom::SessionHistoryInfo* aResult);
};
// Allow sending LoadingSessionHistoryInfo objects over IPC.
template <>
struct IPDLParamTraits<dom::LoadingSessionHistoryInfo> {

View File

@ -1057,6 +1057,6 @@ nsSHEntry::AbandonBFCacheEntry() {
NS_IMETHODIMP
nsSHEntry::GetBfcacheID(uint64_t* aBFCacheID) {
*aBFCacheID = mShared->GetID();
*aBFCacheID = mShared->GetId();
return NS_OK;
}

View File

@ -7,6 +7,7 @@
#include "nsSHEntryShared.h"
#include "nsArray.h"
#include "nsContentUtils.h"
#include "nsDocShellEditorData.h"
#include "nsIContentViewer.h"
#include "nsISHistory.h"
@ -23,24 +24,66 @@ namespace dom = mozilla::dom;
namespace {
uint64_t gSHEntrySharedID = 0;
nsDataHashtable<nsUint64HashKey, mozilla::dom::SHEntrySharedParentState*>*
sIdToSharedState = nullptr;
} // namespace
namespace mozilla {
namespace dom {
SHEntrySharedParentState::SHEntrySharedParentState()
: mDocShellID({0}),
mViewerBounds(0, 0, 0, 0),
mCacheKey(0),
mLastTouched(0),
mID(++gSHEntrySharedID),
mIsFrameNavigation(false),
mSticky(true),
mDynamicallyCreated(false),
mExpired(false),
mSaveLayoutState(true) {}
/* static */
uint64_t SHEntrySharedState::GenerateId() {
return nsContentUtils::GenerateProcessSpecificId(++gSHEntrySharedID);
}
SHEntrySharedParentState::~SHEntrySharedParentState() {}
/* static */
SHEntrySharedParentState* SHEntrySharedParentState::Lookup(uint64_t aId) {
MOZ_ASSERT(aId != 0);
return sIdToSharedState ? sIdToSharedState->Get(aId) : nullptr;
}
static void AddSHEntrySharedParentState(
SHEntrySharedParentState* aSharedState) {
MOZ_ASSERT(aSharedState->mId != 0);
if (!sIdToSharedState) {
sIdToSharedState =
new nsDataHashtable<nsUint64HashKey, SHEntrySharedParentState*>();
}
sIdToSharedState->Put(aSharedState->mId, aSharedState);
}
SHEntrySharedParentState::SHEntrySharedParentState() {
AddSHEntrySharedParentState(this);
}
SHEntrySharedParentState::SHEntrySharedParentState(
nsIPrincipal* aTriggeringPrincipal, nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp, const nsACString& aContentType)
: SHEntrySharedState(aTriggeringPrincipal, aPrincipalToInherit,
aPartitionedPrincipalToInherit, aCsp, aContentType) {
AddSHEntrySharedParentState(this);
}
SHEntrySharedParentState::~SHEntrySharedParentState() {
MOZ_ASSERT(mId != 0);
sIdToSharedState->Remove(mId);
if (sIdToSharedState->IsEmpty()) {
delete sIdToSharedState;
sIdToSharedState = nullptr;
}
}
void SHEntrySharedParentState::ChangeId(uint64_t aId) {
MOZ_ASSERT(aId != 0);
sIdToSharedState->Remove(mId);
mId = aId;
sIdToSharedState->Put(mId, this);
}
void SHEntrySharedParentState::CopyFrom(SHEntrySharedParentState* aEntry) {
mDocShellID = aEntry->mDocShellID;

View File

@ -43,17 +43,68 @@ namespace mozilla {
namespace dom {
class Document;
/**
* SHEntrySharedState holds shared state both in the child process and in the
* parent process.
*/
struct SHEntrySharedState {
SHEntrySharedState() : mId(GenerateId()) {}
SHEntrySharedState(const SHEntrySharedState& aState) = default;
SHEntrySharedState(nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType)
: mId(GenerateId()),
mTriggeringPrincipal(aTriggeringPrincipal),
mPrincipalToInherit(aPrincipalToInherit),
mPartitionedPrincipalToInherit(aPartitionedPrincipalToInherit),
mCsp(aCsp),
mContentType(aContentType) {}
// These members aren't copied by SHEntrySharedParentState::CopyFrom() because
// they're specific to a particular content viewer.
uint64_t mId = 0;
// These members are copied by SHEntrySharedParentState::CopyFrom(). If you
// add a member here, be sure to update the CopyFrom() implementation.
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
nsCOMPtr<nsIPrincipal> mPartitionedPrincipalToInherit;
nsCOMPtr<nsIContentSecurityPolicy> mCsp;
nsCString mContentType;
// Child side updates layout history state when page is being unloaded or
// moved to bfcache.
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
uint32_t mCacheKey = 0;
protected:
static uint64_t GenerateId();
};
/**
* SHEntrySharedParentState holds the shared state that can live in the parent
* process.
*/
class SHEntrySharedParentState {
class SHEntrySharedParentState : public SHEntrySharedState {
public:
uint64_t GetID() const { return mID; }
friend class SessionHistoryInfo;
uint64_t GetId() const { return mId; }
void ChangeId(uint64_t aId);
void NotifyListenersContentViewerEvicted();
SHEntrySharedParentState();
SHEntrySharedParentState(nsIPrincipal* aTriggeringPrincipal,
nsIPrincipal* aPrincipalToInherit,
nsIPrincipal* aPartitionedPrincipalToInherit,
nsIContentSecurityPolicy* aCsp,
const nsACString& aContentType);
// This returns the existing SHEntrySharedParentState that was registered for
// aId, if one exists.
static SHEntrySharedParentState* Lookup(uint64_t aId);
protected:
virtual ~SHEntrySharedParentState();
@ -66,34 +117,24 @@ class SHEntrySharedParentState {
// These members are copied by SHEntrySharedParentState::CopyFrom(). If you
// add a member here, be sure to update the CopyFrom() implementation.
nsID mDocShellID;
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
nsCOMPtr<nsIPrincipal> mPrincipalToInherit;
nsCOMPtr<nsIPrincipal> mPartitionedPrincipalToInherit;
nsCOMPtr<nsIContentSecurityPolicy> mCsp;
// Child side updates layout history state when page is being unloaded or
// moved to bfcache.
nsCOMPtr<nsILayoutHistoryState> mLayoutHistoryState;
nsCString mContentType;
nsID mDocShellID{};
nsIntRect mViewerBounds;
nsIntRect mViewerBounds{0, 0, 0, 0};
uint32_t mCacheKey;
uint32_t mLastTouched;
uint32_t mLastTouched = 0;
// These members aren't copied by SHEntrySharedParentState::CopyFrom() because
// they're specific to a particular content viewer.
uint64_t mID;
nsWeakPtr mSHistory;
bool mIsFrameNavigation;
bool mSticky;
bool mDynamicallyCreated;
bool mIsFrameNavigation = false;
bool mSticky = true;
bool mDynamicallyCreated = false;
// This flag is about necko cache, not bfcache.
bool mExpired;
bool mExpired = false;
bool mSaveLayoutState;
bool mSaveLayoutState = true;
};
/**

View File

@ -1729,9 +1729,22 @@ void nsSHistory::InitiateLoad(nsISHEntry* aFrameEntry,
loadState->SetLoadType(aLoadType);
SessionHistoryEntry::MaybeSynchronizeSharedStateToInfo(aFrameEntry);
loadState->SetSHEntry(aFrameEntry);
loadState->SetLoadIsFromSessionHistory(mRequestedIndex, Length());
// If we're loading from the current active entry we want to treat it as not
// a same-document navigation (see nsDocShell::IsSameDocumentNavigation), so
// record that here in the LoadingSessionHistoryEntry.
bool loadingFromActiveEntry;
if (StaticPrefs::fission_sessionHistoryInParent()) {
loadingFromActiveEntry =
aFrameBC->Canonical()->GetActiveSessionHistoryEntry() == aFrameEntry;
} else {
loadingFromActiveEntry =
aFrameBC->GetDocShell() &&
nsDocShell::Cast(aFrameBC->GetDocShell())->IsOSHE(aFrameEntry);
}
loadState->SetLoadIsFromSessionHistory(mRequestedIndex, Length(),
loadingFromActiveEntry);
nsCOMPtr<nsIURI> originalURI = aFrameEntry->GetOriginalURI();
loadState->SetOriginalURI(originalURI);

View File

@ -16783,14 +16783,7 @@ void Document::AddPendingFrameStaticClone(nsFrameLoaderOwner* aElement,
}
bool Document::ShouldAvoidNativeTheme() const {
bool nativeThemeIsPrefDisabled = false;
#ifndef ANDROID
nativeThemeIsPrefDisabled =
StaticPrefs::widget_disable_native_theme_for_content();
#endif
return nativeThemeIsPrefDisabled &&
return StaticPrefs::widget_disable_native_theme_for_content() &&
(!IsInChromeDocShell() || XRE_IsContentProcess());
}

View File

@ -1,11 +1,19 @@
<html>
<head>
<script>
var winsToClose = []
onbeforeunload = function() {
for (let win of winsToClose) {
if (win) {
win.close();
}
}
};
for (let i = 0; i < 38; i++) {
customElements.define("custom-element_0", class extends HTMLElement {
constructor() {
try { o1 = document.createElement("custom-element_0") } catch (e) {}
try { o2 = window.open("data:,") } catch (e) {}
try { winsToClose.push(window.open("data:,")); } catch (e) {}
}
})
try { o3 = document.createElement("custom-element_0") } catch (e) {}

View File

@ -251,24 +251,13 @@ void nsHistory::PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
aRv = docShell->AddState(aData, aTitle, aUrl, aReplace, aCx);
}
nsIDocShell* nsHistory::GetDocShell() const {
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryReferent(mInnerWindow);
if (!win) {
return nullptr;
}
return win->GetDocShell();
}
already_AddRefed<ChildSHistory> nsHistory::GetSessionHistory() const {
nsIDocShell* docShell = GetDocShell();
NS_ENSURE_TRUE(docShell, nullptr);
nsCOMPtr<nsPIDOMWindowInner> win = do_QueryReferent(mInnerWindow);
NS_ENSURE_TRUE(win, nullptr);
// Get the root DocShell from it
nsCOMPtr<nsIDocShellTreeItem> root;
docShell->GetInProcessSameTypeRootTreeItem(getter_AddRefs(root));
nsCOMPtr<nsIWebNavigation> webNav(do_QueryInterface(root));
NS_ENSURE_TRUE(webNav, nullptr);
BrowsingContext* bc = win->GetBrowsingContext();
NS_ENSURE_TRUE(bc, nullptr);
// Get SH from nsIWebNavigation
return webNav->GetSessionHistory();
RefPtr<ChildSHistory> childSHistory = bc->Top()->GetChildSessionHistory();
return childSHistory.forget();
}

View File

@ -55,8 +55,6 @@ class nsHistory final : public nsISupports, public nsWrapperCache {
protected:
virtual ~nsHistory();
nsIDocShell* GetDocShell() const;
void PushOrReplaceState(JSContext* aCx, JS::Handle<JS::Value> aData,
const nsAString& aTitle, const nsAString& aUrl,
mozilla::ErrorResult& aRv, bool aReplace);

View File

@ -207,20 +207,22 @@ void GamepadPlatformService::AddChannelParent(
MOZ_ASSERT(!mChannelParents.Contains(aParent));
// We use mutex here to prevent race condition with monitor thread
MutexAutoLock autoLock(mMutex);
mChannelParents.AppendElement(aParent);
{
MutexAutoLock autoLock(mMutex);
mChannelParents.AppendElement(aParent);
// For a new GamepadEventChannel, we have to send the exising GamepadAdded
// to it to make it can have the same amount of gamepads with others.
if (mChannelParents.Length() > 1) {
for (const auto& evt : mGamepadAdded) {
GamepadChangeEventBody body(evt.second);
GamepadChangeEvent e(evt.first, GamepadServiceType::Standard, body);
aParent->DispatchUpdateEvent(e);
// For a new GamepadEventChannel, we have to send the exising GamepadAdded
// to it to make it can have the same amount of gamepads with others.
if (mChannelParents.Length() > 1) {
for (const auto& evt : mGamepadAdded) {
GamepadChangeEventBody body(evt.second);
GamepadChangeEvent e(evt.first, GamepadServiceType::Standard, body);
aParent->DispatchUpdateEvent(e);
}
}
}
FlushPendingEvents();
FlushPendingEvents();
}
StartGamepadMonitoring();
}

View File

@ -6902,13 +6902,13 @@ mozilla::ipc::IPCResult ContentParent::RecvHistoryCommit(
}
mozilla::ipc::IPCResult ContentParent::RecvHistoryGo(
const MaybeDiscarded<BrowsingContext>& aContext, int32_t aOffset,
const MaybeDiscarded<BrowsingContext>& aContext, int32_t aIndex,
HistoryGoResolver&& aResolveRequestedIndex) {
if (!aContext.IsDiscarded()) {
nsSHistory* shistory =
static_cast<nsSHistory*>(aContext.get_canonical()->GetSessionHistory());
nsTArray<nsSHistory::LoadEntryResult> loadResults;
nsresult rv = shistory->GotoIndex(aOffset, loadResults);
nsresult rv = shistory->GotoIndex(aIndex, loadResults);
if (NS_FAILED(rv)) {
return IPC_FAIL(this, "GotoIndex failed");
}
@ -6995,6 +6995,37 @@ mozilla::ipc::IPCResult ContentParent::RecvSessionHistoryEntryCacheKey(
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntryForTop(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
uint32_t aLoadType, const nsID& aChangeID) {
if (!aContext.IsDiscarded()) {
aContext.get_canonical()->SetActiveSessionHistoryEntryForTop(
aPreviousScrollPos, &aInfo, aLoadType, aChangeID);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvSetActiveSessionHistoryEntryForFrame(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
int32_t aChildOffset, const nsID& aChangeID) {
if (!aContext.IsDiscarded()) {
aContext.get_canonical()->SetActiveSessionHistoryEntryForFrame(
aPreviousScrollPos, &aInfo, aChildOffset, aChangeID);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvReplaceActiveSessionHistoryEntry(
const MaybeDiscarded<BrowsingContext>& aContext,
SessionHistoryInfo&& aInfo) {
if (!aContext.IsDiscarded()) {
aContext.get_canonical()->ReplaceActiveSessionHistoryEntry(&aInfo);
}
return IPC_OK();
}
mozilla::ipc::IPCResult ContentParent::RecvCommitWindowContextTransaction(
const MaybeDiscarded<WindowContext>& aContext,
WindowContext::BaseTransaction&& aTransaction, uint64_t aEpoch) {

View File

@ -1354,6 +1354,20 @@ class ContentParent final
const MaybeDiscarded<BrowsingContext>& aContext,
const uint32_t& aCacheKey);
mozilla::ipc::IPCResult RecvSetActiveSessionHistoryEntryForTop(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
uint32_t aLoadType, const nsID& aChangeID);
mozilla::ipc::IPCResult RecvSetActiveSessionHistoryEntryForFrame(
const MaybeDiscarded<BrowsingContext>& aContext,
const Maybe<nsPoint>& aPreviousScrollPos, SessionHistoryInfo&& aInfo,
int32_t aChildOffset, const nsID& aChangeID);
mozilla::ipc::IPCResult RecvReplaceActiveSessionHistoryEntry(
const MaybeDiscarded<BrowsingContext>& aContext,
SessionHistoryInfo&& aInfo);
// Notify the ContentChild to enable the input event prioritization when
// initializing.
void MaybeEnableRemoteInputEventQueue();

View File

@ -20,7 +20,7 @@ using struct mozilla::void_t
using moveonly struct mozilla::SerializedStructuredCloneBuffer
from "ipc/IPCMessageUtils.h";
using moveonly mozilla::dom::LoadingSessionHistoryInfo
using class mozilla::dom::LoadingSessionHistoryInfo
from "mozilla/dom/SessionHistoryEntry.h";
using LayoutDeviceIntRect from "Units.h";

View File

@ -129,6 +129,8 @@ using JSActorMessageKind from "mozilla/dom/JSActor.h";
using JSActorMessageMeta from "mozilla/dom/PWindowGlobal.h";
using mozilla::PermissionDelegateHandler::DelegatedPermissionList from "mozilla/PermissionDelegateIPCUtils.h";
using refcounted class nsILayoutHistoryState from "nsILayoutHistoryState.h";
using class mozilla::dom::SessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
using nsPoint from "mozilla/GfxMessageUtils.h";
union ChromeRegistryItem
{
@ -1676,6 +1678,16 @@ parent:
nsID? aAgentClusterId)
returns (BlobURLDataRequestResult aResult);
async SetActiveSessionHistoryEntryForTop(MaybeDiscardedBrowsingContext aContext,
nsPoint? previousScrollPosition,
SessionHistoryInfo info, uint32_t loadType,
nsID changeID);
async SetActiveSessionHistoryEntryForFrame(
MaybeDiscardedBrowsingContext aContext, nsPoint? previousScrollPosition,
SessionHistoryInfo info, int32_t childOffset, nsID changeID);
async ReplaceActiveSessionHistoryEntry(
MaybeDiscardedBrowsingContext aContext, SessionHistoryInfo info);
both:
async ScriptError(nsString message, nsString sourceName, nsString sourceLine,
uint32_t lineNumber, uint32_t colNumber, uint32_t flags,

View File

@ -614,6 +614,23 @@ class IntervalSet {
return false;
}
// Returns if there's any intersection between this and aOther.
bool IntersectsStrict(const SelfType& aOther) const {
const ContainerType& other = aOther.mIntervals;
IndexType i = 0, j = 0;
for (; i < mIntervals.Length() && j < other.Length();) {
if (mIntervals[i].IntersectsStrict(other[j])) {
return true;
}
if (mIntervals[i].mEnd < other[j].mEnd) {
i++;
} else {
j++;
}
}
return false;
}
bool IntersectsWithStrictEnd(const ElemType& aInterval) const {
for (const auto& interval : mIntervals) {
if (interval.IntersectsWithStrictEnd(aInterval)) {

View File

@ -2080,10 +2080,7 @@ void TrackBuffersManager::InsertFrames(TrackBuffer& aSamples,
// the previous step and the next random access point after those removed
// frames.
TimeIntervals intersection = trackBuffer.mBufferedRanges;
intersection.Intersection(aIntervals);
if (!intersection.IsEmpty()) {
if (trackBuffer.mBufferedRanges.IntersectsStrict(aIntervals)) {
if (aSamples[0]->mKeyframe &&
(mType.Type() == MEDIAMIMETYPE("video/webm") ||
mType.Type() == MEDIAMIMETYPE("audio/webm"))) {

View File

@ -2400,20 +2400,14 @@ int64_t GetLastModifiedTime(nsIFile* aFile, bool aPersistent) {
return timestamp;
}
bool FileAlreadyExists(nsresult aValue) {
return aValue == NS_ERROR_FILE_ALREADY_EXISTS;
}
bool FileCorrupted(nsresult aValue) {
return aValue == NS_ERROR_FILE_CORRUPTED;
}
nsresult EnsureDirectory(nsIFile* aDirectory, bool* aCreated) {
AssertIsOnIOThread();
QM_TRY_VAR(const bool exists,
ToResult(aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755),
FileAlreadyExists));
// TODO: Convert to mapOrElse once mozilla::Result supports it.
QM_TRY_VAR(const auto exists,
ToResult(aDirectory->Create(nsIFile::DIRECTORY_TYPE, 0755))
.andThen(OkToOk<false>)
.orElse(ErrToOkOrErr<NS_ERROR_FILE_ALREADY_EXISTS, true>));
if (exists) {
bool isDirectory;
@ -6442,17 +6436,14 @@ nsresult QuotaManager::EnsureStorageIsInitialized() {
}
}
nsCOMPtr<mozIStorageConnection> connection;
QM_TRY_VAR(auto connection,
ToResultInvoke<nsCOMPtr<mozIStorageConnection>>(
std::mem_fn(&mozIStorageService::OpenUnsharedDatabase), ss,
storageFile)
.orElse(ErrToOkOrErr<NS_ERROR_FILE_CORRUPTED, nullptr,
nsCOMPtr<mozIStorageConnection>>));
// TODO: Result<V, E> could have own mapping function for filtering out
// NS_ERROR_FILE_CORRUPTED.
// TODO: We can then use ToResultInvoke here (like below).
QM_TRY_VAR(const auto corrupted,
ToResult(ss->OpenUnsharedDatabase(storageFile,
getter_AddRefs(connection)),
FileCorrupted));
if (corrupted) {
if (!connection) {
// Nuke the database file.
QM_TRY(storageFile->Remove(false));

View File

@ -432,51 +432,17 @@ inline Result<Ok, NotOk> OkIf(bool aValue) {
return Err(NotOk());
}
/**
* Allow MOZ_TRY/QM_TRY to handle `nsresult` values and optionally enforce
* success for some special values.
* This is useful in cases when a specific error shouldn't abort execution of a
* function and we need to distinguish between a normal success and a forced
* success.
*
* Typical use case:
*
* nsresult MyFunc(nsIFile& aDirectory) {
* bool exists;
* QM_TRY_VAR(exists,
* ToResult(aDirectory.Create(nsIFile::DIRECTORY_TYPE, 0755),
* [](auto aValue) {
* return aValue == NS_ERROR_FILE_ALREADY_EXISTS;
* }));
*
* if (exists) {
* QM_TRY(aDirectory.IsDirectory(&isDirectory));
* QM_TRY(isDirectory, NS_ERROR_UNEXPECTED);
* }
*
* return NS_OK;
* }
*
* TODO: Maybe move this to mfbt/ResultExtensions.h
*/
// TODO: Maybe move this to mfbt/ResultExtensions.h
template <auto SuccessValue>
auto OkToOk(Ok) -> Result<decltype(SuccessValue), nsresult> {
return SuccessValue;
}
class Okish {
const bool mEnforced;
public:
explicit Okish(bool aEnforced) : mEnforced(aEnforced) {}
MOZ_IMPLICIT operator bool() const { return mEnforced; }
};
template <typename SuccessEnforcer>
Result<Okish, nsresult> ToResult(nsresult aValue,
const SuccessEnforcer& aSuccessEnforcer) {
if (NS_SUCCEEDED(aValue)) {
return Okish(/* aEnforced */ false);
}
if (aSuccessEnforcer(aValue)) {
return Okish(/* aEnforced */ true);
template <nsresult ErrorValue, auto SuccessValue,
typename V = decltype(SuccessValue)>
auto ErrToOkOrErr(nsresult aValue) -> Result<V, nsresult> {
if (aValue == ErrorValue) {
return V{SuccessValue};
}
return Err(aValue);
}

View File

@ -7,6 +7,8 @@
#include "gtest/gtest.h"
#include "mozilla/dom/quota/QuotaCommon.h"
#include "mozilla/ResultExtensions.h"
#include "nsCOMPtr.h"
#include "nsISupports.h"
using namespace mozilla;
using namespace mozilla::dom::quota;
@ -292,53 +294,88 @@ TEST(QuotaCommon_OkIf, True)
EXPECT_TRUE(res.isOk());
}
TEST(QuotaCommon_SuccessIf, False)
TEST(QuotaCommon_OkIf, False)
{
auto res = OkIf(false);
EXPECT_TRUE(res.isErr());
}
TEST(QuotaCommon_ToResult, SuccessEnforcer_Success)
TEST(QuotaCommon_OkToOk, OkToBool_True)
{
bool flag = false;
auto res = ToResult(NS_OK, [&](auto aValue) {
flag = true;
return false;
});
auto res = OkToOk<true>(Ok());
EXPECT_TRUE(res.isOk());
EXPECT_FALSE(res.unwrap());
EXPECT_FALSE(flag);
EXPECT_EQ(res.unwrap(), true);
}
TEST(QuotaCommon_ToResult, SuccessEnforcer_Failure_EnforcerReturnsTrue)
TEST(QuotaCommon_OkToOk, OkToBool_False)
{
bool flag = false;
auto res = ToResult(NS_ERROR_FAILURE, [&](auto aValue) {
flag = true;
return true;
});
auto res = OkToOk<false>(Ok());
EXPECT_TRUE(res.isOk());
EXPECT_TRUE(res.unwrap());
EXPECT_TRUE(flag);
EXPECT_EQ(res.unwrap(), false);
}
TEST(QuotaCommon_ToResult, SuccessEnforcer_Failure_EnforcerReturnsFalse)
TEST(QuotaCommon_OkToOk, OkToInt_42)
{
bool flag = false;
auto res = OkToOk<42>(Ok());
EXPECT_TRUE(res.isOk());
EXPECT_EQ(res.unwrap(), 42);
}
auto res = ToResult(NS_ERROR_FAILURE, [&](auto aValue) {
flag = true;
return false;
});
TEST(QuotaCommon_ErrToOkOrErr, NsresultToBool_True)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, true>(NS_ERROR_FAILURE);
EXPECT_TRUE(res.isOk());
EXPECT_EQ(res.unwrap(), true);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToBool_True_Err)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, true>(NS_ERROR_UNEXPECTED);
EXPECT_TRUE(res.isErr());
EXPECT_TRUE(flag);
EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToBool_False)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, false>(NS_ERROR_FAILURE);
EXPECT_TRUE(res.isOk());
EXPECT_EQ(res.unwrap(), false);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToBool_False_Err)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, false>(NS_ERROR_UNEXPECTED);
EXPECT_TRUE(res.isErr());
EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToInt_42)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, 42>(NS_ERROR_FAILURE);
EXPECT_TRUE(res.isOk());
EXPECT_EQ(res.unwrap(), 42);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToInt_42_Err)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, 42>(NS_ERROR_UNEXPECTED);
EXPECT_TRUE(res.isErr());
EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToNsCOMPtr_nullptr)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, nullptr, nsCOMPtr<nsISupports>>(
NS_ERROR_FAILURE);
EXPECT_TRUE(res.isOk());
EXPECT_EQ(res.unwrap(), nullptr);
}
TEST(QuotaCommon_ErrToOkOrErr, NsresultToNsCOMPtr_nullptr_Err)
{
auto res = ErrToOkOrErr<NS_ERROR_FAILURE, nullptr, nsCOMPtr<nsISupports>>(
NS_ERROR_UNEXPECTED);
EXPECT_TRUE(res.isErr());
EXPECT_EQ(res.unwrapErr(), NS_ERROR_UNEXPECTED);
}

View File

@ -13,6 +13,7 @@
#include "nsIHttpChannel.h"
#include "nsIMultiPartChannel.h"
#include "nsIURI.h"
#include "nsITransfer.h"
#if defined(XP_WIN)
# include "WinUtils.h"
# include <wininet.h>
@ -1115,7 +1116,7 @@ void nsContentSecurityUtils::LogMessageToConsole(nsIHttpChannel* aChannel,
}
/* static */
bool nsContentSecurityUtils::IsDownloadAllowed(
long nsContentSecurityUtils::ClassifyDownload(
nsIChannel* aChannel, const nsAutoCString& aMimeTypeGuess) {
MOZ_ASSERT(aChannel, "IsDownloadAllowed without channel?");
@ -1151,15 +1152,15 @@ bool nsContentSecurityUtils::IsDownloadAllowed(
if (httpChannel) {
LogMessageToConsole(httpChannel, "MixedContentBlockedDownload");
}
return false;
return nsITransfer::DOWNLOAD_POTENTIALLY_UNSAFE;
}
if (loadInfo->TriggeringPrincipal()->IsSystemPrincipal()) {
return true;
return nsITransfer::DOWNLOAD_ACCEPTABLE;
}
if (!StaticPrefs::dom_block_download_in_sandboxed_iframes()) {
return true;
return nsITransfer::DOWNLOAD_ACCEPTABLE;
}
uint32_t triggeringFlags = loadInfo->GetTriggeringSandboxFlags();
@ -1171,8 +1172,8 @@ bool nsContentSecurityUtils::IsDownloadAllowed(
if (httpChannel) {
LogMessageToConsole(httpChannel, "IframeSandboxBlockedDownload");
}
return false;
return nsITransfer::DOWNLOAD_FORBIDDEN;
}
return true;
}
return nsITransfer::DOWNLOAD_ACCEPTABLE;
}

View File

@ -51,8 +51,8 @@ class nsContentSecurityUtils {
static void PerformCSPFrameAncestorAndXFOCheck(nsIChannel* aChannel);
// Helper function to Check if a Download is allowed;
static bool IsDownloadAllowed(nsIChannel* aChannel,
const nsAutoCString& aMimeTypeGuess);
static long ClassifyDownload(nsIChannel* aChannel,
const nsAutoCString& aMimeTypeGuess);
#if defined(DEBUG)
static void AssertAboutPageHasCSP(mozilla::dom::Document* aDocument);
@ -60,10 +60,6 @@ class nsContentSecurityUtils {
static bool ValidateScriptFilename(const char* aFilename,
bool aIsSystemRealm);
/*
* Checks if a Channel should be able to proceed a download.
*/
static bool IsDownloadAllowed(nsIChannel* aChannel);
// Helper Function to Post a message to the corresponding JS-Console
static void LogMessageToConsole(nsIHttpChannel* aChannel, const char* aMsg);
};

View File

@ -1,3 +1,9 @@
ChromeUtils.defineModuleGetter(
this,
"Downloads",
"resource://gre/modules/Downloads.jsm"
);
let INSECURE_BASE_URL =
getRootDirectory(gTestPath).replace(
"chrome://mochitests/content/",
@ -49,10 +55,41 @@ function shouldConsoleError() {
});
}
async function resetDownloads() {
// Removes all downloads from the download List
let publicList = await Downloads.getList(Downloads.PUBLIC);
let downloads = await publicList.getAll();
for (let download of downloads) {
publicList.remove(download);
await download.finalize(true);
}
}
async function shouldNotifyDownloadUI() {
// Waits until a Blocked download was added to the Download List
let list = await Downloads.getList(Downloads.ALL);
await new Promise(res => {
const view = {
onDownloadAdded: aDownload => {
let { error } = aDownload;
if (
error.becauseBlockedByReputationCheck &&
error.reputationCheckVerdict == Downloads.Error.BLOCK_VERDICT_INSECURE
) {
res(true);
list.removeView(view);
}
},
};
list.addView(view);
});
}
async function runTest(url, link, checkFunction, decscription) {
await SpecialPowers.pushPrefEnv({
set: [["dom.block_download_insecure", true]],
});
await resetDownloads();
let tab = BrowserTestUtils.addTab(gBrowser, url);
gBrowser.selectedTab = tab;
@ -92,7 +129,7 @@ add_task(async function() {
await runTest(
SECURE_BASE_URL,
"insecure",
shouldConsoleError,
() => Promise.all([shouldNotifyDownloadUI(), shouldConsoleError()]),
"Secure -> Insecure should Error"
);
await runTest(

View File

@ -35,6 +35,10 @@ DMABUFTextureData::~DMABUFTextureData() = default;
}
RefPtr<DMABufSurface> surf =
DMABufSurfaceRGBA::CreateDMABufSurface(aSize.width, aSize.height, flags);
if (!surf) {
NS_WARNING("DMABUFTextureData::Create() failed!");
return nullptr;
}
return new DMABUFTextureData(surf, aBackend);
}

View File

@ -1341,7 +1341,16 @@ static bool ParseDate(const CharT* s, size_t length, ClippedTime* result) {
mday = mon;
mon = action;
} else if (year < 0) {
year = mon;
if (mday > 0) {
// If the date is of the form f l month, then when month is
// reached we have f in mon and l in mday. In order to be
// consistent with the f month l and month f l forms, we need to
// swap so that f is in mday and l is in year.
year = mday;
mday = mon;
} else {
year = mon;
}
mon = action;
} else {
return false;
@ -1379,8 +1388,8 @@ static bool ParseDate(const CharT* s, size_t length, ClippedTime* result) {
* If f and l are both greater than or equal to 100 the date
* is invalid.
*
* The year is taken to be either the greater of the values f, l or
* whichever is set to zero.
* The year is taken to be either l, f if f > 31, or whichever
* is set to zero.
*
* Case 2. The input string is of the form "f/m/l" where f, m and l are
* integers, e.g. 7/16/45. mon, mday and year values are adjusted
@ -1396,7 +1405,7 @@ static bool ParseDate(const CharT* s, size_t length, ClippedTime* result) {
return false;
}
if (year > 0 && (mday == 0 || mday > year) && !seenFullYear) {
if (year > 0 && (mday == 0 || mday > 31) && !seenFullYear) {
int temp = year;
year = mday;
mday = temp;

View File

@ -41,21 +41,23 @@ assertEq(new Date("0/10/0").getTime(), new Date(NaN).getTime());
// Written months.
for (let year of Array(1000).keys()) {
let fullDate = new Date(`5/1/${year}`);
let d1 = new Date(`may ${year} 1`);
let d2 = new Date(`may 1 ${year}`);
let d3 = new Date(`1 may ${year}`);
let d4 = new Date(`${year} may 1`);
let d5 = new Date(`1 ${year} may`);
let d6 = new Date(`${year} 1 may`);
let d1 = new Date(`may 1 ${year}`);
let d2 = new Date(`1 may ${year}`);
let d3 = new Date(`1 ${year} may`);
assertEq(d1.getTime(), fullDate.getTime())
assertEq(d2.getTime(), fullDate.getTime())
assertEq(d3.getTime(), fullDate.getTime())
assertEq(d4.getTime(), fullDate.getTime())
assertEq(d5.getTime(), fullDate.getTime())
assertEq(d6.getTime(), fullDate.getTime())
if (year > 31) {
let d4 = new Date(`may ${year} 1`);
let d5 = new Date(`${year} may 1`);
let d6 = new Date(`${year} 1 may`);
assertEq(d4.getTime(), fullDate.getTime())
assertEq(d5.getTime(), fullDate.getTime())
assertEq(d6.getTime(), fullDate.getTime())
}
}
assertEq(new Date("may 1999 1999").getTime(), new Date(NaN).getTime());

View File

@ -10,6 +10,7 @@
<script type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
SimpleTest.requestLongerTimeout(2);
window.openDialog("printpreview_helper.xhtml", "printpreview", "chrome,width=100,height=100,noopener", window);
]]></script>
</window>

View File

@ -733,7 +733,8 @@ nsresult nsPrintJob::DoCommonPrint(bool aIsPrintPreview,
// Now determine how to set up the Frame print UI
printData->mPrintSettings->SetPrintOptions(
nsIPrintSettings::kEnableSelectionRB, !!printData->mSelectionRoot);
nsIPrintSettings::kEnableSelectionRB,
!mDisallowSelectionPrint && printData->mSelectionRoot);
bool printingViaParent =
XRE_IsContentProcess() && Preferences::GetBool("print.print_via_parent");
@ -2534,7 +2535,7 @@ nsresult nsPrintJob::EnablePOsForPrinting() {
// This means we are either printing a selected iframe or
// we are printing the current selection.
MOZ_ASSERT(printRangeType == nsIPrintSettings::kRangeSelection);
NS_ENSURE_STATE(printData->mSelectionRoot);
NS_ENSURE_STATE(!mDisallowSelectionPrint && printData->mSelectionRoot);
// If mSelectionRoot is a selected iframe without a selection, then just
// enable normally from that point.

View File

@ -489,6 +489,66 @@ class MOZ_MUST_USE_TYPE Result final {
: RetResult(unwrap());
}
/**
* Map a function E -> Result<V, E2> over this result's error variant. If
* this result is a success, do not invoke the function and move the success
* over.
*
* `orElse`ing over error values invokes the function to produce a new
* result:
*
* // `orElse` Result<V, int> error variant to another Result<V, int>
* // error variant or Result<V, int> success variant
* auto orElse = [](int x) -> Result<V, int> {
* if (x != 6) {
* return Err(x * x);
* }
* return V(...);
* };
*
* Result<V, int> res(5);
* auto res2 = res.orElse(orElse);
* MOZ_ASSERT(res2.isErr());
* MOZ_ASSERT(res2.unwrapErr() == 25);
*
* Result<V, int> res3(6);
* auto res4 = res3.orElse(orElse);
* MOZ_ASSERT(res4.isOk());
* MOZ_ASSERT(res4.unwrap() == ...);
*
* // `orElse` Result<V, const char*> error variant to Result<V, size_t>
* // error variant or Result<V, size_t> success variant
* auto orElse = [](const char* s) -> Result<V, size_t> {
* if (strcmp(s, "foo")) {
* return Err(strlen(s));
* }
* return V(...);
* };
*
* Result<V, const char*> res("hello, orElse!");
* auto res2 = res.orElse(orElse);
* MOZ_ASSERT(res2.isErr());
* MOZ_ASSERT(res2.unwrapErr() == 14);
*
* Result<V, const char*> res3("foo");
* auto res4 = ress.orElse(orElse);
* MOZ_ASSERT(res4.isOk());
* MOZ_ASSERT(res4.unwrap() == ...);
*
* `orElse`ing over a success does not invoke the function and moves the
* success:
*
* Result<int, E> res(5);
* MOZ_ASSERT(res.isOk());
* Result<int, E2> res2 = res.orElse([](E e) { ... });
* MOZ_ASSERT(res2.isOk());
* MOZ_ASSERT(res2.unwrap() == 5);
*/
template <typename F>
auto orElse(F f) -> Result<V, typename std::result_of_t<F(E)>::err_type> {
return MOZ_UNLIKELY(isErr()) ? f(unwrapErr()) : unwrap();
}
/**
* Given a function V -> Result<V2, E>, apply it to this result's success
* value and return its result. If this result is an error value, it is

View File

@ -293,6 +293,125 @@ static void MapErrTest() {
}
}
static Result<Ok, size_t> strlen_ResultWrapper(const char* aValue) {
return Err(strlen(aValue));
}
static void OrElseTest() {
struct MyError {
int x;
explicit MyError(int y) : x(y) {}
};
struct MyError2 {
int a;
explicit MyError2(int b) : a(b) {}
};
// `orElse`ing over error values, to Result<V, E> (the same error type) error
// variant.
{
MyError err(1);
Result<char, MyError> res(err);
MOZ_RELEASE_ASSERT(res.isErr());
bool invoked = false;
auto res2 = res.orElse([&invoked](const auto err) -> Result<char, MyError> {
MOZ_RELEASE_ASSERT(err.x == 1);
invoked = true;
if (err.x != 42) {
return Err(MyError(2));
}
return 'a';
});
MOZ_RELEASE_ASSERT(res2.isErr());
MOZ_RELEASE_ASSERT(invoked);
MOZ_RELEASE_ASSERT(res2.unwrapErr().x == 2);
}
// `orElse`ing over error values, to Result<V, E> (the same error type)
// success variant.
{
MyError err(42);
Result<char, MyError> res(err);
MOZ_RELEASE_ASSERT(res.isErr());
bool invoked = false;
auto res2 = res.orElse([&invoked](const auto err) -> Result<char, MyError> {
MOZ_RELEASE_ASSERT(err.x == 42);
invoked = true;
if (err.x != 42) {
return Err(MyError(2));
}
return 'a';
});
MOZ_RELEASE_ASSERT(res2.isOk());
MOZ_RELEASE_ASSERT(invoked);
MOZ_RELEASE_ASSERT(res2.unwrap() == 'a');
}
// `orElse`ing over error values, to Result<V, E2> (a different error type)
// error variant.
{
MyError err(1);
Result<char, MyError> res(err);
MOZ_RELEASE_ASSERT(res.isErr());
bool invoked = false;
auto res2 =
res.orElse([&invoked](const auto err) -> Result<char, MyError2> {
MOZ_RELEASE_ASSERT(err.x == 1);
invoked = true;
if (err.x != 42) {
return Err(MyError2(2));
}
return 'a';
});
MOZ_RELEASE_ASSERT(res2.isErr());
MOZ_RELEASE_ASSERT(invoked);
MOZ_RELEASE_ASSERT(res2.unwrapErr().a == 2);
}
// `orElse`ing over error values, to Result<V, E2> (a different error type)
// success variant.
{
MyError err(42);
Result<char, MyError> res(err);
MOZ_RELEASE_ASSERT(res.isErr());
bool invoked = false;
auto res2 =
res.orElse([&invoked](const auto err) -> Result<char, MyError2> {
MOZ_RELEASE_ASSERT(err.x == 42);
invoked = true;
if (err.x != 42) {
return Err(MyError2(2));
}
return 'a';
});
MOZ_RELEASE_ASSERT(res2.isOk());
MOZ_RELEASE_ASSERT(invoked);
MOZ_RELEASE_ASSERT(res2.unwrap() == 'a');
}
// `orElse`ing over success values.
{
Result<int, MyError> res(5);
auto res2 = res.orElse([](const auto err) -> Result<int, MyError> {
MOZ_RELEASE_ASSERT(false);
return Err(MyError(1));
});
MOZ_RELEASE_ASSERT(res2.isOk());
MOZ_RELEASE_ASSERT(res2.unwrap() == 5);
}
// Function pointers instead of lambdas as the `orElse`ing function.
{
Result<Ok, const char*> res("hello");
auto res2 = res.orElse(strlen_ResultWrapper);
MOZ_RELEASE_ASSERT(res2.isErr());
MOZ_RELEASE_ASSERT(res2.unwrapErr() == 5);
}
}
static void AndThenTest() {
// `andThen`ing over success results.
Result<int, const char*> r1(10);
@ -384,6 +503,7 @@ int main() {
ReferenceTest();
MapTest();
MapErrTest();
OrElseTest();
AndThenTest();
UniquePtrTest();
return 0;

View File

@ -8,11 +8,10 @@ installer:
@$(MAKE) -C mobile/android/installer installer
package:
# Setting MOZ_GECKOVIEW_JAR makes the installer generate a separate GeckoView JAR
@$(MAKE) MOZ_GECKOVIEW_JAR=1 -C mobile/android/installer
@$(MAKE) -C mobile/android/installer
stage-package:
$(MAKE) MOZ_GECKOVIEW_JAR=1 -C mobile/android/installer stage-package
$(MAKE) -C mobile/android/installer stage-package
deb: package
@$(MAKE) -C mobile/android/installer deb

View File

@ -31,7 +31,4 @@ MOZ_NO_SMART_CARDS=1
MOZ_RAW=1
# use custom widget for html:select
MOZ_USE_NATIVE_POPUP_WINDOWS=1
MOZ_APP_ID={aa3c5121-dab2-40e2-81ca-7ea25febc110}

View File

@ -8,6 +8,7 @@ import org.mozilla.geckoview.test.rule.GeckoSessionTestRule.WithDisplay
import androidx.test.filters.MediumTest
import androidx.test.ext.junit.runners.AndroidJUnit4
import org.hamcrest.Matchers.*
import org.junit.Ignore
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.geckoview.GeckoResult
@ -261,6 +262,7 @@ class PanZoomControllerTest : BaseSessionTest() {
return result
}
@Ignore // Intermittent failures, Bug 1660357
@WithDisplay(width = 100, height = 100)
@Test
fun touchEventForResult() {

View File

@ -6,13 +6,148 @@
// The JNI wrapper generation tasks depend on the JAR creation task of the :annotations project.
evaluationDependsOn(':annotations')
import groovy.util.FileNameFinder
import java.nio.file.Path
import java.nio.file.Paths
// Bug 1657190: This task works around a bug in the Android-Gradle plugin. When using SNAPSHOT
// builds (and possibly in other situations) the JNI library invalidation process isn't correct. If
// there are two JNI libs `a.so` and `b.so` and a new snapshot updates only `a.so`, then the
// resulting AAR will include both JNI libs but the consuming project's resulting APK will include
// only the modified `a.so`. For GeckoView, it's usually `libxul.so` that is updated. For a
// consumer (like Fenix), this leads to a hard startup crash because `libmozglue.so` will be missing
// when it is read (first, before `libxul.so`)
//
// For !MOZILLA_OFFICIAL builds, we work around this issue to ensure that when *any* library is
// updated then *every* library is updated. We use the ELF build ID baked into each library to
// determine whether any library is updated. We digest (SHA256, for now) all of the ELF build IDs
// and use this as our own Mozilla-specific "library generation ID". We then add our own
// Mozilla-specific ELF section to every library so that they will all be invalidated by the
// Android-Gradle plugin of a consuming project.
class SyncLibsAndUpdateGeneration extends DefaultTask {
@InputDirectory
File source
@OutputDirectory
File destinationDir
// To find the LLVM tools from the Android NDK, there are a few wrinkles. In a compiled build,
// we can use our own `ANDROID_NDK` configure option. But in an artifact build, that isn't
// defined, so we fall back to `android.ndkDirectory` -- but that's defined in
// `local.properties`, which may not define it. In that case, fall back to crawling the
// filesystem.
@Input
String ndkDirectory = {
if (project.mozconfig.substs.ANDROID_NDK) {
return project.mozconfig.substs.ANDROID_NDK
}
if (project.android.ndkDirectory) {
return project.android.ndkDirectory
}
def mozbuild = System.getenv('MOZBUILD_STATE_PATH') ?: "${System.getProperty('user.home')}/.mozbuild"
project.logger.lifecycle("mozbuild: ${mozbuild}")
def files = new FileNameFinder().getFileNames(mozbuild, "android-ndk-*/source.properties")
if (files) {
// It would be nice to sort these by version, but that's too much effort right now.
return project.file(files.first()).parentFile.toString()
}
throw new GradleException("Could not determine Android NDK directory. Set `ndk.dir` in `${project.topsrcdir}/local.properties`")
}()
// The `**` in the pattern depends on the host architecture. We could compute them or bake them
// in, but this is easy enough. `FileNameFinder` won't return a directory, so we find a file
// and return its parent directory.
@Input
File llvmBin = project.file(new FileNameFinder().getFileNames(ndkDirectory, "toolchains/llvm/prebuilt/**/bin/llvm-*").first()).parentFile
// Sibling to `.note.gnu.build-id`.
@Input
String newElfSection = ".note.mozilla.build-id"
@TaskAction
void execute() {
Path root = Paths.get(source.toString())
def libs = project.fileTree(source.toString()).files.collect {
Path lib = Paths.get(it.toString())
root.relativize(lib).toString()
}
def generationId = new ByteArrayOutputStream().withStream { os ->
libs.each { lib ->
// This should never fail. If it does, there's a real problem, so an exception is
// reasonable.
project.exec {
commandLine "${llvmBin}/llvm-readobj"
args '--hex-dump=.note.gnu.build-id'
args "${source}/${lib}"
standardOutput = os
}
}
// Glue all the ordered build ID section dumps together.
def allBuildIDs = os.toString()
// For detailed debugging.
new File("${destinationDir}/${newElfSection}-details").setText(allBuildIDs, 'utf-8')
allBuildIDs.sha256()
}
logger.info("Mozilla-specific library generation ID is ${generationId} (see ${destinationDir}/${newElfSection}-details)")
def generationIdIsStale = libs.any { lib ->
new ByteArrayOutputStream().withStream { os ->
// This can fail, but there's little value letting stderr go to the console in
// general, since it's just noise after a clobber build.
def execResult = project.exec {
ignoreExitValue true
commandLine "${llvmBin}/llvm-readobj"
args "--hex-dump=${newElfSection}"
args "${destinationDir}/${lib}"
standardOutput = os
errorOutput = new ByteArrayOutputStream()
}
if (execResult.exitValue != 0) {
logger.info("Mozilla-specific library generation ID is missing: ${lib}")
} else if (!os.toString().contains(generationId)) {
logger.info("Mozilla-specific library generation ID is stale: ${lib}")
} else {
logger.debug("Mozilla-specific library generation ID is fresh: ${lib}")
}
execResult.exitValue != 0 || !os.toString().contains(generationId)
}
}
if (generationIdIsStale) {
project.mkdir destinationDir
new File("${destinationDir}/${newElfSection}").setText(generationId, 'utf-8')
libs.each { lib ->
project.mkdir project.file("${destinationDir}/${lib}").parent
new ByteArrayOutputStream().withStream { os ->
// This should never fail: if it does, there's a real problem (again).
project.exec {
commandLine "${llvmBin}/llvm-objcopy"
args "--add-section=${newElfSection}=${destinationDir}/${newElfSection}"
args "${source}/${lib}"
args "${destinationDir}/${lib}"
standardOutput = os
}
}
}
} else {
logger.info("Mozilla-specific library generation ID is fresh!")
}
}
}
ext.configureVariantWithGeckoBinaries = { variant ->
// :app needs the full Fennec omni.ja, whereas other projects need the
// GeckoView-specific omni.ja.
def omnijarDir = { "${topobjdir}/dist/${it}" }("app".equals(project.name) ? "fennec" : "geckoview")
// All projects take the same Gecko libraries, which (for historical
// reasons) are in "fennec".
def distDir = "${topobjdir}/dist/fennec"
def omnijarDir = "${topobjdir}/dist/geckoview"
def distDir = "${topobjdir}/dist/geckoview"
def syncOmnijarFromDistDir = task("syncOmnijarFromDistDirFor${variant.name.capitalize()}", type: Sync) {
onlyIf {
@ -30,21 +165,30 @@ ext.configureVariantWithGeckoBinaries = { variant ->
}
}
def syncLibsFromDistDir = task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
onlyIf {
if (!mozconfig.substs.COMPILE_ENVIRONMENT && !mozconfig.substs.MOZ_ARTIFACT_BUILDS) {
// We won't have JNI libraries if we're not compiling and we're not downloading
// artifacts. Such a configuration is used for running lints, generating docs, etc.
return true
}
if (source.empty) {
throw new StopExecutionException("Required JNI libraries not found in ${distDir}/lib. Have you built and packaged?")
}
// For !MOZILLA_OFFICIAL builds, work around an Android-Gradle plugin bug that causes startup
// crashes with local substitution. See class comment above.
def syncLibsFromDistDir = { if (!mozconfig.substs.MOZILLA_OFFICIAL) {
task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: SyncLibsAndUpdateGeneration) {
source file("${distDir}/lib")
destinationDir file("${project.buildDir}/moz.build/src/${variant.name}/jniLibs")
}
} else {
task("syncLibsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
into("${project.buildDir}/moz.build/src/${variant.name}/jniLibs")
from("${distDir}/lib")
}
} }()
syncLibsFromDistDir.onlyIf { task ->
if (!mozconfig.substs.COMPILE_ENVIRONMENT && !mozconfig.substs.MOZ_ARTIFACT_BUILDS) {
// We won't have JNI libraries if we're not compiling and we're not downloading
// artifacts. Such a configuration is used for running lints, generating docs, etc.
return true
}
into("${project.buildDir}/moz.build/src/${variant.name}/jniLibs")
from("${distDir}/lib")
if (files(task.source).empty) {
throw new StopExecutionException("Required JNI libraries not found in ${task.source}. Have you built and packaged?")
}
return true
}
def syncAssetsFromDistDir = task("syncAssetsFromDistDirFor${variant.name.capitalize()}", type: Sync) {
@ -60,15 +204,9 @@ ext.configureVariantWithGeckoBinaries = { variant ->
// moz.build system, which can be re-entrant. Official builds are driven by
// the moz.build system and should never be re-entrant in this way.
if (!mozconfig.substs.MOZILLA_OFFICIAL) {
if ("app".equals(project.name)) {
syncOmnijarFromDistDir.dependsOn rootProject.machStagePackageForFennec
syncLibsFromDistDir.dependsOn rootProject.machStagePackageForFennec
syncAssetsFromDistDir.dependsOn rootProject.machStagePackageForFennec
} else {
syncOmnijarFromDistDir.dependsOn rootProject.machStagePackageForGeckoview
syncLibsFromDistDir.dependsOn rootProject.machStagePackageForGeckoview
syncAssetsFromDistDir.dependsOn rootProject.machStagePackageForGeckoview
}
syncOmnijarFromDistDir.dependsOn rootProject.machStagePackage
syncLibsFromDistDir.dependsOn rootProject.machStagePackage
syncAssetsFromDistDir.dependsOn rootProject.machStagePackage
}
def assetGenTask = tasks.findByName("generate${variant.name.capitalize()}Assets")

View File

@ -42,12 +42,7 @@ ifdef MOZ_ARTIFACT_BUILDS
DEFINES += -DMOZ_ARTIFACT_BUILDS=1
endif
ifdef MOZ_GECKOVIEW_JAR
# Generate a GeckoView-specific omni.ja under dist/geckoview/omni.ja,
# alongside the full omni.ja used by Fennec under dist/fennec/omni.ja.
DEFINES += -DMOZ_GECKOVIEW_JAR=1
MOZ_PKG_DIR = geckoview
endif
ifdef MOZ_ANDROID_FAT_AAR_ARCHITECTURES
DEFINES += -DMOZ_ANDROID_FAT_AAR_ARCHITECTURES=1

View File

@ -24,13 +24,7 @@
@BINPATH@/hyphenation/*
@BINPATH@/localization/*
; We want fennec/lib for both Fennec and GeckoView, so we turn
; geckoview/lib into fennec/lib.
#ifndef MOZ_GECKOVIEW_JAR
[lib destdir="lib/@ANDROID_CPU_ARCH@"]
#else
[lib destdir="../fennec/lib/@ANDROID_CPU_ARCH@"]
#endif
#ifdef MOZ_CLANG_RT_ASAN_LIB
@BINPATH@/@MOZ_CLANG_RT_ASAN_LIB@
@ -139,7 +133,6 @@
; [Default Preferences]
; All the pref files must be part of base to prevent migration bugs
#ifdef MOZ_GECKOVIEW_JAR
#ifndef MOZ_ANDROID_FAT_AAR_ARCHITECTURES
@BINPATH@/@ANDROID_CPU_ARCH@/greprefs.js
@BINPATH@/@PREF_DIR@/@ANDROID_CPU_ARCH@/geckoview-prefs.js
@ -147,10 +140,6 @@
@BINPATH@/*/greprefs.js
@BINPATH@/@PREF_DIR@/*/geckoview-prefs.js
#endif # !MOZ_ANDROID_FAT_AAR_ARCHITECTURES
#else
@BINPATH@/@ANDROID_CPU_ARCH@/greprefs.js
@BINPATH@/@PREF_DIR@/mobile.js
#endif # MOZ_GECKOVIEW_JAR
@BINPATH@/@PREF_DIR@/channel-prefs.js
@BINPATH@/defaults/autoconfig/prefcalls.js
@ -214,12 +203,7 @@
@BINPATH@/chrome/geckoview@JAREXT@
@BINPATH@/chrome/geckoview.manifest
#ifdef MOZ_GECKOVIEW_JAR
@BINPATH@/components/GeckoView.manifest
#else
@BINPATH@/chrome/chrome@JAREXT@
@BINPATH@/chrome/chrome.manifest
#endif
; Remote control protocol
#ifdef ENABLE_MARIONETTE

View File

@ -98,16 +98,6 @@ class MachCommands(MachCommandBase):
return ret
@SubCommand('android', 'generate-fennec-jni-wrappers',
"""Generate Fennec-specific JNI wrappers used when building
Firefox for Android.""")
@CommandArgument('args', nargs=argparse.REMAINDER)
def android_generate_fennec_jni_wrappers(self, args):
ret = self.gradle(
self.substs['GRADLE_ANDROID_GENERATE_FENNEC_JNI_WRAPPERS_TASKS'] + args, verbose=True)
return ret
@SubCommand('android', 'api-lint',
"""Run Android api-lint.
REMOVED/DEPRECATED: Use 'mach lint --linter android-api-lint'.""")

View File

@ -4506,7 +4506,7 @@
#ifdef XP_MACOSX
- name: gfx.webrender.enable-client-storage
type: bool
value: @IS_NIGHTLY_BUILD@
value: true
mirror: once
#endif

View File

@ -11122,6 +11122,12 @@ curv.dev
cyon.link
cyon.site
// Danger Science Group: https://dangerscience.com/
// Submitted by Skylar MacDonald <skylar@dangerscience.com>
fnwk.site
folionetwork.site
platform0.app
// Daplie, Inc : https://daplie.com
// Submitted by AJ ONeal <aj@daplie.com>
daplie.me
@ -12302,6 +12308,10 @@ mayfirst.org
// Submitted by Ilya Zaretskiy <zaretskiy@corp.mail.ru>
hb.cldmail.ru
// mcpe.me : https://mcpe.me
// Submitted by Noa Heyl <hi@noa.dev>
mcpe.me
// McHost : https://mchost.ru
// Submitted by Evgeniy Subbotin <e.subbotin@mchost.ru>
mcdir.ru
@ -12314,7 +12324,7 @@ memset.net
// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/
// Submitted by Zdeněk Šustr <zdenek.sustr@cesnet.cz>
cloud.metacentrum.cz
*.cloud.metacentrum.cz
custom.metacentrum.cz
// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/
@ -12341,6 +12351,10 @@ cloudapp.net
// Submitted by Robert Böttinger <r@minion.systems>
csx.cc
// MobileEducation, LLC : https://joinforte.com
// Submitted by Grayson Martin <grayson.martin@mobileeducation.us>
forte.id
// Mozilla Corporation : https://mozilla.com
// Submitted by Ben Francis <bfrancis@mozilla.com>
mozilla-iot.org
@ -12616,6 +12630,10 @@ cya.gg
// Submitted by Cole Estep <cole@omnibond.com>
cloudycluster.net
// OmniWe Limited: https://omniwe.com
// Submitted by Vicary Archangel <vicary@omniwe.com>
omniwe.site
// One Fold Media : http://www.onefoldmedia.com/
// Submitted by Eddie Jones <eddie@onefoldmedia.com>
nid.io

View File

@ -24,7 +24,7 @@ using class mozilla::TimeStamp from "mozilla/TimeStamp.h";
using refcounted class nsIPropertyBag2 from "mozilla/dom/PropertyBagUtils.h";
using refcounted class nsDOMNavigationTiming from "nsDOMNavigationTiming.h";
using nsILoadInfo::CrossOriginEmbedderPolicy from "nsILoadInfo.h";
using moveonly mozilla::dom::LoadingSessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
using class mozilla::dom::LoadingSessionHistoryInfo from "mozilla/dom/SessionHistoryEntry.h";
namespace mozilla {
namespace net {

View File

@ -1490,7 +1490,6 @@ MOZ_UNIVERSALCHARDET=1
MOZ_XUL=1
MOZ_ZIPWRITER=1
MOZ_NO_SMART_CARDS=
MOZ_USE_NATIVE_POPUP_WINDOWS=
MOZ_EXCLUDE_HYPHENATION_DICTIONARIES=
MOZ_SANDBOX=1
MOZ_BINARY_EXTENSIONS=
@ -1897,10 +1896,6 @@ for extension in $MOZ_EXTENSIONS; do
fi
done
if test -n "$MOZ_USE_NATIVE_POPUP_WINDOWS"; then
AC_DEFINE(MOZ_USE_NATIVE_POPUP_WINDOWS)
fi
# Avoid defining MOZ_ENABLE_CAIRO_FT on Windows platforms because
# "cairo-ft-font.c" includes <dlfcn.h>, which only exists on posix platforms
if test -n "$MOZ_TREE_FREETYPE" -a "$OS_TARGET" != WINNT; then

View File

@ -59,6 +59,8 @@ from taskgraph.util.taskcluster import (
list_artifacts,
)
from mach.util import UserError
from mozbuild.artifact_cache import ArtifactCache
from mozbuild.artifact_builds import JOB_CHOICES
from mozbuild.util import (
@ -991,6 +993,13 @@ class Artifacts(object):
if not hg_hash or hg_hash == zeroes:
continue
hashes.append(hg_hash)
if not hashes:
raise UserError(
'Could not list any recent revisions in your clone. Does your '
'clone have git-cinnabar metadata? If not, consider re-cloning '
'using the directions at '
'https://github.com/glandium/git-cinnabar/wiki/Mozilla:-A-git-'
'workflow-for-Gecko-development')
return hashes
def _get_recent_public_revisions(self):
@ -1010,7 +1019,7 @@ class Artifacts(object):
cwd=self._topsrcdir).splitlines()
if len(last_revs) == 0:
raise Exception("""\
raise UserError("""\
There are no public revisions.
This can happen if the repository is created from bundle file and never pulled
from remote. Please run `hg pull` and build again.

View File

@ -1426,6 +1426,14 @@ class L10NCommands(MachCommandBase):
@CommandArgument('--verbose', action='store_true',
help='Log informative status messages.')
def package_l10n(self, verbose=False, locales=[]):
if 'RecursiveMake' not in self.substs['BUILD_BACKENDS']:
print('Artifact builds do not support localization. '
'If you know what you are doing, you can use:\n'
'ac_add_options --disable-compile-environment\n'
'export BUILD_BACKENDS=FasterMake,RecursiveMake\n'
'in your mozconfig.')
return 1
if 'en-US' not in locales:
self.log(logging.WARN, 'package-multi-locale', {'locales': locales},
'List of locales does not include default locale "en-US": '
@ -1434,6 +1442,9 @@ class L10NCommands(MachCommandBase):
locales = list(sorted(locales))
append_env = {
# We are only (re-)packaging, we don't want to (re-)build
# anything inside Gradle.
'GRADLE_INVOKED_WITHIN_MACH_BUILD': '1',
'MOZ_CHROME_MULTILOCALE': ' '.join(locales),
}

View File

@ -1132,4 +1132,4 @@ static const TransportSecurityPreload kPublicKeyPinningPreloadList[] = {
static const int32_t kUnknownId = -1;
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1606400034096000);
static const PRTime kPreloadPKPinsExpirationTime = INT64_C(1606760753827000);

File diff suppressed because it is too large Load Diff

View File

@ -845,7 +845,7 @@ linux64-asan-fuzzing-ccov/opt:
fetches:
toolchain:
- linux64-binutils
- linux64-clang
- linux64-clang-9
- linux64-rust
- linux64-rust-size
- linux64-cbindgen
@ -854,7 +854,7 @@ linux64-asan-fuzzing-ccov/opt:
- linux64-nasm
- linux64-node
- linux64-lucetc
- wasi-sysroot
- wasi-sysroot-9
linux64-fuzzing-ccov/opt:
description: "Linux64 Fuzzing Opt w/ Coverage"
@ -889,7 +889,7 @@ linux64-fuzzing-ccov/opt:
fetches:
toolchain:
- linux64-binutils
- linux64-clang
- linux64-clang-9
- linux64-gcc-7
- linux64-cbindgen
- linux64-dump-syms
@ -899,7 +899,7 @@ linux64-fuzzing-ccov/opt:
- linux64-nasm
- linux64-node
- linux64-lucetc
- wasi-sysroot
- wasi-sysroot-9
optimization:
build-fuzzing: null
@ -1219,7 +1219,7 @@ linux64-ccov/opt:
fetches:
toolchain:
- linux64-binutils
- linux64-clang
- linux64-clang-9
- linux64-rust
- linux64-gcc-7
- linux64-cbindgen
@ -1229,7 +1229,7 @@ linux64-ccov/opt:
- linux64-node
- linux64-grcov
- linux64-lucetc
- wasi-sysroot
- wasi-sysroot-9
linux64-add-on-devel/opt:
description: "Linux64 add-on-devel"

View File

@ -19,8 +19,6 @@ job-defaults:
fetches:
toolchain:
- linux64-binutils
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-dump-syms
- linux64-hfsplus
- linux64-libdmg
@ -31,7 +29,6 @@ job-defaults:
- linux64-nasm
- linux64-node
- linux64-lucetc
- wasi-sysroot
macosx64/debug:
description: "MacOS X x64 Cross-compile"
@ -56,7 +53,10 @@ macosx64/debug:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
macosx64/opt:
description: "MacOS X x64 Cross-compile"
@ -81,7 +81,10 @@ macosx64/opt:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
macosx64-asan-fuzzing/opt:
description: "MacOS X x64 Cross-compile Fuzzing ASAN"
@ -103,7 +106,10 @@ macosx64-asan-fuzzing/opt:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
optimization:
build-fuzzing: null
@ -129,7 +135,10 @@ macosx64-fuzzing/debug:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
optimization:
build-fuzzing: null
@ -162,6 +171,11 @@ macosx64-devedition/opt:
stage_platform: macosx64-devedition
mozconfig-variant: devedition
run-on-projects: ['mozilla-beta']
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- wasi-sysroot
macosx64-noopt/debug:
description: "MacOS X x64 No-optimize Debug"
@ -184,7 +198,10 @@ macosx64-noopt/debug:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
macosx64-add-on-devel/opt:
description: "MacOS X x64 add-on-devel"
@ -206,7 +223,10 @@ macosx64-add-on-devel/opt:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
macosx64-shippable/opt:
description: "MacOS X x64 Cross-compile"
@ -233,6 +253,11 @@ macosx64-shippable/opt:
- builds/releng_base_firefox.py
- builds/releng_base_mac_64_cross_builds.py
- taskcluster_nightly.py
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- wasi-sysroot
macosx64-ccov/opt:
description: "MacOS X x64 Cross-compile Code Coverage"
@ -257,7 +282,10 @@ macosx64-ccov/opt:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port-clang-9
- linux64-clang-9-macosx-cross
- linux64-sccache
- wasi-sysroot-9
macosx64-gcp/debug:
description: "MacOS X x64 Cross-compile - built on GCP"
@ -283,7 +311,10 @@ macosx64-gcp/debug:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot
optimization:
push-interval-25: null
@ -310,4 +341,7 @@ macosx64-gcp/opt:
use-sccache: true
fetches:
toolchain:
- linux64-cctools-port
- linux64-clang-macosx-cross
- linux64-sccache
- wasi-sysroot

View File

@ -872,7 +872,7 @@ win64-ccov/opt:
use-sccache: true
fetches:
toolchain:
- win64-clang-cl
- win64-clang-cl-9
- win64-rust
- win64-rust-size
- win64-cbindgen

View File

@ -86,6 +86,7 @@ treeherder:
'T-Prof-1proc': 'Talos performance tests on Firefox with Gecko Profiling and without e10s'
'T-Prof-fis': 'Talos performance tests on Firefox with fission and Gecko Profiling'
'T-Prof-gli': 'Talos performance tests with WebGL over IPC and Gecko Profiling'
'T-swr': 'Talos performance tests with software webrender enabled'
'Tss': 'Talos performance tests, Stylo sequential'
'Tss-fis': 'Talos performance tests, Stylo sequential with fission enabled'
'Tss-1proc': 'Talos performance tests with Stylo sequential without e10s'

View File

@ -54,6 +54,10 @@ talos-bcv:
description: "Talos basic compositor video"
try-name: bcv
treeherder-symbol: T(bcv)
variants:
by-test-platform:
linux64.*-qr.*: ['fission', 'webrender-sw']
default: ['fission']
run-on-projects:
by-test-platform:
.*(?:shippable-qr|-qr)/.*: []
@ -195,6 +199,10 @@ talos-g1:
description: "Talos g1"
try-name: g1
treeherder-symbol: T(g1)
variants:
by-test-platform:
linux64.*-qr.*: ['fission', 'webrender-sw']
default: ['fission']
max-run-time:
by-test-platform:
linux64.*: 3600
@ -241,6 +249,10 @@ talos-g4:
description: "Talos g4"
try-name: g4
treeherder-symbol: T(g4)
variants:
by-test-platform:
linux64.*-qr.*: ['fission', 'webrender-sw']
default: ['fission']
run-on-projects:
by-test-platform:
windows10-64-ref-hw-2017/opt: ['mozilla-central']
@ -357,6 +369,10 @@ talos-other:
description: "Talos other"
try-name: other
treeherder-symbol: T(o)
variants:
by-test-platform:
linux64.*-qr.*: ['fission', 'webrender-sw']
default: ['fission']
max-run-time: 1500
mozharness:
extra-options:
@ -441,6 +457,10 @@ talos-svgr:
description: "Talos svgr"
try-name: svgr
treeherder-symbol: T(s)
variants:
by-test-platform:
linux64.*-qr.*: ['fission', 'webrender-sw']
default: ['fission']
max-run-time: 1800
# Bug 1651311 - Disabled for high intermittent failure rate
run-on-projects: []

View File

@ -70,7 +70,7 @@ linux64-clang-9:
toolchain:
- linux64-binutils
- linux64-gcc-7
- wasi-sysroot
- wasi-sysroot-9
linux64-clang-9-mingw-x86:
description: "MinGW-Clang 9 x86 toolchain build"

View File

@ -140,8 +140,8 @@ browsertime:
toolchain:
- linux64-node
wasi-sysroot:
description: "wasi sysroot build process"
wasi-sysroot-9:
description: "wasi sysroot build using clang-9"
attributes:
local-toolchain: true
treeherder:
@ -151,6 +151,7 @@ wasi-sysroot:
script: build-wasi-sysroot.sh
sparse-profile: null
toolchain-artifact: public/build/wasi-sysroot.tar.xz
toolchain-alias: wasi-sysroot
fetches:
fetch:
- clang-9

View File

@ -83,7 +83,7 @@ GARBAGE += $(addsuffix .log,$(MOCHITESTS) reftest crashtest jstestbrowser)
REMOTE_CPPUNITTESTS = \
$(PYTHON3) -u $(topsrcdir)/testing/remotecppunittests.py \
--xre-path=$(DEPTH)/dist/bin \
--localLib=$(DEPTH)/dist/fennec \
--localLib=$(DEPTH)/dist/geckoview \
--deviceIP=${TEST_DEVICE} \
$(TEST_PATH) $(EXTRA_TEST_ARGS)

View File

@ -0,0 +1,4 @@
[2d.gradient.interpolate.colouralpha.html]
[Canvas test: 2d.gradient.interpolate.colouralpha]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]

View File

@ -0,0 +1,4 @@
[2d.gradient.interpolate.overlap.html]
[Canvas test: 2d.gradient.interpolate.overlap]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]

View File

@ -0,0 +1,20 @@
[drawimage_canvas.html]
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 0,0 should be blue.]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 1,1 should be blue.]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 23,23 should be blue.]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 24,24 should be blue.]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]
[Test scenario 12: sx = -20, sy = -20, sw = 50, sh = 50, dx = 20, dy = 20, dw = 125, dh = 125 --- Pixel 82,82 should be blue.]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]

View File

@ -0,0 +1,4 @@
[2d.path.arc.selfintersect.1.html]
[arc() with lineWidth > 2*radius is drawn sensibly]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]

View File

@ -0,0 +1,4 @@
[2d.path.rect.zero.3.html]
[Canvas test: 2d.path.rect.zero.3]
expected:
if (os == "win") and (processor == "x86_64"): ["PASS", "FAIL"]

View File

@ -9,7 +9,7 @@
if not debug and (os == "mac"): TIMEOUT
[coop reporting test Report only tests for an opener without any COOP/COOP report only set to CROSS_ORIGIN with , , same-origin; report-to="coop-popup-report-only-endpoint", ]
expected:
if not debug and (os == "win") and not fission and (processor == "x86_64") and not webrender: TIMEOUT
if not debug and (os == "win") and not fission and (processor == "x86_64") and not webrender: ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and not fission and (processor == "x86_64") and webrender: ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and not fission and (processor == "x86"): ["TIMEOUT", "FAIL"]
if not debug and (os == "linux") and not webrender: ["FAIL", "TIMEOUT"]
@ -23,9 +23,9 @@
[verify remaining reports]
expected:
if not debug and (os == "win") and (processor == "x86_64") and webrender and fission: ["PASS", "NOTRUN"]
if not debug and (os == "win") and (processor == "x86_64") and webrender and not fission: ["NOTRUN", "PASS"]
if not debug and (os == "win") and (processor == "x86_64") and not webrender: NOTRUN
if not debug and (os == "win") and (processor == "x86_64") and webrender and fission: ["PASS", "NOTRUN", "TIMEOUT"]
if not debug and (os == "win") and (processor == "x86_64") and webrender and not fission: ["NOTRUN", "PASS", "TIMEOUT"]
if not debug and (os == "win") and (processor == "x86_64") and not webrender: ["NOTRUN", "TIMEOUT"]
if not debug and (os == "linux") and not webrender: ["PASS", "NOTRUN"]
if not debug and (os == "linux") and webrender: NOTRUN
if not debug and (os == "win") and (processor == "x86"): ["NOTRUN", "PASS", "TIMEOUT"]

View File

@ -8,7 +8,7 @@
[coop reporting test reporting same origin with report-to to CROSS_ORIGIN with , , same-origin; report-to="coop-popup-report-only-endpoint", ]
expected:
if not debug and not webrender and (os == "win") and (processor == "x86"): ["FAIL", "TIMEOUT"]
if not debug and not webrender and (os == "win") and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
if not debug and not webrender and (os == "linux"): ["FAIL", "TIMEOUT"]
if not debug and not webrender and (os == "mac"): TIMEOUT
if not debug and webrender: TIMEOUT
@ -16,7 +16,7 @@
[coop reporting test reporting same origin with report-to to SAME_ORIGIN with , , same-origin; report-to="coop-popup-report-only-endpoint", ]
expected:
if not debug and not webrender and (os == "win") and (processor == "x86_64"): ["NOTRUN", "TIMEOUT"]
if not debug and (os == "win") and (processor == "x86_64"): ["NOTRUN", "TIMEOUT"]
if not debug and not webrender and (os == "win") and (processor == "x86"): ["TIMEOUT", "NOTRUN"]
if not debug and not webrender and (os == "linux"): ["PASS", "NOTRUN", "TIMEOUT"]
if not debug and not webrender and (os == "mac"): NOTRUN

View File

@ -9,7 +9,7 @@
[coop reporting test reporting same origin with report-to to SAME_ORIGIN with unsafe-none, , , ]
expected:
if debug and (os == "win") and not webrender and (processor == "x86"): ["TIMEOUT", "FAIL"]
if debug and (os == "win") and not webrender and (processor == "x86_64"): TIMEOUT
if debug and (os == "win") and not webrender and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
if debug and (os == "win") and webrender: ["TIMEOUT", "FAIL"]
if not debug and (os == "linux") and not webrender: ["TIMEOUT", "NOTRUN", "FAIL"]
if debug and (os == "linux"): ["TIMEOUT", "FAIL"]
@ -29,7 +29,7 @@
expected:
if (os == "win") and (processor == "x86_64") and webrender and not debug and not fission: NOTRUN
if (os == "linux") and webrender and not fission: NOTRUN
if (os == "win") and (processor == "x86_64") and not webrender: NOTRUN
if (os == "win") and (processor == "x86_64") and not webrender: ["NOTRUN", "TIMEOUT"]
if os == "mac": NOTRUN
[NOTRUN, PASS]

View File

@ -7,7 +7,7 @@
if not debug and (processor == "x86"): ["TIMEOUT", "OK"]
[coop reporting test reporting same origin to SAME_ORIGIN with unsafe-none; report-to="coop-popup-report-endpoint", , , ]
expected:
if not debug and (os == "win") and not webrender and (processor == "x86_64"): TIMEOUT
if not debug and (os == "win") and not webrender and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and not webrender and (processor == "x86"): ["TIMEOUT", "FAIL"]
if not debug and (os == "linux") and webrender: ["TIMEOUT", "FAIL"]
if not debug and (os == "linux") and not webrender: ["FAIL", "TIMEOUT"]
@ -18,7 +18,7 @@
[coop reporting test reporting same origin to CROSS_ORIGIN with unsafe-none; report-to="coop-popup-report-endpoint", , , ]
expected:
if not debug and not webrender and (os == "win") and (processor == "x86"): ["NOTRUN", "FAIL", "TIMEOUT"]
if not debug and not webrender and (os == "win") and (processor == "x86_64"): NOTRUN
if not debug and not webrender and (os == "win") and (processor == "x86_64"): ["NOTRUN", "TIMEOUT"]
if not debug and not webrender and (os == "linux"): ["FAIL", "NOTRUN", "TIMEOUT"]
if not debug and not webrender and (os == "mac"): NOTRUN
if not debug and webrender: ["NOTRUN", "TIMEOUT"]

View File

@ -9,7 +9,7 @@
if not debug and (os == "win") and webrender and fission: ["NOTRUN", "TIMEOUT"]
if not debug and (os == "win") and webrender and not fission: ["NOTRUN", "TIMEOUT"]
if not debug and (os == "win") and not webrender and (processor == "x86"): TIMEOUT
if not debug and (os == "win") and not webrender and (processor == "x86_64"): NOTRUN
if not debug and (os == "win") and not webrender and (processor == "x86_64"): ["NOTRUN", "TIMEOUT"]
if not debug and (os == "linux") and webrender: NOTRUN
if not debug and (os == "linux") and not webrender: ["FAIL", "NOTRUN", "TIMEOUT"]
if not debug and (os == "mac"): NOTRUN
@ -19,7 +19,7 @@
expected:
if not debug and (os == "win") and webrender and not fission: ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and webrender and fission: ["TIMEOUT", "FAIL"]
if not debug and (os == "win") and not webrender and (processor == "x86_64"): TIMEOUT
if not debug and (os == "win") and not webrender and (processor == "x86_64"): ["TIMEOUT", "FAIL"]
if not debug and (os == "linux") and not webrender: ["FAIL", "TIMEOUT"]
if not debug and (os == "linux") and webrender: TIMEOUT
if not debug and (os == "mac"): TIMEOUT

View File

@ -4,6 +4,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL

View File

@ -3,6 +3,7 @@
expected:
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
if not debug and (os == "mac"): PASS
FAIL
@ -12,6 +13,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL

View File

@ -4,6 +4,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL
@ -12,6 +13,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL

View File

@ -4,6 +4,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL
@ -12,6 +13,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL

View File

@ -4,6 +4,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL
@ -12,6 +13,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL

View File

@ -4,6 +4,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL
@ -12,6 +13,7 @@
if not debug and (os == "linux") and webrender: ["PASS", "FAIL"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if not debug and (os == "mac"): PASS
if (os == "win") and ccov: FAIL
if not debug and (os == "win"): PASS
FAIL
@ -19,6 +21,7 @@
expected:
if not debug and (os == "linux") and webrender: ["FAIL", "PASS"]
if not debug and (os == "linux") and not webrender: ["PASS", "FAIL"]
if (os == "win") and ccov: PASS
if not debug and (os == "win"): FAIL
if not debug and (os == "mac"): FAIL

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